pax_global_header 0000666 0000000 0000000 00000000064 13654710407 0014521 g ustar 00root root 0000000 0000000 52 comment=0b5953a877a3024d1e515eb7d00de30ffe9794f3
teamwork-5.1.0/ 0000775 0000000 0000000 00000000000 13654710407 0013355 5 ustar 00root root 0000000 0000000 teamwork-5.1.0/.gitignore 0000775 0000000 0000000 00000000154 13654710407 0015350 0 ustar 00root root 0000000 0000000 **/node_modules
**/package-lock.json
coverage.*
**/.DS_Store
**/._*
**/*.pem
**/.vs
**/.vscode
**/.idea
teamwork-5.1.0/.travis.yml 0000775 0000000 0000000 00000000213 13654710407 0015465 0 ustar 00root root 0000000 0000000 language: node_js
node_js:
- "12"
- "14"
- "node"
sudo: false
install:
- "npm install"
os:
- "linux"
- "osx"
- "windows"
teamwork-5.1.0/LICENSE.md 0000775 0000000 0000000 00000002675 13654710407 0014776 0 ustar 00root root 0000000 0000000 Copyright (c) 2015-2020, Sideway Inc, and project contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
* The names of any contributors may not be used to endorse or promote products derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS OFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
teamwork-5.1.0/README.md 0000775 0000000 0000000 00000001713 13654710407 0014641 0 ustar 00root root 0000000 0000000
# @hapi/teamwork
#### Wait for multiple callbacks
**teamwork** is part of the **hapi** ecosystem and was designed to work seamlessly with the [hapi web framework](https://hapi.dev) and its other components (but works great on its own or with other frameworks). If you are using a different web framework and find this module useful, check out [hapi](https://hapi.dev) – they work even better together.
### Visit the [hapi.dev](https://hapi.dev) Developer Portal for tutorials, documentation, and support
## Useful resources
- [Version status](https://hapi.dev/resources/status/#teamwork) (builds, dependencies, node versions, licenses, eol)
- [Changelog](https://hapi.dev/family/teamwork/changelog/)
- [Project policies](https://hapi.dev/policies/)
- [Free and commercial support options](https://hapi.dev/support/)
teamwork-5.1.0/lib/ 0000775 0000000 0000000 00000000000 13654710407 0014123 5 ustar 00root root 0000000 0000000 teamwork-5.1.0/lib/index.d.ts 0000775 0000000 0000000 00000004406 13654710407 0016033 0 ustar 00root root 0000000 0000000 /**
* Team bridges between callbacks and promises. Used to convert callback-based
* interfaces to a promise-based result including support for collecting multiple
* callback events into a single promise.
*/
export class Team {
/**
* Start a new team work.
*
* @param options Configuration of the team work.
*/
constructor(options?: Team.Options);
/**
* Resulting work when all the meetings are done.
*/
work: Promise;
/**
* Attend a single meeting.
*
* @param note An optional note that will be included in the work's results. If an error is provided, the work will be immediately rejected with that error.
*/
attend(note?: Error | Team.ElementOf): void;
/**
* Wait for the current work to be done and start another team work.
*
* @param options New configuration of the team work.
*
* @returns a promise that resolves when the current work is done.
*/
regroup(options?: Team.Options) : Promise;
}
export namespace Team {
/**
* Configuration of the team work.
*/
export interface Options {
/**
* Number of meetings this team should attend before delivering work.
*
* @default 1
*/
readonly meetings?: number;
/**
* Throws when the team attends more than the expected number of `meetings`.
*
* @default false
*/
readonly strict?: boolean;
}
type ElementOf = T extends (infer E)[] ? E : T;
}
/**
* Events emitter via an async iterator interface.
*/
export class Events {
/**
* Returns a standard async iterator interface object.
*
* @returns async iterator interface object.
*/
iterator(): Events.Iterator;
/**
* Emits an event to be consumed via the iterator.
*
* @param value
*/
emit(value: T): void;
/**
* Informs the iterator that no new events will be emitted.
*/
end(): void;
}
export namespace Events {
class Iterator implements AsyncIterator {
constructor(events: Events);
[Symbol.asyncIterator](): AsyncIterator;
next(): Promise>;
}
}
teamwork-5.1.0/lib/index.js 0000775 0000000 0000000 00000004206 13654710407 0015575 0 ustar 00root root 0000000 0000000 'use strict';
const internals = {};
exports.Team = class {
#meetings = null;
#count = null;
#notes = null;
#done = false;
#strict = false;
constructor(options) {
this._init(options);
}
_init(options = {}) {
this.work = new Promise((resolve, reject) => {
this._resolve = resolve;
this._reject = reject;
});
const meetings = options.meetings || 1;
this.#meetings = meetings;
this.#count = meetings;
this.#notes = [];
this.#done = false;
this.#strict = options.strict;
}
attend(note) {
if (this.#strict && this.#done) {
throw new Error('Unscheduled meeting');
}
if (note instanceof Error) {
this.#done = true;
return this._reject(note);
}
this.#notes.push(note);
if (--this.#count) {
return;
}
this.#done = true;
return this._resolve(this.#meetings === 1 ? this.#notes[0] : this.#notes);
}
async regroup(options) {
await this.work;
this._init(options);
}
};
exports.Events = class {
#pending = null;
#queue = [];
static isIterator(iterator) {
return iterator instanceof internals.EventsIterator;
}
iterator() {
return new internals.EventsIterator(this);
}
emit(value) {
this._queue({ value, done: false });
}
end() {
this._queue({ done: true });
}
_next() {
if (this.#queue.length) {
return Promise.resolve(this.#queue.shift());
}
this.#pending = new exports.Team();
return this.#pending.work;
}
_queue(item) {
if (this.#pending) {
this.#pending.attend(item);
this.#pending = null;
}
else {
this.#queue.push(item);
}
}
};
internals.EventsIterator = class {
#events = null;
constructor(events) {
this.#events = events;
}
[Symbol.asyncIterator]() {
return this;
}
next() {
return this.#events._next();
}
};
teamwork-5.1.0/package.json 0000775 0000000 0000000 00000001143 13654710407 0015645 0 ustar 00root root 0000000 0000000 {
"name": "@hapi/teamwork",
"description": "Wait for multiple callback",
"version": "5.1.0",
"repository": "git://github.com/hapijs/teamwork",
"main": "lib/index.js",
"files": [
"lib"
],
"keywords": [
"async",
"flow control",
"callback"
],
"types": "lib/index.d.ts",
"engines": {
"node": ">=12.0.0"
},
"dependencies": {},
"devDependencies": {
"@hapi/code": "8.x.x",
"@hapi/lab": "22.x.x"
},
"scripts": {
"test": "lab -a @hapi/code -t 100 -L -Y",
"test-cov-html": "lab -a @hapi/code -r html -o coverage.html"
},
"license": "BSD-3-Clause"
}
teamwork-5.1.0/test/ 0000775 0000000 0000000 00000000000 13654710407 0014334 5 ustar 00root root 0000000 0000000 teamwork-5.1.0/test/index.js 0000775 0000000 0000000 00000007477 13654710407 0016023 0 ustar 00root root 0000000 0000000 'use strict';
const Code = require('@hapi/code');
const Lab = require('@hapi/lab');
const Teamwork = require('..');
const internals = {};
const { describe, it } = exports.lab = Lab.script();
const expect = Code.expect;
describe('Team', () => {
it('resolves when meeting is attended', async () => {
const team = new Teamwork.Team();
setTimeout(() => {
team.attend();
}, 100);
await team.work;
});
it('resolves when all meetings are attended', async () => {
const team = new Teamwork.Team({ meetings: 2 });
let count = '';
setTimeout(() => {
count += '1';
team.attend();
}, 100);
setTimeout(() => {
count += '2';
team.attend();
}, 150);
await team.work;
expect(count).to.equal('12');
expect(() => team.attend()).not.to.throw();
expect(() => team.attend(new Error())).not.to.throw();
});
it('throws when too many meetings attended', async () => {
const team = new Teamwork.Team({ meetings: 2, strict: true });
team.attend();
team.attend();
await team.work;
expect(() => team.attend()).to.throw('Unscheduled meeting');
expect(() => team.attend(new Error())).to.throw('Unscheduled meeting');
});
it('resolves with a note', async () => {
const team = new Teamwork.Team();
setTimeout(() => {
team.attend('1');
}, 100);
const note = await team.work;
expect(note).to.equal('1');
});
it('resolves with notes', async () => {
const team = new Teamwork.Team({ meetings: 2 });
setTimeout(() => {
team.attend('1');
}, 100);
setTimeout(() => {
team.attend('2');
}, 150);
const notes = await team.work;
expect(notes).to.equal(['1', '2']);
});
it('rejects on first error', async () => {
const team = new Teamwork.Team({ meetings: 2 });
setTimeout(() => {
team.attend(new Error('boom'));
}, 100);
setTimeout(() => {
team.attend('2');
}, 150);
await expect(team.work).to.reject('boom');
});
it('resets condition after initial condition met', async () => {
const team = new Teamwork.Team({ meetings: 2, strict: true });
let count = '';
setTimeout(() => {
count += '1';
team.attend();
}, 100);
setTimeout(() => {
count += '2';
team.attend();
}, 150);
await team.regroup({ strict: true });
expect(count).to.equal('12');
setTimeout(() => {
count += '3';
team.attend();
}, 150);
await team.work;
expect(count).to.equal('123');
});
});
describe('Events', () => {
it('iterates over events', async () => {
const events = new Teamwork.Events();
const iterator = events.iterator();
expect(Teamwork.Events.isIterator(iterator)).to.be.true();
const collect = new Promise(async (resolve) => {
const items = [];
for await (const item of iterator) {
items.push(item);
}
resolve(items);
});
events.emit(1);
events.emit(2);
events.emit(3);
events.end();
expect(await collect).to.equal([1, 2, 3]);
});
it('iterates over events (queued)', async () => {
const events = new Teamwork.Events();
events.emit(1);
events.emit(2);
events.emit(3);
events.end();
const items = [];
for await (const item of events.iterator()) {
items.push(item);
}
expect(items).to.equal([1, 2, 3]);
});
});
teamwork-5.1.0/test/index.ts 0000775 0000000 0000000 00000003527 13654710407 0016025 0 ustar 00root root 0000000 0000000 import * as Code from '@hapi/code';
import * as Lab from '@hapi/lab';
import * as Teamwork from '..';
const { expect } = Lab.types;
// Team
// Constructor tests
expect.type(new Teamwork.Team());
expect.type(new Teamwork.Team({ meetings: 2 }));
expect.type(new Teamwork.Team({ strict: true }));
expect.error(new Teamwork.Team({ foo: true }));
expect.error(new Teamwork.Team({ meetings: 'foo' }));
expect.type>(new Teamwork.Team().work);
// Attend tests
expect.type(new Teamwork.Team().attend());
expect.type(new Teamwork.Team().attend(new Error()));
expect.type(new Teamwork.Team().attend('foo'));
expect.type(new Teamwork.Team().attend('foo'));
expect.error(new Teamwork.Team().attend('foo'));
expect.error(new Teamwork.Team().attend('foo'));
expect.type(new Teamwork.Team<[boolean, string]>().attend('foo'));
// Work tests
expect.type>(new Teamwork.Team().work);
expect.type>(new Teamwork.Team().work);
expect.type>(new Teamwork.Team().work);
// Regroup tests
expect.type>(new Teamwork.Team().regroup());
expect.type>(new Teamwork.Team().regroup({ meetings: 2 }));
expect.type>(new Teamwork.Team().regroup({ strict: true }));
// Events
const events = new Teamwork.Events();
expect.error(events.emit(1));
const iterator = events.iterator();
expect.type>(iterator);
const test = async function () {
const events = new Teamwork.Events();
events.emit(1);
events.emit(2);
events.emit(3);
events.end();
const items = [];
for await (const item of events.iterator()) {
items.push(item);
}
Code.expect(items).to.equal([1, 2, 3]);
};
test();