From ee002ea1cd8aafeb03d5cdd39516ff538aca2112 Mon Sep 17 00:00:00 2001 From: Dmitriy Mozgovoy Date: Sun, 22 Nov 2020 16:54:47 +0200 Subject: [PATCH] Added signals support; Added pause/resume methods; Added allSettled method; Removed CPromiseScope; Refactored; --- README.md | 493 +++++---- jsdoc2md/README.hbs.md | 13 +- lib/abort-controller.js | 23 +- lib/c-promise.js | 1159 ++++++++++---------- lib/c-promise2.js | 1235 ++++++++++++++++++++++ lib/utils.js | 53 + package-lock.json | 2055 +----------------------------------- package.json | 2 + test/tests/CPromise.js | 233 +++- test/tests/EventEmitter.js | 53 - test/tests/PromiseScope.js | 38 - 11 files changed, 2362 insertions(+), 2995 deletions(-) create mode 100644 lib/c-promise2.js create mode 100644 lib/utils.js delete mode 100644 test/tests/EventEmitter.js delete mode 100644 test/tests/PromiseScope.js diff --git a/README.md b/README.md index 03a2e11..82a0bd1 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,14 @@ ![David](https://img.shields.io/david/DigitalBrainJS/c-promise) ## SYNOPSIS :sparkles: -A Promise class built on top of the native that supports some additional features such as cancellation, timeouts, progress capturing and concurrency limit. + +This library provides an advanced version of the built-in Promise by subclassing. +You might be interested in using it if you need the following features: +- promise cancellation (including nested) +- progress capturing +- promise suspending +- timeouts +- concurrent limit for `all` and `allSettled` methods with `mapper` reducer In terms of the library **the cancellation means rejection with a special error subclass**. @@ -79,6 +86,8 @@ has lost its relevance to you. - `CPromise.all` supports concurrency limit - `CPromise.all` and `CPromise.race` methods have cancellation support, so the others nested pending promises will be canceled when the result promise settled + - promise suspending (using `pause` and `resume` methods) + - custom signals (`emitSignal`) - `delay` method to return promise that will be resolved with the value after timeout - ability to set the `weight` for each promise in the chain to manage the impact on chain progress - ability to attach meta info on each setting of the progress @@ -222,7 +231,7 @@ const promise= CPromise.from(function*(){ yield [[CPromise.delay(1000), CPromise.delay(1500)]] // resolve chains using CPromise.race([...chains]); yield new CPromise(resolve=> resolve(true)); // any thenable object will be resolved return "It works!"; -}, [1, 2, 3]) +}) .progress(value=> console.log(`Progress: ${value}`)) .then(message=> console.log(`Done: ${message}`)); ```` @@ -237,185 +246,201 @@ Cancellable Promise with extra features * [CPromise](#module_CPromise) - * [~CPromiseScope](#module_CPromise..CPromiseScope) ⇐ TinyEventEmitter - * [new CPromiseScope(resolve, reject, options)](#new_module_CPromise..CPromiseScope_new) - * _instance_ - * [.signal](#module_CPromise..CPromiseScope+signal) : AbortSignal - * [.isPending](#module_CPromise..CPromiseScope+isPending) ⇒ Boolean - * [.isCanceled](#module_CPromise..CPromiseScope+isCanceled) ⇒ Boolean - * [.isCaptured](#module_CPromise..CPromiseScope+isCaptured) ⇒ boolean - * [.onCancel(listener)](#module_CPromise..CPromiseScope+onCancel) ⇒ CPromiseScope - * [.totalWeight([weight])](#module_CPromise..CPromiseScope+totalWeight) ⇒ Number \| CPromiseScope - * [.innerWeight([weight])](#module_CPromise..CPromiseScope+innerWeight) ⇒ Number \| CPromiseScope - * [.progress(value, [data])](#module_CPromise..CPromiseScope+progress) - * [.propagate(type, data)](#module_CPromise..CPromiseScope+propagate) ⇒ CPromiseScope - * [.captureProgress([options])](#module_CPromise..CPromiseScope+captureProgress) ⇒ CPromiseScope - * [.scopes()](#module_CPromise..CPromiseScope+scopes) ⇒ Array.<CPromiseScope> - * [.timeout(ms)](#module_CPromise..CPromiseScope+timeout) ⇒ Number \| CPromiseScope - * [.weight(weight)](#module_CPromise..CPromiseScope+weight) ⇒ Number \| CPromiseScope - * [.label(label)](#module_CPromise..CPromiseScope+label) ⇒ Number \| CPromiseScope - * [.resolve(value)](#module_CPromise..CPromiseScope+resolve) - * [.reject(err)](#module_CPromise..CPromiseScope+reject) - * [.done(err, value)](#module_CPromise..CPromiseScope+done) - * [.cancel([reason])](#module_CPromise..CPromiseScope+cancel) - * _static_ - * [.execute(executor, resolve, reject, options)](#module_CPromise..CPromiseScope.execute) ⇒ CPromiseScope * [~CPromise](#module_CPromise..CPromise) ⇐ Promise * [new CPromise(executor, [options])](#new_module_CPromise..CPromise_new) * _instance_ + * [.signal](#module_CPromise..CPromise+signal) : AbortSignal * [.isPending](#module_CPromise..CPromise+isPending) ⇒ Boolean * [.isCanceled](#module_CPromise..CPromise+isCanceled) ⇒ Boolean - * [.progress(listener)](#module_CPromise..CPromise+progress) ⇒ Number \| CPromise - * [.captureProgress(options)](#module_CPromise..CPromise+captureProgress) ⇒ CPromise - * [.cancel(reason)](#module_CPromise..CPromise+cancel) ⇒ Boolean + * [.isCaptured](#module_CPromise..CPromise+isCaptured) ⇒ Boolean + * [.isPaused](#module_CPromise..CPromise+isPaused) ⇒ Boolean + * [.parent](#module_CPromise..CPromise+parent) ⇒ CPromise \| null + * [.totalWeight([weight])](#module_CPromise..CPromise+totalWeight) ⇒ Number \| CPromise + * [.innerWeight([weight])](#module_CPromise..CPromise+innerWeight) ⇒ Number \| CPromise + * [.progress(value, [data])](#module_CPromise..CPromise+progress) ⇒ Number \| CPromise + * [.propagate(type, data)](#module_CPromise..CPromise+propagate) ⇒ CPromise + * [.captureProgress([options])](#module_CPromise..CPromise+captureProgress) ⇒ CPromise + * [.scopes()](#module_CPromise..CPromise+scopes) ⇒ Array.<CPromise> + * [.timeout([ms])](#module_CPromise..CPromise+timeout) ⇒ Number \| CPromise + * [.weight([weight])](#module_CPromise..CPromise+weight) ⇒ Number \| CPromise + * [.label([label])](#module_CPromise..CPromise+label) ⇒ Number \| CPromise + * [.resolve(value)](#module_CPromise..CPromise+resolve) ⇒ CPromise + * [.reject(err)](#module_CPromise..CPromise+reject) ⇒ CPromise + * [.pause()](#module_CPromise..CPromise+pause) ⇒ Boolean + * [.resume()](#module_CPromise..CPromise+resume) ⇒ Boolean + * [.cancel([reason])](#module_CPromise..CPromise+cancel) + * [.emitSignal(type, data)](#module_CPromise..CPromise+emitSignal) ⇒ Boolean * [.delay(ms)](#module_CPromise..CPromise+delay) ⇒ CPromise * [.then(onFulfilled, [onRejected])](#module_CPromise..CPromise+then) ⇒ CPromise * [.catch(onRejected, [filter])](#module_CPromise..CPromise+catch) ⇒ CPromise + * [.listenersCount(type)](#module_CPromise..CPromise+listenersCount) ⇒ Number + * [.hasListeners(type)](#module_CPromise..CPromise+hasListeners) ⇒ Boolean + * [.once(type, listener)](#module_CPromise..CPromise+once) ⇒ CPromise + * [.emit(type, ...args)](#module_CPromise..CPromise+emit) ⇒ CPromise + * [.emitHook(type, ...args)](#module_CPromise..CPromise+emitHook) ⇒ Boolean * _static_ * [.isCanceledError(thing)](#module_CPromise..CPromise.isCanceledError) ⇒ boolean * [.delay(ms, value)](#module_CPromise..CPromise.delay) ⇒ CPromise * [.all(iterable, options)](#module_CPromise..CPromise.all) ⇒ CPromise * [.race(thenables)](#module_CPromise..CPromise.race) ⇒ CPromise + * [.allSettled(iterable, options)](#module_CPromise..CPromise.allSettled) ⇒ CPromise * [.from(thing, [resolveSignatures])](#module_CPromise..CPromise.from) ⇒ CPromise - * [~PromiseScopeOptions](#module_CPromise..PromiseScopeOptions) : Object - * [~onFulfilled](#module_CPromise..onFulfilled) : function - * [~onRejected](#module_CPromise..onRejected) : function - * [~OnCancelListener](#module_CPromise..OnCancelListener) : function + * [~EventType](#module_CPromise..EventType) : String \| Symbol * [~CPromiseExecutorFn](#module_CPromise..CPromiseExecutorFn) : function - * [~CPromiseOptions](#module_CPromise..CPromiseOptions) : PromiseScopeOptions \| String \| Number + * [~PromiseOptionsObject](#module_CPromise..PromiseOptionsObject) : Object + * [~CPromiseOptions](#module_CPromise..CPromiseOptions) : PromiseOptionsObject \| String \| Number + * [~OnCancelListener](#module_CPromise..OnCancelListener) : function + * [~OnPauseListener](#module_CPromise..OnPauseListener) : function + * [~OnResumeListener](#module_CPromise..OnResumeListener) : function * [~AllOptions](#module_CPromise..AllOptions) : object - + -### CPromise~CPromiseScope ⇐ TinyEventEmitter -Scope for CPromises instances +### CPromise~CPromise ⇐ Promise +CPromise class **Kind**: inner class of [CPromise](#module_CPromise) -**Extends**: TinyEventEmitter +**Extends**: Promise -* [~CPromiseScope](#module_CPromise..CPromiseScope) ⇐ TinyEventEmitter - * [new CPromiseScope(resolve, reject, options)](#new_module_CPromise..CPromiseScope_new) +* [~CPromise](#module_CPromise..CPromise) ⇐ Promise + * [new CPromise(executor, [options])](#new_module_CPromise..CPromise_new) * _instance_ - * [.signal](#module_CPromise..CPromiseScope+signal) : AbortSignal - * [.isPending](#module_CPromise..CPromiseScope+isPending) ⇒ Boolean - * [.isCanceled](#module_CPromise..CPromiseScope+isCanceled) ⇒ Boolean - * [.isCaptured](#module_CPromise..CPromiseScope+isCaptured) ⇒ boolean - * [.onCancel(listener)](#module_CPromise..CPromiseScope+onCancel) ⇒ CPromiseScope - * [.totalWeight([weight])](#module_CPromise..CPromiseScope+totalWeight) ⇒ Number \| CPromiseScope - * [.innerWeight([weight])](#module_CPromise..CPromiseScope+innerWeight) ⇒ Number \| CPromiseScope - * [.progress(value, [data])](#module_CPromise..CPromiseScope+progress) - * [.propagate(type, data)](#module_CPromise..CPromiseScope+propagate) ⇒ CPromiseScope - * [.captureProgress([options])](#module_CPromise..CPromiseScope+captureProgress) ⇒ CPromiseScope - * [.scopes()](#module_CPromise..CPromiseScope+scopes) ⇒ Array.<CPromiseScope> - * [.timeout(ms)](#module_CPromise..CPromiseScope+timeout) ⇒ Number \| CPromiseScope - * [.weight(weight)](#module_CPromise..CPromiseScope+weight) ⇒ Number \| CPromiseScope - * [.label(label)](#module_CPromise..CPromiseScope+label) ⇒ Number \| CPromiseScope - * [.resolve(value)](#module_CPromise..CPromiseScope+resolve) - * [.reject(err)](#module_CPromise..CPromiseScope+reject) - * [.done(err, value)](#module_CPromise..CPromiseScope+done) - * [.cancel([reason])](#module_CPromise..CPromiseScope+cancel) + * [.signal](#module_CPromise..CPromise+signal) : AbortSignal + * [.isPending](#module_CPromise..CPromise+isPending) ⇒ Boolean + * [.isCanceled](#module_CPromise..CPromise+isCanceled) ⇒ Boolean + * [.isCaptured](#module_CPromise..CPromise+isCaptured) ⇒ Boolean + * [.isPaused](#module_CPromise..CPromise+isPaused) ⇒ Boolean + * [.parent](#module_CPromise..CPromise+parent) ⇒ CPromise \| null + * [.totalWeight([weight])](#module_CPromise..CPromise+totalWeight) ⇒ Number \| CPromise + * [.innerWeight([weight])](#module_CPromise..CPromise+innerWeight) ⇒ Number \| CPromise + * [.progress(value, [data])](#module_CPromise..CPromise+progress) ⇒ Number \| CPromise + * [.propagate(type, data)](#module_CPromise..CPromise+propagate) ⇒ CPromise + * [.captureProgress([options])](#module_CPromise..CPromise+captureProgress) ⇒ CPromise + * [.scopes()](#module_CPromise..CPromise+scopes) ⇒ Array.<CPromise> + * [.timeout([ms])](#module_CPromise..CPromise+timeout) ⇒ Number \| CPromise + * [.weight([weight])](#module_CPromise..CPromise+weight) ⇒ Number \| CPromise + * [.label([label])](#module_CPromise..CPromise+label) ⇒ Number \| CPromise + * [.resolve(value)](#module_CPromise..CPromise+resolve) ⇒ CPromise + * [.reject(err)](#module_CPromise..CPromise+reject) ⇒ CPromise + * [.pause()](#module_CPromise..CPromise+pause) ⇒ Boolean + * [.resume()](#module_CPromise..CPromise+resume) ⇒ Boolean + * [.cancel([reason])](#module_CPromise..CPromise+cancel) + * [.emitSignal(type, data)](#module_CPromise..CPromise+emitSignal) ⇒ Boolean + * [.delay(ms)](#module_CPromise..CPromise+delay) ⇒ CPromise + * [.then(onFulfilled, [onRejected])](#module_CPromise..CPromise+then) ⇒ CPromise + * [.catch(onRejected, [filter])](#module_CPromise..CPromise+catch) ⇒ CPromise + * [.listenersCount(type)](#module_CPromise..CPromise+listenersCount) ⇒ Number + * [.hasListeners(type)](#module_CPromise..CPromise+hasListeners) ⇒ Boolean + * [.once(type, listener)](#module_CPromise..CPromise+once) ⇒ CPromise + * [.emit(type, ...args)](#module_CPromise..CPromise+emit) ⇒ CPromise + * [.emitHook(type, ...args)](#module_CPromise..CPromise+emitHook) ⇒ Boolean * _static_ - * [.execute(executor, resolve, reject, options)](#module_CPromise..CPromiseScope.execute) ⇒ CPromiseScope + * [.isCanceledError(thing)](#module_CPromise..CPromise.isCanceledError) ⇒ boolean + * [.delay(ms, value)](#module_CPromise..CPromise.delay) ⇒ CPromise + * [.all(iterable, options)](#module_CPromise..CPromise.all) ⇒ CPromise + * [.race(thenables)](#module_CPromise..CPromise.race) ⇒ CPromise + * [.allSettled(iterable, options)](#module_CPromise..CPromise.allSettled) ⇒ CPromise + * [.from(thing, [resolveSignatures])](#module_CPromise..CPromise.from) ⇒ CPromise - + -#### new CPromiseScope(resolve, reject, options) -Constructs PromiseScope instance +#### new CPromise(executor, [options]) +Constructs new CPromise instance -| Param | Type | -| --- | --- | -| resolve | function | -| reject | function | -| options | PromiseScopeOptions | +| Param | Type | Description | +| --- | --- | --- | +| executor | CPromiseExecutorFn | promise executor function that will be invoked in the context of the new CPromiseScope instance | +| [options] | CPromiseOptions | | - + -#### cPromiseScope.signal : AbortSignal +#### cPromise.signal : AbortSignal get promise abort signal object -**Kind**: instance property of [CPromiseScope](#module_CPromise..CPromiseScope) - +**Kind**: instance property of [CPromise](#module_CPromise..CPromise) + -#### cPromiseScope.isPending ⇒ Boolean +#### cPromise.isPending ⇒ Boolean indicates if the promise is pending -**Kind**: instance property of [CPromiseScope](#module_CPromise..CPromiseScope) - +**Kind**: instance property of [CPromise](#module_CPromise..CPromise) + -#### cPromiseScope.isCanceled ⇒ Boolean +#### cPromise.isCanceled ⇒ Boolean indicates if the promise is pending -**Kind**: instance property of [CPromiseScope](#module_CPromise..CPromiseScope) - +**Kind**: instance property of [CPromise](#module_CPromise..CPromise) + -#### cPromiseScope.isCaptured ⇒ boolean +#### cPromise.isCaptured ⇒ Boolean indicates if the promise progress is captured -**Kind**: instance property of [CPromiseScope](#module_CPromise..CPromiseScope) - +**Kind**: instance property of [CPromise](#module_CPromise..CPromise) + -#### cPromiseScope.onCancel(listener) ⇒ CPromiseScope -registers the listener for cancel event +#### cPromise.isPaused ⇒ Boolean +indicates if the promise is paused -**Kind**: instance method of [CPromiseScope](#module_CPromise..CPromiseScope) +**Kind**: instance property of [CPromise](#module_CPromise..CPromise) + -| Param | Type | -| --- | --- | -| listener | OnCancelListener | +#### cPromise.parent ⇒ CPromise \| null +get parent promise - +**Kind**: instance property of [CPromise](#module_CPromise..CPromise) + -#### cPromiseScope.totalWeight([weight]) ⇒ Number \| CPromiseScope +#### cPromise.totalWeight([weight]) ⇒ Number \| CPromise Set or get the total weight of the inner chains -**Kind**: instance method of [CPromiseScope](#module_CPromise..CPromiseScope) +**Kind**: instance method of [CPromise](#module_CPromise..CPromise) | Param | Type | | --- | --- | | [weight] | Number | - + -#### cPromiseScope.innerWeight([weight]) ⇒ Number \| CPromiseScope +#### cPromise.innerWeight([weight]) ⇒ Number \| CPromise Set or get the total weight of the inner chains -**Kind**: instance method of [CPromiseScope](#module_CPromise..CPromiseScope) +**Kind**: instance method of [CPromise](#module_CPromise..CPromise) | Param | Type | | --- | --- | | [weight] | Number | - + -#### cPromiseScope.progress(value, [data]) +#### cPromise.progress(value, [data]) ⇒ Number \| CPromise Set promise progress -**Kind**: instance method of [CPromiseScope](#module_CPromise..CPromiseScope) +**Kind**: instance method of [CPromise](#module_CPromise..CPromise) | Param | Type | Description | | --- | --- | --- | | value | Number | a number between [0, 1] | | [data] | \* | any data to send for progress event listeners | - + -#### cPromiseScope.propagate(type, data) ⇒ CPromiseScope +#### cPromise.propagate(type, data) ⇒ CPromise emit propagate event that will propagate through each promise scope in the chain (bubbling) -**Kind**: instance method of [CPromiseScope](#module_CPromise..CPromiseScope) +**Kind**: instance method of [CPromise](#module_CPromise..CPromise) | Param | Type | Default | Description | | --- | --- | --- | --- | | type | String \| symbol | | some type to identify the data kind | | data | \* | | some data | - + -#### cPromiseScope.captureProgress([options]) ⇒ CPromiseScope +#### cPromise.captureProgress([options]) ⇒ CPromise capture initial progress state of the chain -**Kind**: instance method of [CPromiseScope](#module_CPromise..CPromiseScope) +**Kind**: instance method of [CPromise](#module_CPromise..CPromise) | Param | Type | Description | | --- | --- | --- | @@ -423,224 +448,197 @@ capture initial progress state of the chain | options.throttle | Number | set min interval for firing progress event | | options.innerWeight | Number | set weight of the nested promises | - + -#### cPromiseScope.scopes() ⇒ Array.<CPromiseScope> +#### cPromise.scopes() ⇒ Array.<CPromise> Returns all parent scopes that are in pending state -**Kind**: instance method of [CPromiseScope](#module_CPromise..CPromiseScope) - +**Kind**: instance method of [CPromise](#module_CPromise..CPromise) + -#### cPromiseScope.timeout(ms) ⇒ Number \| CPromiseScope +#### cPromise.timeout([ms]) ⇒ Number \| CPromise timeout before the promise will be canceled -**Kind**: instance method of [CPromiseScope](#module_CPromise..CPromiseScope) +**Kind**: instance method of [CPromise](#module_CPromise..CPromise) | Param | Type | Description | | --- | --- | --- | -| ms | Number | timeout in ms | +| [ms] | Number | timeout in ms | - + -#### cPromiseScope.weight(weight) ⇒ Number \| CPromiseScope +#### cPromise.weight([weight]) ⇒ Number \| CPromise Sets the promise weight in progress capturing process -**Kind**: instance method of [CPromiseScope](#module_CPromise..CPromiseScope) -**Returns**: Number \| CPromiseScope - returns weight if no arguments were specified +**Kind**: instance method of [CPromise](#module_CPromise..CPromise) +**Returns**: Number \| CPromise - returns weight if no arguments were specified | Param | Type | Description | | --- | --- | --- | -| weight | Number | any number greater or equal 0 | +| [weight] | Number | any number greater or equal 0 | - + -#### cPromiseScope.label(label) ⇒ Number \| CPromiseScope +#### cPromise.label([label]) ⇒ Number \| CPromise Sets the promise label -**Kind**: instance method of [CPromiseScope](#module_CPromise..CPromiseScope) -**Returns**: Number \| CPromiseScope - returns weight if no arguments were specified +**Kind**: instance method of [CPromise](#module_CPromise..CPromise) +**Returns**: Number \| CPromise - returns weight if no arguments were specified | Param | Type | Description | | --- | --- | --- | -| label | String | any string | +| [label] | String | any string | - + -#### cPromiseScope.resolve(value) +#### cPromise.resolve(value) ⇒ CPromise Resolves the promise with given value -**Kind**: instance method of [CPromiseScope](#module_CPromise..CPromiseScope) +**Kind**: instance method of [CPromise](#module_CPromise..CPromise) | Param | | --- | | value | - + -#### cPromiseScope.reject(err) +#### cPromise.reject(err) ⇒ CPromise Rejects the promise with given error -**Kind**: instance method of [CPromiseScope](#module_CPromise..CPromiseScope) +**Kind**: instance method of [CPromise](#module_CPromise..CPromise) | Param | | --- | | err | - + -#### cPromiseScope.done(err, value) -Resolves or rejects the promise depending on the arguments +#### cPromise.pause() ⇒ Boolean +Pause promise -**Kind**: instance method of [CPromiseScope](#module_CPromise..CPromiseScope) +**Kind**: instance method of [CPromise](#module_CPromise..CPromise) + -| Param | Type | Description | -| --- | --- | --- | -| err | | error object, if specified the promise will be rejected with this error, resolves otherwise | -| value | \* | | +#### cPromise.resume() ⇒ Boolean +Resume promise - +**Kind**: instance method of [CPromise](#module_CPromise..CPromise) + -#### cPromiseScope.cancel([reason]) +#### cPromise.cancel([reason]) throws the CanceledError that cause promise chain cancellation -**Kind**: instance method of [CPromiseScope](#module_CPromise..CPromiseScope) +**Kind**: instance method of [CPromise](#module_CPromise..CPromise) | Param | Type | | --- | --- | | [reason] | String \| Error | - + -#### CPromiseScope.execute(executor, resolve, reject, options) ⇒ CPromiseScope -Executes the promise executor in the PromiseScope context +#### cPromise.emitSignal(type, data) ⇒ Boolean +Emit a signal of the specific type -**Kind**: static method of [CPromiseScope](#module_CPromise..CPromiseScope) +**Kind**: instance method of [CPromise](#module_CPromise..CPromise) | Param | Type | | --- | --- | -| executor | CPromiseExecutorFn | -| resolve | function | -| reject | function | -| options | Object | - - - -### CPromise~CPromise ⇐ Promise -CPromise class - -**Kind**: inner class of [CPromise](#module_CPromise) -**Extends**: Promise - -* [~CPromise](#module_CPromise..CPromise) ⇐ Promise - * [new CPromise(executor, [options])](#new_module_CPromise..CPromise_new) - * _instance_ - * [.isPending](#module_CPromise..CPromise+isPending) ⇒ Boolean - * [.isCanceled](#module_CPromise..CPromise+isCanceled) ⇒ Boolean - * [.progress(listener)](#module_CPromise..CPromise+progress) ⇒ Number \| CPromise - * [.captureProgress(options)](#module_CPromise..CPromise+captureProgress) ⇒ CPromise - * [.cancel(reason)](#module_CPromise..CPromise+cancel) ⇒ Boolean - * [.delay(ms)](#module_CPromise..CPromise+delay) ⇒ CPromise - * [.then(onFulfilled, [onRejected])](#module_CPromise..CPromise+then) ⇒ CPromise - * [.catch(onRejected, [filter])](#module_CPromise..CPromise+catch) ⇒ CPromise - * _static_ - * [.isCanceledError(thing)](#module_CPromise..CPromise.isCanceledError) ⇒ boolean - * [.delay(ms, value)](#module_CPromise..CPromise.delay) ⇒ CPromise - * [.all(iterable, options)](#module_CPromise..CPromise.all) ⇒ CPromise - * [.race(thenables)](#module_CPromise..CPromise.race) ⇒ CPromise - * [.from(thing, [resolveSignatures])](#module_CPromise..CPromise.from) ⇒ CPromise +| type | String \| Symbol | +| data | \* | - + -#### new CPromise(executor, [options]) -Constructs new CPromise instance +#### cPromise.delay(ms) ⇒ CPromise +Returns a chain that will be resolved after specified timeout +**Kind**: instance method of [CPromise](#module_CPromise..CPromise) -| Param | Type | Description | -| --- | --- | --- | -| executor | CPromiseExecutorFn | promise executor function that will be invoked in the context of the new CPromiseScope instance | -| [options] | CPromiseOptions | | +| Param | Type | +| --- | --- | +| ms | Number | - + -#### cPromise.isPending ⇒ Boolean -indicates if the promise is pending +#### cPromise.then(onFulfilled, [onRejected]) ⇒ CPromise +returns a CPromise. It takes up to two arguments: callback functions for the success and failure cases of the Promise. -**Kind**: instance property of [CPromise](#module_CPromise..CPromise) - +**Kind**: instance method of [CPromise](#module_CPromise..CPromise) -#### cPromise.isCanceled ⇒ Boolean -indicates if promise has been canceled +| Param | Type | +| --- | --- | +| onFulfilled | onFulfilled | +| [onRejected] | onRejected | -**Kind**: instance property of [CPromise](#module_CPromise..CPromise) - + -#### cPromise.progress(listener) ⇒ Number \| CPromise -returns chains progress synchronously or adds a progress event listener if the argument was specified +#### cPromise.catch(onRejected, [filter]) ⇒ CPromise +Catches rejection with optionally specified Error class **Kind**: instance method of [CPromise](#module_CPromise..CPromise) | Param | Type | | --- | --- | -| listener | function | +| onRejected | function | +| [filter] | Error | - + -#### cPromise.captureProgress(options) ⇒ CPromise -capture initial progress state of the chain +#### cPromise.listenersCount(type) ⇒ Number +returns listeners count of the specific event type **Kind**: instance method of [CPromise](#module_CPromise..CPromise) | Param | Type | | --- | --- | -| options | Object | -| options.throttle | Number | +| type | EventType | - + -#### cPromise.cancel(reason) ⇒ Boolean -cancel the promise chain with specified reason +#### cPromise.hasListeners(type) ⇒ Boolean +checks if there are listeners of a specific type **Kind**: instance method of [CPromise](#module_CPromise..CPromise) -**Returns**: Boolean - true if success | Param | Type | | --- | --- | -| reason | String | +| type | String \| Symbol | - + -#### cPromise.delay(ms) ⇒ CPromise -Returns a chain that will be resolved after specified timeout +#### cPromise.once(type, listener) ⇒ CPromise +add 'once' listener **Kind**: instance method of [CPromise](#module_CPromise..CPromise) | Param | Type | | --- | --- | -| ms | Number | +| type | EventType | +| listener | function | - + -#### cPromise.then(onFulfilled, [onRejected]) ⇒ CPromise -returns a CPromise. It takes up to two arguments: callback functions for the success and failure cases of the Promise. +#### cPromise.emit(type, ...args) ⇒ CPromise +emits the event **Kind**: instance method of [CPromise](#module_CPromise..CPromise) | Param | Type | | --- | --- | -| onFulfilled | onFulfilled | -| [onRejected] | onRejected | +| type | EventType | +| ...args | | - + -#### cPromise.catch(onRejected, [filter]) ⇒ CPromise -Catches rejection with optionally specified Error class +#### cPromise.emitHook(type, ...args) ⇒ Boolean +emits the hook event **Kind**: instance method of [CPromise](#module_CPromise..CPromise) +**Returns**: Boolean - - false if some listener returned false | Param | Type | | --- | --- | -| onRejected | function | -| [filter] | Error | +| type | EventType | +| ...args | | @@ -692,6 +690,18 @@ returns a promise that fulfills or rejects as soon as one of the promises in an | --- | --- | | thenables | Iterable | + + +#### CPromise.allSettled(iterable, options) ⇒ CPromise +returns a promise that resolves after all of the given promises have either fulfilled or rejected + +**Kind**: static method of [CPromise](#module_CPromise..CPromise) + +| Param | Type | +| --- | --- | +| iterable | Iterable \| Generator \| GeneratorFunction | +| options | AllOptions | + #### CPromise.from(thing, [resolveSignatures]) ⇒ CPromise @@ -704,41 +714,40 @@ Converts thing to CPromise using the following rules: - CPromise instance return | thing | \* | | | [resolveSignatures] | boolean | true | - + -### CPromise~PromiseScopeOptions : Object +### CPromise~EventType : String \| Symbol **Kind**: inner typedef of [CPromise](#module_CPromise) -**Properties** - -| Name | Type | Default | Description | -| --- | --- | --- | --- | -| label | String | | the label for the promise | -| weight | Number | 1 | the progress weight of the promise | -| timeout | Number | 0 | max pending time | -| signal | AbortSignal | | AbortController signal | - - + -### CPromise~onFulfilled : function +### CPromise~CPromiseExecutorFn : function **Kind**: inner typedef of [CPromise](#module_CPromise) -**this**: CPromiseScope +**this**: CPromise | Param | Type | | --- | --- | -| value | | -| scope | CPromiseScope | +| resolve | function | +| reject | function | +| scope | CPromise | - + -### CPromise~onRejected : function +### CPromise~PromiseOptionsObject : Object **Kind**: inner typedef of [CPromise](#module_CPromise) -**this**: CPromiseScope +**Properties** -| Param | Type | +| Name | Type | | --- | --- | -| err | | -| scope | CPromiseScope | +| label | String | +| timeout | Number | +| weight | Number | + + +### CPromise~CPromiseOptions : PromiseOptionsObject \| String \| Number +If value is a number it will be considered as the value for timeout option If value is a string it will be considered as a label + +**Kind**: inner typedef of [CPromise](#module_CPromise) ### CPromise~OnCancelListener : function @@ -748,23 +757,13 @@ Converts thing to CPromise using the following rules: - CPromise instance return | --- | --- | | reason | CanceledError | - + -### CPromise~CPromiseExecutorFn : function +### CPromise~OnPauseListener : function **Kind**: inner typedef of [CPromise](#module_CPromise) -**this**: CPromiseScope - -| Param | Type | -| --- | --- | -| resolve | function | -| reject | function | -| scope | CPromiseScope | - - - -### CPromise~CPromiseOptions : PromiseScopeOptions \| String \| Number -If value is a number it will be considered as the value for timeout option If value is a string it will be considered as a label + +### CPromise~OnResumeListener : function **Kind**: inner typedef of [CPromise](#module_CPromise) diff --git a/jsdoc2md/README.hbs.md b/jsdoc2md/README.hbs.md index d33b432..97bbed7 100644 --- a/jsdoc2md/README.hbs.md +++ b/jsdoc2md/README.hbs.md @@ -5,7 +5,14 @@ ![David](https://img.shields.io/david/DigitalBrainJS/c-promise) ## SYNOPSIS :sparkles: -A Promise class built on top of the native that supports some additional features such as cancellation, timeouts, progress capturing and concurrency limit. + +This library provides an advanced version of the built-in Promise by subclassing. +You might be interested in using it if you need the following features: +- promise cancellation (including nested) +- progress capturing +- promise suspending +- timeouts +- concurrent limit for `all` and `allSettled` methods with `mapper` reducer In terms of the library **the cancellation means rejection with a special error subclass**. @@ -79,6 +86,8 @@ has lost its relevance to you. - `CPromise.all` supports concurrency limit - `CPromise.all` and `CPromise.race` methods have cancellation support, so the others nested pending promises will be canceled when the result promise settled + - promise suspending (using `pause` and `resume` methods) + - custom signals (`emitSignal`) - `delay` method to return promise that will be resolved with the value after timeout - ability to set the `weight` for each promise in the chain to manage the impact on chain progress - ability to attach meta info on each setting of the progress @@ -222,7 +231,7 @@ const promise= CPromise.from(function*(){ yield [[CPromise.delay(1000), CPromise.delay(1500)]] // resolve chains using CPromise.race([...chains]); yield new CPromise(resolve=> resolve(true)); // any thenable object will be resolved return "It works!"; -}, [1, 2, 3]) +}) .progress(value=> console.log(`Progress: ${value}`)) .then(message=> console.log(`Done: ${message}`)); ```` diff --git a/lib/abort-controller.js b/lib/abort-controller.js index 5b45071..c4a1caf 100644 --- a/lib/abort-controller.js +++ b/lib/abort-controller.js @@ -91,7 +91,7 @@ class AbortSignal{ * AbortController class */ -class AbortController { +class AbortControllerPolyfill { /** * Constructs new AbortController instance */ @@ -129,7 +129,24 @@ class AbortController { } } +const isAbortSignal = (thing) => { + return thing && + typeof thing === 'object' && + typeof thing.aborted === 'boolean' && + typeof thing.addEventListener === 'function' && + typeof thing.removeEventListener === 'function'; +} + module.exports= { - AbortController, - AbortSignal + AbortController: (() => { + try { + if (typeof AbortController === 'function' && (new AbortController()).toString() === '[object AbortController]') { + return AbortController; + } + } catch (e) { + } + return AbortControllerPolyfill; + })(), + AbortSignal, + isAbortSignal }; diff --git a/lib/c-promise.js b/lib/c-promise.js index 2ba1082..6ecbb8f 100644 --- a/lib/c-promise.js +++ b/lib/c-promise.js @@ -4,119 +4,45 @@ * @exports CPromise */ +/** + * @typedef {String|Symbol} EventType + */ const {CanceledError} = require('./canceled-error'); -const {AbortController: _AbortController} = require('./abort-controller'); -const {TinyEventEmitter} = require('./tiny-event-emitter'); -const {validateOptions, validators}= require('./validator'); +const {AbortController, isAbortSignal} = require('./abort-controller'); +const {validateOptions, validators} = require('./validator'); +const {isThenable, EmptyObject, setImmediate, isGeneratorFunction, isGenerator, toGenerator, toArray} = require('./utils'); const {now} = Date; -const {isArray}= Array; +const {isArray} = Array; + +const _toCPromise = Symbol.for('toCPromise'); -const _scope = Symbol('scope'); const _handleCancelRejection = Symbol('handleCancelRejection'); -const _isPending = Symbol('isPending'); -const _isCanceled = Symbol('isCanceled'); -const _resolve = Symbol('resolve'); -const _reject = Symbol('reject'); -const _parent = Symbol('parent'); -const _cancel = Symbol('cancel'); -const _innerChain = Symbol('innerChain'); -const _controller = Symbol('controller'); + const _shadow = Symbol('shadow'); -const _attachScope = Symbol('attachScope'); -const _isChain = Symbol('isChain'); -const _timer = Symbol('timer'); -const _timeout = Symbol('timeout'); +const _events = Symbol('events'); +const _resolve = Symbol('done'); const _objectToCPromise = Symbol('objectToCPromise'); -const _done= Symbol('done'); -const TYPE_PROGRESS = Symbol('TYPE_PROGRESS'); - -const promiseAssocStore= new WeakMap(); - -const _toCPromise= Symbol.for('toCPromise'); - -const __AbortController = - (() => { - try { - if (typeof AbortController === 'function' && (new AbortController()).toString() === '[object AbortController]') { - return AbortController; - } - } catch (e) { - } - return _AbortController; - })(); - -const _setImmediate = typeof setImmediate === 'function' ? setImmediate : function setImmediateShim(cb) { - setTimeout(cb, 0) -} - -const isThenable = obj => !!obj && (typeof obj === 'function' || typeof obj === 'object') && typeof obj.then === 'function'; - -function isGeneratorFunction(thing) { - return typeof thing === 'function' && thing.constructor && thing.constructor.name === 'GeneratorFunction'; -} - -function isGenerator(thing) { - return thing && typeof thing === 'object' && typeof thing.next === 'function'; -} - -const GENERATOR_TYPE_GENERAL= 1; -const GENERATOR_TYPE_ASYNC= 2; - -function getGeneratorFnType(thing) { - return typeof thing === 'function' && - thing.constructor && - (thing.constructor.name === 'GeneratorFunction' && GENERATOR_TYPE_GENERAL || - thing.constructor.name === 'AsyncGeneratorFunction' && GENERATOR_TYPE_ASYNC) || 0; -} - -const toGenerator= function(thing, args, context= null){ - if(isGeneratorFunction(thing)){ - return thing.apply(context, args); - } - return thing && (isGenerator(thing)? thing : (thing[Symbol.iterator] && thing[Symbol.iterator]())) || null; -} - -const toArray= (thing, mapper)=>{ - - if (thing) { - if (Array.isArray(thing)) { - return mapper ? thing.map(mapper) : thing; - } - if ((thing= toGenerator(thing))) { - const arr = []; - let item; - while ((item = thing.next()) && item.done === false) { - arr.push(mapper ? mapper(item.value) : item.value); - } - return arr; - } - } - - return null; -} +const TYPE_PROGRESS = Symbol('TYPE_PROGRESS'); +const SIGNAL_CANCEL = Symbol('SIGNAL_CANCEL'); +const SIGNAL_PAUSE = Symbol('SIGNAL_PAUSE'); +const SIGNAL_RESUME = Symbol('SIGNAL_RESUME'); -const isAbortSignal = (thing) => { - return thing && - typeof thing === 'object' && - typeof thing.aborted === 'boolean' && - typeof thing.addEventListener === 'function' && - typeof thing.removeEventListener === 'function'; -} +const promiseAssocStore = new WeakMap(); const computeWeightSum = promises => { let i = promises.length; let sum = 0; while (i-- > 0) { - sum += promises[i][_scope][_shadow].weight; + sum += promises[i][_shadow].weight; } return sum; } function resolveGenerator(generatorFn) { return new this((resolve, reject, scope) => { - const generator = generatorFn.apply(scope, scope); + const generator = generatorFn.call(scope, scope); if (!isGenerator(generator)) { return reject(new TypeError('function must return a generator object')); @@ -152,16 +78,24 @@ function resolveGenerator(generatorFn) { try { next(generator.throw(err)); } catch (e) { - return reject(e); + reject(e); } } - scope.on('cancelhook', (err) => { - if (promise instanceof this) { - return promise.cancel(err) + scope.on('signal', (type, err) => { + switch (type) { + case SIGNAL_CANCEL: + if (!promise.cancel(err)) { + onRejected(err); + } + return false; + case SIGNAL_PAUSE: + promise.pause(); + return false; + case SIGNAL_RESUME: + promise.resume(); + return false; } - - return !!onRejected(err); }); const next = (r) => { @@ -174,7 +108,7 @@ function resolveGenerator(generatorFn) { sum += weight; weight = promise.isChain ? 1 : promise.weight(); - _setImmediate(() => { + setImmediate(() => { isCaptured && promise.progress((value, scope, data) => { setProgress(value, scope, data); }); @@ -191,88 +125,121 @@ function resolveGenerator(generatorFn) { } /** - * @typedef PromiseScopeOptions {Object} - * @property {String} label the label for the promise - * @property {Number} weight=1 the progress weight of the promise - * @property {Number} timeout=0 max pending time - * @property {AbortSignal} signal AbortController signal + * @typedef {Function} CPromiseExecutorFn + * @this CPromise + * @param {Function} resolve + * @param {Function} reject + * @param {CPromise} scope */ /** - * @typedef {Function} onFulfilled - * @this CPromiseScope - * @param value - * @param {CPromiseScope} scope + * @typedef {Object} PromiseOptionsObject + * @property {String} label + * @property {Number} timeout + * @property {Number} weight */ /** - * @typedef {Function} onRejected - * @this CPromiseScope - * @param err - * @param {CPromiseScope} scope + * If value is a number it will be considered as the value for timeout option + * If value is a string it will be considered as a label + * @typedef {PromiseOptionsObject|String|Number} CPromiseOptions */ /** - * Scope for CPromises instances - * @extends TinyEventEmitter + * CPromise class + * @namespace + * @extends Promise */ -class CPromiseScope extends TinyEventEmitter { +class CPromise extends Promise { /** - * Constructs PromiseScope instance - * @param {Function} resolve - * @param {Function} reject - * @param {PromiseScopeOptions} options + * Constructs new CPromise instance + * @param {CPromiseExecutorFn} executor - promise executor function that will be invoked + * in the context of the new CPromiseScope instance + * @param {CPromiseOptions} [options] */ - constructor(resolve, reject, {label, weight, timeout, signal} = {}) { - super(); - if (signal !== undefined) { - if (!isAbortSignal(signal)) { - throw TypeError('signal should implement AbortSignal interface'); - } - const signalListener = () => { - this.cancel(); + constructor(executor, options) { + if (options !== undefined && options !== null) { + switch (typeof options) { + case 'string': + options = {label: options}; + break; + case 'number': + options = {timeout: options}; + break; + case 'object': + break; + default: + throw TypeError('options must be an object|string|number'); } - signal.addEventListener('abort', signalListener); - this.on('done', () => { - signal.removeEventListener('abort', signalListener); - }) } + let {label, weight, timeout, signal} = options || {}; + + let resolve, reject; + + super((_resolve, _reject) => { + resolve = _resolve; + reject = _reject; + }); + + this[_events] = new EmptyObject(); + const shadow = this[_shadow] = { - captured: false, + resolve, + reject, + paused: false, + timestamp: -1, + innerChain: null, + parent: null, + isCaptured: false, progress: 0, computedProgress: -1, totalWeight: -1, innerWeight: -1, - isListening: false, throttle: 0, - throttleTimer: 0 + throttleTimer: 0, + isListening: false, + isPending: true, + isCanceled: false, + isChain: true, + label: '', + weight: 1 }; - this[_resolve] = resolve; - this[_reject] = reject; - this[_isPending] = true; - this[_isCanceled] = false; - this[_parent] = null; - this[_isChain] = true; + this.onCancel = this.onCancel.bind(this); + this.onPause = this.onPause.bind(this); + this.onResume = this.onResume.bind(this); - if (timeout !== undefined) { - this.timeout(timeout); + try { + executor.call(this, value => { + this.resolve(value) + }, err => { + this.reject(err) + }, this); + } catch (err) { + this.reject(err); } - if (weight !== undefined) { - this.weight(weight); - } else { - shadow.weight = 1; + if (signal !== undefined) { + if (!isAbortSignal(signal)) { + throw TypeError('signal should implement AbortSignal interface'); + } + const signalListener = () => { + this.cancel(); + } + signal.addEventListener('abort', signalListener); + this.on('done', () => { + signal.removeEventListener('abort', signalListener); + }) } - if (label !== undefined) { - this.label(label); - } else { - shadow.label = ''; - } + timeout !== undefined && this.timeout(timeout); + + weight !== undefined && this.weight(weight); + + label !== undefined && this.label(label); this.on('propagate', (type, scope, data) => { if (type === TYPE_PROGRESS) { @@ -283,8 +250,8 @@ class CPromiseScope extends TinyEventEmitter { this.on('newListener', (event) => { if (event === 'progress') { - shadow.isListening= true; - if (!shadow.captured) { + shadow.isListening = true; + if (!shadow.isCaptured) { this.captureProgress() } } @@ -293,7 +260,7 @@ class CPromiseScope extends TinyEventEmitter { this.on('removeListener', (event) => { if (event === 'progress') { if (shadow.isListening && !this.hasListeners('progress')) { - shadow.isListening= false; + shadow.isListening = false; } } }) @@ -304,24 +271,39 @@ class CPromiseScope extends TinyEventEmitter { * @param {CanceledError} reason */ + /** + * @typedef {Function} OnPauseListener + */ + + /** + * @typedef {Function} OnResumeListener + */ + /** * registers the listener for cancel event + * @name CPromise#onCancel * @param {OnCancelListener} listener - * @returns {CPromiseScope} + * @returns {CPromise} */ - onCancel(listener) { - if (!this[_isPending]) { - throw Error('Unable to subscribe to close event since promise has been already settled'); - } - this.on('cancel', listener); - return this; - } + /** + * registers the listener for pause event + * @name CPromise#onPause + * @param {OnPauseListener} listener + * @returns {CPromise} + */ + + /** + * registers the listener for resume event + * @name CPromise#onResume + * @param {OnResumeListener} listener + * @returns {CPromise} + */ /** * Set or get the total weight of the inner chains * @param {Number} [weight] - * @return {Number|CPromiseScope} + * @return {Number|CPromise} */ totalWeight(weight) { @@ -338,7 +320,7 @@ class CPromiseScope extends TinyEventEmitter { /** * Set or get the total weight of the inner chains * @param {Number} [weight] - * @return {Number|CPromiseScope} + * @return {Number|CPromise} */ innerWeight(weight) { @@ -357,16 +339,29 @@ class CPromiseScope extends TinyEventEmitter { return this[_shadow].innerWeight; } + /** + * Subscribe to progress event + * @param {Function} listener + * @returns {CPromise} + */ + /** * Set promise progress * @param {Number} value a number between [0, 1] * @param {*} [data] any data to send for progress event listeners + * @returns {Number|CPromise} */ progress(value, data) { const shadow = this[_shadow]; if (arguments.length) { + + if (typeof value === 'function') { + this.on('progress', value); + return this; + } + if (!Number.isFinite(value)) { throw TypeError('value must be a number [0, 1]'); } @@ -377,7 +372,7 @@ class CPromiseScope extends TinyEventEmitter { value = 1; } - if(!shadow.captured) return; + if (!shadow.isCaptured) return this; if (value !== 0 && value !== 1) { value = value.toFixed(10) * 1; @@ -387,13 +382,13 @@ class CPromiseScope extends TinyEventEmitter { shadow.progress = value; if (value !== 1 && shadow.throttle) { - if(!shadow.throttleTimer) { + if (!shadow.throttleTimer) { shadow.throttleTimer = setTimeout(() => { shadow.throttleTimer = 0; this.propagate(TYPE_PROGRESS, data); }, shadow.throttle); } - return; + return this; } this.propagate(TYPE_PROGRESS, data); @@ -402,75 +397,45 @@ class CPromiseScope extends TinyEventEmitter { return this; } - if(shadow.computedProgress === -1) { - shadow.totalWeight===-1 && this.captureProgress(); - - const scopes = this.scopes(); - let i = scopes.length; - let sum = 0; - let progress= 0; - - while (i-- > 0) { - const scope = scopes[i]; - const thatShadow = scope[_shadow]; - const weight = thatShadow.weight; - if (weight > 0) { - sum += weight; - progress += thatShadow.progress * weight; - } - } + if (shadow.computedProgress === -1) { + shadow.totalWeight === -1 && this.captureProgress(); + + const scopes = this.scopes(); + let i = scopes.length; + let sum = 0; + let progress = 0; + + while (i-- > 0) { + const scope = scopes[i]; + const thatShadow = scope[_shadow]; + const weight = thatShadow.weight; + if (weight > 0) { + sum += weight; + progress += thatShadow.progress * weight; + } + } - let total = shadow.totalWeight; + let total = shadow.totalWeight; - if (total > 0) { - return (shadow.computedProgress = (progress + (total - sum)) / total); - } + if (total > 0) { + return (shadow.computedProgress = (progress + (total - sum)) / total); + } - shadow.computedProgress = progress / sum; - } + shadow.computedProgress = progress / sum; + } - return shadow.computedProgress; + return shadow.computedProgress; } /** * emit propagate event that will propagate through each promise scope in the chain (bubbling) * @param {String|symbol} type - some type to identify the data kind * @param {*} data - some data - * @returns {CPromiseScope} + * @returns {CPromise} */ propagate(type, data = null) { - this.emit('propagate', type, this, data); - return this; - } - - [_attachScope](thatScope, innerChain = false) { - if (innerChain) { - const shadow = this[_shadow]; - this[_innerChain] = thatScope; - - thatScope.on('propagate', (type, scope, data) => { - if (type === TYPE_PROGRESS) { - const progress = thatScope.progress(); - if (scope === thatScope) { - this.progress(progress, data); - return; - } - } - - this.emit('propagate', type, scope, data); - }); - - shadow.captured && thatScope.captureProgress(); - - shadow.innerWeight= thatScope[_shadow].totalWeight; - } else { - thatScope[_parent] = this; - this.on('propagate', (type, scope, data) => { - thatScope.emit('propagate', type, scope, data); - }); - thatScope[_isChain] = false; - } + return this.emit('propagate', type, this, data); } /** @@ -478,11 +443,10 @@ class CPromiseScope extends TinyEventEmitter { * @param {Object} [options] * @param {Number} options.throttle set min interval for firing progress event * @param {Number} options.innerWeight set weight of the nested promises - * @returns {CPromiseScope} + * @returns {CPromise} */ captureProgress(options) { - if (options) { validateOptions(options, { throttle: validators.numberFinitePositive, @@ -491,7 +455,7 @@ class CPromiseScope extends TinyEventEmitter { const {throttle, innerWeight} = options; - if (throttle!==undefined){ + if (throttle !== undefined) { this[_shadow].throttle = throttle; } @@ -513,13 +477,13 @@ class CPromiseScope extends TinyEventEmitter { if (weight > 0) { sum += weight; - if(!thatShadow.captured){ - thatShadow.captured = true; + if (!thatShadow.isCaptured) { + thatShadow.isCaptured = true; scope.emit('capture', scope); } - const inner = scope[_innerChain]; - if(inner && !inner[_shadow].captured){ + const inner = thatShadow.innerChain; + if (inner && !inner[_shadow].isCaptured) { inner.captureProgress(options); } } @@ -532,13 +496,13 @@ class CPromiseScope extends TinyEventEmitter { /** * Returns all parent scopes that are in pending state - * @returns {CPromiseScope[]} + * @returns {CPromise[]} */ scopes() { let scope = this; const scopes = [scope]; - while ((scope = scope[_parent])) { + while ((scope = scope[_shadow].parent)) { scopes.push(scope); } return scopes; @@ -546,15 +510,18 @@ class CPromiseScope extends TinyEventEmitter { /** * timeout before the promise will be canceled - * @param {Number} ms - timeout in ms - * @returns {Number|CPromiseScope} + * @param {Number} [ms] - timeout in ms + * @returns {Number|CPromise} */ timeout(ms) { + const shadow = this[_shadow]; + if (arguments.length) { - if (this[_timer]) { - clearTimeout(this[_timer]); - this[_timer] = null; + if (shadow.timer) { + shadow.timestamp = -1; + clearTimeout(shadow.timer); + shadow.timer = null; } if (typeof ms !== 'number' || ms < 0) { @@ -562,14 +529,15 @@ class CPromiseScope extends TinyEventEmitter { } if (ms > 0) { + shadow.timestamp = now(); setTimeout(() => { this.cancel('timeout'); - }, (this[_timeout] = ms)); + }, (shadow.timeout = ms)); } return this; } - return this[_timeout]; + return shadow.timeout; } /** @@ -578,15 +546,15 @@ class CPromiseScope extends TinyEventEmitter { */ get signal() { - if (this[_controller]) return this[_controller].signal; + if (this[_shadow].controller) return this[_shadow].controller.signal; - return (this[_controller] = new __AbortController()).signal; + return (this[_shadow].controller = new AbortController()).signal; } /** * Sets the promise weight in progress capturing process - * @param {Number} weight - any number greater or equal 0 - * @returns {Number|CPromiseScope} returns weight if no arguments were specified + * @param {Number} [weight] - any number greater or equal 0 + * @returns {Number|CPromise} returns weight if no arguments were specified */ weight(weight) { @@ -607,8 +575,8 @@ class CPromiseScope extends TinyEventEmitter { /** * Sets the promise label - * @param {String} label - any string - * @returns {Number|CPromiseScope} returns weight if no arguments were specified + * @param {String} [label] - any string + * @returns {Number|CPromise} returns weight if no arguments were specified */ label(label) { @@ -625,7 +593,7 @@ class CPromiseScope extends TinyEventEmitter { */ get isPending() { - return this[_isPending]; + return this[_shadow].isPending; } /** @@ -634,273 +602,224 @@ class CPromiseScope extends TinyEventEmitter { */ get isCanceled() { - return this[_isCanceled]; + return this[_shadow].isCanceled; } /** * indicates if the promise progress is captured - * @return {boolean} + * @return {Boolean} */ - get isCaptured(){ - return this[_shadow].captured; + get isCaptured() { + return this[_shadow].isCaptured; } /** - * Resolves the promise with given value - * @param value + * indicates if the promise is paused + * @returns {Boolean} */ - resolve(value) { - if (!this[_isPending]) return; - - if (isThenable(value)) { - if (value instanceof CPromise) { - this[_attachScope](value[_scope], true); - } - value.then( - (value) => this[_done](null, value), - (err) => this[_done](err, undefined, true) - ) - } else { - this[_done](null, value); - } + get isPaused() { + return this[_shadow].paused; } /** - * Rejects the promise with given error - * @param err + * get parent promise + * @returns {CPromise|null} */ - reject(err) { - this[_done](err, undefined, true); + get parent() { + return this[_shadow].parent; } /** - * @param err + * Resolves the promise with given value * @param value - * @param {boolean} [reject] - * @private - */ - - [_done](err, value, reject) { - if (!this[_isPending]) return; - this[_isPending] = false; - - this[_timer] && clearTimeout(this[_timer]); - - if (err || reject) { - if (err && err instanceof CanceledError) { - this[_handleCancelRejection](err); - } - this.emit('done', err); - this[_reject](err); - }else { - this[_shadow].captured && this.progress(1); - this.emit('done', undefined, value); - this[_resolve](value); - } - - this.removeAllListeners(); - - this[_innerChain] = null; - this[_parent] = null; - } - - /** - * Resolves or rejects the promise depending on the arguments - * @param err - error object, if specified the promise will be rejected with this error, resolves otherwise - * @param {*} value + * @returns {CPromise} */ - done(err, value){ - return this[_done](err, value); - } - - [_handleCancelRejection](err) { - this[_isCanceled] = true; - - err.scope || (err.scope = this); - - if (this[_controller]) { - this[_controller].abort(); - this[_controller] = null; - } - - this.emit('cancel', err); + resolve(value) { + this[_resolve](value, false); + return this; } /** - * throws the CanceledError that cause promise chain cancellation - * @param {String|Error} [reason] + * Rejects the promise with given error + * @param err + * @returns {CPromise} */ - cancel(reason) { - return this[_cancel](CanceledError.from(reason)); + reject(err) { + this[_resolve](err, true); + return this; } - [_cancel](err) { - if (!this[_isPending] || this[_isCanceled]) return false; - - let parent = this[_parent]; + [_resolve](value, isRejected) { + const shadow = this[_shadow]; + if (!shadow.isPending) return this; + + const complete = (value, isRejected) => { + shadow.timer && clearTimeout(shadow.timer); + + const resolve = () => { + if (isRejected) { + this.emit('done', value); + shadow.reject(value); + } else { + shadow.isCaptured && this.progress(1); + this.emit('done', undefined, value); + shadow.resolve(value); + } + shadow.isPending = false; + shadow.innerChain = null; + shadow.parent = null; + this[_events] = null; + } - if (parent && parent[_cancel](err)) { - return true; - } + if (isRejected && value && value instanceof CanceledError) { + this[_handleCancelRejection](value); + resolve(); + return; + } - const innerChain = this[_innerChain]; + if (shadow.paused) { + return this.on('resume', resolve); + } - if (innerChain && innerChain[_cancel](err)) { - return true; + resolve(); } - if (this.hasListeners('cancelhook')) { - return this.emitHook('cancelhook', err, this); + if (!isThenable(value)) { + complete(value, isRejected); + return; } - this.reject(err); + if (value instanceof CPromise) { + shadow.innerChain = value; - return true; - } + value.on('propagate', (type, scope, data) => { + if (type === TYPE_PROGRESS) { + const progress = value.progress(); + if (scope === value) { + this.progress(progress, data); + return; + } + } - /** - * Executes the promise executor in the PromiseScope context - * @param {CPromiseExecutorFn} executor - * @param {Function?} resolve - * @param {Function?} reject - * @param {Object?} options - * @returns {CPromiseScope} - */ + this.emit('propagate', type, scope, data); + }); - static execute(executor, resolve, reject, options) { - const scope = new this(resolve, reject, options); + shadow.isCaptured && value.captureProgress(); - try { - executor.call(scope, (value) => { - scope.resolve(value); - }, (err) => { - scope.reject(err); - }, scope - ); - } catch (err) { - scope.reject(err); + shadow.innerWeight = value[_shadow].totalWeight; } - return scope; + super.then.call( + value, + (value) => { + complete(value) + }, + (err) => { + complete(err, true) + } + ); } -} - -/** - * @typedef {Function} CPromiseExecutorFn - * @this CPromiseScope - * @param {Function} resolve - * @param {Function} reject - * @param {CPromiseScope} scope - */ -/** - * If value is a number it will be considered as the value for timeout option - * If value is a string it will be considered as a label - * @typedef {PromiseScopeOptions|String|Number} CPromiseOptions - */ - -/** - * CPromise class - * @namespace - * @extends Promise - */ - -class CPromise extends Promise { - /** - * Constructs new CPromise instance - * @param {CPromiseExecutorFn} executor - promise executor function that will be invoked - * in the context of the new CPromiseScope instance - * @param {CPromiseOptions} [options] - */ + [_handleCancelRejection](err) { + const shadow = this[_shadow]; + shadow.isCanceled = true; - constructor(executor, options) { - let scope; + err.scope || (err.scope = this); - if (options !== undefined && options !== null) { - switch (typeof options) { - case 'string': - options = {label: options}; - break; - case 'number': - options = {timeout: options}; - break; - case 'object': - break; - default: - throw TypeError('options must be an object|string|number'); - } + if (shadow.controller) { + shadow.controller.abort(); + shadow.controller = null; } - super((resolve, reject) => { - - scope = CPromiseScope.execute(executor, resolve, reject, options); - }); - - this[_scope] = scope; + this.emit('cancel', err); } /** - * indicates if the promise is pending + * Pause promise * @returns {Boolean} */ - get isPending() { - return this[_scope][_isPending]; + pause() { + return this.emitSignal(SIGNAL_PAUSE); } /** - * indicates if promise has been canceled + * Resume promise * @returns {Boolean} */ - get isCanceled() { - return this[_scope][_isCanceled]; - } - - get isChain() { - return this[_scope][_isChain]; + resume() { + return this.emitSignal(SIGNAL_RESUME); } /** - * returns chains progress synchronously or adds a progress event listener if the argument was specified - * @param {Function} listener - * @returns {Number|CPromise} + * throws the CanceledError that cause promise chain cancellation + * @param {String|Error} [reason] */ - progress(listener) { - if (arguments.length === 0) { - return this[_scope].progress(); - } - - this.on('progress', listener); - return this; + cancel(reason) { + return this.emitSignal(SIGNAL_CANCEL, CanceledError.from(reason)); } /** - * capture initial progress state of the chain - * @param {Object} options - * @param {Number} options.throttle - * @returns {CPromise} + * Emit a signal of the specific type + * @param {String|Symbol} type + * @param {*} data + * @returns {Boolean} */ - captureProgress(options) { - this[_scope].captureProgress(options); - return this; - } + emitSignal(type, data) { + const shadow = this[_shadow]; + if (!shadow.isPending) return false; - /** - * cancel the promise chain with specified reason - * @param {String} reason - * @returns {Boolean} true if success - */ + let {parent, innerChain} = shadow; - cancel(reason) { - return this[_scope].cancel(reason); + if (parent && parent.emitSignal(type, data)) { + return true; + } + + if (innerChain && innerChain.emitSignal(type, data)) { + return true; + } + + const flag = this.emitHook('signal', type, data); + + if (flag !== false) { + switch (type) { + case SIGNAL_CANCEL: + this.reject(data); + return true; + case SIGNAL_PAUSE: + if (!shadow.paused) { + shadow.paused = true; + if (shadow.timer) { + clearTimeout(shadow.timer); + shadow.timer = null; + shadow.timestamp !== -1 && (shadow.timeLeft = now() - shadow.timestamp); + } + + this.emit('pause'); + } + return true; + case SIGNAL_RESUME: + if (shadow.paused) { + shadow.paused = false; + if (shadow.timeLeft) { + this.timeout(shadow.timeLeft); + shadow.timeLeft = 0; + } + this.emit('resume'); + } + return true; + } + } + + return true; } /** @@ -922,11 +841,15 @@ class CPromise extends Promise { then(onFulfilled, onRejected) { const promise = super.then( - onFulfilled && ((value) => onFulfilled.call(promise[_scope], value, promise[_scope])), - onRejected && ((err) => onRejected.call(promise[_scope], err, promise[_scope])) + onFulfilled && ((value) => onFulfilled.call(promise, value, promise)), + onRejected && ((err) => onRejected.call(promise, err, promise)) ); - this[_scope][_attachScope](promise[_scope]); + promise[_shadow].parent = this; + + this.on('propagate', (type, scope, data) => { + promise.emit('propagate', type, scope, data); + }); return promise; } @@ -1005,7 +928,7 @@ class CPromise extends Promise { return new this((resolve, reject, scope) => { let pending; let results; - let progressAcc= 0; + let progressAcc = 0; let isCaptured; let endReached; let generator; @@ -1024,10 +947,10 @@ class CPromise extends Promise { ignoreResults, signatures, mapper - }= options || {} + } = options || {} - const cancel= (reason)=>{ - const {length}= pending; + const cancel = (reason) => { + const {length} = pending; for (let i = 0; i < length; i++) { pending[i].cancel(reason); } @@ -1035,7 +958,21 @@ class CPromise extends Promise { scope.onCancel(cancel); - const handleProgress= (value, _scope, data) => { + scope.onPause(() => { + const {length} = pending; + for (let i = 0; i < length; i++) { + pending[i].pause(); + } + }); + + scope.onResume(() => { + const {length} = pending; + for (let i = 0; i < length; i++) { + pending[i].resume(); + } + }) + + const handleProgress = (value, _scope, data) => { let total = scope.innerWeight(); let sum = progressAcc; const {length} = pending; @@ -1046,12 +983,12 @@ class CPromise extends Promise { sum <= total && scope.progress(sum / total, _scope, data); }; - const _reject= err=> { + const _reject = err => { reject(err); cancel(); } - function throwConvertError(){ + function throwConvertError() { throw TypeError('unable to convert object to iterable'); } @@ -1065,8 +1002,8 @@ class CPromise extends Promise { }); if (!concurrency) { - pending = toArray(iterable, (value, i)=> { - return this.from(mapper? mapper(value, i) : value, signatures); + pending = toArray(iterable, (value, i) => { + return this.from(mapper ? mapper(value, i) : value, signatures); }) || throwConvertError(); return super.all(pending).then(resolve, _reject); @@ -1074,10 +1011,10 @@ class CPromise extends Promise { generator = toGenerator(iterable) || throwConvertError(); - pending= []; - !ignoreResults && (results= []); + pending = []; + !ignoreResults && (results = []); - const next= (value)=> { + const next = (value) => { const promise = this.from(value, signatures); pending.push(promise); @@ -1107,16 +1044,16 @@ class CPromise extends Promise { let item; try { item = generator.next(); - }catch(err){ + } catch (err) { _reject(err); return; } - if (item.done){ - endReached= true; + if (item.done) { + endReached = true; return; } - next(mapper? mapper(item.value) : item.value); + next(mapper ? mapper(item.value) : item.value); } } @@ -1163,6 +1100,18 @@ class CPromise extends Promise { scope.onCancel(cancel); + scope.onPause(() => { + for (let i = 0; i < length; i++) { + thenables[i].pause(); + } + }) + + scope.onResume(() => { + for (let i = 0; i < length; i++) { + thenables[i].resume(); + } + }) + super.race(thenables).then((value) => { resolve(value); cancel(); @@ -1173,6 +1122,33 @@ class CPromise extends Promise { }); } + /** + * returns a promise that resolves after all of the given promises have either fulfilled or rejected + * @param {Iterable|Generator|GeneratorFunction} iterable + * @param {AllOptions} options + * @returns {CPromise} + */ + + static allSettled(iterable, options) { + const {mapper, ...allOptions} = options || {}; + + if (mapper !== undefined) { + validateOptions(options, { + mapper + }) + } + + return this.all(iterable, { + ...allOptions, + mapper: (value, i) => { + return this.resolve(mapper ? mapper(value, i) : value).then( + value => ({status: "fulfilled", value}), + err => ({status: "rejected", reason: err}) + ) + } + }) + } + static [_objectToCPromise](thing) { const convertMethod = thing[_toCPromise]; @@ -1225,12 +1201,12 @@ class CPromise extends Promise { * @returns {CPromise} */ - static from(thing, resolveSignatures= true) { + static from(thing, resolveSignatures = true) { if (thing && thing instanceof this) { return thing; } - if(resolveSignatures) { + if (resolveSignatures) { const type = typeof thing; if (type === 'object') { @@ -1256,153 +1232,196 @@ class CPromise extends Promise { } /** - * inner weight accessor - * @name CPromise#innerWeight - * @function - * @param {number} weight - the weight to set + * adds a new listener + * @alias CPromise#addEventListener + * @param {EventType} type + * @param {Function} listener * @returns {CPromise} */ - /** - * weight accessor - * @name CPromise#weight - * @function - * @param {number} [weight] - * @returns {number|CPromise} - */ + on(type, listener) { + const events = this[_events]; + if (!events) return this; + const listeners = events[type]; - /** - * label accessor - * @name CPromise#label - * @function - * @param {string} [label] - * @returns {string|CPromise} - */ + events['newListener'] && this.emit('newListener', type, listener); - /** - * timeout accessor - * @name CPromise#timeout - * @function - * @param {number} [timeout] - * @returns {number|CPromise} - */ + if (!listeners) { + events[type] = listener; + return this; + } + + if (typeof listeners === 'function') { + events[type] = [listeners, listener]; + return this; + } + + listeners.push(listener); + return this; + } /** - * add a new event listener - * @name CPromise#on - * @function - * @param {string|symbol} listener - * @param {function} listener + * removes the listener + * @alias CPromise#removeEventListener + * @param {EventType} type + * @param {Function} listener * @returns {CPromise} */ + off(type, listener) { + if (typeof listener !== 'function') { + throw TypeError('listener must be a function'); + } + + const events = this[_events] + if (!events) return this; + const listeners = events[type]; + if (!listeners) { + return this; + } + + if (typeof listeners === 'function' && listeners === listener) { + events[type] = null; + events['removeListener'] && this.emit('removeListener', type, listener); + return this; + } + + const len = listeners.length; + + for (let i = 0; i < len; i++) { + if (listeners[i] === listener) { + len === 1 ? events[type] = null : listeners.splice(i, 1); + events['removeListener'] && this.emit('removeListener', type, listener); + return this; + } + } + + return this; + } + /** - * remove the event listener - * @name CPromise#off - * @function - * @param {string|symbol} listener - * @param {function} listener - * @returns {CPromise} + * returns listeners count of the specific event type + * @param {EventType} type + * @returns {Number} */ + listenersCount(type) { + const events = this[_events]; + if (!events) return 0; + const listeners = events[type]; + if (!listeners) return 0; + return typeof listeners === 'function' ? 1 : listeners.length; + } + /** - * add a new event listener that will be fired only once - * @name CPromise#once - * @function - * @param {string|symbol} listener - * @param {function} listener - * @returns {CPromise} + * checks if there are listeners of a specific type + * @param {String|Symbol} type + * @returns {Boolean} */ + hasListeners(type) { + const events = this[_events]; + return !!(events && events[type]); + } + /** - * @name CPromise.CanceledError - * @constructor - * @param {string} reason + * add 'once' listener + * @param {EventType} type + * @param {Function} listener + * @returns {CPromise} */ + once(type, listener) { + const emitter = this; + + function _listener() { + emitter.off(type, _listener); + listener.apply(emitter, arguments); + } + + return this.on(type, _listener); + } + /** - * AbortController class - * @name CPromise.AbortController - * @class + * emits the event + * @param {EventType} type + * @param args + * @returns {CPromise} */ -} -const {prototype} = CPromise; + emit(type, ...args) { + const events = this[_events]; + if (!events) return this; + const listeners = events[type]; + if (!listeners) return this; -['on', 'off', 'once'].forEach(methodName => { - const scopeMethod = CPromiseScope.prototype[methodName]; + if (typeof listeners === 'function') { + listeners.apply(this, args); + return this; + } - prototype[methodName] = function () { - try { - scopeMethod.apply(this[_scope], arguments); - }catch(err){ - this[_scope].reject(err); + for (let i = 0; i < listeners.length; i++) { + listeners[i].apply(this, args) } + return this; } -}); -['captureProgress'].forEach(method=>{ - const fn= prototype[method]; - prototype[method]= function(){ - try{ - fn.apply(this, arguments); - }catch(err){ - this[_scope].reject(err); - } - return this; - } -}); + /** + * emits the hook event + * @param {EventType} type + * @param args + * @returns {Boolean} - false if some listener returned false + */ -['weight', 'label', 'timeout', 'innerWeight'].forEach(methodName => { - const scopeMethod = CPromiseScope.prototype[methodName]; - prototype[methodName] = function () { - if (arguments.length) { - try { - scopeMethod.apply(this[_scope], arguments); - }catch(err){ - this[_scope].reject(err); + emitHook(type, ...args) { + const events = this[_events]; + if (!events) return false; + const listeners = events[type]; + if (!listeners) return true; + + let returnValue; + + if (typeof listeners === 'function') { + returnValue = listeners.apply(this, args); + return returnValue === undefined ? undefined : !!returnValue; + } + + for (let i = 0; i < listeners.length; i++) { + returnValue = listeners[i].apply(this, args); + if (returnValue === true) { + return true; } - return this; } - return scopeMethod.call(this[_scope]); + + return returnValue; } -}) -function bindMethod(prototype, methodName) { - const descriptor = Object.getOwnPropertyDescriptor(prototype, methodName); - if (!descriptor) { - throw Error(`Property ${methodName} doesn't exists`); + static overload() { + const _global = typeof window === 'undefined' ? global : window; + _global.Promise = this; } - const method = descriptor.value; - const boundSymbol = Symbol(`${methodName}Bound`); - - Object.defineProperty(prototype, methodName, { - get() { - const context = this; - return this[boundSymbol] || (this[boundSymbol] = function () { - return method.apply(context, arguments); - }) - } - }); } -bindMethod(CPromiseScope.prototype, 'onCancel'); +const {prototype} = CPromise; + +prototype.addEventListener = prototype.on; +prototype.removeEventListener = prototype.off; + +['Cancel', 'Pause', 'Resume'].forEach(type => { + const typeL = type.toLowerCase(); + prototype['on' + type] = function (listener) { + if (!this[_shadow].isPending) { + throw Error(`Unable to subscribe to ${typeL} event since promise has been already settled`); + } + return this.on(typeL, listener); + } +}); Object.defineProperties(CPromise, { CanceledError: {value: CanceledError, configurable: true}, - AbortController: {value: _AbortController, configurable: true}, - CPromiseScope: {value: CPromiseScope, configurable: true} + AbortController: {value: AbortController, configurable: true} }); -/** - * Exports CPromise class as a default - * @exports CPromise - */ module.exports = CPromise; - - - - - diff --git a/lib/c-promise2.js b/lib/c-promise2.js new file mode 100644 index 0000000..bf2a6b2 --- /dev/null +++ b/lib/c-promise2.js @@ -0,0 +1,1235 @@ +/** + * Cancellable Promise with extra features + * @module CPromise + * @exports CPromise + */ + +/** + * @typedef {String|Symbol} EventType + */ + +const {CanceledError} = require('./canceled-error'); +const {AbortController, isAbortSignal} = require('./abort-controller'); +const {validateOptions, validators}= require('./validator'); +const {isThenable, EmptyObject, setImmediate, isGeneratorFunction, isGenerator, toGenerator, toArray}= require('./utils'); + +const {now} = Date; +const {isArray}= Array; + +const _toCPromise= Symbol.for('toCPromise'); + +const TYPE_PROGRESS = Symbol('TYPE_PROGRESS'); +const _handleCancelRejection = Symbol('handleCancelRejection'); + +const _shadow = Symbol('shadow'); +const _events = Symbol('events'); + +const computeWeightSum = promises => { + let i = promises.length; + let sum = 0; + while (i-- > 0) { + sum += promises[i][_shadow].weight; + } + return sum; +} + +function resolveGenerator(generatorFn) { + return new this((resolve, reject, scope) => { + const generator = generatorFn.apply(scope, scope); + + if (!isGenerator(generator)) { + return reject(new TypeError('function must return a generator object')); + } + + let isCaptured; + let progress = 0; + let sum = 0; + let weight = 0; + let promise; + + scope.on('capture', () => { + isCaptured = true; + }); + + const setProgress = (value, _scope, data) => { + progress = (value * weight + sum) / scope.innerWeight(); + if (progress > 1) { + progress = 1; + } + scope.progress(progress, _scope, data); + } + + const onFulfilled = (result) => { + try { + next(generator.next(result)); + } catch (e) { + return reject(e); + } + } + + const onRejected = (err) => { + try { + next(generator.throw(err)); + } catch (e) { + return reject(e); + } + } + + scope.on('cancelhook', (err) => { + if (promise instanceof this) { + return promise.cancel(err) + } + + return !!onRejected(err); + }); + + const next = (r) => { + if (r.done) { + return resolve(r.value); + } + + promise = this.from(r.value); + + sum += weight; + weight = promise.isChain ? 1 : promise.weight(); + + _setImmediate(() => { + isCaptured && promise.progress((value, scope, data) => { + setProgress(value, scope, data); + }); + }); + + return promise.then((value) => { + setProgress(1, promise); + onFulfilled(value) + }, onRejected); + } + + onFulfilled(); + }) +} + +/** + * @typedef {Function} CPromiseExecutorFn + * @this CPromise + * @param {Function} resolve + * @param {Function} reject + * @param {CPromise} scope + */ + +/** + * @typedef {Object} PromiseOptionsObject + * @property {String} label + * @property {Number} timeout + * @property {Number} weight + */ + +/** + * If value is a number it will be considered as the value for timeout option + * If value is a string it will be considered as a label + * @typedef {PromiseOptionsObject|String|Number} CPromiseOptions + */ + +/** + * CPromise class + * @namespace + * @extends Promise + */ + +class CPromise extends Promise { + /** + * Constructs new CPromise instance + * @param {CPromiseExecutorFn} executor - promise executor function that will be invoked + * in the context of the new CPromiseScope instance + * @param {CPromiseOptions} [options] + */ + + constructor(executor, options ) { + if (options !== undefined && options !== null) { + switch (typeof options) { + case 'string': + options = {label: options}; + break; + case 'number': + options = {timeout: options}; + break; + case 'object': + break; + default: + throw TypeError('options must be an object|string|number'); + } + } + + let {label, weight, timeout, signal}= options || {}; + + let resolve, reject; + + super((_resolve, _reject) => { + resolve= _resolve; + reject= _reject; + }); + + const shadow = this[_shadow] = { + resolve, + reject, + innerChain: null, + parent: null, + captured: false, + progress: 0, + computedProgress: -1, + totalWeight: -1, + innerWeight: -1, + isListening: false, + throttle: 0, + throttleTimer: 0, + isPending: true, + isCanceled: false, + isChain: true, + label: '', + weight: 1 + }; + + try { + executor.call(this, this.resolve, this.reject, this); + }catch(err){ + this.reject(err); + } + + if (signal !== undefined) { + if (!isAbortSignal(signal)) { + throw TypeError('signal should implement AbortSignal interface'); + } + const signalListener = () => { + this.cancel(); + } + signal.addEventListener('abort', signalListener); + this.on('done', () => { + signal.removeEventListener('abort', signalListener); + }) + } + + timeout !== undefined && this.timeout(timeout); + + weight !== undefined && this.weight(weight); + + label !== undefined && this.label(label); + + this.on('propagate', (type, scope, data) => { + if (type === TYPE_PROGRESS) { + shadow.computedProgress = -1; + shadow.isListening && this.emit('progress', this.progress(), scope, data); + } + }); + + this.on('newListener', (event) => { + if (event === 'progress') { + shadow.isListening= true; + if (!shadow.captured) { + this.captureProgress() + } + } + }) + + this.on('removeListener', (event) => { + if (event === 'progress') { + if (shadow.isListening && !this.hasListeners('progress')) { + shadow.isListening= false; + } + } + }) + } + + /** + * @typedef {Function} OnCancelListener + * @param {CanceledError} reason + */ + + /** + * registers the listener for cancel event + * @param {OnCancelListener} listener + * @returns {CPromise} + */ + + onCancel(listener) { + if (!this[_shadow].isPending) { + throw Error('Unable to subscribe to close event since promise has been already settled'); + } + this.on('cancel', listener); + return this; + } + + /** + * Set or get the total weight of the inner chains + * @param {Number} [weight] + * @return {Number|CPromise} + */ + + totalWeight(weight) { + if (arguments.length) { + if (weight <= 0 || !Number.isFinite(weight)) { + throw Error('weight must be a number greater than 0') + } + this[_shadow].totalWeight = weight; + return this; + } + return this[_shadow].totalWeight; + } + + /** + * Set or get the total weight of the inner chains + * @param {Number} [weight] + * @return {Number|CPromise} + */ + + innerWeight(weight) { + if (arguments.length) { + if (!Number.isFinite(weight)) { + throw Error('inner weight must be a number') + } + + if (weight <= 0) { + throw Error('inner weight must be greater than 0') + } + + this[_shadow].innerWeight = weight; + return this; + } + return this[_shadow].innerWeight; + } + + /** + * Subscribe to progress event + * @param {Function} listener + * @returns {CPromise} + *//** + * Set promise progress + * @param {Number} value a number between [0, 1] + * @param {*} [data] any data to send for progress event listeners + * @returns {Number|CPromise} + */ + + progress(value, data) { + const shadow = this[_shadow]; + + if (arguments.length) { + + if (typeof value === 'function') { + this.on('progress', value); + return this; + } + + if (!Number.isFinite(value)) { + throw TypeError('value must be a number [0, 1]'); + } + + if (value < 0) { + value = 0; + } else if (value > 1) { + value = 1; + } + + if(!shadow.captured) return this; + + if (value !== 0 && value !== 1) { + value = value.toFixed(10) * 1; + } + + if (shadow.progress !== value) { + shadow.progress = value; + + if (value !== 1 && shadow.throttle) { + if(!shadow.throttleTimer) { + shadow.throttleTimer = setTimeout(() => { + shadow.throttleTimer = 0; + this.propagate(TYPE_PROGRESS, data); + }, shadow.throttle); + } + return this; + } + + this.propagate(TYPE_PROGRESS, data); + } + + return this; + } + + if(shadow.computedProgress === -1) { + shadow.totalWeight===-1 && this.captureProgress(); + + const scopes = this.scopes(); + let i = scopes.length; + let sum = 0; + let progress= 0; + + while (i-- > 0) { + const scope = scopes[i]; + const thatShadow = scope[_shadow]; + const weight = thatShadow.weight; + if (weight > 0) { + sum += weight; + progress += thatShadow.progress * weight; + } + } + + let total = shadow.totalWeight; + + if (total > 0) { + return (shadow.computedProgress = (progress + (total - sum)) / total); + } + + shadow.computedProgress = progress / sum; + } + + return shadow.computedProgress; + } + + /** + * emit propagate event that will propagate through each promise scope in the chain (bubbling) + * @param {String|symbol} type - some type to identify the data kind + * @param {*} data - some data + * @returns {CPromise} + */ + + propagate(type, data = null) { + return this.emit('propagate', type, this, data); + } + + /** + * capture initial progress state of the chain + * @param {Object} [options] + * @param {Number} options.throttle set min interval for firing progress event + * @param {Number} options.innerWeight set weight of the nested promises + * @returns {CPromise} + */ + + captureProgress(options) { + if (options) { + validateOptions(options, { + throttle: validators.numberFinitePositive, + innerWeight: validators.numberFinitePositive + }) + + const {throttle, innerWeight} = options; + + if (throttle !== undefined) { + this[_shadow].throttle = throttle; + } + + if (innerWeight !== undefined) { + this.innerWeight(innerWeight); + } + } + + const shadow = this[_shadow]; + const scopes = this.scopes(); + let i = scopes.length; + let sum = 0; + + while (i-- > 0) { + const scope = scopes[i]; + const thatShadow = scope[_shadow]; + const weight = thatShadow.weight; + + if (weight > 0) { + sum += weight; + + if (!thatShadow.captured) { + thatShadow.captured = true; + scope.emit('capture', scope); + } + + const inner = thatShadow.innerChain; + if (inner && !inner[_shadow].captured) { + inner.captureProgress(options); + } + } + } + + shadow.totalWeight = sum; + + return this; + } + + /** + * Returns all parent scopes that are in pending state + * @returns {CPromise[]} + */ + + scopes() { + let scope = this; + const scopes = [scope]; + while ((scope = scope[_shadow].parent)) { + scopes.push(scope); + } + return scopes; + } + + /** + * timeout before the promise will be canceled + * @param {Number} ms - timeout in ms + * @returns {Number|CPromise} + */ + + timeout(ms) { + if (arguments.length) { + if (this[_shadow].timer) { + clearTimeout(this[_shadow].timer); + this[_shadow].timer = null; + } + + if (typeof ms !== 'number' || ms < 0) { + throw TypeError('timeout must be a positive number'); + } + + if (ms > 0) { + setTimeout(() => { + this.cancel('timeout'); + }, (this[_shadow].timeout = ms)); + } + return this; + } + + return this[_shadow].timeout; + } + + /** + * get promise abort signal object + * @type {AbortSignal} + */ + + get signal() { + if (this[_shadow].controller) return this[_shadow].controller.signal; + + return (this[_shadow].controller = new AbortController()).signal; + } + + /** + * Sets the promise weight in progress capturing process + * @param {Number} weight - any number greater or equal 0 + * @returns {Number|CPromise} returns weight if no arguments were specified + */ + + weight(weight) { + if (arguments.length) { + if (typeof weight !== 'number') { + throw TypeError('weight must be a number'); + } + + if (weight < 0) { + throw Error('weight must must be a positive number'); + } + + this[_shadow].weight = weight; + return this; + } + return this[_shadow].weight; + } + + /** + * Sets the promise label + * @param {String} label - any string + * @returns {Number|CPromise} returns weight if no arguments were specified + */ + + label(label) { + if (arguments.length) { + this[_shadow].label = label; + return this; + } + return this[_shadow].label; + } + + /** + * indicates if the promise is pending + * @returns {Boolean} + */ + + get isPending() { + return this[_shadow].isPending; + } + + /** + * indicates if the promise is pending + * @returns {Boolean} + */ + + get isCanceled() { + return this[_shadow].isCanceled; + } + + /** + * indicates if the promise progress is captured + * @return {boolean} + */ + + get isCaptured(){ + return this[_shadow].captured; + } + + /** + * Resolves the promise with given value + * @param value + * @returns {CPromise} + */ + + resolve(value) { + if (!this[_shadow].isPending) return this; + + if (isThenable(value)) { + if (value instanceof CPromise) { + const promise= value; + const shadow = this[_shadow]; + + shadow.innerChain = promise; + + promise.on('propagate', (type, scope, data) => { + if (type === TYPE_PROGRESS) { + const progress = promise.progress(); + if (scope === promise) { + this.progress(progress, data); + return; + } + } + + this.emit('propagate', type, scope, data); + }); + + shadow.captured && promise.captureProgress(); + + shadow.innerWeight= promise[_shadow].totalWeight; + } + value.then( + (value) => this[_done](null, value), + (err) => this[_done](err) + ) + } else { + this[_done](null, value); + } + return this; + } + + /** + * Rejects the promise with given error + * @param err + * @returns {CPromise} + */ + + reject(err) { + this[_done](err, undefined, true); + return this; + } + + /** + * Resolves or rejects the promise depending on the arguments + * @param err - error object, if specified the promise will be rejected with this error, resolves otherwise + * @param {*} value + * @returns {CPromise} + */ + + done(err, value){ + const shadow= this[_shadow]; + if (!shadow.isPending) return; + shadow.isPending = false; + + shadow.timer && clearTimeout(shadow.timer); + + if (arguments.length < 2) { + if (err && err instanceof CanceledError) { + this[_handleCancelRejection](err); + } + this.emit('done', err); + shadow.reject(err); + }else { + shadow.captured && this.progress(1); + this.emit('done', undefined, value); + shadow.resolve(value); + } + + this.removeAllListeners(); + + shadow.innerChain = null; + shadow.parent = null; + return this; + } + + [_handleCancelRejection](err) { + const shadow= this[_shadow]; + shadow.isCanceled = true; + + err.scope || (err.scope = this); + + if (shadow.controller) { + shadow.controller.abort(); + shadow.controller = null; + } + + this.emit('cancel', err); + } + + /** + * throws the CanceledError that cause promise chain cancellation + * @param {String|Error} [reason] + */ + + cancel(reason) { + return this[_cancel](CanceledError.from(reason)); + } + + [_cancel](err) { + if (!this[_isPending] || this[_isCanceled]) return false; + + let parent = this[_parent]; + + if (parent && parent[_cancel](err)) { + return true; + } + + const innerChain = this[_innerChain]; + + if (innerChain && innerChain[_cancel](err)) { + return true; + } + + if (this.hasListeners('cancelhook')) { + return this.emitHook('cancelhook', err, this); + } + + this.reject(err); + + return true; + } + + /** + * Returns a chain that will be resolved after specified timeout + * @param {Number} ms + * @returns {CPromise} + */ + + delay(ms) { + return this.then((value) => this.constructor.delay(ms, value)); + } + + /** + * returns a CPromise. It takes up to two arguments: callback functions for the success and failure cases of the Promise. + * @param {onFulfilled} onFulfilled + * @param {onRejected} [onRejected] + * @returns {CPromise} + */ + + then(onFulfilled, onRejected) { + const promise = super.then( + onFulfilled && ((value) => onFulfilled.call(promise, value, promise)), + onRejected && ((err) => onRejected.call(promise, err, promise)) + ); + + promise[_shadow].parent = this; + + this.on('propagate', (type, scope, data) => { + promise.emit('propagate', type, scope, data); + }); + + return promise; + } + + /** + * Catches rejection with optionally specified Error class + * @param {Function} onRejected + * @param {Error} [filter] + * @returns {CPromise} + */ + + catch(onRejected, filter) { + if (filter) { + return super.catch((err) => { + if (err instanceof filter) { + onRejected(err); + return; + } + throw err; + }); + } + + return super.catch(onRejected); + } + + /** + * Checks if thing is an CanceledError instance + * @param thing + * @returns {boolean} + */ + + static isCanceledError(thing) { + return thing instanceof CanceledError; + } + + /** + * Returns a CPromise that will be resolved after specified timeout + * @param {Number} ms - delay before resolve the promise with specified value + * @param value + * @returns {CPromise} + */ + + static delay(ms, value) { + return new this((resolve, reject, scope) => { + if (!Number.isFinite(ms)) { + throw TypeError('timeout must be a finite number'); + } + const timer = setTimeout(() => resolve(value), ms); + scope.onCancel(() => clearTimeout(timer)); + }) + } + + /** + * @typedef {object} AllOptions + * @property {number} concurrency limit concurrency of promise being run simultaneously + * @property {function} mapper function to map each element + * @property {boolean} ignoreResults do not collect results + * @property {boolean} signatures use advanced signatures for vales resolving + */ + + /** + * Returns a single CPromise that resolves to an array of the results of the input promises. + * If one fails then other promises will be canceled immediately + * @param {Iterable|Generator|GeneratorFunction} iterable + * @param {AllOptions} options + * @returns {CPromise} + * @example + * CPromise.all(function*(){ + * yield axios.get(url1); + * yield axios.get(url2); + * yield axios.get(url3); + * }, {concurrency: 1}).then(console.log) + */ + + static all(iterable, options) { + return new this((resolve, reject, scope) => { + let pending; + let results; + let progressAcc= 0; + let isCaptured; + let endReached; + let generator; + + if (options !== undefined) { + validateOptions(options, { + concurrency: validators.numberFinitePositive, + ignoreResults: validators.boolean, + signatures: validators.boolean, + mapper: validators.function + }) + } + + let { + concurrency = 0, + ignoreResults, + signatures, + mapper + }= options || {} + + const cancel= (reason)=>{ + const {length}= pending; + for (let i = 0; i < length; i++) { + pending[i].cancel(reason); + } + } + + scope.onCancel(cancel); + + const handleProgress= (value, _scope, data) => { + let total = scope.innerWeight(); + let sum = progressAcc; + const {length} = pending; + for (let i = 0; i < length; i++) { + const promise = pending[i]; + sum += promise.progress() * promise.weight(); + } + sum <= total && scope.progress(sum / total, _scope, data); + }; + + const _reject= err=> { + reject(err); + cancel(); + } + + function throwConvertError(){ + throw TypeError('unable to convert object to iterable'); + } + + scope.on('capture', () => { + let i = pending.length; + while (i-- > 0) { + pending[i].progress(handleProgress); + } + isCaptured = true; + scope.innerWeight() === -1 && scope.innerWeight(computeWeightSum(pending)); + }); + + if (!concurrency) { + pending = toArray(iterable, (value, i)=> { + return this.from(mapper? mapper(value, i) : value, signatures); + }) || throwConvertError(); + + return super.all(pending).then(resolve, _reject); + } + + generator = toGenerator(iterable) || throwConvertError(); + + pending= []; + !ignoreResults && (results= []); + + const next= (value)=> { + const promise = this.from(value, signatures); + + pending.push(promise); + + isCaptured && promise.progress(handleProgress); + + promise.then(resolved => { + const index = pending.indexOf(promise); + if (index !== -1) { + pending.splice(index, 1); + } + + !ignoreResults && results.push(resolved); + + isCaptured && (progressAcc += promise.weight()); + + !endReached && pump(); + + if (!pending.length) { + resolve(ignoreResults ? undefined : results); + } + }, _reject); + } + + const pump = () => { + while (!endReached && pending.length < concurrency) { + let item; + try { + item = generator.next(); + }catch(err){ + _reject(err); + return; + } + + if (item.done){ + endReached= true; + return; + } + next(mapper? mapper(item.value) : item.value); + } + } + + pump(); + }) + } + + /** + * returns a promise that fulfills or rejects as soon as one of the promises in an iterable fulfills or rejects, + * with the value or reason from that promise. Other pending promises will be canceled immediately + * @param {Iterable} thenables + * @returns {CPromise} + */ + + static race(thenables) { + return new this((resolve, reject, scope) => { + thenables = toArray(thenables); + + const {length} = thenables; + + for (let i = 0; i < length; i++) { + thenables[i] = this.from(thenables[i]); + } + + const cancel = (reason) => { + for (let i = 0; i < length; i++) { + thenables[i].cancel(reason); + } + }; + + scope.on('capture', () => { + let max = 0; + for (let i = 0; i < length; i++) { + thenables[i].progress((value, scope, data) => { + for (let i = 0; i < length; i++) { + if (value > max) { + max = value; + return scope.set(value, data); + } + } + }) + } + }); + + scope.onCancel(cancel); + + super.race(thenables).then((value) => { + resolve(value); + cancel(); + }, (err) => { + reject(err); + cancel(); + }); + }); + } + + static [_objectToCPromise](thing) { + const convertMethod = thing[_toCPromise]; + + if (typeof convertMethod === 'function') { + if (promiseAssocStore.has(thing)) { + return promiseAssocStore.get(thing) + } + + const returnedValue = convertMethod.call(thing, this); + + if (!(returnedValue instanceof this)) { + throw Error(`method '[${convertMethod}]' must return a CPromise instance`) + } + + promiseAssocStore.set(thing, returnedValue); + + return returnedValue; + } + + if (thing && typeof thing.then === 'function') { + return new this((resolve, reject, {onCancel}) => { + if (typeof thing.cancel === 'function') { + onCancel(reason => { + try { + thing.cancel(reason); + } catch (err) { + reject(err); + } + }); + } + return thing.then(resolve, reject); + }); + } + + return null; + } + + /** + * Converts thing to CPromise using the following rules: + * - CPromise instance returns as is + * - Objects with special method defined with key `Symbol.for('toCPromise')` will be converted using this method + * The result will be cached for future calls + * - Thenable wraps into a new CPromise instance, if thenable has the `cancel` method it will be used for canceling + * - Generator function will be resolved to CPromise + * - Array will be resoled via `CPromise.all`, arrays with one element (e.g. `[[1000]]`) will be resolved via `CPromise.race` + * + * This method returns null if the conversion failed. + * @param {*} thing + * @param {boolean} [resolveSignatures= true] + * @returns {CPromise} + */ + + static from(thing, resolveSignatures= true) { + if (thing && thing instanceof this) { + return thing; + } + + if(resolveSignatures) { + const type = typeof thing; + + if (type === 'object') { + if (isArray(thing)) { + if (thing.length === 1) { + const first = thing[0]; + if (isArray(first)) { + return this.race(first.map(this.from, this)); + } + } + return this.all(thing.map(this.from, this)) + } + } else if (type === 'function') { + if (isGeneratorFunction(thing)) { + return resolveGenerator.call(this, thing) + } + } + + return this[_objectToCPromise](thing) || this.resolve(thing); + } + + return this.resolve(thing); + } + + + /** + * adds a new listener + * @alias CPromise#addEventListener + * @param {EventType} type + * @param {Function} listener + * @returns {CPromise} + */ + on(type, listener) { + const events = this[_events] || (this[_events] = new EmptyObject()); + const listeners = events[type]; + + events['newListener'] && this.emit('newListener', type, listener); + + if (!listeners) { + events[type] = listener; + return this; + } + + if (typeof listeners === 'function') { + events[type] = [listeners, listener]; + return this; + } + + listeners.push(listener); + return this; + } + + /** + * removes the listener + * @alias CPromise#removeEventListener + * @param {EventType} type + * @param {Function} listener + * @returns {CPromise} + */ + + off(type, listener) { + if(typeof listener!=='function'){ + throw TypeError('listener must be a function'); + } + + const events = this[_events] + if (!events) return this; + const listeners = events[type]; + if (!listeners) { + return this; + } + + if (typeof listeners === 'function' && listeners === listener) { + events[type] = null; + events['removeListener'] && this.emit('removeListener', type, listener); + return this; + } + + const len = listeners.length; + + for (let i = 0; i < len; i++) { + if (listeners[i] === listener) { + len === 1 ? events[type] = null : listeners.splice(i, 1); + events['removeListener'] && this.emit('removeListener', type, listener); + return this; + } + } + + return this; + } + + /** + * returns listeners count of the specific event type + * @param {EventType} type + * @returns {Number} + */ + + listenersCount(type){ + const events = this[_events]; + if (!events) return 0; + const listeners= events[type]; + if(!listeners) return 0; + return typeof listeners==='function'? 1 : listeners.length; + } + + /** + * checks if there are listeners of a specific type + * @param {String|Symbol} type + * @returns {Boolean} + */ + + hasListeners(type){ + const events = this[_events]; + return !!(events && events[type]); + } + + /** + * add 'once' listener + * @param {EventType} type + * @param {Function} listener + * @returns {CPromise} + */ + + once(type, listener) { + const emitter = this; + + function _listener() { + emitter.off(type, _listener); + listener.apply(emitter, arguments); + } + + return this.on(type, _listener); + } + + /** + * emits the event + * @param {EventType} type + * @param args + * @returns {CPromise} + */ + + emit(type, ...args) { + const events = this[_events]; + if (!events) return this; + const listeners = events[type]; + if (!listeners) return this; + + if (typeof listeners === 'function') { + listeners.apply(this, args); + return this; + } + + for (let i = 0; i < listeners.length; i++) { + listeners[i].apply(this, args) + } + + return this; + } + + /** + * emits the hook event + * @param {EventType} type + * @param args + * @returns {Boolean} - false if some listener returned false + */ + + emitHook(type, ...args) { + const events = this[_events]; + if (!events) return this; + const listeners = events[type]; + if (!listeners) return true; + + if (typeof listeners === 'function') { + return listeners.apply(this, args) !== false; + } + + for (let i = 0; i < listeners.length; i++) { + if (listeners[i].apply(this, args) === false) { + return false; + } + } + + return true; + } + + /** + * removes all listeners + * @returns {CPromise} + */ + + removeAllListeners() { + this[_events] = null; + return this; + } +} + +const {prototype}= CPromise; + +prototype.addEventListener = prototype.on; +prototype.removeEventListener = prototype.off; + +module.exports= CPromise; diff --git a/lib/utils.js b/lib/utils.js new file mode 100644 index 0000000..28fd768 --- /dev/null +++ b/lib/utils.js @@ -0,0 +1,53 @@ +const isThenable = obj => !!obj && (typeof obj === 'function' || typeof obj === 'object') && typeof obj.then === 'function'; +const _setImmediate = typeof setImmediate === 'function' ? setImmediate : function setImmediateShim(cb) { + setTimeout(cb, 0) +} +function isGeneratorFunction(thing) { + return typeof thing === 'function' && thing.constructor && thing.constructor.name === 'GeneratorFunction'; +} + +function isGenerator(thing) { + return thing && typeof thing === 'object' && typeof thing.next === 'function'; +} + +function EmptyObject() { +} + +EmptyObject.prototype = null; + +const toGenerator= function(thing, args, context= null){ + if(isGeneratorFunction(thing)){ + return thing.apply(context, args); + } + return thing && (isGenerator(thing)? thing : (thing[Symbol.iterator] && thing[Symbol.iterator]())) || null; +} + +const toArray= (thing, mapper)=>{ + + if (thing) { + if (Array.isArray(thing)) { + return mapper ? thing.map(mapper) : thing; + } + + if ((thing= toGenerator(thing))) { + const arr = []; + let item; + while ((item = thing.next()) && item.done === false) { + arr.push(mapper ? mapper(item.value) : item.value); + } + return arr; + } + } + + return null; +} + +module.exports={ + isThenable, + setImmediate: _setImmediate, + isGenerator, + isGeneratorFunction, + EmptyObject, + toGenerator, + toArray +}; diff --git a/package-lock.json b/package-lock.json index ea439db..7b95fdd 100644 --- a/package-lock.json +++ b/package-lock.json @@ -346,22 +346,6 @@ "integrity": "sha512-tsAQNx32a8CoFhjhijUIhI4kccIAgmGhy8LZMZgGfmXcpMbPRUqn5LWmgRttILi6yeGmBJd2xsPkFMs0PzgPCw==", "dev": true }, - "@mrmlnc/readdir-enhanced": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2.1.tgz", - "integrity": "sha512-bPHp6Ji8b41szTOcaP63VlnbbO5Ny6dwAATtY6JTjh5N2OLrb5Qk/Th5cRkRQhkWCt+EJsYrNB0MiL+Gpn6e3g==", - "dev": true, - "requires": { - "call-me-maybe": "^1.0.1", - "glob-to-regexp": "^0.3.0" - } - }, - "@nodelib/fs.stat": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-1.1.3.tgz", - "integrity": "sha512-shAmDyaQC4H92APFoIaVDHCx5bStIocgvbwQyxPRrbUY20V1EYTbSDchWbuwlMG3V17cprZhA6+78JfB+3DTPw==", - "dev": true - }, "@rollup/plugin-commonjs": { "version": "15.0.0", "resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-15.0.0.tgz", @@ -624,51 +608,12 @@ "sprintf-js": "~1.0.2" } }, - "arr-diff": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", - "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", - "dev": true - }, - "arr-flatten": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", - "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", - "dev": true - }, - "arr-union": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", - "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=", - "dev": true - }, "array-back": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/array-back/-/array-back-4.0.1.tgz", "integrity": "sha512-Z/JnaVEXv+A9xabHzN43FiiiWEE7gPCRXMrVmRm00tWbjZRul1iHm7ECzlyNq1p4a4ATXz+G9FJ3GqGOkOV3fg==", "dev": true }, - "array-union": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", - "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=", - "dev": true, - "requires": { - "array-uniq": "^1.0.1" - } - }, - "array-uniq": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", - "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=", - "dev": true - }, - "array-unique": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", - "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", - "dev": true - }, "array.prototype.map": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/array.prototype.map/-/array.prototype.map-1.0.2.tgz", @@ -696,33 +641,12 @@ "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", "dev": true }, - "assign-symbols": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", - "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=", - "dev": true - }, - "async": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/async/-/async-2.6.3.tgz", - "integrity": "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==", - "dev": true, - "requires": { - "lodash": "^4.17.14" - } - }, "asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", "dev": true }, - "atob": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", - "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", - "dev": true - }, "aws-sign2": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", @@ -741,61 +665,6 @@ "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", "dev": true }, - "base": { - "version": "0.11.2", - "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", - "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", - "dev": true, - "requires": { - "cache-base": "^1.0.1", - "class-utils": "^0.3.5", - "component-emitter": "^1.2.1", - "define-property": "^1.0.0", - "isobject": "^3.0.1", - "mixin-deep": "^1.2.0", - "pascalcase": "^0.1.1" - }, - "dependencies": { - "define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "dev": true, - "requires": { - "is-descriptor": "^1.0.0" - } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - } - } - }, "bcrypt-pbkdf": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", @@ -920,23 +789,6 @@ "integrity": "sha512-k0KL0aWZuBt2lrxrcASWDfwOLMnodeQjodT/1SxEQAXsHANgo6ZC/VEaSEHCXt7aSTZ4/4H5LKa+tBXmW7Vtvw==", "dev": true }, - "cache-base": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", - "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", - "dev": true, - "requires": { - "collection-visit": "^1.0.0", - "component-emitter": "^1.2.1", - "get-value": "^2.0.6", - "has-value": "^1.0.0", - "isobject": "^3.0.1", - "set-value": "^2.0.0", - "to-object-path": "^0.3.0", - "union-value": "^1.0.0", - "unset-value": "^1.0.0" - } - }, "cache-point": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/cache-point/-/cache-point-2.0.0.tgz", @@ -992,12 +844,6 @@ "write-file-atomic": "^3.0.0" } }, - "call-me-maybe": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/call-me-maybe/-/call-me-maybe-1.0.1.tgz", - "integrity": "sha1-JtII6onje1y95gJQoV8DHBak1ms=", - "dev": true - }, "callsites": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", @@ -1010,12 +856,6 @@ "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", "dev": true }, - "capture-stack-trace": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/capture-stack-trace/-/capture-stack-trace-1.0.1.tgz", - "integrity": "sha512-mYQLZnx5Qt1JgB1WEiMCf2647plpGeQ2NMR/5L0HNZzGQo4fuSPnK+wjfPnKZV0aiJDgzmWqqkV/g7JD+DW0qw==", - "dev": true - }, "caseless": { "version": "0.12.0", "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", @@ -1063,29 +903,6 @@ "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", "dev": true }, - "class-utils": { - "version": "0.3.6", - "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", - "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", - "dev": true, - "requires": { - "arr-union": "^3.1.0", - "define-property": "^0.2.5", - "isobject": "^3.0.0", - "static-extend": "^0.1.1" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - } - } - }, "clean-stack": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", @@ -1156,16 +973,6 @@ "stream-via": "^1.0.4" } }, - "collection-visit": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", - "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", - "dev": true, - "requires": { - "map-visit": "^1.0.0", - "object-visit": "^1.0.0" - } - }, "color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -1287,12 +1094,6 @@ "integrity": "sha512-W6Af2Iw1z4CB7q4uU4hv646dW9GQuBM+YpC0UvUCWSD8w90SJjp+ujJuXaEMtAXBtSqGfMPuFOVn4/+FlaqfBA==", "dev": true }, - "component-emitter": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", - "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==", - "dev": true - }, "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -1347,12 +1148,6 @@ } } }, - "copy-descriptor": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", - "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=", - "dev": true - }, "core-util-is": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", @@ -1385,15 +1180,6 @@ "request": "^2.88.2" } }, - "create-error-class": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/create-error-class/-/create-error-class-3.0.2.tgz", - "integrity": "sha1-Br56vvlHo/FKMP1hBnHUAbyot7Y=", - "dev": true, - "requires": { - "capture-stack-trace": "^1.0.0" - } - }, "cross-env": { "version": "7.0.2", "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-7.0.2.tgz", @@ -1444,12 +1230,6 @@ "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", "dev": true }, - "decode-uri-component": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", - "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=", - "dev": true - }, "decompress-response": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz", @@ -1495,47 +1275,6 @@ "object-keys": "^1.0.12" } }, - "define-property": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", - "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", - "dev": true, - "requires": { - "is-descriptor": "^1.0.2", - "isobject": "^3.0.1" - }, - "dependencies": { - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - } - } - }, "delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", @@ -1548,32 +1287,6 @@ "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", "dev": true }, - "dir-glob": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-2.2.2.tgz", - "integrity": "sha512-f9LBi5QWzIW3I6e//uxZoLBlUt9kcp66qo0sSCxL6YZKc75R1c4MFCoe/LaZiBGmgujvQdxc5Bn3QhfyvK5Hsw==", - "dev": true, - "requires": { - "path-type": "^3.0.0" - }, - "dependencies": { - "path-type": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", - "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", - "dev": true, - "requires": { - "pify": "^3.0.0" - } - }, - "pify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", - "dev": true - } - } - }, "dmd": { "version": "5.0.2", "resolved": "https://registry.npmjs.org/dmd/-/dmd-5.0.2.tgz", @@ -1611,547 +1324,20 @@ "is-obj": "^2.0.0" } }, - "dox": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/dox/-/dox-0.9.0.tgz", - "integrity": "sha1-vpewhcufSgt+gINdVH53uGh9Cgw=", + "duplexer3": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz", + "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=", + "dev": true + }, + "ecc-jsbn": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", + "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", "dev": true, "requires": { - "commander": "~2.9.0", - "jsdoctypeparser": "^1.2.0", - "markdown-it": "~7.0.0" - }, - "dependencies": { - "commander": { - "version": "2.9.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.9.0.tgz", - "integrity": "sha1-nJkJQXbhIkDLItbFFGCYQA/g99Q=", - "dev": true, - "requires": { - "graceful-readlink": ">= 1.0.0" - } - }, - "entities": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz", - "integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==", - "dev": true - }, - "markdown-it": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-7.0.1.tgz", - "integrity": "sha1-8S2LiKk+ZCVDSN/Rg71wv2BWekI=", - "dev": true, - "requires": { - "argparse": "^1.0.7", - "entities": "~1.1.1", - "linkify-it": "^2.0.0", - "mdurl": "^1.0.1", - "uc.micro": "^1.0.1" - } - } - } - }, - "doxdox": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doxdox/-/doxdox-3.0.0.tgz", - "integrity": "sha512-6yvubIVhlPcTyoszMET9Za/61M2R1/IJXrnIH8uzCHIio1+oTZpbZtjDfarQlWynruhXtatm3b0LrhacrsevBw==", - "dev": true, - "requires": { - "chalk": "2.4.2", - "doxdox-parser-dox": "~2.0.0", - "doxdox-plugin-bootstrap": "~2.0.0", - "doxdox-plugin-handlebars": "~2.0.0", - "doxdox-plugin-markdown": "~2.0.0", - "globby": "9.0.0", - "parse-cmd-args": "2.0.0", - "update-notifier": "2.5.0" - }, - "dependencies": { - "ansi-align": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-2.0.0.tgz", - "integrity": "sha1-w2rsy6VjuJzrVW82kPCx2eNUf38=", - "dev": true, - "requires": { - "string-width": "^2.0.0" - } - }, - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - }, - "boxen": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/boxen/-/boxen-1.3.0.tgz", - "integrity": "sha512-TNPjfTr432qx7yOjQyaXm3dSR0MH9vXp7eT1BFSl/C51g+EFnOR9hTg1IreahGBmDNCehscshe45f+C1TBZbLw==", - "dev": true, - "requires": { - "ansi-align": "^2.0.0", - "camelcase": "^4.0.0", - "chalk": "^2.0.1", - "cli-boxes": "^1.0.0", - "string-width": "^2.0.0", - "term-size": "^1.2.0", - "widest-line": "^2.0.0" - } - }, - "camelcase": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", - "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=", - "dev": true - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "ci-info": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-1.6.0.tgz", - "integrity": "sha512-vsGdkwSCDpWmP80ncATX7iea5DWQemg1UgCW5J8tqjU3lYw4FBYuj89J0CTVomA7BEfvSZd84GmHko+MxFQU2A==", - "dev": true - }, - "cli-boxes": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-1.0.0.tgz", - "integrity": "sha1-T6kXw+WclKAEzWH47lCdplFocUM=", - "dev": true - }, - "color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "requires": { - "color-name": "1.1.3" - } - }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", - "dev": true - }, - "configstore": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/configstore/-/configstore-3.1.5.tgz", - "integrity": "sha512-nlOhI4+fdzoK5xmJ+NY+1gZK56bwEaWZr8fYuXohZ9Vkc1o3a4T/R3M+yE/w7x/ZVJ1zF8c+oaOvF0dztdUgmA==", - "dev": true, - "requires": { - "dot-prop": "^4.2.1", - "graceful-fs": "^4.1.2", - "make-dir": "^1.0.0", - "unique-string": "^1.0.0", - "write-file-atomic": "^2.0.0", - "xdg-basedir": "^3.0.0" - } - }, - "crypto-random-string": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-1.0.0.tgz", - "integrity": "sha1-ojD2T1aDEOFJgAmUB5DsmVRbyn4=", - "dev": true - }, - "dot-prop": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-4.2.1.tgz", - "integrity": "sha512-l0p4+mIuJIua0mhxGoh4a+iNL9bmeK5DvnSVQa6T0OhrVmaEa1XScX5Etc673FePCJOArq/4Pa2cLGODUWTPOQ==", - "dev": true, - "requires": { - "is-obj": "^1.0.0" - } - }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", - "dev": true - }, - "get-stream": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", - "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=", - "dev": true - }, - "global-dirs": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-0.1.1.tgz", - "integrity": "sha1-sxnA3UYH81PzvpzKTHL8FIxJ9EU=", - "dev": true, - "requires": { - "ini": "^1.3.4" - } - }, - "got": { - "version": "6.7.1", - "resolved": "https://registry.npmjs.org/got/-/got-6.7.1.tgz", - "integrity": "sha1-JAzQV4WpoY5WHcG0S0HHY+8ejbA=", - "dev": true, - "requires": { - "create-error-class": "^3.0.0", - "duplexer3": "^0.1.4", - "get-stream": "^3.0.0", - "is-redirect": "^1.0.0", - "is-retry-allowed": "^1.0.0", - "is-stream": "^1.0.0", - "lowercase-keys": "^1.0.0", - "safe-buffer": "^5.0.1", - "timed-out": "^4.0.0", - "unzip-response": "^2.0.1", - "url-parse-lax": "^1.0.0" - } - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true - }, - "is-ci": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-1.2.1.tgz", - "integrity": "sha512-s6tfsaQaQi3JNciBH6shVqEDvhGut0SUXr31ag8Pd8BBbVVlcGfWhpPmEOoM6RJ5TFhbypvf5yyRw/VXW1IiWg==", - "dev": true, - "requires": { - "ci-info": "^1.5.0" - } - }, - "is-installed-globally": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.1.0.tgz", - "integrity": "sha1-Df2Y9akRFxbdU13aZJL2e/PSWoA=", - "dev": true, - "requires": { - "global-dirs": "^0.1.0", - "is-path-inside": "^1.0.0" - } - }, - "is-npm": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-1.0.0.tgz", - "integrity": "sha1-8vtjpl5JBbQGyGBydloaTceTufQ=", - "dev": true - }, - "is-obj": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz", - "integrity": "sha1-PkcprB9f3gJc19g6iW2rn09n2w8=", - "dev": true - }, - "is-path-inside": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.1.tgz", - "integrity": "sha1-jvW33lBDej/cprToZe96pVy0gDY=", - "dev": true, - "requires": { - "path-is-inside": "^1.0.1" - } - }, - "is-stream": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", - "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", - "dev": true - }, - "latest-version": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-3.1.0.tgz", - "integrity": "sha1-ogU4P+oyKzO1rjsYq+4NwvNW7hU=", - "dev": true, - "requires": { - "package-json": "^4.0.0" - } - }, - "make-dir": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.3.0.tgz", - "integrity": "sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==", - "dev": true, - "requires": { - "pify": "^3.0.0" - } - }, - "package-json": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/package-json/-/package-json-4.0.1.tgz", - "integrity": "sha1-iGmgQBJTZhxMTKPabCEh7VVfXu0=", - "dev": true, - "requires": { - "got": "^6.7.1", - "registry-auth-token": "^3.0.1", - "registry-url": "^3.0.3", - "semver": "^5.1.0" - } - }, - "pify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", - "dev": true - }, - "prepend-http": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-1.0.4.tgz", - "integrity": "sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw=", - "dev": true - }, - "registry-auth-token": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-3.4.0.tgz", - "integrity": "sha512-4LM6Fw8eBQdwMYcES4yTnn2TqIasbXuwDx3um+QRs7S55aMKCBKBxvPXl2RiUjHwuJLTyYfxSpmfSAjQpcuP+A==", - "dev": true, - "requires": { - "rc": "^1.1.6", - "safe-buffer": "^5.0.1" - } - }, - "registry-url": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-3.1.0.tgz", - "integrity": "sha1-PU74cPc93h138M+aOBQyRE4XSUI=", - "dev": true, - "requires": { - "rc": "^1.0.1" - } - }, - "semver-diff": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/semver-diff/-/semver-diff-2.1.0.tgz", - "integrity": "sha1-S7uEN8jTfksM8aaP1ybsbWRdbTY=", - "dev": true, - "requires": { - "semver": "^5.0.3" - } - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - }, - "term-size": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/term-size/-/term-size-1.2.0.tgz", - "integrity": "sha1-RYuDiH8oj8Vtb/+/rSYuJmOO+mk=", - "dev": true, - "requires": { - "execa": "^0.7.0" - } - }, - "unique-string": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-1.0.0.tgz", - "integrity": "sha1-nhBXzKhRq7kzmPizOuGHuZyuwRo=", - "dev": true, - "requires": { - "crypto-random-string": "^1.0.0" - } - }, - "update-notifier": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-2.5.0.tgz", - "integrity": "sha512-gwMdhgJHGuj/+wHJJs9e6PcCszpxR1b236igrOkUofGhqJuG+amlIKwApH1IW1WWl7ovZxsX49lMBWLxSdm5Dw==", - "dev": true, - "requires": { - "boxen": "^1.2.1", - "chalk": "^2.0.1", - "configstore": "^3.0.0", - "import-lazy": "^2.1.0", - "is-ci": "^1.0.10", - "is-installed-globally": "^0.1.0", - "is-npm": "^1.0.0", - "latest-version": "^3.0.0", - "semver-diff": "^2.0.0", - "xdg-basedir": "^3.0.0" - } - }, - "url-parse-lax": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-1.0.0.tgz", - "integrity": "sha1-evjzA2Rem9eaJy56FKxovAYJ2nM=", - "dev": true, - "requires": { - "prepend-http": "^1.0.1" - } - }, - "widest-line": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-2.0.1.tgz", - "integrity": "sha512-Ba5m9/Fa4Xt9eb2ELXt77JxVDV8w7qQrH0zS/TWSJdLyAwQjWoOzpzj5lwVftDz6n/EOu3tNACS84v509qwnJA==", - "dev": true, - "requires": { - "string-width": "^2.1.1" - } - }, - "write-file-atomic": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.4.3.tgz", - "integrity": "sha512-GaETH5wwsX+GcnzhPgKcKjJ6M2Cq3/iZp1WyY/X1CSqrW+jVNM9Y7D8EC2sM4ZG/V8wZlSniJnCKWPmBYAucRQ==", - "dev": true, - "requires": { - "graceful-fs": "^4.1.11", - "imurmurhash": "^0.1.4", - "signal-exit": "^3.0.2" - } - }, - "xdg-basedir": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-3.0.0.tgz", - "integrity": "sha1-SWsswQnsqNus/i3HK2A8F8WHCtQ=", - "dev": true - } - } - }, - "doxdox-parser-dox": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/doxdox-parser-dox/-/doxdox-parser-dox-2.0.0.tgz", - "integrity": "sha512-XWuitnRJjUZixPDc+VYv/QeAgk+G7UJAtGmOxhy4L8xoTqm8S9Xlfr8fZQvewPXUIraF5JrkjqYVvrIqQWVosA==", - "dev": true, - "requires": { - "dox": "0.9.0" - } - }, - "doxdox-plugin-bootstrap": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/doxdox-plugin-bootstrap/-/doxdox-plugin-bootstrap-2.0.0.tgz", - "integrity": "sha512-ODrtIk8K/Ln84bhTd+Th4sC5gPX7UJcvQ045mIluFa3UjeJsuofs+AiPo+LrLCIVzXaqIe7FBAckqduxBDencg==", - "dev": true, - "requires": { - "handlebars": "4.1.0", - "highlight.js": "9.15.6", - "markdown-it": "8.4.2" - }, - "dependencies": { - "entities": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz", - "integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==", - "dev": true - }, - "handlebars": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.1.0.tgz", - "integrity": "sha512-l2jRuU1NAWK6AW5qqcTATWQJvNPEwkM7NEKSiv/gqOsoSQbVoWyqVEY5GS+XPQ88zLNmqASRpzfdm8d79hJS+w==", - "dev": true, - "requires": { - "async": "^2.5.0", - "optimist": "^0.6.1", - "source-map": "^0.6.1", - "uglify-js": "^3.1.4" - } - }, - "markdown-it": { - "version": "8.4.2", - "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-8.4.2.tgz", - "integrity": "sha512-GcRz3AWTqSUphY3vsUqQSFMbgR38a4Lh3GWlHRh/7MRwz8mcu9n2IO7HOh+bXHrR9kOPDl5RNCaEsrneb+xhHQ==", - "dev": true, - "requires": { - "argparse": "^1.0.7", - "entities": "~1.1.1", - "linkify-it": "^2.0.0", - "mdurl": "^1.0.1", - "uc.micro": "^1.0.5" - } - } - } - }, - "doxdox-plugin-handlebars": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/doxdox-plugin-handlebars/-/doxdox-plugin-handlebars-2.0.0.tgz", - "integrity": "sha512-NQyMDJZM9Z7Mfs5ETSCKIPl2z4F9bw9W39oCDKXIhiEsn7pRmjWonKI7i5TMsfBqXNQEzO4aNraLt+424n/Tdw==", - "dev": true, - "requires": { - "handlebars": "4.1.0", - "highlight.js": "9.15.6", - "markdown-it": "8.4.2" - }, - "dependencies": { - "entities": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz", - "integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==", - "dev": true - }, - "handlebars": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.1.0.tgz", - "integrity": "sha512-l2jRuU1NAWK6AW5qqcTATWQJvNPEwkM7NEKSiv/gqOsoSQbVoWyqVEY5GS+XPQ88zLNmqASRpzfdm8d79hJS+w==", - "dev": true, - "requires": { - "async": "^2.5.0", - "optimist": "^0.6.1", - "source-map": "^0.6.1", - "uglify-js": "^3.1.4" - } - }, - "markdown-it": { - "version": "8.4.2", - "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-8.4.2.tgz", - "integrity": "sha512-GcRz3AWTqSUphY3vsUqQSFMbgR38a4Lh3GWlHRh/7MRwz8mcu9n2IO7HOh+bXHrR9kOPDl5RNCaEsrneb+xhHQ==", - "dev": true, - "requires": { - "argparse": "^1.0.7", - "entities": "~1.1.1", - "linkify-it": "^2.0.0", - "mdurl": "^1.0.1", - "uc.micro": "^1.0.5" - } - } - } - }, - "doxdox-plugin-markdown": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/doxdox-plugin-markdown/-/doxdox-plugin-markdown-2.0.0.tgz", - "integrity": "sha512-KKiGEPPmc/34QhcxzxWA9cxmBHYAKMfGKfQmOKFvvvrwblWNCaiSnKRKAyDaANXKjvstbuokOJkV5Z2/xrkHvA==", - "dev": true, - "requires": { - "handlebars": "4.1.0" - }, - "dependencies": { - "handlebars": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.1.0.tgz", - "integrity": "sha512-l2jRuU1NAWK6AW5qqcTATWQJvNPEwkM7NEKSiv/gqOsoSQbVoWyqVEY5GS+XPQ88zLNmqASRpzfdm8d79hJS+w==", - "dev": true, - "requires": { - "async": "^2.5.0", - "optimist": "^0.6.1", - "source-map": "^0.6.1", - "uglify-js": "^3.1.4" - } - } - } - }, - "duplexer3": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz", - "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=", - "dev": true - }, - "ecc-jsbn": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", - "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", - "dev": true, - "requires": { - "jsbn": "~0.1.0", - "safer-buffer": "^2.1.0" + "jsbn": "~0.1.0", + "safer-buffer": "^2.1.0" } }, "emoji-regex": { @@ -2265,212 +1451,12 @@ "integrity": "sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==", "dev": true }, - "execa": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-0.7.0.tgz", - "integrity": "sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c=", - "dev": true, - "requires": { - "cross-spawn": "^5.0.1", - "get-stream": "^3.0.0", - "is-stream": "^1.1.0", - "npm-run-path": "^2.0.0", - "p-finally": "^1.0.0", - "signal-exit": "^3.0.0", - "strip-eof": "^1.0.0" - }, - "dependencies": { - "cross-spawn": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", - "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=", - "dev": true, - "requires": { - "lru-cache": "^4.0.1", - "shebang-command": "^1.2.0", - "which": "^1.2.9" - } - }, - "get-stream": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", - "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=", - "dev": true - }, - "is-stream": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", - "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", - "dev": true - }, - "shebang-command": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", - "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", - "dev": true, - "requires": { - "shebang-regex": "^1.0.0" - } - }, - "shebang-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", - "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", - "dev": true - }, - "which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", - "dev": true, - "requires": { - "isexe": "^2.0.0" - } - } - } - }, - "expand-brackets": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", - "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", - "dev": true, - "requires": { - "debug": "^2.3.3", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "posix-character-classes": "^0.1.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - } - } - }, "extend": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", "dev": true }, - "extend-shallow": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", - "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", - "dev": true, - "requires": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" - }, - "dependencies": { - "is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "dev": true, - "requires": { - "is-plain-object": "^2.0.4" - } - } - } - }, - "extglob": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", - "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", - "dev": true, - "requires": { - "array-unique": "^0.3.2", - "define-property": "^1.0.0", - "expand-brackets": "^2.1.4", - "extend-shallow": "^2.0.1", - "fragment-cache": "^0.2.1", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "dependencies": { - "define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "dev": true, - "requires": { - "is-descriptor": "^1.0.0" - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - } - } - }, "extsprintf": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", @@ -2483,43 +1469,6 @@ "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", "dev": true }, - "fast-glob": { - "version": "2.2.7", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-2.2.7.tgz", - "integrity": "sha512-g1KuQwHOZAmOZMuBtHdxDtju+T2RT8jgCC9aANsbpdiDDTSnjgfuVsIBNKbUeJI3oKMRExcfNDtJl4OhbffMsw==", - "dev": true, - "requires": { - "@mrmlnc/readdir-enhanced": "^2.2.1", - "@nodelib/fs.stat": "^1.1.2", - "glob-parent": "^3.1.0", - "is-glob": "^4.0.0", - "merge2": "^1.2.3", - "micromatch": "^3.1.10" - }, - "dependencies": { - "glob-parent": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", - "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", - "dev": true, - "requires": { - "is-glob": "^3.1.0", - "path-dirname": "^1.0.0" - }, - "dependencies": { - "is-glob": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", - "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", - "dev": true, - "requires": { - "is-extglob": "^2.1.0" - } - } - } - } - } - }, "fast-json-stable-stringify": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", @@ -2601,12 +1550,6 @@ "is-buffer": "~2.0.3" } }, - "for-in": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", - "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", - "dev": true - }, "foreground-child": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-2.0.0.tgz", @@ -2634,15 +1577,6 @@ "mime-types": "^2.1.12" } }, - "fragment-cache": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", - "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", - "dev": true, - "requires": { - "map-cache": "^0.2.2" - } - }, "fromentries": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/fromentries/-/fromentries-1.2.1.tgz", @@ -2701,12 +1635,6 @@ "pump": "^3.0.0" } }, - "get-value": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", - "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=", - "dev": true - }, "getpass": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", @@ -2739,12 +1667,6 @@ "is-glob": "^4.0.1" } }, - "glob-to-regexp": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.3.0.tgz", - "integrity": "sha1-jFoUlNIGbFcMw7/kSWF1rMTVAqs=", - "dev": true - }, "global-dirs": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-2.0.1.tgz", @@ -2760,29 +1682,6 @@ "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", "dev": true }, - "globby": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-9.0.0.tgz", - "integrity": "sha512-q0qiO/p1w/yJ0hk8V9x1UXlgsXUxlGd0AHUOXZVXBO6aznDtpx7M8D1kBrCAItoPm+4l8r6ATXV1JpjY2SBQOw==", - "dev": true, - "requires": { - "array-union": "^1.0.2", - "dir-glob": "^2.2.1", - "fast-glob": "^2.2.6", - "glob": "^7.1.3", - "ignore": "^4.0.3", - "pify": "^4.0.1", - "slash": "^2.0.0" - }, - "dependencies": { - "slash": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", - "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==", - "dev": true - } - } - }, "got": { "version": "9.6.0", "resolved": "https://registry.npmjs.org/got/-/got-9.6.0.tgz", @@ -2808,12 +1707,6 @@ "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==", "dev": true }, - "graceful-readlink": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz", - "integrity": "sha1-TK+tdrxi8C+gObL5Tpo906ORpyU=", - "dev": true - }, "growl": { "version": "1.10.5", "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", @@ -2870,64 +1763,6 @@ "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==", "dev": true }, - "has-value": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", - "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", - "dev": true, - "requires": { - "get-value": "^2.0.6", - "has-values": "^1.0.0", - "isobject": "^3.0.0" - } - }, - "has-values": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", - "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", - "dev": true, - "requires": { - "is-number": "^3.0.0", - "kind-of": "^4.0.0" - }, - "dependencies": { - "is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", - "dev": true - }, - "is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "kind-of": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", - "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, "has-yarn": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/has-yarn/-/has-yarn-2.1.0.tgz", @@ -2950,12 +1785,6 @@ "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", "dev": true }, - "highlight.js": { - "version": "9.15.6", - "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-9.15.6.tgz", - "integrity": "sha512-zozTAWM1D6sozHo8kqhfYgsac+B+q0PmsjXeyDrYIHHcBN0zTVT66+s2GW1GZv7DbyaROdLXKdabwS/WqPyIdQ==", - "dev": true - }, "html-escaper": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", @@ -2997,12 +1826,6 @@ "which-pm-runs": "^1.0.0" } }, - "ignore": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", - "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", - "dev": true - }, "ignore-by-default": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", @@ -3073,32 +1896,6 @@ "integrity": "sha512-zDml/jzr2PKU9I8J/xyZBQn8rPCAY//UOYNmR01XwNwyfhEWObo2SWfSl1+0tm1u6PhxLwDnfsT/6jB7OUxqFA==", "dev": true }, - "is-accessor-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", - "dev": true - }, - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, "is-arguments": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.0.4.tgz", @@ -3141,63 +1938,12 @@ "ci-info": "^2.0.0" } }, - "is-data-descriptor": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", - "dev": true - }, - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, "is-date-object": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.2.tgz", "integrity": "sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g==", "dev": true }, - "is-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" - }, - "dependencies": { - "kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", - "dev": true - } - } - }, - "is-extendable": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", - "dev": true - }, "is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", @@ -3271,21 +2017,6 @@ "integrity": "sha1-caUMhCnfync8kqOQpKA7OfzVHT4=", "dev": true }, - "is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dev": true, - "requires": { - "isobject": "^3.0.1" - } - }, - "is-redirect": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-redirect/-/is-redirect-1.0.0.tgz", - "integrity": "sha1-HQPd7VO9jbDzDCbk+V02/HyH3CQ=", - "dev": true - }, "is-reference": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-1.2.1.tgz", @@ -3304,12 +2035,6 @@ "has-symbols": "^1.0.1" } }, - "is-retry-allowed": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/is-retry-allowed/-/is-retry-allowed-1.2.0.tgz", - "integrity": "sha512-RUbUeKwvm3XG2VYamhJL1xFktgjvPzL0Hq8C+6yrWIswDy3BIXGqCxhxkc30N9jqK311gVU137K8Ei55/zVJRg==", - "dev": true - }, "is-set": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.1.tgz", @@ -3367,12 +2092,6 @@ "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", "dev": true }, - "isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", - "dev": true - }, "isstream": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", @@ -3607,23 +2326,6 @@ "walk-back": "^4.0.0" } }, - "jsdoctypeparser": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/jsdoctypeparser/-/jsdoctypeparser-1.2.0.tgz", - "integrity": "sha1-597cFToRhJ/8UUEUSuhqfvDCU5I=", - "dev": true, - "requires": { - "lodash": "^3.7.0" - }, - "dependencies": { - "lodash": { - "version": "3.10.1", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-3.10.1.tgz", - "integrity": "sha1-W/Rejkm6QYnhfUgnid/RW9FAt7Y=", - "dev": true - } - } - }, "jsesc": { "version": "2.5.2", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", @@ -3690,12 +2392,6 @@ "json-buffer": "3.0.0" } }, - "kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "dev": true - }, "klaw": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/klaw/-/klaw-3.0.0.tgz", @@ -3801,16 +2497,6 @@ "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==", "dev": true }, - "lru-cache": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", - "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", - "dev": true, - "requires": { - "pseudomap": "^1.0.2", - "yallist": "^2.1.2" - } - }, "magic-string": { "version": "0.25.7", "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.7.tgz", @@ -3837,21 +2523,6 @@ } } }, - "map-cache": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", - "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=", - "dev": true - }, - "map-visit": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", - "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", - "dev": true, - "requires": { - "object-visit": "^1.0.0" - } - }, "markdown-it": { "version": "10.0.0", "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-10.0.0.tgz", @@ -3889,123 +2560,6 @@ "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", "dev": true }, - "merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "dev": true - }, - "micromatch": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", - "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", - "dev": true, - "requires": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "braces": "^2.3.1", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "extglob": "^2.0.4", - "fragment-cache": "^0.2.1", - "kind-of": "^6.0.2", - "nanomatch": "^1.2.9", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.2" - }, - "dependencies": { - "braces": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", - "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", - "dev": true, - "requires": { - "arr-flatten": "^1.1.0", - "array-unique": "^0.3.2", - "extend-shallow": "^2.0.1", - "fill-range": "^4.0.0", - "isobject": "^3.0.1", - "repeat-element": "^1.1.2", - "snapdragon": "^0.8.1", - "snapdragon-node": "^2.0.1", - "split-string": "^3.0.2", - "to-regex": "^3.0.1" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "fill-range": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", - "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", - "dev": true, - "requires": { - "extend-shallow": "^2.0.1", - "is-number": "^3.0.0", - "repeat-string": "^1.6.1", - "to-regex-range": "^2.1.0" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", - "dev": true - }, - "is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "to-regex-range": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", - "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", - "dev": true, - "requires": { - "is-number": "^3.0.0", - "repeat-string": "^1.6.1" - } - } - } - }, "mime-db": { "version": "1.44.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.44.0.tgz", @@ -4042,27 +2596,6 @@ "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", "dev": true }, - "mixin-deep": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", - "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==", - "dev": true, - "requires": { - "for-in": "^1.0.2", - "is-extendable": "^1.0.1" - }, - "dependencies": { - "is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "dev": true, - "requires": { - "is-plain-object": "^2.0.4" - } - } - } - }, "mkdirp": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", @@ -4125,25 +2658,6 @@ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true }, - "nanomatch": { - "version": "1.2.13", - "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", - "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", - "dev": true, - "requires": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "fragment-cache": "^0.2.1", - "is-windows": "^1.0.2", - "kind-of": "^6.0.2", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - } - }, "neo-async": { "version": "2.6.2", "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", @@ -7741,23 +6255,6 @@ } } }, - "npm-run-path": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", - "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", - "dev": true, - "requires": { - "path-key": "^2.0.0" - }, - "dependencies": { - "path-key": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", - "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", - "dev": true - } - } - }, "nyc": { "version": "15.1.0", "resolved": "https://registry.npmjs.org/nyc/-/nyc-15.1.0.tgz", @@ -7911,59 +6408,22 @@ }, "yargs-parser": { "version": "18.1.3", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", - "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", - "dev": true, - "requires": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" - } - } - } - }, - "oauth-sign": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", - "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", - "dev": true - }, - "object-copy": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", - "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", - "dev": true, - "requires": { - "copy-descriptor": "^0.1.0", - "define-property": "^0.2.5", - "kind-of": "^3.0.3" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - }, - "is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", - "dev": true - }, - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", + "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", "dev": true, "requires": { - "is-buffer": "^1.1.5" + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" } } } }, + "oauth-sign": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", + "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", + "dev": true + }, "object-get": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/object-get/-/object-get-2.1.1.tgz", @@ -7988,15 +6448,6 @@ "integrity": "sha512-ZMT4owlXg3JGegecLlAgAA/6BsdKHn63R3ayXcAa3zFkF7oUBHcSb0oxszeutYe0FO2c1lT5pwCuidLkC4Gx3g==", "dev": true }, - "object-visit": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", - "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", - "dev": true, - "requires": { - "isobject": "^3.0.0" - } - }, "object.assign": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz", @@ -8009,15 +6460,6 @@ "object-keys": "^1.0.11" } }, - "object.pick": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", - "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", - "dev": true, - "requires": { - "isobject": "^3.0.1" - } - }, "once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -8033,42 +6475,12 @@ "integrity": "sha512-8AV/sCtuzUeTo8gQK5qDZzARrulB3egtLzFgteqB2tcT4Mw7B8Kt7JcDHmltjz6FOAHsvTevk70gZEbhM4ZS9Q==", "dev": true }, - "optimist": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz", - "integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=", - "dev": true, - "requires": { - "minimist": "~0.0.1", - "wordwrap": "~0.0.2" - }, - "dependencies": { - "minimist": { - "version": "0.0.10", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz", - "integrity": "sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8=", - "dev": true - }, - "wordwrap": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz", - "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc=", - "dev": true - } - } - }, "p-cancelable": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-1.1.0.tgz", "integrity": "sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw==", "dev": true }, - "p-finally": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", - "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", - "dev": true - }, "p-limit": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.0.2.tgz", @@ -8143,12 +6555,6 @@ "callsites": "^3.0.0" } }, - "parse-cmd-args": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/parse-cmd-args/-/parse-cmd-args-2.0.0.tgz", - "integrity": "sha1-KtbQ/UhdeWMs1AbIPU2HfXk6k1U=", - "dev": true - }, "parse-json": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.1.0.tgz", @@ -8161,18 +6567,6 @@ "lines-and-columns": "^1.1.6" } }, - "pascalcase": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", - "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=", - "dev": true - }, - "path-dirname": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz", - "integrity": "sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA=", - "dev": true - }, "path-exists": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", @@ -8185,12 +6579,6 @@ "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", "dev": true }, - "path-is-inside": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", - "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=", - "dev": true - }, "path-key": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", @@ -8221,12 +6609,6 @@ "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==", "dev": true }, - "pify": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", - "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", - "dev": true - }, "pkg-dir": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", @@ -8284,12 +6666,6 @@ "semver-compare": "^1.0.0" } }, - "posix-character-classes": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", - "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=", - "dev": true - }, "prepend-http": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz", @@ -8318,12 +6694,6 @@ "iterate-value": "^1.0.0" } }, - "pseudomap": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", - "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=", - "dev": true - }, "psl": { "version": "1.8.0", "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", @@ -8477,16 +6847,6 @@ } } }, - "regex-not": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", - "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", - "dev": true, - "requires": { - "extend-shallow": "^3.0.2", - "safe-regex": "^1.1.0" - } - }, "registry-auth-token": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-4.2.0.tgz", @@ -8514,18 +6874,6 @@ "es6-error": "^4.0.1" } }, - "repeat-element": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.3.tgz", - "integrity": "sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g==", - "dev": true - }, - "repeat-string": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", - "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", - "dev": true - }, "request": { "version": "2.88.2", "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", @@ -8590,12 +6938,6 @@ "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", "dev": true }, - "resolve-url": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", - "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=", - "dev": true - }, "responselike": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/responselike/-/responselike-1.0.2.tgz", @@ -8605,12 +6947,6 @@ "lowercase-keys": "^1.0.0" } }, - "ret": { - "version": "0.1.15", - "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", - "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", - "dev": true - }, "rimraf": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", @@ -8647,15 +6983,6 @@ "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", "dev": true }, - "safe-regex": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", - "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", - "dev": true, - "requires": { - "ret": "~0.1.10" - } - }, "safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", @@ -8712,29 +7039,6 @@ "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", "dev": true }, - "set-value": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", - "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==", - "dev": true, - "requires": { - "extend-shallow": "^2.0.1", - "is-extendable": "^0.1.1", - "is-plain-object": "^2.0.3", - "split-string": "^3.0.1" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, "shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -8762,140 +7066,6 @@ "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", "dev": true }, - "snapdragon": { - "version": "0.8.2", - "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", - "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", - "dev": true, - "requires": { - "base": "^0.11.1", - "debug": "^2.2.0", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "map-cache": "^0.2.2", - "source-map": "^0.5.6", - "source-map-resolve": "^0.5.0", - "use": "^3.1.0" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - }, - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true - } - } - }, - "snapdragon-node": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", - "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", - "dev": true, - "requires": { - "define-property": "^1.0.0", - "isobject": "^3.0.0", - "snapdragon-util": "^3.0.1" - }, - "dependencies": { - "define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "dev": true, - "requires": { - "is-descriptor": "^1.0.0" - } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - } - } - }, - "snapdragon-util": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", - "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", - "dev": true, - "requires": { - "kind-of": "^3.2.0" - }, - "dependencies": { - "is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", - "dev": true - }, - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, "sort-array": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/sort-array/-/sort-array-4.1.2.tgz", @@ -8920,19 +7090,6 @@ "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true }, - "source-map-resolve": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.3.tgz", - "integrity": "sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==", - "dev": true, - "requires": { - "atob": "^2.1.2", - "decode-uri-component": "^0.2.0", - "resolve-url": "^0.2.1", - "source-map-url": "^0.4.0", - "urix": "^0.1.0" - } - }, "source-map-support": { "version": "0.5.19", "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz", @@ -8951,12 +7108,6 @@ } } }, - "source-map-url": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.0.tgz", - "integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=", - "dev": true - }, "sourcemap-codec": { "version": "1.4.8", "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz", @@ -8977,15 +7128,6 @@ "which": "^2.0.1" } }, - "split-string": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", - "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", - "dev": true, - "requires": { - "extend-shallow": "^3.0.0" - } - }, "sprintf-js": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", @@ -9009,27 +7151,6 @@ "tweetnacl": "~0.14.0" } }, - "static-extend": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", - "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", - "dev": true, - "requires": { - "define-property": "^0.2.5", - "object-copy": "^0.1.0" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - } - } - }, "stream-connect": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/stream-connect/-/stream-connect-1.0.2.tgz", @@ -9101,12 +7222,6 @@ "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", "dev": true }, - "strip-eof": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", - "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=", - "dev": true - }, "strip-json-comments": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.0.1.tgz", @@ -9215,62 +7330,18 @@ } } }, - "timed-out": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/timed-out/-/timed-out-4.0.1.tgz", - "integrity": "sha1-8y6srFoXW+ol1/q1Zas+2HQe9W8=", - "dev": true - }, "to-fast-properties": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", "dev": true }, - "to-object-path": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", - "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", - "dev": true - }, - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, "to-readable-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/to-readable-stream/-/to-readable-stream-1.0.0.tgz", "integrity": "sha512-Iq25XBt6zD5npPhlLVXGFN3/gyR2/qODcKNNyTMd4vbm39HUaOiAM4PMq0eMVC/Tkxz+Zjdsc55g9yyz+Yq00Q==", "dev": true }, - "to-regex": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", - "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", - "dev": true, - "requires": { - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "regex-not": "^1.0.2", - "safe-regex": "^1.1.0" - } - }, "to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", @@ -9380,18 +7451,6 @@ "integrity": "sha512-N4P+Q/BuyuEKFJ43B9gYuOj4TQUHXX+j2FqguVOpjkssLUUrnJofCcBccJSCoeturDoZU6GorDTHSvUDlSQbTg==", "dev": true }, - "union-value": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", - "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==", - "dev": true, - "requires": { - "arr-union": "^3.1.0", - "get-value": "^2.0.6", - "is-extendable": "^0.1.1", - "set-value": "^2.0.1" - } - }, "unique-string": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-2.0.0.tgz", @@ -9401,58 +7460,6 @@ "crypto-random-string": "^2.0.0" } }, - "unset-value": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", - "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", - "dev": true, - "requires": { - "has-value": "^0.3.1", - "isobject": "^3.0.0" - }, - "dependencies": { - "has-value": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", - "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", - "dev": true, - "requires": { - "get-value": "^2.0.3", - "has-values": "^0.1.4", - "isobject": "^2.0.0" - }, - "dependencies": { - "isobject": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", - "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", - "dev": true, - "requires": { - "isarray": "1.0.0" - } - } - } - }, - "has-values": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", - "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=", - "dev": true - }, - "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", - "dev": true - } - } - }, - "unzip-response": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/unzip-response/-/unzip-response-2.0.1.tgz", - "integrity": "sha1-0vD3N9FrBhXnKmk17QQhRXLVb5c=", - "dev": true - }, "update-notifier": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-4.1.1.tgz", @@ -9495,12 +7502,6 @@ "punycode": "^2.1.0" } }, - "urix": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", - "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=", - "dev": true - }, "url-parse-lax": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-3.0.0.tgz", @@ -9510,12 +7511,6 @@ "prepend-http": "^2.0.0" } }, - "use": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", - "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==", - "dev": true - }, "uuid": { "version": "3.4.0", "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", @@ -9739,12 +7734,6 @@ "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==", "dev": true }, - "yallist": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", - "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", - "dev": true - }, "yaml": { "version": "1.10.0", "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.0.tgz", diff --git a/package.json b/package.json index a857512..e202458 100644 --- a/package.json +++ b/package.json @@ -89,6 +89,7 @@ "yield", "race", "delay", + "suspending", "wait", "bluebird", "deferred", @@ -96,6 +97,7 @@ "aborting", "close", "closable", + "pause", "task", "p-cancelable" ], diff --git a/test/tests/CPromise.js b/test/tests/CPromise.js index ed53f70..6e28747 100644 --- a/test/tests/CPromise.js +++ b/test/tests/CPromise.js @@ -43,7 +43,7 @@ module.exports = { }) }, - 'prototype.cancel()': { + 'cancellation': { 'should reject the promise with CanceledError': async function () { const promise = new CPromise((resolve, reject) => { setTimeout(resolve, 1000, 123); @@ -111,9 +111,38 @@ module.exports = { } throw err; }); - } + }, + + 'throwing the CanceledError inside the promise': { + "should lead to chains cancellation": async function () { + let canceled = false; + let signaled = false; + + return CPromise.delay(10, 123).then((value, {signal, onCancel}) => { + onCancel((reason) => { + assert.equal(reason.message, 'test'); + canceled = true; + }); + + signal.addEventListener('abort', () => { + signaled = true; + }) + + return CPromise.delay(20).then(() => { + throw new CPromise.CanceledError('test'); + }); + }).then(() => { + assert.fail("has not been rejected"); + }, (err) => { + assert.equal(err.message, 'test'); + assert.ok(canceled, "not cancelled"); + assert.ok(signaled, "not signaled"); + assert.ok(err instanceof CPromise.CanceledError); + }) + } + }, }, - 'prototype.progress': { + 'progress capturing': { 'should return correct chain progress': async function () { const chain = delay(100) .then(() => { @@ -143,33 +172,36 @@ module.exports = { }) } }, - - "throwing the CanceledError inside the promise": { - "should lead to chains cancellation": async function () { - let canceled = false; - let signaled = false; - - return CPromise.delay(10, 123).then((value, {signal, onCancel}) => { - onCancel((reason) => { - assert.equal(reason.message, 'test'); - canceled = true; + 'suspension': { + 'should support pause and resume methods': async function() { + let timestamp = Date.now(); + let pauseEmitted, resumeEmitted; + const passed = () => { + return Date.now() - timestamp; + } + const chain = new CPromise((resolve, reject, {onPause, onResume}) => { + setTimeout(resolve, 500); + onPause(() => { + pauseEmitted = true; }); - signal.addEventListener('abort', () => { - signaled = true; - }) - - return CPromise.delay(20).then(() => { - throw new CPromise.CanceledError('test'); + onResume(() => { + resumeEmitted = true; }); }).then(() => { - assert.fail("has not been rejected"); - }, (err) => { - assert.equal(err.message, 'test'); - assert.ok(canceled, "not cancelled"); - assert.ok(signaled, "not signaled"); - assert.ok(err instanceof CPromise.CanceledError); - }) + assert.ok(passed() > 1200, `early completion (${passed()}ms)`); + assert.ok(pauseEmitted, 'pause event has not been emitted'); + assert.ok(resumeEmitted, 'resume event has not been emitted'); + }); + + setTimeout(() => { + chain.pause(); + setTimeout(() => { + chain.resume(); + }, 1000); + }, 300); + + return chain; } }, @@ -190,7 +222,63 @@ module.exports = { } }, - 'from': { + 'CPromise#Symbol(toCPromise)': { + 'should be invoked to convert the object to an CPromise instance': async function () { + const toCPromise = Symbol.for('toCPromise'); + let invoked = false; + const obj = { + [toCPromise]: function (CPromise) { + invoked = true; + return new CPromise((resolve) => resolve(123)); + } + }; + + const promise = CPromise.from(obj); + + assert.ok(invoked); + assert.ok(promise instanceof CPromise); + + return promise.then(value => { + assert.equal(value, 123); + }) + } + }, + + 'CPromise#setProgress()': { + 'should set the value of the promise progress': function (done) { + const p = new CPromise(function (resolve, reject) { + let progress = 0; + let i = 0; + const timer = setInterval(() => { + progress += 0.2; + this.progress(progress, {description: 'test', value: i++}); + if (progress >= 1) { + clearInterval(timer); + resolve('done'); + } + + }, 10); + }); + + const expect = [0.2, 0.4, 0.6, 0.8, 1]; + let index = 0; + + p.on('progress', (actualProgress, scope, data) => { + const expected = expect[index]; + + assert.equal(actualProgress, expected); + assert.deepStrictEqual(data, {description: 'test', value: index}); + index++; + }) + + p.then(result => { + assert.equal(result, 'done'); + done(); + }).catch(done); + } + }, + + 'CPromise.from': { 'should convert thing to a CPromise instance': async function () { let isCanceled = false; const thenable = { @@ -253,7 +341,8 @@ module.exports = { const delay = (ms) => new CPromise((resolve, reject, {onCancel}) => { onCancel(() => { canceledInternals = true; - }) + }); + setTimeout(resolve, ms); }); const chain = CPromise.from(function* () { @@ -262,13 +351,14 @@ module.exports = { yield delay(100); } catch (err) { thrown = true; - assert.ok(err instanceof CanceledError); + assert.ok(err instanceof CanceledError, 'error is not an instanceof CanceledError'); } + yield CPromise.delay(100); + if (!thrown) { assert.fail('The canceled error was not thrown'); } - }); setTimeout(() => { @@ -296,7 +386,8 @@ module.exports = { } } }, - 'all': { + + 'CPromise.all': { 'should resolved with array of inner chain vales': async function () { const v1 = 123; const v2 = 456; @@ -355,7 +446,8 @@ module.exports = { }) } }, - 'race': { + + 'CPromise.race': { 'should return a promise that fulfills or rejects as soon as one of the promises settled': async function () { const v1 = 123; const v2 = 456; @@ -381,25 +473,68 @@ module.exports = { }); } }, - 'method Symbol(toCPromise)': { - 'should be invoked to convert the object to an CPromise instance': async function () { - const toCPromise = Symbol.for('toCPromise'); - let invoked = false; - const obj = { - [toCPromise]: function (CPromise) { - invoked = true; - return new CPromise((resolve) => resolve(123)); - } - }; - const promise = CPromise.from(obj); + 'CPromise.allSettled': async function(){ + const err= new Error('test1'); + return CPromise.allSettled([ + delay(100, 123), + CPromise.reject(err), + CPromise.resolve(456) + ]).then(results=>{ + assert.deepStrictEqual(results, [ + {status: 'fulfilled', value: 123}, + {status: 'rejected', reason: err}, + {status: 'fulfilled', value: 456} + ]); + }) + }, - assert.ok(invoked); - assert.ok(promise instanceof CPromise); + 'CPromise.on': { + 'should add new listener': function () { + const ee= new CPromise(resolve=>{}); + assert.equal(ee.listenersCount('test'), 0); + ee.on('test', function(){}); + assert.equal(ee.listenersCount('test'), 1); + ee.on('test', function(){}); + assert.equal(ee.listenersCount('test'), 2); + } + }, - return promise.then(value => { - assert.equal(value, 123); - }) + 'CPromise.off': { + 'should remove the listener': function () { + const ee= new CPromise(resolve=>{}); + const listener1= function(){}; + const listener2= function(){}; + ee.on('test', listener1); + assert.equal(ee.listenersCount('test'), 1); + ee.on('test', listener2); + assert.equal(ee.listenersCount('test'), 2); + ee.off('test', listener1); + assert.equal(ee.listenersCount('test'), 1); + ee.off('test', listener2); + assert.equal(ee.listenersCount('test'), 0); } - } + }, + + 'CPromise.emit': { + 'should emit the event listeners': function () { + const ee= new CPromise(resolve=>{}); + let invoked1, invoked2; + const listener1= function(...data){ + invoked1= true; + assert.deepStrictEqual(data, [1, 2, 3]); + }; + const listener2= function(...data){ + invoked2= true; + assert.deepStrictEqual(data, [1, 2, 3]); + }; + ee.on('test', listener1); + ee.on('test', listener2); + + ee.emit('test', 1, 2, 3); + + assert.ok(invoked1); + assert.ok(invoked2); + } + }, }; diff --git a/test/tests/EventEmitter.js b/test/tests/EventEmitter.js deleted file mode 100644 index 2d2f83a..0000000 --- a/test/tests/EventEmitter.js +++ /dev/null @@ -1,53 +0,0 @@ -const assert= require('assert'); -const {TinyEventEmitter} = require( '../../lib/tiny-event-emitter'); - -module.exports = { - on: { - 'should add new listener': function () { - const ee= new TinyEventEmitter(); - assert.equal(ee.listenersCount('test'), 0); - ee.on('test', function(){}); - assert.equal(ee.listenersCount('test'), 1); - ee.on('test', function(){}); - assert.equal(ee.listenersCount('test'), 2); - } - }, - - off: { - 'should remove the listener': function () { - const ee= new TinyEventEmitter(); - const listener1= function(){}; - const listener2= function(){}; - ee.on('test', listener1); - assert.equal(ee.listenersCount('test'), 1); - ee.on('test', listener2); - assert.equal(ee.listenersCount('test'), 2); - ee.off('test', listener1); - assert.equal(ee.listenersCount('test'), 1); - ee.off('test', listener2); - assert.equal(ee.listenersCount('test'), 0); - } - }, - - emit: { - 'should emit the event listeners': function () { - const ee= new TinyEventEmitter(); - let invoked1, invoked2; - const listener1= function(...data){ - invoked1= true; - assert.deepStrictEqual(data, [1, 2, 3]); - }; - const listener2= function(...data){ - invoked2= true; - assert.deepStrictEqual(data, [1, 2, 3]); - }; - ee.on('test', listener1); - ee.on('test', listener2); - - ee.emit('test', 1, 2, 3); - - assert.ok(invoked1); - assert.ok(invoked2); - } - }, -} diff --git a/test/tests/PromiseScope.js b/test/tests/PromiseScope.js deleted file mode 100644 index 814686b..0000000 --- a/test/tests/PromiseScope.js +++ /dev/null @@ -1,38 +0,0 @@ -const assert= require('assert'); -const CPromise = require( '../../lib/c-promise'); - -module.exports = { - 'setProgress()': { - 'should set the value of the promise progress': function (done) { - const p = new CPromise(function (resolve, reject) { - let progress = 0; - let i = 0; - const timer = setInterval(() => { - progress += 0.2; - this.progress(progress, {description: 'test', value: i++}); - if (progress >= 1) { - clearInterval(timer); - resolve('done'); - } - - }, 10); - }); - - const expect = [0.2, 0.4, 0.6, 0.8, 1]; - let index = 0; - - p.on('progress', (actualProgress, scope, data) => { - const expected = expect[index]; - - assert.equal(actualProgress, expected); - assert.deepStrictEqual(data, {description: 'test', value: index}); - index++; - }) - - p.then(result => { - assert.equal(result, 'done'); - done(); - }).catch(done); - } - } -}