From b0f23071a1539d151c8af53c91011e872d3a458b Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 26 Apr 2026 17:07:26 +0000 Subject: [PATCH 1/8] docs(types): add JSDoc types to lib sources and generate .d.ts via TypeScript Annotate every file in lib/ with JSDoc types that mirror the public types in tapable.d.ts. Add a tsconfig.json and a `build:types` script so .d.ts files can be generated from the JSDoc sources into ./types (gitignored). The public tapable.d.ts is unchanged so consumer types are unaffected. Use the EXPECTED_ANY / EXPECTED_FUNCTION typedefs (mirroring the eslint-config-webpack convention) to satisfy strict JSDoc rules. Adding typescript as a direct devDependency activates the project's strict JSDoc rules on README and benchmark files; restore prior lint behavior for those paths via narrow rule overrides. --- .gitignore | 1 + .prettierignore | 1 + eslint.config.mjs | 25 +++- lib/AsyncParallelBailHook.js | 29 ++++- lib/AsyncParallelHook.js | 25 +++- lib/AsyncSeriesBailHook.js | 31 ++++- lib/AsyncSeriesHook.js | 25 +++- lib/AsyncSeriesLoopHook.js | 25 +++- lib/AsyncSeriesWaterfallHook.js | 32 +++++- lib/Hook.js | 157 +++++++++++++++++++++++-- lib/HookCodeFactory.js | 198 ++++++++++++++++++++++++++------ lib/HookMap.js | 104 ++++++++++++++--- lib/MultiHook.js | 77 ++++++++++++- lib/SyncBailHook.js | 31 ++++- lib/SyncHook.js | 25 +++- lib/SyncLoopHook.js | 25 +++- lib/SyncWaterfallHook.js | 32 +++++- lib/util-browser.js | 12 ++ package-lock.json | 8 +- package.json | 4 +- tsconfig.json | 17 +++ 21 files changed, 788 insertions(+), 96 deletions(-) create mode 100644 tsconfig.json diff --git a/.gitignore b/.gitignore index 7a07923..29f2273 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ /node_modules /coverage +/types ############ ## Windows diff --git a/.prettierignore b/.prettierignore index cce0279..c8c9787 100644 --- a/.prettierignore +++ b/.prettierignore @@ -1,2 +1,3 @@ package.json package-lock.json +types diff --git a/eslint.config.mjs b/eslint.config.mjs index 2379219..d0426f1 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -3,7 +3,7 @@ import config from "eslint-config-webpack"; export default defineConfig([ { - ignores: [".changeset/"] + ignores: [".changeset/", "types/"] }, { extends: [config], @@ -19,6 +19,17 @@ export default defineConfig([ } } }, + { + // README code samples use `Function` and `Array<...>` to mirror the + // public `tapable.d.ts` types. Disable the strict TypeScript rules + // for README — they only activate when `typescript` is a direct + // devDependency (added for type generation in `lib/`). + files: ["**/*.md/*"], + rules: { + "@typescript-eslint/no-unsafe-function-type": "off", + "@typescript-eslint/array-type": "off" + } + }, { files: ["benchmark/**/*"], languageOptions: { @@ -32,7 +43,17 @@ export default defineConfig([ "n/hashbang": "off", "n/no-unsupported-features/es-syntax": "off", "n/no-unsupported-features/node-builtins": "off", - "n/no-process-exit": "off" + "n/no-process-exit": "off", + // Benchmark files predate strict JSDoc rules and use loose JSDoc. + // The strict rules only activate when `typescript` is a direct + // devDependency (added for type generation in `lib/`). + "jsdoc/require-jsdoc": "off", + "jsdoc/require-param-description": "off", + "jsdoc/require-returns-description": "off", + "jsdoc/no-restricted-syntax": "off", + "jsdoc/reject-function-type": "off", + "jsdoc/type-formatting": "off", + "jsdoc/tag-lines": "off" } } ]); diff --git a/lib/AsyncParallelBailHook.js b/lib/AsyncParallelBailHook.js index 5cabeaa..b3e6277 100644 --- a/lib/AsyncParallelBailHook.js +++ b/lib/AsyncParallelBailHook.js @@ -7,20 +7,33 @@ const Hook = require("./Hook"); const HookCodeFactory = require("./HookCodeFactory"); +// eslint-disable-next-line jsdoc/reject-function-type +/** @typedef {Function} EXPECTED_FUNCTION */ +// eslint-disable-next-line jsdoc/reject-any-type +/** @typedef {any} EXPECTED_ANY */ + +/** @typedef {import("./Hook").CompileOptions} CompileOptions */ +/** @typedef {import("./HookCodeFactory").ContentOptions} ContentOptions */ + class AsyncParallelBailHookCodeFactory extends HookCodeFactory { + /** + * @param {ContentOptions} options content generation options + * @returns {string} generated body code + */ content({ onError, onResult, onDone }) { + const opts = /** @type {CompileOptions} */ (this.options); let code = ""; - code += `var _results = new Array(${this.options.taps.length});\n`; + code += `var _results = new Array(${opts.taps.length});\n`; code += "var _checkDone = function() {\n"; code += "for(var i = 0; i < _results.length; i++) {\n"; code += "var item = _results[i];\n"; code += "if(item === undefined) return false;\n"; code += "if(item.result !== undefined) {\n"; - code += onResult("item.result"); + code += /** @type {(result: string) => string} */ (onResult)("item.result"); code += "return true;\n"; code += "}\n"; code += "if(item.error) {\n"; - code += onError("item.error"); + code += /** @type {(err: string) => string} */ (onError)("item.error"); code += "return true;\n"; code += "}\n"; code += "}\n"; @@ -68,11 +81,21 @@ class AsyncParallelBailHookCodeFactory extends HookCodeFactory { const factory = new AsyncParallelBailHookCodeFactory(); +/** + * @this {Hook} + * @param {CompileOptions} options compile options + * @returns {EXPECTED_FUNCTION} the compiled call function + */ function COMPILE(options) { factory.setup(this, options); return factory.create(options); } +/** + * @param {string[]=} args argument names of the hook + * @param {string=} name name of the hook + * @returns {Hook} a new AsyncParallelBailHook instance + */ function AsyncParallelBailHook(args = [], name = undefined) { const hook = new Hook(args, name); hook.constructor = AsyncParallelBailHook; diff --git a/lib/AsyncParallelHook.js b/lib/AsyncParallelHook.js index 3fa0722..b4f7934 100644 --- a/lib/AsyncParallelHook.js +++ b/lib/AsyncParallelHook.js @@ -7,10 +7,23 @@ const Hook = require("./Hook"); const HookCodeFactory = require("./HookCodeFactory"); +// eslint-disable-next-line jsdoc/reject-function-type +/** @typedef {Function} EXPECTED_FUNCTION */ +// eslint-disable-next-line jsdoc/reject-any-type +/** @typedef {any} EXPECTED_ANY */ + +/** @typedef {import("./Hook").CompileOptions} CompileOptions */ +/** @typedef {import("./HookCodeFactory").ContentOptions} ContentOptions */ + class AsyncParallelHookCodeFactory extends HookCodeFactory { + /** + * @param {ContentOptions} options content generation options + * @returns {string} generated body code + */ content({ onError, onDone }) { return this.callTapsParallel({ - onError: (i, err, done, doneBreak) => onError(err) + doneBreak(true), + onError: (i, err, done, doneBreak) => + /** @type {(err: string) => string} */ (onError)(err) + doneBreak(true), onDone }); } @@ -18,11 +31,21 @@ class AsyncParallelHookCodeFactory extends HookCodeFactory { const factory = new AsyncParallelHookCodeFactory(); +/** + * @this {Hook} + * @param {CompileOptions} options compile options + * @returns {EXPECTED_FUNCTION} the compiled call function + */ function COMPILE(options) { factory.setup(this, options); return factory.create(options); } +/** + * @param {string[]=} args argument names of the hook + * @param {string=} name name of the hook + * @returns {Hook} a new AsyncParallelHook instance + */ function AsyncParallelHook(args = [], name = undefined) { const hook = new Hook(args, name); hook.constructor = AsyncParallelHook; diff --git a/lib/AsyncSeriesBailHook.js b/lib/AsyncSeriesBailHook.js index a46d3d2..c374f07 100644 --- a/lib/AsyncSeriesBailHook.js +++ b/lib/AsyncSeriesBailHook.js @@ -7,14 +7,27 @@ const Hook = require("./Hook"); const HookCodeFactory = require("./HookCodeFactory"); +// eslint-disable-next-line jsdoc/reject-function-type +/** @typedef {Function} EXPECTED_FUNCTION */ +// eslint-disable-next-line jsdoc/reject-any-type +/** @typedef {any} EXPECTED_ANY */ + +/** @typedef {import("./Hook").CompileOptions} CompileOptions */ +/** @typedef {import("./HookCodeFactory").ContentOptions} ContentOptions */ + class AsyncSeriesBailHookCodeFactory extends HookCodeFactory { + /** + * @param {ContentOptions} options content generation options + * @returns {string} generated body code + */ content({ onError, onResult, resultReturns, onDone }) { return this.callTapsSeries({ - onError: (i, err, next, doneBreak) => onError(err) + doneBreak(true), + onError: (i, err, next, doneBreak) => + /** @type {(err: string) => string} */ (onError)(err) + doneBreak(true), onResult: (i, result, next) => - `if(${result} !== undefined) {\n${onResult( - result - )}\n} else {\n${next()}}\n`, + `if(${result} !== undefined) {\n${ + /** @type {(result: string) => string} */ (onResult)(result) + }\n} else {\n${next()}}\n`, resultReturns, onDone }); @@ -23,11 +36,21 @@ class AsyncSeriesBailHookCodeFactory extends HookCodeFactory { const factory = new AsyncSeriesBailHookCodeFactory(); +/** + * @this {Hook} + * @param {CompileOptions} options compile options + * @returns {EXPECTED_FUNCTION} the compiled call function + */ function COMPILE(options) { factory.setup(this, options); return factory.create(options); } +/** + * @param {string[]=} args argument names of the hook + * @param {string=} name name of the hook + * @returns {Hook} a new AsyncSeriesBailHook instance + */ function AsyncSeriesBailHook(args = [], name = undefined) { const hook = new Hook(args, name); hook.constructor = AsyncSeriesBailHook; diff --git a/lib/AsyncSeriesHook.js b/lib/AsyncSeriesHook.js index 569d480..2d32961 100644 --- a/lib/AsyncSeriesHook.js +++ b/lib/AsyncSeriesHook.js @@ -7,10 +7,23 @@ const Hook = require("./Hook"); const HookCodeFactory = require("./HookCodeFactory"); +// eslint-disable-next-line jsdoc/reject-function-type +/** @typedef {Function} EXPECTED_FUNCTION */ +// eslint-disable-next-line jsdoc/reject-any-type +/** @typedef {any} EXPECTED_ANY */ + +/** @typedef {import("./Hook").CompileOptions} CompileOptions */ +/** @typedef {import("./HookCodeFactory").ContentOptions} ContentOptions */ + class AsyncSeriesHookCodeFactory extends HookCodeFactory { + /** + * @param {ContentOptions} options content generation options + * @returns {string} generated body code + */ content({ onError, onDone }) { return this.callTapsSeries({ - onError: (i, err, next, doneBreak) => onError(err) + doneBreak(true), + onError: (i, err, next, doneBreak) => + /** @type {(err: string) => string} */ (onError)(err) + doneBreak(true), onDone }); } @@ -18,11 +31,21 @@ class AsyncSeriesHookCodeFactory extends HookCodeFactory { const factory = new AsyncSeriesHookCodeFactory(); +/** + * @this {Hook} + * @param {CompileOptions} options compile options + * @returns {EXPECTED_FUNCTION} the compiled call function + */ function COMPILE(options) { factory.setup(this, options); return factory.create(options); } +/** + * @param {string[]=} args argument names of the hook + * @param {string=} name name of the hook + * @returns {Hook} a new AsyncSeriesHook instance + */ function AsyncSeriesHook(args = [], name = undefined) { const hook = new Hook(args, name); hook.constructor = AsyncSeriesHook; diff --git a/lib/AsyncSeriesLoopHook.js b/lib/AsyncSeriesLoopHook.js index 5c3c21d..edd6b39 100644 --- a/lib/AsyncSeriesLoopHook.js +++ b/lib/AsyncSeriesLoopHook.js @@ -7,10 +7,23 @@ const Hook = require("./Hook"); const HookCodeFactory = require("./HookCodeFactory"); +// eslint-disable-next-line jsdoc/reject-function-type +/** @typedef {Function} EXPECTED_FUNCTION */ +// eslint-disable-next-line jsdoc/reject-any-type +/** @typedef {any} EXPECTED_ANY */ + +/** @typedef {import("./Hook").CompileOptions} CompileOptions */ +/** @typedef {import("./HookCodeFactory").ContentOptions} ContentOptions */ + class AsyncSeriesLoopHookCodeFactory extends HookCodeFactory { + /** + * @param {ContentOptions} options content generation options + * @returns {string} generated body code + */ content({ onError, onDone }) { return this.callTapsLooping({ - onError: (i, err, next, doneBreak) => onError(err) + doneBreak(true), + onError: (i, err, next, doneBreak) => + /** @type {(err: string) => string} */ (onError)(err) + doneBreak(true), onDone }); } @@ -18,11 +31,21 @@ class AsyncSeriesLoopHookCodeFactory extends HookCodeFactory { const factory = new AsyncSeriesLoopHookCodeFactory(); +/** + * @this {Hook} + * @param {CompileOptions} options compile options + * @returns {EXPECTED_FUNCTION} the compiled call function + */ function COMPILE(options) { factory.setup(this, options); return factory.create(options); } +/** + * @param {string[]=} args argument names of the hook + * @param {string=} name name of the hook + * @returns {Hook} a new AsyncSeriesLoopHook instance + */ function AsyncSeriesLoopHook(args = [], name = undefined) { const hook = new Hook(args, name); hook.constructor = AsyncSeriesLoopHook; diff --git a/lib/AsyncSeriesWaterfallHook.js b/lib/AsyncSeriesWaterfallHook.js index 21a0701..8a10b8f 100644 --- a/lib/AsyncSeriesWaterfallHook.js +++ b/lib/AsyncSeriesWaterfallHook.js @@ -7,30 +7,56 @@ const Hook = require("./Hook"); const HookCodeFactory = require("./HookCodeFactory"); +// eslint-disable-next-line jsdoc/reject-function-type +/** @typedef {Function} EXPECTED_FUNCTION */ +// eslint-disable-next-line jsdoc/reject-any-type +/** @typedef {any} EXPECTED_ANY */ + +/** @typedef {import("./Hook").CompileOptions} CompileOptions */ +/** @typedef {import("./HookCodeFactory").ContentOptions} ContentOptions */ + class AsyncSeriesWaterfallHookCodeFactory extends HookCodeFactory { + /** + * @param {ContentOptions} options content generation options + * @returns {string} generated body code + */ content({ onError, onResult, _onDone }) { return this.callTapsSeries({ - onError: (i, err, next, doneBreak) => onError(err) + doneBreak(true), + onError: (i, err, next, doneBreak) => + /** @type {(err: string) => string} */ (onError)(err) + doneBreak(true), onResult: (i, result, next) => { let code = ""; code += `if(${result} !== undefined) {\n`; - code += `${this._args[0]} = ${result};\n`; + code += `${/** @type {string[]} */ (this._args)[0]} = ${result};\n`; code += "}\n"; code += next(); return code; }, - onDone: () => onResult(this._args[0]) + onDone: () => + /** @type {(result: string) => string} */ (onResult)( + /** @type {string[]} */ (this._args)[0] + ) }); } } const factory = new AsyncSeriesWaterfallHookCodeFactory(); +/** + * @this {Hook} + * @param {CompileOptions} options compile options + * @returns {EXPECTED_FUNCTION} the compiled call function + */ function COMPILE(options) { factory.setup(this, options); return factory.create(options); } +/** + * @param {string[]=} args argument names of the hook (must contain at least one) + * @param {string=} name name of the hook + * @returns {Hook} a new AsyncSeriesWaterfallHook instance + */ function AsyncSeriesWaterfallHook(args = [], name = undefined) { if (args.length < 1) { throw new Error("Waterfall hooks must have at least one argument"); diff --git a/lib/Hook.js b/lib/Hook.js index 5bf7417..5aaf67e 100644 --- a/lib/Hook.js +++ b/lib/Hook.js @@ -6,31 +6,110 @@ const util = require("util"); +// eslint-disable-next-line jsdoc/reject-function-type +/** @typedef {Function} EXPECTED_FUNCTION */ +// eslint-disable-next-line jsdoc/reject-any-type +/** @typedef {any} EXPECTED_ANY */ + +/** + * @typedef {object} TapOptions + * @property {string=} before name of an earlier tap to insert this tap before + * @property {number=} stage stage to schedule the tap in (lower runs earlier) + */ + +/** + * @typedef {TapOptions & { name: string }} Tap + */ + +/** + * @typedef {Tap & { type: "sync" | "async" | "promise", fn: EXPECTED_FUNCTION }} FullTap + */ + +/** + * @template E, T + * @typedef {(error: E | null, result?: T) => void} Callback + */ + +/** + * @template E, T + * @typedef {(error?: E | null | false, result?: T) => void} InnerCallback + */ + +/** + * @template T, R, AdditionalOptions + * @typedef {object} HookInterceptor + * @property {string=} name optional name of the interceptor + * @property {((tap: FullTap & AdditionalOptions) => void)=} tap called for each tap before it runs + * @property {((...args: EXPECTED_ANY[]) => void)=} call called when the hook is called + * @property {((...args: EXPECTED_ANY[]) => void)=} loop called for each loop iteration of looping hooks + * @property {((err: Error) => void)=} error called when an error occurs + * @property {((result: R) => void)=} result called with the hook's result + * @property {(() => void)=} done called when the hook is fully done + * @property {((tap: FullTap & AdditionalOptions) => FullTap & AdditionalOptions)=} register called whenever a tap is registered + * @property {boolean=} context true to pass a `_context` argument to interceptor callbacks + */ + +/** + * @typedef {object} CompileOptions + * @property {FullTap[]} taps the registered taps + * @property {HookInterceptor[]} interceptors the registered interceptors + * @property {string[]} args names of the hook arguments (used for code generation) + * @property {"sync" | "async" | "promise"} type call type + */ + const deprecateContext = util.deprecate( () => {}, "Hook.context is deprecated and will be removed" ); +/** + * @this {Hook} + * @param {...EXPECTED_ANY} args hook call arguments + * @returns {EXPECTED_ANY} hook call result + */ function CALL_DELEGATE(...args) { this.call = this._createCall("sync"); return this.call(...args); } +/** + * @this {Hook} + * @param {...EXPECTED_ANY} args hook call arguments + * @returns {EXPECTED_ANY} hook call result + */ function CALL_ASYNC_DELEGATE(...args) { this.callAsync = this._createCall("async"); return this.callAsync(...args); } +/** + * @this {Hook} + * @param {...EXPECTED_ANY} args hook call arguments + * @returns {Promise} resolves with the hook result + */ function PROMISE_DELEGATE(...args) { this.promise = this._createCall("promise"); return this.promise(...args); } +/** + * @template T + * @template [R=void] + * @template [AdditionalOptions=object] + */ class Hook { + /** + * @param {string[]=} args argument names of the hook (used for code generation) + * @param {string=} name name of the hook + */ constructor(args = [], name = undefined) { + /** @type {string[]} */ this._args = args; + /** @type {string | undefined} */ this.name = name; + /** @type {FullTap[]} */ this.taps = []; + /** @type {HookInterceptor[]} */ this.interceptors = []; this._call = CALL_DELEGATE; this.call = CALL_DELEGATE; @@ -38,6 +117,7 @@ class Hook { this.callAsync = CALL_ASYNC_DELEGATE; this._promise = PROMISE_DELEGATE; this.promise = PROMISE_DELEGATE; + /** @type {EXPECTED_FUNCTION[] | undefined} */ this._x = undefined; // eslint-disable-next-line no-self-assign @@ -50,10 +130,19 @@ class Hook { this.tapPromise = this.tapPromise; } + /** + * @abstract + * @param {CompileOptions} _options compile options + * @returns {EXPECTED_FUNCTION} the compiled call function + */ compile(_options) { throw new Error("Abstract: should be overridden"); } + /** + * @param {"sync" | "async" | "promise"} type the call type + * @returns {EXPECTED_FUNCTION} the compiled call function + */ _createCall(type) { return this.compile({ taps: this.taps, @@ -63,6 +152,12 @@ class Hook { }); } + /** + * @param {"sync" | "async" | "promise"} type the tap type + * @param {string | (Tap & AdditionalOptions)} options name or full tap options + * @param {EXPECTED_FUNCTION} fn callback registered with the tap + * @returns {void} + */ _tap(type, options, fn) { if (typeof options === "string") { // Fast path: a string options ("name") is by far the most common @@ -72,7 +167,7 @@ class Hook { if (name === "") { throw new Error("Missing name for tap"); } - options = { type, fn, name }; + options = /** @type {Tap & AdditionalOptions} */ ({ type, fn, name }); } else { if (typeof options !== "object" || options === null) { throw new Error("Invalid tap options"); @@ -84,7 +179,10 @@ class Hook { if (typeof name !== "string" || name === "") { throw new Error("Missing name for tap"); } - if (typeof options.context !== "undefined") { + if ( + typeof (/** @type {{ context?: unknown }} */ (options).context) !== + "undefined" + ) { deprecateContext(); } // Fast path: only `name` is set. Build the descriptor as a literal @@ -101,29 +199,50 @@ class Hook { } } if (onlyName) { - options = { type, fn, name }; + options = /** @type {Tap & AdditionalOptions} */ ({ type, fn, name }); } else { options.name = name; // Preserve previous precedence: user-provided keys win over the internal `type`/`fn`. options = Object.assign({ type, fn }, options); } } - options = this._runRegisterInterceptors(options); + options = this._runRegisterInterceptors( + /** @type {FullTap & AdditionalOptions} */ (options) + ); this._insert(options); } + /** + * @param {string | (Tap & AdditionalOptions)} options tap name or full tap options + * @param {EXPECTED_FUNCTION} fn the function to register + * @returns {void} + */ tap(options, fn) { this._tap("sync", options, fn); } + /** + * @param {string | (Tap & AdditionalOptions)} options tap name or full tap options + * @param {EXPECTED_FUNCTION} fn the function to register + * @returns {void} + */ tapAsync(options, fn) { this._tap("async", options, fn); } + /** + * @param {string | (Tap & AdditionalOptions)} options tap name or full tap options + * @param {EXPECTED_FUNCTION} fn the function to register + * @returns {void} + */ tapPromise(options, fn) { this._tap("promise", options, fn); } + /** + * @param {FullTap & AdditionalOptions} options the tap descriptor + * @returns {FullTap & AdditionalOptions} possibly transformed options + */ _runRegisterInterceptors(options) { const { interceptors } = this; const { length } = interceptors; @@ -132,7 +251,12 @@ class Hook { for (let i = 0; i < length; i++) { const interceptor = interceptors[i]; if (interceptor.register) { - const newOptions = interceptor.register(options); + const newOptions = + /** @type {FullTap & AdditionalOptions | undefined} */ ( + interceptor.register( + /** @type {FullTap & AdditionalOptions} */ (options) + ) + ); if (newOptions !== undefined) { options = newOptions; } @@ -141,11 +265,15 @@ class Hook { return options; } + /** + * @param {TapOptions & AdditionalOptions} options the options to merge into each tap + * @returns {Omit} a wrapper that pre-applies the options + */ withOptions(options) { const mergeOptions = (opt) => Object.assign({}, options, typeof opt === "string" ? { name: opt } : opt); - return { + return /** @type {Omit} */ ({ name: this.name, tap: (opt, fn) => this.tap(mergeOptions(opt), fn), tapAsync: (opt, fn) => this.tapAsync(mergeOptions(opt), fn), @@ -153,13 +281,20 @@ class Hook { intercept: (interceptor) => this.intercept(interceptor), isUsed: () => this.isUsed(), withOptions: (opt) => this.withOptions(mergeOptions(opt)) - }; + }); } + /** + * @returns {boolean} true if the hook has any taps or interceptors registered + */ isUsed() { return this.taps.length > 0 || this.interceptors.length > 0; } + /** + * @param {HookInterceptor} interceptor the interceptor to register + * @returns {void} + */ intercept(interceptor) { this._resetCompilation(); this.interceptors.push(Object.assign({}, interceptor)); @@ -170,12 +305,19 @@ class Hook { } } + /** + * @returns {void} + */ _resetCompilation() { this.call = this._call; this.callAsync = this._callAsync; this.promise = this._promise; } + /** + * @param {FullTap & AdditionalOptions} item the tap to insert into the ordered taps list + * @returns {void} + */ _insert(item) { this._resetCompilation(); const { taps } = this; @@ -194,6 +336,7 @@ class Hook { } } + /** @type {Set | undefined} */ let before; if (typeof item.before === "string") { diff --git a/lib/HookCodeFactory.js b/lib/HookCodeFactory.js index 2e0e6c1..e55e1c9 100644 --- a/lib/HookCodeFactory.js +++ b/lib/HookCodeFactory.js @@ -4,13 +4,70 @@ */ "use strict"; +// eslint-disable-next-line jsdoc/reject-function-type +/** @typedef {Function} EXPECTED_FUNCTION */ +// eslint-disable-next-line jsdoc/reject-any-type +/** @typedef {any} EXPECTED_ANY */ +/** @typedef {Record} EXPECTED_OBJECT */ + +/** @typedef {import("./Hook")} Hook */ +/** @typedef {import("./Hook").FullTap} FullTap */ +/** @typedef {import("./Hook").CompileOptions} CompileOptions */ + +/** + * @template T, R, AdditionalOptions + * @typedef {import("./Hook").HookInterceptor} HookInterceptor + */ + +/** + * @typedef {(error: string) => string} OnErrorCallback + */ + +/** + * @typedef {(result: string) => string} OnResultCallback + */ + +/** + * @typedef {() => string} OnDoneCallback + */ + +/** + * @typedef {object} ContentOptions + * @property {OnErrorCallback=} onError generates code for handling an error + * @property {OnResultCallback=} onResult generates code for handling a result + * @property {boolean=} resultReturns true if the generated function returns a result + * @property {OnDoneCallback=} onDone generates code for completion + * @property {boolean=} doneReturns true if the generated function returns when done + * @property {boolean=} rethrowIfPossible true to rethrow errors when safe + */ + +/** + * @typedef {object} TapsSeriesOptions + * @property {((tapIndex: number, error: string, next: () => string, doneBreak: (skipDone: boolean) => string) => string)=} onError generates per-tap error code + * @property {((tapIndex: number, result: string, next: () => string, doneBreak: (skipDone: boolean) => string) => string)=} onResult generates per-tap result code + * @property {boolean=} resultReturns true if the generated function returns a result + * @property {OnDoneCallback=} onDone generates code for completion + * @property {boolean=} doneReturns true if the generated function returns when done + * @property {boolean=} rethrowIfPossible true to rethrow errors when safe + */ + class HookCodeFactory { + /** + * @param {EXPECTED_OBJECT=} config optional configuration object passed through by subclasses + */ constructor(config) { + /** @type {EXPECTED_OBJECT | undefined} */ this.config = config; + /** @type {CompileOptions | undefined} */ this.options = undefined; + /** @type {string[] | undefined} */ this._args = undefined; } + /** + * @param {CompileOptions} options compile options + * @returns {EXPECTED_FUNCTION} the compiled hook function + */ create(options) { this.init(options); let fn; @@ -73,9 +130,14 @@ class HookCodeFactory { } } this.deinit(); - return fn; + return /** @type {EXPECTED_FUNCTION} */ (fn); } + /** + * @param {Hook} instance the hook instance to attach the resolved tap function array to + * @param {CompileOptions} options compile options containing the taps + * @returns {void} + */ setup(instance, options) { const { taps } = options; const { length } = taps; @@ -83,11 +145,12 @@ class HookCodeFactory { for (let i = 0; i < length; i++) { fns[i] = taps[i].fn; } - instance._x = fns; + instance._x = /** @type {EXPECTED_FUNCTION[]} */ (fns); } /** - * @param {{ type: "sync" | "promise" | "async", taps: Array, interceptors: Array }} options + * @param {CompileOptions} options compile options + * @returns {void} */ init(options) { this.options = options; @@ -95,21 +158,30 @@ class HookCodeFactory { // can share the caller's array directly instead of paying for a copy // on every compile. this._args = options.args; + /** @type {string | undefined} */ this._joinedArgs = undefined; } + /** + * @returns {void} + */ deinit() { this.options = undefined; this._args = undefined; this._joinedArgs = undefined; } + /** + * @param {ContentOptions} options content generation options + * @returns {string} generated code with interceptor calls wrapped around content + */ contentWithInterceptors(options) { - if (this.options.interceptors.length > 0) { + if (/** @type {CompileOptions} */ (this.options).interceptors.length > 0) { const { onError, onResult, onDone } = options; let code = ""; - for (let i = 0; i < this.options.interceptors.length; i++) { - const interceptor = this.options.interceptors[i]; + const opts = /** @type {CompileOptions} */ (this.options); + for (let i = 0; i < opts.interceptors.length; i++) { + const interceptor = opts.interceptors[i]; if (interceptor.call) { code += `${this.getInterceptor(i)}.call(${this.args({ before: interceptor.context ? "_context" : undefined @@ -122,8 +194,8 @@ class HookCodeFactory { onError && ((err) => { let code = ""; - for (let i = 0; i < this.options.interceptors.length; i++) { - const interceptor = this.options.interceptors[i]; + for (let i = 0; i < opts.interceptors.length; i++) { + const interceptor = opts.interceptors[i]; if (interceptor.error) { code += `${this.getInterceptor(i)}.error(${err});\n`; } @@ -135,8 +207,8 @@ class HookCodeFactory { onResult && ((result) => { let code = ""; - for (let i = 0; i < this.options.interceptors.length; i++) { - const interceptor = this.options.interceptors[i]; + for (let i = 0; i < opts.interceptors.length; i++) { + const interceptor = opts.interceptors[i]; if (interceptor.result) { code += `${this.getInterceptor(i)}.result(${result});\n`; } @@ -148,8 +220,8 @@ class HookCodeFactory { onDone && (() => { let code = ""; - for (let i = 0; i < this.options.interceptors.length; i++) { - const interceptor = this.options.interceptors[i]; + for (let i = 0; i < opts.interceptors.length; i++) { + const interceptor = opts.interceptors[i]; if (interceptor.done) { code += `${this.getInterceptor(i)}.done();\n`; } @@ -164,30 +236,42 @@ class HookCodeFactory { return this.content(options); } + /** + * @returns {string} generated header preamble shared across all call types + */ header() { let code = ""; code += this.needContext() ? "var _context = {};\n" : "var _context;\n"; code += "var _x = this._x;\n"; - if (this.options.interceptors.length > 0) { + if (/** @type {CompileOptions} */ (this.options).interceptors.length > 0) { code += "var _taps = this.taps;\n"; code += "var _interceptors = this.interceptors;\n"; } return code; } + /** + * @returns {boolean} true if any tap requested a `_context` + */ needContext() { - const { taps } = this.options; + const { taps } = /** @type {CompileOptions} */ (this.options); for (let i = 0; i < taps.length; i++) { - if (taps[i].context) return true; + if (/** @type {{ context?: boolean }} */ (taps[i]).context) return true; } return false; } + /** + * @param {number} tapIndex index of the tap to call + * @param {ContentOptions} options content generation options + * @returns {string} generated code that invokes the tap + */ callTap(tapIndex, { onError, onResult, onDone, rethrowIfPossible }) { let code = ""; let hasTapCached = false; - for (let i = 0; i < this.options.interceptors.length; i++) { - const interceptor = this.options.interceptors[i]; + const opts = /** @type {CompileOptions} */ (this.options); + for (let i = 0; i < opts.interceptors.length; i++) { + const interceptor = opts.interceptors[i]; if (interceptor.tap) { if (!hasTapCached) { code += `var _tap${tapIndex} = ${this.getTap(tapIndex)};\n`; @@ -199,7 +283,9 @@ class HookCodeFactory { } } code += `var _fn${tapIndex} = ${this.getTapFn(tapIndex)};\n`; - const tap = this.options.taps[tapIndex]; + const tap = /** @type {FullTap & { context?: boolean }} */ ( + opts.taps[tapIndex] + ); switch (tap.type) { case "sync": if (!rethrowIfPossible) { @@ -218,7 +304,7 @@ class HookCodeFactory { if (!rethrowIfPossible) { code += "} catch(_err) {\n"; code += `_hasError${tapIndex} = true;\n`; - code += onError("_err"); + code += /** @type {OnErrorCallback} */ (onError)("_err"); code += "}\n"; code += `if(!_hasError${tapIndex}) {\n`; } @@ -238,7 +324,7 @@ class HookCodeFactory { ? `(function(_err${tapIndex}, _result${tapIndex}) {\n` : `(function(_err${tapIndex}) {\n`; cbCode += `if(_err${tapIndex}) {\n`; - cbCode += onError(`_err${tapIndex}`); + cbCode += /** @type {OnErrorCallback} */ (onError)(`_err${tapIndex}`); cbCode += "} else {\n"; if (onResult) { cbCode += onResult(`_result${tapIndex}`); @@ -271,7 +357,7 @@ class HookCodeFactory { } code += `}), function(_err${tapIndex}) {\n`; code += `if(_hasResult${tapIndex}) throw _err${tapIndex};\n`; - code += onError( + code += /** @type {OnErrorCallback} */ (onError)( `!_err${tapIndex} ? new Error('Tap function (tapPromise) rejects "' + _err${tapIndex} + '" value') : _err${tapIndex}` ); code += "});\n"; @@ -280,6 +366,10 @@ class HookCodeFactory { return code; } + /** + * @param {TapsSeriesOptions} options series-call options + * @returns {string} generated code calling all taps in series + */ callTapsSeries({ onError, onResult, @@ -288,9 +378,9 @@ class HookCodeFactory { doneReturns, rethrowIfPossible }) { - const { taps } = this.options; + const { taps } = /** @type {CompileOptions} */ (this.options); const tapsLength = taps.length; - if (tapsLength === 0) return onDone(); + if (tapsLength === 0) return /** @type {OnDoneCallback} */ (onDone)(); // Inlined findIndex to avoid the callback allocation. let firstAsync = -1; for (let i = 0; i < tapsLength; i++) { @@ -303,7 +393,7 @@ class HookCodeFactory { // doneBreak doesn't depend on the loop variable - hoist to allocate once. const doneBreak = (skipDone) => { if (skipDone) return ""; - return onDone(); + return /** @type {OnDoneCallback} */ (onDone)(); }; let code = ""; let current = onDone; @@ -315,13 +405,19 @@ class HookCodeFactory { if (unroll) { unrollCounter = 0; code += `function _next${i}() {\n`; - code += current(); + code += /** @type {OnDoneCallback} */ (current)(); code += "}\n"; current = () => `${somethingReturns ? "return " : ""}_next${i}();\n`; } - const done = current; + const done = /** @type {OnDoneCallback} */ (current); const content = this.callTap(i, { - onError: (error) => onError(i, error, done, doneBreak), + onError: (error) => + /** @type {NonNullable} */ (onError)( + i, + error, + done, + doneBreak + ), onResult: onResult && ((result) => onResult(i, result, done, doneBreak)), onDone: !onResult && done, @@ -330,13 +426,18 @@ class HookCodeFactory { }); current = () => content; } - code += current(); + code += /** @type {OnDoneCallback} */ (current)(); return code; } + /** + * @param {TapsSeriesOptions} options looping-call options + * @returns {string} generated code that calls taps in a loop + */ callTapsLooping({ onError, onDone, rethrowIfPossible }) { - if (this.options.taps.length === 0) return onDone(); - const syncOnly = this.options.taps.every((t) => t.type === "sync"); + const opts = /** @type {CompileOptions} */ (this.options); + if (opts.taps.length === 0) return /** @type {OnDoneCallback} */ (onDone)(); + const syncOnly = opts.taps.every((t) => t.type === "sync"); let code = ""; if (!syncOnly) { code += "var _looper = (function() {\n"; @@ -345,8 +446,8 @@ class HookCodeFactory { code += "var _loop;\n"; code += "do {\n"; code += "_loop = false;\n"; - for (let i = 0; i < this.options.interceptors.length; i++) { - const interceptor = this.options.interceptors[i]; + for (let i = 0; i < opts.interceptors.length; i++) { + const interceptor = opts.interceptors[i]; if (interceptor.loop) { code += `${this.getInterceptor(i)}.loop(${this.args({ before: interceptor.context ? "_context" : undefined @@ -386,6 +487,10 @@ class HookCodeFactory { return code; } + /** + * @param {TapsSeriesOptions & { onTap?: (tapIndex: number, run: () => string, done: () => string, doneBreak: (skipDone: boolean) => string) => string }} options parallel-call options + * @returns {string} generated code that calls all taps in parallel + */ callTapsParallel({ onError, onResult, @@ -393,7 +498,7 @@ class HookCodeFactory { rethrowIfPossible, onTap = (i, run) => run() }) { - const { taps } = this.options; + const { taps } = /** @type {CompileOptions} */ (this.options); const tapsLength = taps.length; if (tapsLength <= 1) { return this.callTapsSeries({ @@ -430,7 +535,9 @@ class HookCodeFactory { onError: (error) => { let code = ""; code += "if(_counter > 0) {\n"; - code += onError(i, error, done, doneBreak); + code += /** @type {NonNullable} */ ( + onError + )(i, error, done, doneBreak); code += "}\n"; return code; }, @@ -454,6 +561,10 @@ class HookCodeFactory { return code; } + /** + * @param {{ before?: string, after?: string }=} options optional arguments to prepend or append + * @returns {string} comma-separated argument list as JS source + */ args({ before, after } = {}) { // Hot during code generation. Join `_args` once and cache the result, // then build the customized variants via string concat instead of @@ -461,27 +572,42 @@ class HookCodeFactory { // arrays and re-joining. let joined = this._joinedArgs; if (joined === undefined) { - joined = this._args.length === 0 ? "" : this._args.join(", "); + joined = + /** @type {string[]} */ (this._args).length === 0 + ? "" + : /** @type {string[]} */ (this._args).join(", "); this._joinedArgs = joined; } if (!before && !after) return joined; if (joined.length === 0) { if (before && after) return `${before}, ${after}`; - return before || after; + return /** @type {string} */ (before || after); } if (before && after) return `${before}, ${joined}, ${after}`; if (before) return `${before}, ${joined}`; return `${joined}, ${after}`; } + /** + * @param {number} idx tap index + * @returns {string} JS expression that resolves to the registered tap function at index `idx` + */ getTapFn(idx) { return `_x[${idx}]`; } + /** + * @param {number} idx tap index + * @returns {string} JS expression that resolves to the tap descriptor at index `idx` + */ getTap(idx) { return `_taps[${idx}]`; } + /** + * @param {number} idx interceptor index + * @returns {string} JS expression that resolves to the interceptor at index `idx` + */ getInterceptor(idx) { return `_interceptors[${idx}]`; } diff --git a/lib/HookMap.js b/lib/HookMap.js index ca91cd6..664ede8 100644 --- a/lib/HookMap.js +++ b/lib/HookMap.js @@ -6,20 +6,59 @@ const util = require("util"); +// eslint-disable-next-line jsdoc/reject-any-type +/** @typedef {any} EXPECTED_ANY */ + +/** + * @template H, K + * @typedef {(key: K) => H} HookFactory + */ + +/** + * @template H, K + * @typedef {object} HookMapInterceptor + * @property {((key: K, hook: H) => H)=} factory called when a hook is created for a new key + */ + +/** + * @template H, K + * @param {K} key key passed through unchanged + * @param {H} hook hook returned unchanged + * @returns {H} the hook unchanged + */ const defaultFactory = (key, hook) => hook; +/** + * @template H + */ class HookMap { + /** + * @param {HookFactory} factory factory creating new hooks for unknown keys + * @param {string=} name name of the hook map + */ constructor(factory, name = undefined) { + /** @type {Map} */ this._map = new Map(); + /** @type {string | undefined} */ this.name = name; + /** @type {HookFactory} */ this._factory = factory; + /** @type {HookMapInterceptor[]} */ this._interceptors = []; } + /** + * @param {EXPECTED_ANY} key the key to look up + * @returns {H | undefined} the hook stored for `key`, if any + */ get(key) { return this._map.get(key); } + /** + * @param {EXPECTED_ANY} key the key to look up or create + * @returns {H} the hook stored for `key`, creating one via the factory if missing + */ for(key) { // Hot path: inline the map lookup to skip the `this.get(key)` // indirection. This gets hit on every hook access in consumers @@ -32,12 +71,19 @@ class HookMap { let newHook = this._factory(key); const interceptors = this._interceptors; for (let i = 0; i < interceptors.length; i++) { - newHook = interceptors[i].factory(key, newHook); + newHook = + /** @type {NonNullable["factory"]>} */ ( + interceptors[i].factory + )(key, newHook); } map.set(key, newHook); return newHook; } + /** + * @param {HookMapInterceptor} interceptor the interceptor to register + * @returns {void} + */ intercept(interceptor) { this._interceptors.push( Object.assign( @@ -50,24 +96,46 @@ class HookMap { } } -HookMap.prototype.tap = util.deprecate(function tap(key, options, fn) { - return this.for(key).tap(options, fn); -}, "HookMap#tap(key,…) is deprecated. Use HookMap#for(key).tap(…) instead."); +HookMap.prototype.tap = util.deprecate( + /** + * @this {HookMap} + * @param {EXPECTED_ANY} key key for the hook to tap + * @param {EXPECTED_ANY} options tap options or name + * @param {EXPECTED_ANY} fn the function to register + * @returns {EXPECTED_ANY} result of the underlying tap + */ + function tap(key, options, fn) { + return this.for(key).tap(options, fn); + }, + "HookMap#tap(key,…) is deprecated. Use HookMap#for(key).tap(…) instead." +); -HookMap.prototype.tapAsync = util.deprecate(function tapAsync( - key, - options, - fn -) { - return this.for(key).tapAsync(options, fn); -}, "HookMap#tapAsync(key,…) is deprecated. Use HookMap#for(key).tapAsync(…) instead."); +HookMap.prototype.tapAsync = util.deprecate( + /** + * @this {HookMap} + * @param {EXPECTED_ANY} key key for the hook to tap + * @param {EXPECTED_ANY} options tap options or name + * @param {EXPECTED_ANY} fn the function to register + * @returns {EXPECTED_ANY} result of the underlying tapAsync + */ + function tapAsync(key, options, fn) { + return this.for(key).tapAsync(options, fn); + }, + "HookMap#tapAsync(key,…) is deprecated. Use HookMap#for(key).tapAsync(…) instead." +); -HookMap.prototype.tapPromise = util.deprecate(function tapPromise( - key, - options, - fn -) { - return this.for(key).tapPromise(options, fn); -}, "HookMap#tapPromise(key,…) is deprecated. Use HookMap#for(key).tapPromise(…) instead."); +HookMap.prototype.tapPromise = util.deprecate( + /** + * @this {HookMap} + * @param {EXPECTED_ANY} key key for the hook to tap + * @param {EXPECTED_ANY} options tap options or name + * @param {EXPECTED_ANY} fn the function to register + * @returns {EXPECTED_ANY} result of the underlying tapPromise + */ + function tapPromise(key, options, fn) { + return this.for(key).tapPromise(options, fn); + }, + "HookMap#tapPromise(key,…) is deprecated. Use HookMap#for(key).tapPromise(…) instead." +); module.exports = HookMap; diff --git a/lib/MultiHook.js b/lib/MultiHook.js index 900abbd..78ed418 100644 --- a/lib/MultiHook.js +++ b/lib/MultiHook.js @@ -4,51 +4,116 @@ */ "use strict"; +// eslint-disable-next-line jsdoc/reject-function-type +/** @typedef {Function} EXPECTED_FUNCTION */ +// eslint-disable-next-line jsdoc/reject-any-type +/** @typedef {any} EXPECTED_ANY */ + +/** @typedef {import("./Hook").Tap} Tap */ +/** @typedef {import("./Hook").TapOptions} TapOptions */ + +/** + * @template T, R, AdditionalOptions + * @typedef {import("./Hook").HookInterceptor} HookInterceptor + */ + +/** + * @template H + */ class MultiHook { + /** + * @param {H[]} hooks the underlying hooks to multiplex tap calls across + * @param {string=} name name of the multi hook + */ constructor(hooks, name = undefined) { + /** @type {H[]} */ this.hooks = hooks; + /** @type {string | undefined} */ this.name = name; } + /** + * @param {string | Tap} options tap name or full tap options + * @param {EXPECTED_FUNCTION=} fn the function to register + * @returns {void} + */ tap(options, fn) { const { hooks } = this; for (let i = 0; i < hooks.length; i++) { - hooks[i].tap(options, fn); + /** @type {{ tap: (o: EXPECTED_ANY, fn?: EXPECTED_FUNCTION) => void }} */ ( + hooks[i] + ).tap(options, fn); } } + /** + * @param {string | Tap} options tap name or full tap options + * @param {EXPECTED_FUNCTION=} fn the function to register + * @returns {void} + */ tapAsync(options, fn) { const { hooks } = this; for (let i = 0; i < hooks.length; i++) { - hooks[i].tapAsync(options, fn); + /** @type {{ tapAsync: (o: EXPECTED_ANY, fn?: EXPECTED_FUNCTION) => void }} */ ( + hooks[i] + ).tapAsync(options, fn); } } + /** + * @param {string | Tap} options tap name or full tap options + * @param {EXPECTED_FUNCTION=} fn the function to register + * @returns {void} + */ tapPromise(options, fn) { const { hooks } = this; for (let i = 0; i < hooks.length; i++) { - hooks[i].tapPromise(options, fn); + /** @type {{ tapPromise: (o: EXPECTED_ANY, fn?: EXPECTED_FUNCTION) => void }} */ ( + hooks[i] + ).tapPromise(options, fn); } } + /** + * @returns {boolean} true if any of the underlying hooks reports usage + */ isUsed() { const { hooks } = this; for (let i = 0; i < hooks.length; i++) { - if (hooks[i].isUsed()) return true; + if (/** @type {{ isUsed: () => boolean }} */ (hooks[i]).isUsed()) { + return true; + } } return false; } + /** + * @param {HookInterceptor} interceptor the interceptor to register + * @returns {void} + */ intercept(interceptor) { const { hooks } = this; for (let i = 0; i < hooks.length; i++) { - hooks[i].intercept(interceptor); + /** @type {{ intercept: (i: HookInterceptor) => void }} */ ( + hooks[i] + ).intercept(interceptor); } } + /** + * @param {TapOptions} options the options to merge into each tap + * @returns {MultiHook} a new MultiHook wrapping each underlying hook with the options + */ withOptions(options) { return new MultiHook( - this.hooks.map((hook) => hook.withOptions(options)), + this.hooks.map( + (hook) => + /** @type {H} */ ( + /** @type {{ withOptions: (o: TapOptions) => H }} */ ( + hook + ).withOptions(options) + ) + ), this.name ); } diff --git a/lib/SyncBailHook.js b/lib/SyncBailHook.js index 4b538c3..12e376a 100644 --- a/lib/SyncBailHook.js +++ b/lib/SyncBailHook.js @@ -7,14 +7,27 @@ const Hook = require("./Hook"); const HookCodeFactory = require("./HookCodeFactory"); +// eslint-disable-next-line jsdoc/reject-function-type +/** @typedef {Function} EXPECTED_FUNCTION */ +// eslint-disable-next-line jsdoc/reject-any-type +/** @typedef {any} EXPECTED_ANY */ + +/** @typedef {import("./Hook").CompileOptions} CompileOptions */ +/** @typedef {import("./HookCodeFactory").ContentOptions} ContentOptions */ + class SyncBailHookCodeFactory extends HookCodeFactory { + /** + * @param {ContentOptions} options content generation options + * @returns {string} generated body code + */ content({ onError, onResult, resultReturns, onDone, rethrowIfPossible }) { return this.callTapsSeries({ - onError: (i, err) => onError(err), + onError: (i, err) => + /** @type {(err: string) => string} */ (onError)(err), onResult: (i, result, next) => - `if(${result} !== undefined) {\n${onResult( - result - )};\n} else {\n${next()}}\n`, + `if(${result} !== undefined) {\n${ + /** @type {(result: string) => string} */ (onResult)(result) + };\n} else {\n${next()}}\n`, resultReturns, onDone, rethrowIfPossible @@ -32,11 +45,21 @@ const TAP_PROMISE = () => { throw new Error("tapPromise is not supported on a SyncBailHook"); }; +/** + * @this {Hook} + * @param {CompileOptions} options compile options + * @returns {EXPECTED_FUNCTION} the compiled call function + */ function COMPILE(options) { factory.setup(this, options); return factory.create(options); } +/** + * @param {string[]=} args argument names of the hook + * @param {string=} name name of the hook + * @returns {Hook} a new SyncBailHook instance + */ function SyncBailHook(args = [], name = undefined) { const hook = new Hook(args, name); hook.constructor = SyncBailHook; diff --git a/lib/SyncHook.js b/lib/SyncHook.js index 968dea2..48765db 100644 --- a/lib/SyncHook.js +++ b/lib/SyncHook.js @@ -7,10 +7,23 @@ const Hook = require("./Hook"); const HookCodeFactory = require("./HookCodeFactory"); +// eslint-disable-next-line jsdoc/reject-function-type +/** @typedef {Function} EXPECTED_FUNCTION */ +// eslint-disable-next-line jsdoc/reject-any-type +/** @typedef {any} EXPECTED_ANY */ + +/** @typedef {import("./Hook").CompileOptions} CompileOptions */ +/** @typedef {import("./HookCodeFactory").ContentOptions} ContentOptions */ + class SyncHookCodeFactory extends HookCodeFactory { + /** + * @param {ContentOptions} options content generation options + * @returns {string} generated body code + */ content({ onError, onDone, rethrowIfPossible }) { return this.callTapsSeries({ - onError: (i, err) => onError(err), + onError: (i, err) => + /** @type {(err: string) => string} */ (onError)(err), onDone, rethrowIfPossible }); @@ -27,11 +40,21 @@ const TAP_PROMISE = () => { throw new Error("tapPromise is not supported on a SyncHook"); }; +/** + * @this {Hook} + * @param {CompileOptions} options compile options + * @returns {EXPECTED_FUNCTION} the compiled call function + */ function COMPILE(options) { factory.setup(this, options); return factory.create(options); } +/** + * @param {string[]=} args argument names of the hook + * @param {string=} name name of the hook + * @returns {Hook} a new SyncHook instance + */ function SyncHook(args = [], name = undefined) { const hook = new Hook(args, name); hook.constructor = SyncHook; diff --git a/lib/SyncLoopHook.js b/lib/SyncLoopHook.js index da48ca1..b7022c7 100644 --- a/lib/SyncLoopHook.js +++ b/lib/SyncLoopHook.js @@ -7,10 +7,23 @@ const Hook = require("./Hook"); const HookCodeFactory = require("./HookCodeFactory"); +// eslint-disable-next-line jsdoc/reject-function-type +/** @typedef {Function} EXPECTED_FUNCTION */ +// eslint-disable-next-line jsdoc/reject-any-type +/** @typedef {any} EXPECTED_ANY */ + +/** @typedef {import("./Hook").CompileOptions} CompileOptions */ +/** @typedef {import("./HookCodeFactory").ContentOptions} ContentOptions */ + class SyncLoopHookCodeFactory extends HookCodeFactory { + /** + * @param {ContentOptions} options content generation options + * @returns {string} generated body code + */ content({ onError, onDone, rethrowIfPossible }) { return this.callTapsLooping({ - onError: (i, err) => onError(err), + onError: (i, err) => + /** @type {(err: string) => string} */ (onError)(err), onDone, rethrowIfPossible }); @@ -27,11 +40,21 @@ const TAP_PROMISE = () => { throw new Error("tapPromise is not supported on a SyncLoopHook"); }; +/** + * @this {Hook} + * @param {CompileOptions} options compile options + * @returns {EXPECTED_FUNCTION} the compiled call function + */ function COMPILE(options) { factory.setup(this, options); return factory.create(options); } +/** + * @param {string[]=} args argument names of the hook + * @param {string=} name name of the hook + * @returns {Hook} a new SyncLoopHook instance + */ function SyncLoopHook(args = [], name = undefined) { const hook = new Hook(args, name); hook.constructor = SyncLoopHook; diff --git a/lib/SyncWaterfallHook.js b/lib/SyncWaterfallHook.js index 8eca528..88edc58 100644 --- a/lib/SyncWaterfallHook.js +++ b/lib/SyncWaterfallHook.js @@ -7,19 +7,35 @@ const Hook = require("./Hook"); const HookCodeFactory = require("./HookCodeFactory"); +// eslint-disable-next-line jsdoc/reject-function-type +/** @typedef {Function} EXPECTED_FUNCTION */ +// eslint-disable-next-line jsdoc/reject-any-type +/** @typedef {any} EXPECTED_ANY */ + +/** @typedef {import("./Hook").CompileOptions} CompileOptions */ +/** @typedef {import("./HookCodeFactory").ContentOptions} ContentOptions */ + class SyncWaterfallHookCodeFactory extends HookCodeFactory { + /** + * @param {ContentOptions} options content generation options + * @returns {string} generated body code + */ content({ onError, onResult, resultReturns, rethrowIfPossible }) { return this.callTapsSeries({ - onError: (i, err) => onError(err), + onError: (i, err) => + /** @type {(err: string) => string} */ (onError)(err), onResult: (i, result, next) => { let code = ""; code += `if(${result} !== undefined) {\n`; - code += `${this._args[0]} = ${result};\n`; + code += `${/** @type {string[]} */ (this._args)[0]} = ${result};\n`; code += "}\n"; code += next(); return code; }, - onDone: () => onResult(this._args[0]), + onDone: () => + /** @type {(result: string) => string} */ (onResult)( + /** @type {string[]} */ (this._args)[0] + ), doneReturns: resultReturns, rethrowIfPossible }); @@ -36,11 +52,21 @@ const TAP_PROMISE = () => { throw new Error("tapPromise is not supported on a SyncWaterfallHook"); }; +/** + * @this {Hook} + * @param {CompileOptions} options compile options + * @returns {EXPECTED_FUNCTION} the compiled call function + */ function COMPILE(options) { factory.setup(this, options); return factory.create(options); } +/** + * @param {string[]=} args argument names of the hook (must contain at least one) + * @param {string=} name name of the hook + * @returns {Hook} a new SyncWaterfallHook instance + */ function SyncWaterfallHook(args = [], name = undefined) { if (args.length < 1) { throw new Error("Waterfall hooks must have at least one argument"); diff --git a/lib/util-browser.js b/lib/util-browser.js index d07eb6c..9fc2f65 100644 --- a/lib/util-browser.js +++ b/lib/util-browser.js @@ -4,6 +4,18 @@ */ "use strict"; +// eslint-disable-next-line jsdoc/reject-function-type +/** @typedef {Function} EXPECTED_FUNCTION */ +// eslint-disable-next-line jsdoc/reject-any-type +/** @typedef {any} EXPECTED_ANY */ + +/** + * Browser shim for `util.deprecate`. Logs the deprecation message once on the + * first call, then forwards arguments to `fn`. + * @param {EXPECTED_FUNCTION} fn the function to wrap + * @param {string} msg the deprecation message + * @returns {EXPECTED_FUNCTION} the wrapped function + */ module.exports.deprecate = (fn, msg) => { let once = true; return function deprecate() { diff --git a/package-lock.json b/package-lock.json index 6c8f4bd..2020e47 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "tapable", - "version": "2.3.2", + "version": "2.3.3", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "tapable", - "version": "2.3.2", + "version": "2.3.3", "license": "MIT", "devDependencies": { "@babel/core": "^7.4.4", @@ -21,7 +21,8 @@ "jest": "^30.3.0", "prettier": "^3.8.3", "prettier-1": "npm:prettier@^1", - "tinybench": "^6.0.0" + "tinybench": "^6.0.0", + "typescript": "^5.9.3" }, "engines": { "node": ">=6" @@ -12056,7 +12057,6 @@ "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", "dev": true, "license": "Apache-2.0", - "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" diff --git a/package.json b/package.json index 9d63912..d7ca17f 100644 --- a/package.json +++ b/package.json @@ -31,6 +31,7 @@ "fix": "npm run fix:code && npm run fmt", "fix:code": "npm run lint:code -- --fix", "test": "jest", + "build:types": "tsc", "benchmark": "node --max-old-space-size=4096 --hash-seed=1 --random-seed=1 --no-opt --predictable --predictable-gc-schedule --interpreted-frames-native-stack --allow-natives-syntax --expose-gc --no-concurrent-sweeping ./benchmark/run.mjs", "version": "changeset version", "release": "changeset publish" @@ -57,7 +58,8 @@ "jest": "^30.3.0", "prettier": "^3.8.3", "prettier-1": "npm:prettier@^1", - "tinybench": "^6.0.0" + "tinybench": "^6.0.0", + "typescript": "^5.9.3" }, "engines": { "node": ">=6" diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..7a4d88f --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,17 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "CommonJS", + "moduleResolution": "node", + "allowJs": true, + "checkJs": false, + "declaration": true, + "emitDeclarationOnly": true, + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "outDir": "./types", + "rootDir": "./lib" + }, + "include": ["lib/**/*.js"] +} From 6cd99d66ea6f87648f9a5d6a3c8d8c7770b2f087 Mon Sep 17 00:00:00 2001 From: alexander-akait Date: Tue, 28 Apr 2026 03:01:19 +0300 Subject: [PATCH 2/8] refactor: code --- lib/AsyncParallelBailHook.js | 39 +- lib/AsyncParallelHook.js | 27 +- lib/AsyncSeriesBailHook.js | 34 +- lib/AsyncSeriesHook.js | 27 +- lib/AsyncSeriesLoopHook.js | 27 +- lib/AsyncSeriesWaterfallHook.js | 35 +- lib/Hook.js | 167 +- lib/HookCodeFactory.js | 190 +- lib/HookMap.js | 73 +- lib/MultiHook.js | 65 +- lib/SyncBailHook.js | 35 +- lib/SyncHook.js | 29 +- lib/SyncLoopHook.js | 27 +- lib/SyncWaterfallHook.js | 33 +- lib/util-browser.js | 6 +- package-lock.json | 44 +- package.json | 5 +- test/AsyncParallelBailHook.test.js | 18 + test/AsyncParallelHooks.test.js | 11 - test/AsyncSeriesBailHook.test.js | 28 + test/AsyncSeriesHooks.test.js | 79 - test/AsyncSeriesLoopHook.test.js | 18 + test/AsyncSeriesWaterfallHook.test.js | 54 + test/SyncBailHook.test.js | 25 +- test/SyncHooks.test.js | 33 - test/SyncLoopHook.test.js | 19 +- test/SyncWaterfallHook.test.js | 41 +- .../AsyncParallelBailHook.test.js.snap | 798 +++++++ .../AsyncParallelHooks.test.js.snap | 797 ------- .../AsyncSeriesBailHook.test.js.snap | 776 +++++++ .../AsyncSeriesHooks.test.js.snap | 1904 ++--------------- .../AsyncSeriesLoopHook.test.js.snap | 131 ++ .../AsyncSeriesWaterfallHook.test.js.snap | 740 +++++++ test/__snapshots__/SyncBailHook.test.js.snap | 258 +++ test/__snapshots__/SyncHooks.test.js.snap | 602 ------ test/__snapshots__/SyncLoopHook.test.js.snap | 88 + .../SyncWaterfallHook.test.js.snap | 259 +++ tsconfig.json | 31 +- 38 files changed, 3908 insertions(+), 3665 deletions(-) create mode 100644 test/AsyncParallelBailHook.test.js create mode 100644 test/AsyncSeriesBailHook.test.js create mode 100644 test/AsyncSeriesLoopHook.test.js create mode 100644 test/AsyncSeriesWaterfallHook.test.js create mode 100644 test/__snapshots__/AsyncParallelBailHook.test.js.snap create mode 100644 test/__snapshots__/AsyncSeriesBailHook.test.js.snap create mode 100644 test/__snapshots__/AsyncSeriesLoopHook.test.js.snap create mode 100644 test/__snapshots__/AsyncSeriesWaterfallHook.test.js.snap create mode 100644 test/__snapshots__/SyncBailHook.test.js.snap create mode 100644 test/__snapshots__/SyncLoopHook.test.js.snap create mode 100644 test/__snapshots__/SyncWaterfallHook.test.js.snap diff --git a/lib/AsyncParallelBailHook.js b/lib/AsyncParallelBailHook.js index b3e6277..907cfb6 100644 --- a/lib/AsyncParallelBailHook.js +++ b/lib/AsyncParallelBailHook.js @@ -7,13 +7,19 @@ const Hook = require("./Hook"); const HookCodeFactory = require("./HookCodeFactory"); -// eslint-disable-next-line jsdoc/reject-function-type -/** @typedef {Function} EXPECTED_FUNCTION */ -// eslint-disable-next-line jsdoc/reject-any-type -/** @typedef {any} EXPECTED_ANY */ - +/** @typedef {import("./Hook").EXPECTED_ANY} EXPECTED_ANY */ +/** @typedef {import("./Hook").EXPECTED_FUNCTION} EXPECTED_FUNCTION */ +/** @typedef {import("./Hook").UnsetAdditionalOptions} UnsetAdditionalOptions */ /** @typedef {import("./Hook").CompileOptions} CompileOptions */ /** @typedef {import("./HookCodeFactory").ContentOptions} ContentOptions */ +/** + * @template {EXPECTED_ANY[]} T + * @typedef {import("./Hook").ArgumentNames} ArgumentNames + */ +/** + * @template T + * @typedef {import("./Hook").AsArray} AsArray + */ class AsyncParallelBailHookCodeFactory extends HookCodeFactory { /** @@ -29,11 +35,11 @@ class AsyncParallelBailHookCodeFactory extends HookCodeFactory { code += "var item = _results[i];\n"; code += "if(item === undefined) return false;\n"; code += "if(item.result !== undefined) {\n"; - code += /** @type {(result: string) => string} */ (onResult)("item.result"); + code += onResult("item.result"); code += "return true;\n"; code += "}\n"; code += "if(item.error) {\n"; - code += /** @type {(err: string) => string} */ (onError)("item.error"); + code += onError("item.error"); code += "return true;\n"; code += "}\n"; code += "}\n"; @@ -82,7 +88,10 @@ class AsyncParallelBailHookCodeFactory extends HookCodeFactory { const factory = new AsyncParallelBailHookCodeFactory(); /** - * @this {Hook} + * @template T + * @template R + * @template [AdditionalOptions=UnsetAdditionalOptions] + * @this {Hook} * @param {CompileOptions} options compile options * @returns {EXPECTED_FUNCTION} the compiled call function */ @@ -92,11 +101,18 @@ function COMPILE(options) { } /** - * @param {string[]=} args argument names of the hook + * @constructor + * @template T + * @template R + * @template [AdditionalOptions=UnsetAdditionalOptions] + * @param {ArgumentNames>=} args argument names of the hook * @param {string=} name name of the hook - * @returns {Hook} a new AsyncParallelBailHook instance + * @returns {Hook} a new AsyncParallelBailHook instance */ -function AsyncParallelBailHook(args = [], name = undefined) { +function AsyncParallelBailHook( + args = /** @type {ArgumentNames>} */ ([]), + name = undefined +) { const hook = new Hook(args, name); hook.constructor = AsyncParallelBailHook; hook.compile = COMPILE; @@ -105,6 +121,7 @@ function AsyncParallelBailHook(args = [], name = undefined) { return hook; } +/** @type {EXPECTED_ANY} */ AsyncParallelBailHook.prototype = null; module.exports = AsyncParallelBailHook; diff --git a/lib/AsyncParallelHook.js b/lib/AsyncParallelHook.js index b4f7934..288930d 100644 --- a/lib/AsyncParallelHook.js +++ b/lib/AsyncParallelHook.js @@ -7,13 +7,19 @@ const Hook = require("./Hook"); const HookCodeFactory = require("./HookCodeFactory"); -// eslint-disable-next-line jsdoc/reject-function-type -/** @typedef {Function} EXPECTED_FUNCTION */ -// eslint-disable-next-line jsdoc/reject-any-type -/** @typedef {any} EXPECTED_ANY */ - +/** @typedef {import("./Hook").EXPECTED_ANY} EXPECTED_ANY */ +/** @typedef {import("./Hook").EXPECTED_FUNCTION} EXPECTED_FUNCTION */ /** @typedef {import("./Hook").CompileOptions} CompileOptions */ +/** @typedef {import("./Hook").UnsetAdditionalOptions} UnsetAdditionalOptions */ /** @typedef {import("./HookCodeFactory").ContentOptions} ContentOptions */ +/** + * @template {EXPECTED_ANY[]} T + * @typedef {import("./Hook").ArgumentNames} ArgumentNames + */ +/** + * @template T + * @typedef {import("./Hook").AsArray} AsArray + */ class AsyncParallelHookCodeFactory extends HookCodeFactory { /** @@ -22,8 +28,7 @@ class AsyncParallelHookCodeFactory extends HookCodeFactory { */ content({ onError, onDone }) { return this.callTapsParallel({ - onError: (i, err, done, doneBreak) => - /** @type {(err: string) => string} */ (onError)(err) + doneBreak(true), + onError: (i, err, done, doneBreak) => onError(err) + doneBreak(true), onDone }); } @@ -42,9 +47,12 @@ function COMPILE(options) { } /** - * @param {string[]=} args argument names of the hook + * @constructor + * @template T + * @template [AdditionalOptions=UnsetAdditionalOptions] + * @param {ArgumentNames>=} args argument names of the hook * @param {string=} name name of the hook - * @returns {Hook} a new AsyncParallelHook instance + * @returns {Hook} a new AsyncParallelBailHook instance */ function AsyncParallelHook(args = [], name = undefined) { const hook = new Hook(args, name); @@ -55,6 +63,7 @@ function AsyncParallelHook(args = [], name = undefined) { return hook; } +/** @type {EXPECTED_ANY} */ AsyncParallelHook.prototype = null; module.exports = AsyncParallelHook; diff --git a/lib/AsyncSeriesBailHook.js b/lib/AsyncSeriesBailHook.js index c374f07..3bd105a 100644 --- a/lib/AsyncSeriesBailHook.js +++ b/lib/AsyncSeriesBailHook.js @@ -7,13 +7,19 @@ const Hook = require("./Hook"); const HookCodeFactory = require("./HookCodeFactory"); -// eslint-disable-next-line jsdoc/reject-function-type -/** @typedef {Function} EXPECTED_FUNCTION */ -// eslint-disable-next-line jsdoc/reject-any-type -/** @typedef {any} EXPECTED_ANY */ - +/** @typedef {import("./Hook").EXPECTED_ANY} EXPECTED_ANY */ +/** @typedef {import("./Hook").EXPECTED_FUNCTION} EXPECTED_FUNCTION */ /** @typedef {import("./Hook").CompileOptions} CompileOptions */ +/** @typedef {import("./Hook").UnsetAdditionalOptions} UnsetAdditionalOptions */ /** @typedef {import("./HookCodeFactory").ContentOptions} ContentOptions */ +/** + * @template {EXPECTED_ANY[]} T + * @typedef {import("./Hook").ArgumentNames} ArgumentNames + */ +/** + * @template T + * @typedef {import("./Hook").AsArray} AsArray + */ class AsyncSeriesBailHookCodeFactory extends HookCodeFactory { /** @@ -22,12 +28,11 @@ class AsyncSeriesBailHookCodeFactory extends HookCodeFactory { */ content({ onError, onResult, resultReturns, onDone }) { return this.callTapsSeries({ - onError: (i, err, next, doneBreak) => - /** @type {(err: string) => string} */ (onError)(err) + doneBreak(true), + onError: (i, err, next, doneBreak) => onError(err) + doneBreak(true), onResult: (i, result, next) => - `if(${result} !== undefined) {\n${ - /** @type {(result: string) => string} */ (onResult)(result) - }\n} else {\n${next()}}\n`, + `if(${result} !== undefined) {\n${onResult( + result + )}\n} else {\n${next()}}\n`, resultReturns, onDone }); @@ -47,9 +52,13 @@ function COMPILE(options) { } /** - * @param {string[]=} args argument names of the hook + * @constructor + * @template T + * @template R + * @template [AdditionalOptions=UnsetAdditionalOptions] + * @param {ArgumentNames>=} args argument names of the hook * @param {string=} name name of the hook - * @returns {Hook} a new AsyncSeriesBailHook instance + * @returns {Hook} a new AsyncParallelBailHook instance */ function AsyncSeriesBailHook(args = [], name = undefined) { const hook = new Hook(args, name); @@ -60,6 +69,7 @@ function AsyncSeriesBailHook(args = [], name = undefined) { return hook; } +/** @type {EXPECTED_ANY} */ AsyncSeriesBailHook.prototype = null; module.exports = AsyncSeriesBailHook; diff --git a/lib/AsyncSeriesHook.js b/lib/AsyncSeriesHook.js index 2d32961..6a118b6 100644 --- a/lib/AsyncSeriesHook.js +++ b/lib/AsyncSeriesHook.js @@ -7,13 +7,19 @@ const Hook = require("./Hook"); const HookCodeFactory = require("./HookCodeFactory"); -// eslint-disable-next-line jsdoc/reject-function-type -/** @typedef {Function} EXPECTED_FUNCTION */ -// eslint-disable-next-line jsdoc/reject-any-type -/** @typedef {any} EXPECTED_ANY */ - +/** @typedef {import("./Hook").EXPECTED_ANY} EXPECTED_ANY */ +/** @typedef {import("./Hook").EXPECTED_FUNCTION} EXPECTED_FUNCTION */ /** @typedef {import("./Hook").CompileOptions} CompileOptions */ +/** @typedef {import("./Hook").UnsetAdditionalOptions} UnsetAdditionalOptions */ /** @typedef {import("./HookCodeFactory").ContentOptions} ContentOptions */ +/** + * @template {EXPECTED_ANY[]} T + * @typedef {import("./Hook").ArgumentNames} ArgumentNames + */ +/** + * @template T + * @typedef {import("./Hook").AsArray} AsArray + */ class AsyncSeriesHookCodeFactory extends HookCodeFactory { /** @@ -22,8 +28,7 @@ class AsyncSeriesHookCodeFactory extends HookCodeFactory { */ content({ onError, onDone }) { return this.callTapsSeries({ - onError: (i, err, next, doneBreak) => - /** @type {(err: string) => string} */ (onError)(err) + doneBreak(true), + onError: (i, err, next, doneBreak) => onError(err) + doneBreak(true), onDone }); } @@ -42,9 +47,12 @@ function COMPILE(options) { } /** - * @param {string[]=} args argument names of the hook + * @constructor + * @template T + * @template [AdditionalOptions=UnsetAdditionalOptions] + * @param {ArgumentNames>=} args argument names of the hook * @param {string=} name name of the hook - * @returns {Hook} a new AsyncSeriesHook instance + * @returns {Hook} a new AsyncParallelBailHook instance */ function AsyncSeriesHook(args = [], name = undefined) { const hook = new Hook(args, name); @@ -55,6 +63,7 @@ function AsyncSeriesHook(args = [], name = undefined) { return hook; } +/** @type {EXPECTED_ANY} */ AsyncSeriesHook.prototype = null; module.exports = AsyncSeriesHook; diff --git a/lib/AsyncSeriesLoopHook.js b/lib/AsyncSeriesLoopHook.js index edd6b39..b795d46 100644 --- a/lib/AsyncSeriesLoopHook.js +++ b/lib/AsyncSeriesLoopHook.js @@ -7,13 +7,19 @@ const Hook = require("./Hook"); const HookCodeFactory = require("./HookCodeFactory"); -// eslint-disable-next-line jsdoc/reject-function-type -/** @typedef {Function} EXPECTED_FUNCTION */ -// eslint-disable-next-line jsdoc/reject-any-type -/** @typedef {any} EXPECTED_ANY */ - +/** @typedef {import("./Hook").EXPECTED_ANY} EXPECTED_ANY */ +/** @typedef {import("./Hook").EXPECTED_FUNCTION} EXPECTED_FUNCTION */ /** @typedef {import("./Hook").CompileOptions} CompileOptions */ +/** @typedef {import("./Hook").UnsetAdditionalOptions} UnsetAdditionalOptions */ /** @typedef {import("./HookCodeFactory").ContentOptions} ContentOptions */ +/** + * @template {EXPECTED_ANY[]} T + * @typedef {import("./Hook").ArgumentNames} ArgumentNames + */ +/** + * @template T + * @typedef {import("./Hook").AsArray} AsArray + */ class AsyncSeriesLoopHookCodeFactory extends HookCodeFactory { /** @@ -22,8 +28,7 @@ class AsyncSeriesLoopHookCodeFactory extends HookCodeFactory { */ content({ onError, onDone }) { return this.callTapsLooping({ - onError: (i, err, next, doneBreak) => - /** @type {(err: string) => string} */ (onError)(err) + doneBreak(true), + onError: (i, err, next, doneBreak) => onError(err) + doneBreak(true), onDone }); } @@ -42,9 +47,12 @@ function COMPILE(options) { } /** - * @param {string[]=} args argument names of the hook + * @constructor + * @template T + * @template [AdditionalOptions=UnsetAdditionalOptions] + * @param {ArgumentNames>=} args argument names of the hook * @param {string=} name name of the hook - * @returns {Hook} a new AsyncSeriesLoopHook instance + * @returns {Hook} a new AsyncParallelBailHook instance */ function AsyncSeriesLoopHook(args = [], name = undefined) { const hook = new Hook(args, name); @@ -55,6 +63,7 @@ function AsyncSeriesLoopHook(args = [], name = undefined) { return hook; } +/** @type {EXPECTED_ANY} */ AsyncSeriesLoopHook.prototype = null; module.exports = AsyncSeriesLoopHook; diff --git a/lib/AsyncSeriesWaterfallHook.js b/lib/AsyncSeriesWaterfallHook.js index 8a10b8f..aba298d 100644 --- a/lib/AsyncSeriesWaterfallHook.js +++ b/lib/AsyncSeriesWaterfallHook.js @@ -7,23 +7,28 @@ const Hook = require("./Hook"); const HookCodeFactory = require("./HookCodeFactory"); -// eslint-disable-next-line jsdoc/reject-function-type -/** @typedef {Function} EXPECTED_FUNCTION */ -// eslint-disable-next-line jsdoc/reject-any-type -/** @typedef {any} EXPECTED_ANY */ - +/** @typedef {import("./Hook").EXPECTED_ANY} EXPECTED_ANY */ +/** @typedef {import("./Hook").EXPECTED_FUNCTION} EXPECTED_FUNCTION */ /** @typedef {import("./Hook").CompileOptions} CompileOptions */ +/** @typedef {import("./Hook").UnsetAdditionalOptions} UnsetAdditionalOptions */ /** @typedef {import("./HookCodeFactory").ContentOptions} ContentOptions */ +/** + * @template {EXPECTED_ANY[]} T + * @typedef {import("./Hook").ArgumentNames} ArgumentNames + */ +/** + * @template T + * @typedef {import("./Hook").AsArray} AsArray + */ class AsyncSeriesWaterfallHookCodeFactory extends HookCodeFactory { /** * @param {ContentOptions} options content generation options * @returns {string} generated body code */ - content({ onError, onResult, _onDone }) { + content({ onError, onResult }) { return this.callTapsSeries({ - onError: (i, err, next, doneBreak) => - /** @type {(err: string) => string} */ (onError)(err) + doneBreak(true), + onError: (i, err, next, doneBreak) => onError(err) + doneBreak(true), onResult: (i, result, next) => { let code = ""; code += `if(${result} !== undefined) {\n`; @@ -32,10 +37,7 @@ class AsyncSeriesWaterfallHookCodeFactory extends HookCodeFactory { code += next(); return code; }, - onDone: () => - /** @type {(result: string) => string} */ (onResult)( - /** @type {string[]} */ (this._args)[0] - ) + onDone: () => onResult(/** @type {string[]} */ (this._args)[0]) }); } } @@ -53,9 +55,13 @@ function COMPILE(options) { } /** - * @param {string[]=} args argument names of the hook (must contain at least one) + * @constructor + * @template T + * @template [R=AsArray[0]] + * @template [AdditionalOptions=UnsetAdditionalOptions] + * @param {ArgumentNames>=} args argument names of the hook * @param {string=} name name of the hook - * @returns {Hook} a new AsyncSeriesWaterfallHook instance + * @returns {Hook} a new AsyncParallelBailHook instance */ function AsyncSeriesWaterfallHook(args = [], name = undefined) { if (args.length < 1) { @@ -69,6 +75,7 @@ function AsyncSeriesWaterfallHook(args = [], name = undefined) { return hook; } +/** @type {EXPECTED_ANY} */ AsyncSeriesWaterfallHook.prototype = null; module.exports = AsyncSeriesWaterfallHook; diff --git a/lib/Hook.js b/lib/Hook.js index 5aaf67e..c1b7b2c 100644 --- a/lib/Hook.js +++ b/lib/Hook.js @@ -10,6 +10,51 @@ const util = require("util"); /** @typedef {Function} EXPECTED_FUNCTION */ // eslint-disable-next-line jsdoc/reject-any-type /** @typedef {any} EXPECTED_ANY */ +/** @typedef {Record} EXPECTED_OBJECT */ + +/** + * @template T + * @typedef {T extends EXPECTED_ANY[] ? T : [T]} AsArray + */ + +/** + * @template {number} T + * @typedef {T extends 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 ? T : never} Measure + */ + +/** + * @template {EXPECTED_ANY[]} T + * @template U + * @typedef {{ + * 0: [U]; + * 1: [T[0], U]; + * 2: [T[0], T[1], U]; + * 3: [T[0], T[1], T[2], U]; + * 4: [T[0], T[1], T[2], T[3], U]; + * 5: [T[0], T[1], T[2], T[3], T[4], U]; + * 6: [T[0], T[1], T[2], T[3], T[4], T[5], U]; + * 7: [T[0], T[1], T[2], T[3], T[4], T[5], T[6], U]; + * 8: [T[0], T[1], T[2], T[3], T[4], T[5], T[6], T[7], U]; + * }[Measure]} Append + */ + +/* eslint-disable jsdoc/ts-no-empty-object-type */ +/** + * @template X + * @typedef {X extends UnsetAdditionalOptions ? { } : X} IfSet + */ +/* eslint-enable jsdoc/ts-no-empty-object-type */ + +/** + * @template {number} T + * @template U + * @typedef {T extends 0 ? void[] : ReadonlyArray & { 0: U, length: T }} FixedSizeArray + */ + +/** + * @template {EXPECTED_ANY[]} T + * @typedef {FixedSizeArray} ArgumentNames + */ /** * @typedef {object} TapOptions @@ -36,24 +81,34 @@ const util = require("util"); */ /** - * @template T, R, AdditionalOptions + * @template T + * @template R + * @template [AdditionalOptions=UnsetAdditionalOptions] * @typedef {object} HookInterceptor * @property {string=} name optional name of the interceptor - * @property {((tap: FullTap & AdditionalOptions) => void)=} tap called for each tap before it runs + * @property {((tap: FullTap & IfSet) => void)=} tap called for each tap before it runs * @property {((...args: EXPECTED_ANY[]) => void)=} call called when the hook is called * @property {((...args: EXPECTED_ANY[]) => void)=} loop called for each loop iteration of looping hooks * @property {((err: Error) => void)=} error called when an error occurs * @property {((result: R) => void)=} result called with the hook's result * @property {(() => void)=} done called when the hook is fully done - * @property {((tap: FullTap & AdditionalOptions) => FullTap & AdditionalOptions)=} register called whenever a tap is registered + * @property {((tap: FullTap & IfSet) => FullTap & IfSet)=} register called whenever a tap is registered * @property {boolean=} context true to pass a `_context` argument to interceptor callbacks */ /** + * @typedef {object} UnsetAdditionalOptions + * @property {true} _UnsetAdditionalOptions unset + */ + +/** + * @template T + * @template R + * @template [AdditionalOptions=UnsetAdditionalOptions] * @typedef {object} CompileOptions * @property {FullTap[]} taps the registered taps - * @property {HookInterceptor[]} interceptors the registered interceptors - * @property {string[]} args names of the hook arguments (used for code generation) + * @property {HookInterceptor[]} interceptors the registered interceptors + * @property {ArgumentNames>[]} args names of the hook arguments (used for code generation) * @property {"sync" | "async" | "promise"} type call type */ @@ -63,9 +118,16 @@ const deprecateContext = util.deprecate( ); /** - * @this {Hook} - * @param {...EXPECTED_ANY} args hook call arguments - * @returns {EXPECTED_ANY} hook call result + * @template T, R + * @callback CallDelegate + * @param {...AsArray} args + * @returns {R} + */ + +/** + * @template T, R + * @type {CallDelegate} + * @this {Hook} */ function CALL_DELEGATE(...args) { this.call = this._createCall("sync"); @@ -73,9 +135,16 @@ function CALL_DELEGATE(...args) { } /** - * @this {Hook} - * @param {...EXPECTED_ANY} args hook call arguments - * @returns {EXPECTED_ANY} hook call result + * @template T, R + * @callback CallAsyncDelegate + * @param {...Append, Callback>} args + * @returns void + */ + +/** + * @template T, R + * @type {CallAsyncDelegate} + * @this {Hook} */ function CALL_ASYNC_DELEGATE(...args) { this.callAsync = this._createCall("async"); @@ -83,9 +152,16 @@ function CALL_ASYNC_DELEGATE(...args) { } /** - * @this {Hook} - * @param {...EXPECTED_ANY} args hook call arguments - * @returns {Promise} resolves with the hook result + * @template T, R + * @callback PromiseDeledate + * @param {...AsArray} args + * @returns {Promise} + */ + +/** + * @template T, R + * @type {PromiseDeledate} + * @this {Hook} */ function PROMISE_DELEGATE(...args) { this.promise = this._createCall("promise"); @@ -95,15 +171,15 @@ function PROMISE_DELEGATE(...args) { /** * @template T * @template [R=void] - * @template [AdditionalOptions=object] + * @template [AdditionalOptions=UnsetAdditionalOptions] */ class Hook { /** - * @param {string[]=} args argument names of the hook (used for code generation) + * @param {ArgumentNames>=} args argument names of the hook (used for code generation) * @param {string=} name name of the hook */ constructor(args = [], name = undefined) { - /** @type {string[]} */ + /** @type {ArgumentNames>} */ this._args = args; /** @type {string | undefined} */ this.name = name; @@ -111,11 +187,17 @@ class Hook { this.taps = []; /** @type {HookInterceptor[]} */ this.interceptors = []; + /** @type {CallDelegate | undefined} */ this._call = CALL_DELEGATE; + /** @type {CallDelegate | undefined} */ this.call = CALL_DELEGATE; + /** @type {CallAsyncDelegate} */ this._callAsync = CALL_ASYNC_DELEGATE; + /** @type {CallAsyncDelegate} */ this.callAsync = CALL_ASYNC_DELEGATE; + /** @type {PromiseDeledate} */ this._promise = PROMISE_DELEGATE; + /** @type {PromiseDeledate} */ this.promise = PROMISE_DELEGATE; /** @type {EXPECTED_FUNCTION[] | undefined} */ this._x = undefined; @@ -132,7 +214,7 @@ class Hook { /** * @abstract - * @param {CompileOptions} _options compile options + * @param {CompileOptions} _options compile options * @returns {EXPECTED_FUNCTION} the compiled call function */ compile(_options) { @@ -154,7 +236,7 @@ class Hook { /** * @param {"sync" | "async" | "promise"} type the tap type - * @param {string | (Tap & AdditionalOptions)} options name or full tap options + * @param {string | (Tap & IfSet)} options name or full tap options * @param {EXPECTED_FUNCTION} fn callback registered with the tap * @returns {void} */ @@ -167,7 +249,9 @@ class Hook { if (name === "") { throw new Error("Missing name for tap"); } - options = /** @type {Tap & AdditionalOptions} */ ({ type, fn, name }); + options = + /** @type {FullTap & IfSet} */ + ({ type, fn, name }); } else { if (typeof options !== "object" || options === null) { throw new Error("Invalid tap options"); @@ -199,7 +283,9 @@ class Hook { } } if (onlyName) { - options = /** @type {Tap & AdditionalOptions} */ ({ type, fn, name }); + options = + /** @type {FullTap & IfSet} */ + ({ type, fn, name }); } else { options.name = name; // Preserve previous precedence: user-provided keys win over the internal `type`/`fn`. @@ -207,14 +293,18 @@ class Hook { } } options = this._runRegisterInterceptors( - /** @type {FullTap & AdditionalOptions} */ (options) + /** @type {FullTap & IfSet} */ + (options) + ); + this._insert( + /** @type {FullTap & IfSet} */ + (options) ); - this._insert(options); } /** - * @param {string | (Tap & AdditionalOptions)} options tap name or full tap options - * @param {EXPECTED_FUNCTION} fn the function to register + * @param {string | (Tap & IfSet)} options tap name or full tap options + * @param {(...args: AsArray) => R} fn the function to register * @returns {void} */ tap(options, fn) { @@ -222,8 +312,8 @@ class Hook { } /** - * @param {string | (Tap & AdditionalOptions)} options tap name or full tap options - * @param {EXPECTED_FUNCTION} fn the function to register + * @param {string | (Tap & IfSet)} options tap name or full tap options + * @param {(...args: Append, InnerCallback>) => void} fn the function to register * @returns {void} */ tapAsync(options, fn) { @@ -231,8 +321,8 @@ class Hook { } /** - * @param {string | (Tap & AdditionalOptions)} options tap name or full tap options - * @param {EXPECTED_FUNCTION} fn the function to register + * @param {string | (Tap & IfSet)} options tap name or full tap options + * @param {(...args: AsArray) => Promise} fn the function to register * @returns {void} */ tapPromise(options, fn) { @@ -240,8 +330,8 @@ class Hook { } /** - * @param {FullTap & AdditionalOptions} options the tap descriptor - * @returns {FullTap & AdditionalOptions} possibly transformed options + * @param {FullTap & IfSet} options the tap descriptor + * @returns {FullTap & IfSet} possibly transformed options */ _runRegisterInterceptors(options) { const { interceptors } = this; @@ -251,12 +341,7 @@ class Hook { for (let i = 0; i < length; i++) { const interceptor = interceptors[i]; if (interceptor.register) { - const newOptions = - /** @type {FullTap & AdditionalOptions | undefined} */ ( - interceptor.register( - /** @type {FullTap & AdditionalOptions} */ (options) - ) - ); + const newOptions = interceptor.register(options); if (newOptions !== undefined) { options = newOptions; } @@ -266,10 +351,14 @@ class Hook { } /** - * @param {TapOptions & AdditionalOptions} options the options to merge into each tap + * @param {TapOptions & IfSet} options the options to merge into each tap * @returns {Omit} a wrapper that pre-applies the options */ withOptions(options) { + /** + * @param {string | (Tap & IfSet)} opt options + * @returns {Tap & IfSet} merged options + */ const mergeOptions = (opt) => Object.assign({}, options, typeof opt === "string" ? { name: opt } : opt); @@ -315,7 +404,7 @@ class Hook { } /** - * @param {FullTap & AdditionalOptions} item the tap to insert into the ordered taps list + * @param {FullTap & IfSet} item the tap to insert into the ordered taps list * @returns {void} */ _insert(item) { diff --git a/lib/HookCodeFactory.js b/lib/HookCodeFactory.js index e55e1c9..f089924 100644 --- a/lib/HookCodeFactory.js +++ b/lib/HookCodeFactory.js @@ -4,13 +4,9 @@ */ "use strict"; -// eslint-disable-next-line jsdoc/reject-function-type -/** @typedef {Function} EXPECTED_FUNCTION */ -// eslint-disable-next-line jsdoc/reject-any-type -/** @typedef {any} EXPECTED_ANY */ -/** @typedef {Record} EXPECTED_OBJECT */ - -/** @typedef {import("./Hook")} Hook */ +/** @typedef {import("./Hook").EXPECTED_ANY} EXPECTED_ANY */ +/** @typedef {import("./Hook").EXPECTED_OBJECT} EXPECTED_OBJECT */ +/** @typedef {import("./Hook").EXPECTED_FUNCTION} EXPECTED_FUNCTION */ /** @typedef {import("./Hook").FullTap} FullTap */ /** @typedef {import("./Hook").CompileOptions} CompileOptions */ @@ -19,6 +15,11 @@ * @typedef {import("./Hook").HookInterceptor} HookInterceptor */ +/** + * @template T, R, AdditionalOptions + * @typedef {import("./Hook")} Hook + */ + /** * @typedef {(error: string) => string} OnErrorCallback */ @@ -33,31 +34,43 @@ /** * @typedef {object} ContentOptions - * @property {OnErrorCallback=} onError generates code for handling an error - * @property {OnResultCallback=} onResult generates code for handling a result + * @property {OnErrorCallback} onError generates code for handling an error + * @property {OnResultCallback} onResult generates code for handling a result + * @property {OnDoneCallback} onDone generates code for completion * @property {boolean=} resultReturns true if the generated function returns a result - * @property {OnDoneCallback=} onDone generates code for completion * @property {boolean=} doneReturns true if the generated function returns when done * @property {boolean=} rethrowIfPossible true to rethrow errors when safe */ /** - * @typedef {object} TapsSeriesOptions - * @property {((tapIndex: number, error: string, next: () => string, doneBreak: (skipDone: boolean) => string) => string)=} onError generates per-tap error code - * @property {((tapIndex: number, result: string, next: () => string, doneBreak: (skipDone: boolean) => string) => string)=} onResult generates per-tap result code - * @property {boolean=} resultReturns true if the generated function returns a result + * @typedef {object} CallTapOptions + * @property {OnErrorCallback} onError generates code for handling an error + * @property {OnResultCallback=} onResult generates code for handling a result * @property {OnDoneCallback=} onDone generates code for completion + * @property {boolean=} rethrowIfPossible true to rethrow errors when safe + */ + +/** + * @typedef {object} CallTapsOptions + * @property {((tapIndex: number, error: string, next: () => string, doneBreak: (skipDone: boolean) => string) => string)} onError generates code for handling an error + * @property {((tapIndex: number, result: string, next: () => string, doneBreak: (skipDone: boolean) => string) => string)=} onResult generates code for handling a result + * @property {OnDoneCallback} onDone generates code for completion + * @property {boolean=} rethrowIfPossible true to rethrow errors when safe * @property {boolean=} doneReturns true if the generated function returns when done + * @property {boolean=} resultReturns true if the generated function returns a result + */ + +/** + * @typedef {object} CallTapsParallelOptions + * @property {((tapIndex: number, error: string, next: () => string, doneBreak: (skipDone: boolean) => string) => string)} onError generates code for handling an error + * @property {((tapIndex: number, result: string, next: () => string, doneBreak: (skipDone: boolean) => string) => string)=} onResult generates code for handling a result + * @property {(tapIndex: number, run: () => string, done: () => string, doneBreak: (skipDone: boolean) => string) => string=} onTap options + * @property {OnDoneCallback=} onDone generates code for completion * @property {boolean=} rethrowIfPossible true to rethrow errors when safe */ class HookCodeFactory { - /** - * @param {EXPECTED_OBJECT=} config optional configuration object passed through by subclasses - */ - constructor(config) { - /** @type {EXPECTED_OBJECT | undefined} */ - this.config = config; + constructor() { /** @type {CompileOptions | undefined} */ this.options = undefined; /** @type {string[] | undefined} */ @@ -70,6 +83,7 @@ class HookCodeFactory { */ create(options) { this.init(options); + /** @type {EXPECTED_FUNCTION} */ let fn; switch (options.type) { case "sync": @@ -78,8 +92,8 @@ class HookCodeFactory { `"use strict";\n${this.header()}${this.contentWithInterceptors({ onError: (err) => `throw ${err};\n`, onResult: (result) => `return ${result};\n`, - resultReturns: true, onDone: () => "", + resultReturns: true, rethrowIfPossible: true })}` ); @@ -130,7 +144,16 @@ class HookCodeFactory { } } this.deinit(); - return /** @type {EXPECTED_FUNCTION} */ (fn); + return fn; + } + + /** + * @abstract + * @param {ContentOptions} _options content generation options + * @returns {string} generated body code + */ + content(_options) { + throw new Error("Abstract: should be overridden"); } /** @@ -141,11 +164,12 @@ class HookCodeFactory { setup(instance, options) { const { taps } = options; const { length } = taps; + /** @type {EXPECTED_FUNCTION[]}} */ const fns = Array.from({ length }); for (let i = 0; i < length; i++) { fns[i] = taps[i].fn; } - instance._x = /** @type {EXPECTED_FUNCTION[]} */ (fns); + instance._x = fns; } /** @@ -192,43 +216,52 @@ class HookCodeFactory { Object.assign(options, { onError: onError && - ((err) => { - let code = ""; - for (let i = 0; i < opts.interceptors.length; i++) { - const interceptor = opts.interceptors[i]; - if (interceptor.error) { - code += `${this.getInterceptor(i)}.error(${err});\n`; + /** @type {OnErrorCallback} */ + ( + (err) => { + let code = ""; + for (let i = 0; i < opts.interceptors.length; i++) { + const interceptor = opts.interceptors[i]; + if (interceptor.error) { + code += `${this.getInterceptor(i)}.error(${err});\n`; + } } + code += onError(err); + return code; } - code += onError(err); - return code; - }), + ), onResult: onResult && - ((result) => { - let code = ""; - for (let i = 0; i < opts.interceptors.length; i++) { - const interceptor = opts.interceptors[i]; - if (interceptor.result) { - code += `${this.getInterceptor(i)}.result(${result});\n`; + /** @type {OnResultCallback} */ + ( + (result) => { + let code = ""; + for (let i = 0; i < opts.interceptors.length; i++) { + const interceptor = opts.interceptors[i]; + if (interceptor.result) { + code += `${this.getInterceptor(i)}.result(${result});\n`; + } } + code += onResult(result); + return code; } - code += onResult(result); - return code; - }), + ), onDone: onDone && - (() => { - let code = ""; - for (let i = 0; i < opts.interceptors.length; i++) { - const interceptor = opts.interceptors[i]; - if (interceptor.done) { - code += `${this.getInterceptor(i)}.done();\n`; + /** @type {OnDoneCallback} */ + ( + () => { + let code = ""; + for (let i = 0; i < opts.interceptors.length; i++) { + const interceptor = opts.interceptors[i]; + if (interceptor.done) { + code += `${this.getInterceptor(i)}.done();\n`; + } } + code += onDone(); + return code; } - code += onDone(); - return code; - }) + ) }) ); return code; @@ -263,7 +296,7 @@ class HookCodeFactory { /** * @param {number} tapIndex index of the tap to call - * @param {ContentOptions} options content generation options + * @param {CallTapOptions} options content generation options * @returns {string} generated code that invokes the tap */ callTap(tapIndex, { onError, onResult, onDone, rethrowIfPossible }) { @@ -283,9 +316,9 @@ class HookCodeFactory { } } code += `var _fn${tapIndex} = ${this.getTapFn(tapIndex)};\n`; - const tap = /** @type {FullTap & { context?: boolean }} */ ( - opts.taps[tapIndex] - ); + const tap = + /** @type {FullTap & { context?: boolean }} */ + (opts.taps[tapIndex]); switch (tap.type) { case "sync": if (!rethrowIfPossible) { @@ -304,7 +337,7 @@ class HookCodeFactory { if (!rethrowIfPossible) { code += "} catch(_err) {\n"; code += `_hasError${tapIndex} = true;\n`; - code += /** @type {OnErrorCallback} */ (onError)("_err"); + code += onError("_err"); code += "}\n"; code += `if(!_hasError${tapIndex}) {\n`; } @@ -324,7 +357,7 @@ class HookCodeFactory { ? `(function(_err${tapIndex}, _result${tapIndex}) {\n` : `(function(_err${tapIndex}) {\n`; cbCode += `if(_err${tapIndex}) {\n`; - cbCode += /** @type {OnErrorCallback} */ (onError)(`_err${tapIndex}`); + cbCode += onError(`_err${tapIndex}`); cbCode += "} else {\n"; if (onResult) { cbCode += onResult(`_result${tapIndex}`); @@ -357,7 +390,7 @@ class HookCodeFactory { } code += `}), function(_err${tapIndex}) {\n`; code += `if(_hasResult${tapIndex}) throw _err${tapIndex};\n`; - code += /** @type {OnErrorCallback} */ (onError)( + code += onError( `!_err${tapIndex} ? new Error('Tap function (tapPromise) rejects "' + _err${tapIndex} + '" value') : _err${tapIndex}` ); code += "});\n"; @@ -367,7 +400,7 @@ class HookCodeFactory { } /** - * @param {TapsSeriesOptions} options series-call options + * @param {CallTapsOptions} options series-call options * @returns {string} generated code calling all taps in series */ callTapsSeries({ @@ -380,7 +413,7 @@ class HookCodeFactory { }) { const { taps } = /** @type {CompileOptions} */ (this.options); const tapsLength = taps.length; - if (tapsLength === 0) return /** @type {OnDoneCallback} */ (onDone)(); + if (tapsLength === 0) return onDone(); // Inlined findIndex to avoid the callback allocation. let firstAsync = -1; for (let i = 0; i < tapsLength; i++) { @@ -391,9 +424,13 @@ class HookCodeFactory { } const somethingReturns = resultReturns || doneReturns; // doneBreak doesn't depend on the loop variable - hoist to allocate once. + /** + * @param {boolean} skipDone true when need to skip done, otherwise false + * @returns {string} code + */ const doneBreak = (skipDone) => { if (skipDone) return ""; - return /** @type {OnDoneCallback} */ (onDone)(); + return onDone(); }; let code = ""; let current = onDone; @@ -405,38 +442,32 @@ class HookCodeFactory { if (unroll) { unrollCounter = 0; code += `function _next${i}() {\n`; - code += /** @type {OnDoneCallback} */ (current)(); + code += current(); code += "}\n"; current = () => `${somethingReturns ? "return " : ""}_next${i}();\n`; } - const done = /** @type {OnDoneCallback} */ (current); + const done = current; const content = this.callTap(i, { - onError: (error) => - /** @type {NonNullable} */ (onError)( - i, - error, - done, - doneBreak - ), + onError: (error) => onError(i, error, done, doneBreak), onResult: onResult && ((result) => onResult(i, result, done, doneBreak)), - onDone: !onResult && done, + onDone: !onResult ? done : undefined, rethrowIfPossible: rethrowIfPossible && (firstAsync < 0 || i < firstAsync) }); current = () => content; } - code += /** @type {OnDoneCallback} */ (current)(); + code += current(); return code; } /** - * @param {TapsSeriesOptions} options looping-call options + * @param {CallTapsOptions} options looping-call options * @returns {string} generated code that calls taps in a loop */ callTapsLooping({ onError, onDone, rethrowIfPossible }) { const opts = /** @type {CompileOptions} */ (this.options); - if (opts.taps.length === 0) return /** @type {OnDoneCallback} */ (onDone)(); + if (opts.taps.length === 0) return onDone(); const syncOnly = opts.taps.every((t) => t.type === "sync"); let code = ""; if (!syncOnly) { @@ -488,7 +519,7 @@ class HookCodeFactory { } /** - * @param {TapsSeriesOptions & { onTap?: (tapIndex: number, run: () => string, done: () => string, doneBreak: (skipDone: boolean) => string) => string }} options parallel-call options + * @param {CallTapsParallelOptions} options parallel-call options * @returns {string} generated code that calls all taps in parallel */ callTapsParallel({ @@ -504,6 +535,7 @@ class HookCodeFactory { return this.callTapsSeries({ onError, onResult, + // @ts-expect-error is it a bug? onDone, rethrowIfPossible }); @@ -514,6 +546,10 @@ class HookCodeFactory { if (onDone) return "if(--_counter === 0) _done();\n"; return "--_counter;"; }; + /** + * @param {boolean} skipDone true when need to skip done, otherwise false + * @returns {string} code + */ const doneBreak = (skipDone) => { if (skipDone || !onDone) return "_counter = 0;\n"; return "_counter = 0;\n_done();\n"; @@ -535,9 +571,7 @@ class HookCodeFactory { onError: (error) => { let code = ""; code += "if(_counter > 0) {\n"; - code += /** @type {NonNullable} */ ( - onError - )(i, error, done, doneBreak); + code += onError(i, error, done, doneBreak); code += "}\n"; return code; }, @@ -550,7 +584,7 @@ class HookCodeFactory { code += "}\n"; return code; }), - onDone: !onResult && (() => done()), + onDone: !onResult ? () => done() : undefined, rethrowIfPossible }), done, diff --git a/lib/HookMap.js b/lib/HookMap.js index 664ede8..a083584 100644 --- a/lib/HookMap.js +++ b/lib/HookMap.js @@ -6,16 +6,17 @@ const util = require("util"); -// eslint-disable-next-line jsdoc/reject-any-type -/** @typedef {any} EXPECTED_ANY */ +/** @typedef {import("./Hook").EXPECTED_ANY} EXPECTED_ANY */ /** - * @template H, K + * @template H + * @template [K=EXPECTED_ANY] * @typedef {(key: K) => H} HookFactory */ /** - * @template H, K + * @template H + * @template [K=EXPECTED_ANY] * @typedef {object} HookMapInterceptor * @property {((key: K, hook: H) => H)=} factory called when a hook is created for a new key */ @@ -33,7 +34,7 @@ const defaultFactory = (key, hook) => hook; */ class HookMap { /** - * @param {HookFactory} factory factory creating new hooks for unknown keys + * @param {HookFactory} factory factory creating new hooks for unknown keys * @param {string=} name name of the hook map */ constructor(factory, name = undefined) { @@ -41,9 +42,9 @@ class HookMap { this._map = new Map(); /** @type {string | undefined} */ this.name = name; - /** @type {HookFactory} */ + /** @type {HookFactory} */ this._factory = factory; - /** @type {HookMapInterceptor[]} */ + /** @type {HookMapInterceptor[]} */ this._interceptors = []; } @@ -72,16 +73,15 @@ class HookMap { const interceptors = this._interceptors; for (let i = 0; i < interceptors.length; i++) { newHook = - /** @type {NonNullable["factory"]>} */ ( - interceptors[i].factory - )(key, newHook); + /** @type {NonNullable["factory"]>} */ + (interceptors[i].factory)(key, newHook); } map.set(key, newHook); return newHook; } /** - * @param {HookMapInterceptor} interceptor the interceptor to register + * @param {HookMapInterceptor} interceptor the interceptor to register * @returns {void} */ intercept(interceptor) { @@ -96,46 +96,25 @@ class HookMap { } } -HookMap.prototype.tap = util.deprecate( - /** - * @this {HookMap} - * @param {EXPECTED_ANY} key key for the hook to tap - * @param {EXPECTED_ANY} options tap options or name - * @param {EXPECTED_ANY} fn the function to register - * @returns {EXPECTED_ANY} result of the underlying tap - */ - function tap(key, options, fn) { +HookMap.prototype.tap = + // @ts-expect-error deprecated + util.deprecate(function tap(key, options, fn) { + // @ts-expect-error deprecated return this.for(key).tap(options, fn); - }, - "HookMap#tap(key,…) is deprecated. Use HookMap#for(key).tap(…) instead." -); + }, "HookMap#tap(key,…) is deprecated. Use HookMap#for(key).tap(…) instead."); -HookMap.prototype.tapAsync = util.deprecate( - /** - * @this {HookMap} - * @param {EXPECTED_ANY} key key for the hook to tap - * @param {EXPECTED_ANY} options tap options or name - * @param {EXPECTED_ANY} fn the function to register - * @returns {EXPECTED_ANY} result of the underlying tapAsync - */ - function tapAsync(key, options, fn) { +HookMap.prototype.tapAsync = + // @ts-expect-error deprecated + util.deprecate(function tapAsync(key, options, fn) { + // @ts-expect-error deprecated return this.for(key).tapAsync(options, fn); - }, - "HookMap#tapAsync(key,…) is deprecated. Use HookMap#for(key).tapAsync(…) instead." -); + }, "HookMap#tapAsync(key,…) is deprecated. Use HookMap#for(key).tapAsync(…) instead."); -HookMap.prototype.tapPromise = util.deprecate( - /** - * @this {HookMap} - * @param {EXPECTED_ANY} key key for the hook to tap - * @param {EXPECTED_ANY} options tap options or name - * @param {EXPECTED_ANY} fn the function to register - * @returns {EXPECTED_ANY} result of the underlying tapPromise - */ - function tapPromise(key, options, fn) { +HookMap.prototype.tapPromise = + // @ts-expect-error deprecated + util.deprecate(function tapPromise(key, options, fn) { + // @ts-expect-error deprecated return this.for(key).tapPromise(options, fn); - }, - "HookMap#tapPromise(key,…) is deprecated. Use HookMap#for(key).tapPromise(…) instead." -); + }, "HookMap#tapPromise(key,…) is deprecated. Use HookMap#for(key).tapPromise(…) instead."); module.exports = HookMap; diff --git a/lib/MultiHook.js b/lib/MultiHook.js index 78ed418..78cdd74 100644 --- a/lib/MultiHook.js +++ b/lib/MultiHook.js @@ -4,21 +4,41 @@ */ "use strict"; -// eslint-disable-next-line jsdoc/reject-function-type -/** @typedef {Function} EXPECTED_FUNCTION */ -// eslint-disable-next-line jsdoc/reject-any-type -/** @typedef {any} EXPECTED_ANY */ - +/** @typedef {import("./Hook").EXPECTED_ANY} EXPECTED_ANY */ +/** @typedef {import("./Hook").EXPECTED_FUNCTION} EXPECTED_FUNCTION */ /** @typedef {import("./Hook").Tap} Tap */ /** @typedef {import("./Hook").TapOptions} TapOptions */ +/** + * @template T + * @typedef {import("./Hook").AsArray} AsArray + */ + +/** + * @template {EXPECTED_ANY[]} T + * @template U + * @typedef {import("./Hook").Append} Append + */ + +/** + * @template E, T + * @typedef {import("./Hook").InnerCallback} InnerCallback + */ + +/** + * @template T + * @template [R=void] + * @template [AdditionalOptions=object] + * @typedef {import("./Hook")} Hook + */ + /** * @template T, R, AdditionalOptions * @typedef {import("./Hook").HookInterceptor} HookInterceptor */ /** - * @template H + * @template {Hook} H */ class MultiHook { /** @@ -34,43 +54,37 @@ class MultiHook { /** * @param {string | Tap} options tap name or full tap options - * @param {EXPECTED_FUNCTION=} fn the function to register + * @param {(...args: AsArray) => R} fn the function to register * @returns {void} */ tap(options, fn) { const { hooks } = this; for (let i = 0; i < hooks.length; i++) { - /** @type {{ tap: (o: EXPECTED_ANY, fn?: EXPECTED_FUNCTION) => void }} */ ( - hooks[i] - ).tap(options, fn); + hooks[i].tap(options, fn); } } /** * @param {string | Tap} options tap name or full tap options - * @param {EXPECTED_FUNCTION=} fn the function to register + * @param {(...args: Append, InnerCallback>) => void} fn the function to register * @returns {void} */ tapAsync(options, fn) { const { hooks } = this; for (let i = 0; i < hooks.length; i++) { - /** @type {{ tapAsync: (o: EXPECTED_ANY, fn?: EXPECTED_FUNCTION) => void }} */ ( - hooks[i] - ).tapAsync(options, fn); + hooks[i].tapAsync(options, fn); } } /** * @param {string | Tap} options tap name or full tap options - * @param {EXPECTED_FUNCTION=} fn the function to register + * @param {(...args: AsArray) => Promise} fn the function to register * @returns {void} */ tapPromise(options, fn) { const { hooks } = this; for (let i = 0; i < hooks.length; i++) { - /** @type {{ tapPromise: (o: EXPECTED_ANY, fn?: EXPECTED_FUNCTION) => void }} */ ( - hooks[i] - ).tapPromise(options, fn); + hooks[i].tapPromise(options, fn); } } @@ -80,7 +94,7 @@ class MultiHook { isUsed() { const { hooks } = this; for (let i = 0; i < hooks.length; i++) { - if (/** @type {{ isUsed: () => boolean }} */ (hooks[i]).isUsed()) { + if (hooks[i].isUsed()) { return true; } } @@ -94,9 +108,7 @@ class MultiHook { intercept(interceptor) { const { hooks } = this; for (let i = 0; i < hooks.length; i++) { - /** @type {{ intercept: (i: HookInterceptor) => void }} */ ( - hooks[i] - ).intercept(interceptor); + hooks[i].intercept(interceptor); } } @@ -106,14 +118,7 @@ class MultiHook { */ withOptions(options) { return new MultiHook( - this.hooks.map( - (hook) => - /** @type {H} */ ( - /** @type {{ withOptions: (o: TapOptions) => H }} */ ( - hook - ).withOptions(options) - ) - ), + this.hooks.map((hook) => hook.withOptions(options)), this.name ); } diff --git a/lib/SyncBailHook.js b/lib/SyncBailHook.js index 12e376a..efdc0fb 100644 --- a/lib/SyncBailHook.js +++ b/lib/SyncBailHook.js @@ -7,14 +7,21 @@ const Hook = require("./Hook"); const HookCodeFactory = require("./HookCodeFactory"); -// eslint-disable-next-line jsdoc/reject-function-type -/** @typedef {Function} EXPECTED_FUNCTION */ -// eslint-disable-next-line jsdoc/reject-any-type -/** @typedef {any} EXPECTED_ANY */ - +/** @typedef {import("./Hook").EXPECTED_ANY} EXPECTED_ANY */ +/** @typedef {import("./Hook").EXPECTED_FUNCTION} EXPECTED_FUNCTION */ +/** @typedef {import("./Hook").UnsetAdditionalOptions} UnsetAdditionalOptions */ /** @typedef {import("./Hook").CompileOptions} CompileOptions */ /** @typedef {import("./HookCodeFactory").ContentOptions} ContentOptions */ +/** + * @template T + * @typedef {import("./Hook").AsArray} AsArray + */ +/** + * @template {EXPECTED_ANY[]} T + * @typedef {import("./Hook").ArgumentNames} ArgumentNames + */ + class SyncBailHookCodeFactory extends HookCodeFactory { /** * @param {ContentOptions} options content generation options @@ -22,12 +29,11 @@ class SyncBailHookCodeFactory extends HookCodeFactory { */ content({ onError, onResult, resultReturns, onDone, rethrowIfPossible }) { return this.callTapsSeries({ - onError: (i, err) => - /** @type {(err: string) => string} */ (onError)(err), + onError: (i, err) => onError(err), onResult: (i, result, next) => - `if(${result} !== undefined) {\n${ - /** @type {(result: string) => string} */ (onResult)(result) - };\n} else {\n${next()}}\n`, + `if(${result} !== undefined) {\n${onResult( + result + )};\n} else {\n${next()}}\n`, resultReturns, onDone, rethrowIfPossible @@ -56,9 +62,13 @@ function COMPILE(options) { } /** - * @param {string[]=} args argument names of the hook + * @constructor + * @template T + * @template R + * @template [AdditionalOptions=UnsetAdditionalOptions] + * @param {ArgumentNames>=} args argument names of the hook * @param {string=} name name of the hook - * @returns {Hook} a new SyncBailHook instance + * @returns {Hook} a new AsyncParallelBailHook instance */ function SyncBailHook(args = [], name = undefined) { const hook = new Hook(args, name); @@ -69,6 +79,7 @@ function SyncBailHook(args = [], name = undefined) { return hook; } +/** @type {EXPECTED_ANY} */ SyncBailHook.prototype = null; module.exports = SyncBailHook; diff --git a/lib/SyncHook.js b/lib/SyncHook.js index 48765db..0a9485a 100644 --- a/lib/SyncHook.js +++ b/lib/SyncHook.js @@ -7,14 +7,21 @@ const Hook = require("./Hook"); const HookCodeFactory = require("./HookCodeFactory"); -// eslint-disable-next-line jsdoc/reject-function-type -/** @typedef {Function} EXPECTED_FUNCTION */ -// eslint-disable-next-line jsdoc/reject-any-type -/** @typedef {any} EXPECTED_ANY */ - +/** @typedef {import("./Hook").EXPECTED_ANY} EXPECTED_ANY */ +/** @typedef {import("./Hook").EXPECTED_FUNCTION} EXPECTED_FUNCTION */ +/** @typedef {import("./Hook").UnsetAdditionalOptions} UnsetAdditionalOptions */ /** @typedef {import("./Hook").CompileOptions} CompileOptions */ /** @typedef {import("./HookCodeFactory").ContentOptions} ContentOptions */ +/** + * @template T + * @typedef {import("./Hook").AsArray} AsArray + */ +/** + * @template {EXPECTED_ANY[]} T + * @typedef {import("./Hook").ArgumentNames} ArgumentNames + */ + class SyncHookCodeFactory extends HookCodeFactory { /** * @param {ContentOptions} options content generation options @@ -22,8 +29,7 @@ class SyncHookCodeFactory extends HookCodeFactory { */ content({ onError, onDone, rethrowIfPossible }) { return this.callTapsSeries({ - onError: (i, err) => - /** @type {(err: string) => string} */ (onError)(err), + onError: (i, err) => onError(err), onDone, rethrowIfPossible }); @@ -51,9 +57,13 @@ function COMPILE(options) { } /** - * @param {string[]=} args argument names of the hook + * @constructor + * @template T + * @template [R=void] + * @template [AdditionalOptions=UnsetAdditionalOptions] + * @param {ArgumentNames>=} args argument names of the hook * @param {string=} name name of the hook - * @returns {Hook} a new SyncHook instance + * @returns {Hook} a new AsyncParallelBailHook instance */ function SyncHook(args = [], name = undefined) { const hook = new Hook(args, name); @@ -64,6 +74,7 @@ function SyncHook(args = [], name = undefined) { return hook; } +/** @type {EXPECTED_ANY} */ SyncHook.prototype = null; module.exports = SyncHook; diff --git a/lib/SyncLoopHook.js b/lib/SyncLoopHook.js index b7022c7..245136d 100644 --- a/lib/SyncLoopHook.js +++ b/lib/SyncLoopHook.js @@ -7,13 +7,19 @@ const Hook = require("./Hook"); const HookCodeFactory = require("./HookCodeFactory"); -// eslint-disable-next-line jsdoc/reject-function-type -/** @typedef {Function} EXPECTED_FUNCTION */ -// eslint-disable-next-line jsdoc/reject-any-type -/** @typedef {any} EXPECTED_ANY */ - +/** @typedef {import("./Hook").EXPECTED_ANY} EXPECTED_ANY */ +/** @typedef {import("./Hook").EXPECTED_FUNCTION} EXPECTED_FUNCTION */ /** @typedef {import("./Hook").CompileOptions} CompileOptions */ +/** @typedef {import("./Hook").UnsetAdditionalOptions} UnsetAdditionalOptions */ /** @typedef {import("./HookCodeFactory").ContentOptions} ContentOptions */ +/** + * @template T + * @typedef {import("./Hook").AsArray} AsArray + */ +/** + * @template {EXPECTED_ANY[]} T + * @typedef {import("./Hook").ArgumentNames} ArgumentNames + */ class SyncLoopHookCodeFactory extends HookCodeFactory { /** @@ -22,8 +28,7 @@ class SyncLoopHookCodeFactory extends HookCodeFactory { */ content({ onError, onDone, rethrowIfPossible }) { return this.callTapsLooping({ - onError: (i, err) => - /** @type {(err: string) => string} */ (onError)(err), + onError: (i, err) => onError(err), onDone, rethrowIfPossible }); @@ -51,9 +56,12 @@ function COMPILE(options) { } /** - * @param {string[]=} args argument names of the hook + * @constructor + * @template T + * @template [AdditionalOptions=UnsetAdditionalOptions] + * @param {ArgumentNames>=} args argument names of the hook * @param {string=} name name of the hook - * @returns {Hook} a new SyncLoopHook instance + * @returns {Hook} a new AsyncParallelBailHook instance */ function SyncLoopHook(args = [], name = undefined) { const hook = new Hook(args, name); @@ -64,6 +72,7 @@ function SyncLoopHook(args = [], name = undefined) { return hook; } +/** @type {EXPECTED_ANY} */ SyncLoopHook.prototype = null; module.exports = SyncLoopHook; diff --git a/lib/SyncWaterfallHook.js b/lib/SyncWaterfallHook.js index 88edc58..556eef8 100644 --- a/lib/SyncWaterfallHook.js +++ b/lib/SyncWaterfallHook.js @@ -7,13 +7,19 @@ const Hook = require("./Hook"); const HookCodeFactory = require("./HookCodeFactory"); -// eslint-disable-next-line jsdoc/reject-function-type -/** @typedef {Function} EXPECTED_FUNCTION */ -// eslint-disable-next-line jsdoc/reject-any-type -/** @typedef {any} EXPECTED_ANY */ - +/** @typedef {import("./Hook").EXPECTED_ANY} EXPECTED_ANY */ +/** @typedef {import("./Hook").EXPECTED_FUNCTION} EXPECTED_FUNCTION */ /** @typedef {import("./Hook").CompileOptions} CompileOptions */ +/** @typedef {import("./Hook").UnsetAdditionalOptions} UnsetAdditionalOptions */ /** @typedef {import("./HookCodeFactory").ContentOptions} ContentOptions */ +/** + * @template T + * @typedef {import("./Hook").AsArray} AsArray + */ +/** + * @template {EXPECTED_ANY[]} T + * @typedef {import("./Hook").ArgumentNames} ArgumentNames + */ class SyncWaterfallHookCodeFactory extends HookCodeFactory { /** @@ -22,8 +28,7 @@ class SyncWaterfallHookCodeFactory extends HookCodeFactory { */ content({ onError, onResult, resultReturns, rethrowIfPossible }) { return this.callTapsSeries({ - onError: (i, err) => - /** @type {(err: string) => string} */ (onError)(err), + onError: (i, err) => onError(err), onResult: (i, result, next) => { let code = ""; code += `if(${result} !== undefined) {\n`; @@ -32,10 +37,7 @@ class SyncWaterfallHookCodeFactory extends HookCodeFactory { code += next(); return code; }, - onDone: () => - /** @type {(result: string) => string} */ (onResult)( - /** @type {string[]} */ (this._args)[0] - ), + onDone: () => onResult(/** @type {string[]} */ (this._args)[0]), doneReturns: resultReturns, rethrowIfPossible }); @@ -63,9 +65,13 @@ function COMPILE(options) { } /** - * @param {string[]=} args argument names of the hook (must contain at least one) + * @constructor + * @template T + * @template [R=AsArray[0]] + * @template [AdditionalOptions=UnsetAdditionalOptions] + * @param {ArgumentNames>=} args argument names of the hook * @param {string=} name name of the hook - * @returns {Hook} a new SyncWaterfallHook instance + * @returns {Hook} a new AsyncParallelBailHook instance */ function SyncWaterfallHook(args = [], name = undefined) { if (args.length < 1) { @@ -79,6 +85,7 @@ function SyncWaterfallHook(args = [], name = undefined) { return hook; } +/** @type {EXPECTED_ANY} */ SyncWaterfallHook.prototype = null; module.exports = SyncWaterfallHook; diff --git a/lib/util-browser.js b/lib/util-browser.js index 9fc2f65..9cfb733 100644 --- a/lib/util-browser.js +++ b/lib/util-browser.js @@ -4,10 +4,7 @@ */ "use strict"; -// eslint-disable-next-line jsdoc/reject-function-type -/** @typedef {Function} EXPECTED_FUNCTION */ -// eslint-disable-next-line jsdoc/reject-any-type -/** @typedef {any} EXPECTED_ANY */ +/** @typedef {import("./Hook").EXPECTED_FUNCTION} EXPECTED_FUNCTION */ /** * Browser shim for `util.deprecate`. Logs the deprecation message once on the @@ -24,6 +21,7 @@ module.exports.deprecate = (fn, msg) => { console.warn(`DeprecationWarning: ${msg}`); once = false; } + // @ts-expect-error expected // eslint-disable-next-line prefer-rest-params return fn.apply(this, arguments); }; diff --git a/package-lock.json b/package-lock.json index 2020e47..3d45f75 100644 --- a/package-lock.json +++ b/package-lock.json @@ -22,7 +22,7 @@ "prettier": "^3.8.3", "prettier-1": "npm:prettier@^1", "tinybench": "^6.0.0", - "typescript": "^5.9.3" + "typescript": "^6.0.3" }, "engines": { "node": ">=6" @@ -2956,9 +2956,9 @@ } }, "node_modules/@jest/reporters/node_modules/brace-expansion": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", - "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.0.tgz", + "integrity": "sha512-TN1kCZAgdgweJhWWpgKYrQaMNHcDULHkWwQIspdtjV4Y5aurRdZpjAqn6yX3FPqTA9ngHCc4hJxMAMgGfve85w==", "dev": true, "license": "MIT", "dependencies": { @@ -4256,9 +4256,9 @@ } }, "node_modules/anymatch/node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", "dev": true, "license": "MIT", "engines": { @@ -4678,9 +4678,9 @@ } }, "node_modules/brace-expansion": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", - "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.14.tgz", + "integrity": "sha512-MWPGfDxnyzKU7rNOW9SP/c50vi3xrmrua/+6hfPbCS2ABNWfx24vPidzvC7krjU/RTo235sV776ymlsMtGKj8g==", "dev": true, "license": "MIT", "dependencies": { @@ -8169,9 +8169,9 @@ } }, "node_modules/jest-config/node_modules/brace-expansion": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", - "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.0.tgz", + "integrity": "sha512-TN1kCZAgdgweJhWWpgKYrQaMNHcDULHkWwQIspdtjV4Y5aurRdZpjAqn6yX3FPqTA9ngHCc4hJxMAMgGfve85w==", "dev": true, "license": "MIT", "dependencies": { @@ -8519,9 +8519,9 @@ } }, "node_modules/jest-runtime/node_modules/brace-expansion": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", - "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.0.tgz", + "integrity": "sha512-TN1kCZAgdgweJhWWpgKYrQaMNHcDULHkWwQIspdtjV4Y5aurRdZpjAqn6yX3FPqTA9ngHCc4hJxMAMgGfve85w==", "dev": true, "license": "MIT", "dependencies": { @@ -10603,9 +10603,9 @@ "license": "ISC" }, "node_modules/picomatch": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", - "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", "dev": true, "license": "MIT", "engines": { @@ -12052,9 +12052,9 @@ } }, "node_modules/typescript": { - "version": "5.9.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", - "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-6.0.3.tgz", + "integrity": "sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==", "dev": true, "license": "Apache-2.0", "bin": { diff --git a/package.json b/package.json index d7ca17f..47c9096 100644 --- a/package.json +++ b/package.json @@ -23,7 +23,8 @@ "tapable.d.ts" ], "scripts": { - "lint": "npm run lint:code && npm run fmt:check", + "lint": "npm run lint:code && npm run lint:types && npm run fmt:check", + "lint:types": "tsc --pretty --noEmit", "lint:code": "eslint --cache .", "fmt": "npm run fmt:base -- --log-level warn --write", "fmt:check": "npm run fmt:base -- --check", @@ -59,7 +60,7 @@ "prettier": "^3.8.3", "prettier-1": "npm:prettier@^1", "tinybench": "^6.0.0", - "typescript": "^5.9.3" + "typescript": "^6.0.3" }, "engines": { "node": ">=6" diff --git a/test/AsyncParallelBailHook.test.js b/test/AsyncParallelBailHook.test.js new file mode 100644 index 0000000..3613be0 --- /dev/null +++ b/test/AsyncParallelBailHook.test.js @@ -0,0 +1,18 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +const AsyncParallelBailHook = require("../lib/AsyncParallelBailHook"); +const HookTester = require("./HookTester.test"); + +describe("AsyncParallelBailHook", () => { + it("should have to correct behavior", async () => { + const tester = new HookTester((args) => new AsyncParallelBailHook(args)); + + const result = await tester.run(); + + expect(result).toMatchSnapshot(); + }, 15000); +}); diff --git a/test/AsyncParallelHooks.test.js b/test/AsyncParallelHooks.test.js index b730cd2..3925af3 100644 --- a/test/AsyncParallelHooks.test.js +++ b/test/AsyncParallelHooks.test.js @@ -4,7 +4,6 @@ */ "use strict"; -const AsyncParallelBailHook = require("../lib/AsyncParallelBailHook"); const AsyncParallelHook = require("../lib/AsyncParallelHook"); const HookTester = require("./HookTester.test"); @@ -17,13 +16,3 @@ describe("AsyncParallelHook", () => { expect(result).toMatchSnapshot(); }, 15000); }); - -describe("AsyncParallelBailHook", () => { - it("should have to correct behavior", async () => { - const tester = new HookTester((args) => new AsyncParallelBailHook(args)); - - const result = await tester.run(); - - expect(result).toMatchSnapshot(); - }, 15000); -}); diff --git a/test/AsyncSeriesBailHook.test.js b/test/AsyncSeriesBailHook.test.js new file mode 100644 index 0000000..cbe45f2 --- /dev/null +++ b/test/AsyncSeriesBailHook.test.js @@ -0,0 +1,28 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +const AsyncSeriesBailHook = require("../lib/AsyncSeriesBailHook"); +const HookTester = require("./HookTester.test"); + +describe("AsyncSeriesBailHook", () => { + it("should have to correct behavior", async () => { + const tester = new HookTester((args) => new AsyncSeriesBailHook(args)); + + const result = await tester.run(); + + expect(result).toMatchSnapshot(); + }); + + it("should not crash with many plugins", () => { + const hook = new AsyncSeriesBailHook(["x"]); + for (let i = 0; i < 1000; i++) { + hook.tap("Test", () => 42); + } + hook.tapAsync("Test", (x, callback) => callback(null, 42)); + hook.tapPromise("Test", (_x) => Promise.resolve(42)); + return expect(hook.promise()).resolves.toBe(42); + }); +}); diff --git a/test/AsyncSeriesHooks.test.js b/test/AsyncSeriesHooks.test.js index 8aaf12f..7ec9cd2 100644 --- a/test/AsyncSeriesHooks.test.js +++ b/test/AsyncSeriesHooks.test.js @@ -4,10 +4,7 @@ */ "use strict"; -const AsyncSeriesBailHook = require("../lib/AsyncSeriesBailHook"); const AsyncSeriesHook = require("../lib/AsyncSeriesHook"); -const AsyncSeriesLoopHook = require("../lib/AsyncSeriesLoopHook"); -const AsyncSeriesWaterfallHook = require("../lib/AsyncSeriesWaterfallHook"); const HookTester = require("./HookTester.test"); describe("AsyncSeriesHook", () => { @@ -42,79 +39,3 @@ describe("AsyncSeriesHook", () => { expect(result).toMatchSnapshot(); }); }); - -describe("AsyncSeriesBailHook", () => { - it("should have to correct behavior", async () => { - const tester = new HookTester((args) => new AsyncSeriesBailHook(args)); - - const result = await tester.run(); - - expect(result).toMatchSnapshot(); - }); - - it("should not crash with many plugins", () => { - const hook = new AsyncSeriesBailHook(["x"]); - for (let i = 0; i < 1000; i++) { - hook.tap("Test", () => 42); - } - hook.tapAsync("Test", (x, callback) => callback(null, 42)); - hook.tapPromise("Test", (_x) => Promise.resolve(42)); - return expect(hook.promise()).resolves.toBe(42); - }); -}); - -describe("AsyncSeriesWaterfallHook", () => { - it("should have to correct behavior", async () => { - const tester = new HookTester((args) => new AsyncSeriesWaterfallHook(args)); - - const result = await tester.run(); - - expect(result).toMatchSnapshot(); - }); - - it("should work with undefined", async () => { - const hook = new AsyncSeriesWaterfallHook(["x"]); - hook.tap("number", () => 42); - hook.tap("undefined", () => undefined); - return expect(hook.promise()).resolves.toBe(42); - }); - - it("should work with void", async () => { - const hook = new AsyncSeriesWaterfallHook(["x"]); - hook.tap("number", () => 42); - hook.tap("undefined", () => {}); - return expect(hook.promise()).resolves.toBe(42); - }); - - it("should work with undefined and number again", async () => { - const hook = new AsyncSeriesWaterfallHook(["x"]); - hook.tap("number", () => 42); - hook.tap("undefined", () => {}); - hook.tap("number-again", () => 43); - return expect(hook.promise()).resolves.toBe(43); - }); - - it("should work with null", async () => { - const hook = new AsyncSeriesWaterfallHook(["x"]); - hook.tap("number", () => 42); - hook.tap("undefined", () => null); - return expect(hook.promise()).resolves.toBeNull(); - }); - - it("should work with different types", async () => { - const hook = new AsyncSeriesWaterfallHook(["x"]); - hook.tap("number", () => 42); - hook.tap("string", () => "string"); - return expect(hook.promise()).resolves.toBe("string"); - }); -}); - -describe("AsyncSeriesLoopHook", () => { - it("should have to correct behavior", async () => { - const tester = new HookTester((args) => new AsyncSeriesLoopHook(args)); - - const result = await tester.runForLoop(); - - expect(result).toMatchSnapshot(); - }); -}); diff --git a/test/AsyncSeriesLoopHook.test.js b/test/AsyncSeriesLoopHook.test.js new file mode 100644 index 0000000..e963f5f --- /dev/null +++ b/test/AsyncSeriesLoopHook.test.js @@ -0,0 +1,18 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +const AsyncSeriesLoopHook = require("../lib/AsyncSeriesLoopHook"); +const HookTester = require("./HookTester.test"); + +describe("AsyncSeriesLoopHook", () => { + it("should have to correct behavior", async () => { + const tester = new HookTester((args) => new AsyncSeriesLoopHook(args)); + + const result = await tester.runForLoop(); + + expect(result).toMatchSnapshot(); + }); +}); diff --git a/test/AsyncSeriesWaterfallHook.test.js b/test/AsyncSeriesWaterfallHook.test.js new file mode 100644 index 0000000..4687f55 --- /dev/null +++ b/test/AsyncSeriesWaterfallHook.test.js @@ -0,0 +1,54 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +const AsyncSeriesWaterfallHook = require("../lib/AsyncSeriesWaterfallHook"); +const HookTester = require("./HookTester.test"); + +describe("AsyncSeriesWaterfallHook", () => { + it("should have to correct behavior", async () => { + const tester = new HookTester((args) => new AsyncSeriesWaterfallHook(args)); + + const result = await tester.run(); + + expect(result).toMatchSnapshot(); + }); + + it("should work with undefined", async () => { + const hook = new AsyncSeriesWaterfallHook(["x"]); + hook.tap("number", () => 42); + hook.tap("undefined", () => undefined); + return expect(hook.promise()).resolves.toBe(42); + }); + + it("should work with void", async () => { + const hook = new AsyncSeriesWaterfallHook(["x"]); + hook.tap("number", () => 42); + hook.tap("undefined", () => {}); + return expect(hook.promise()).resolves.toBe(42); + }); + + it("should work with undefined and number again", async () => { + const hook = new AsyncSeriesWaterfallHook(["x"]); + hook.tap("number", () => 42); + hook.tap("undefined", () => {}); + hook.tap("number-again", () => 43); + return expect(hook.promise()).resolves.toBe(43); + }); + + it("should work with null", async () => { + const hook = new AsyncSeriesWaterfallHook(["x"]); + hook.tap("number", () => 42); + hook.tap("undefined", () => null); + return expect(hook.promise()).resolves.toBeNull(); + }); + + it("should work with different types", async () => { + const hook = new AsyncSeriesWaterfallHook(["x"]); + hook.tap("number", () => 42); + hook.tap("string", () => "string"); + return expect(hook.promise()).resolves.toBe("string"); + }); +}); diff --git a/test/SyncBailHook.test.js b/test/SyncBailHook.test.js index a6d93c3..b47840f 100644 --- a/test/SyncBailHook.test.js +++ b/test/SyncBailHook.test.js @@ -4,7 +4,8 @@ */ "use strict"; -const SyncBailHookTest = require("../lib/SyncBailHook"); +const SyncBailHook = require("../lib/SyncBailHook"); +const HookTester = require("./HookTester.test"); function pify(fn) { return new Promise((resolve, reject) => { @@ -16,9 +17,17 @@ function pify(fn) { } describe("SyncBailHook", () => { + it("should have to correct behavior", async () => { + const tester = new HookTester((args) => new SyncBailHook(args)); + + const result = await tester.run(true); + + expect(result).toMatchSnapshot(); + }, 15000); + it("should allow to create sync bail hooks", async () => { - const h1 = new SyncBailHookTest(["a"]); - const h2 = new SyncBailHookTest(["a", "b"]); + const h1 = new SyncBailHook(["a"]); + const h2 = new SyncBailHook(["a", "b"]); const r = h1.call(1); expect(r).toBeUndefined(); @@ -45,7 +54,7 @@ describe("SyncBailHook", () => { }); it("should bail on non-null return", async () => { - const h1 = new SyncBailHookTest(["a"]); + const h1 = new SyncBailHook(["a"]); const mockCall1 = jest.fn(); const mockCall2 = jest.fn(() => "B"); const mockCall3 = jest.fn(() => "C"); @@ -59,7 +68,7 @@ describe("SyncBailHook", () => { }); it("should allow to intercept calls", () => { - const hook = new SyncBailHookTest(["x"]); + const hook = new SyncBailHook(["x"]); const mockCall = jest.fn(); const mockTap = jest.fn((x) => x); @@ -83,17 +92,17 @@ describe("SyncBailHook", () => { }); it("should throw on tapAsync", () => { - const hook = new SyncBailHookTest(["x"]); + const hook = new SyncBailHook(["x"]); expect(() => hook.tapAsync()).toThrow(/tapAsync/); }); it("should throw on tapPromise", () => { - const hook = new SyncBailHookTest(["x"]); + const hook = new SyncBailHook(["x"]); expect(() => hook.tapPromise()).toThrow(/tapPromise/); }); it("should not crash with many plugins", () => { - const hook = new SyncBailHookTest(["x"]); + const hook = new SyncBailHook(["x"]); for (let i = 0; i < 1000; i++) { hook.tap("Test", () => 42); } diff --git a/test/SyncHooks.test.js b/test/SyncHooks.test.js index e30ee65..c9584c4 100644 --- a/test/SyncHooks.test.js +++ b/test/SyncHooks.test.js @@ -4,10 +4,7 @@ */ "use strict"; -const SyncBailHook = require("../lib/SyncBailHook"); const SyncHook = require("../lib/SyncHook"); -const SyncLoopHook = require("../lib/SyncLoopHook"); -const SyncWaterfallHook = require("../lib/SyncWaterfallHook"); const HookTester = require("./HookTester.test"); describe("SyncHook", () => { @@ -19,33 +16,3 @@ describe("SyncHook", () => { expect(result).toMatchSnapshot(); }, 15000); }); - -describe("SyncBailHook", () => { - it("should have to correct behavior", async () => { - const tester = new HookTester((args) => new SyncBailHook(args)); - - const result = await tester.run(true); - - expect(result).toMatchSnapshot(); - }, 15000); -}); - -describe("SyncWaterfallHook", () => { - it("should have to correct behavior", async () => { - const tester = new HookTester((args) => new SyncWaterfallHook(args)); - - const result = await tester.run(true); - - expect(result).toMatchSnapshot(); - }, 15000); -}); - -describe("SyncLoopHook", () => { - it("should have to correct behavior", async () => { - const tester = new HookTester((args) => new SyncLoopHook(args)); - - const result = await tester.runForLoop(true); - - expect(result).toMatchSnapshot(); - }, 15000); -}); diff --git a/test/SyncLoopHook.test.js b/test/SyncLoopHook.test.js index e742224..c7ae025 100644 --- a/test/SyncLoopHook.test.js +++ b/test/SyncLoopHook.test.js @@ -3,25 +3,34 @@ */ "use strict"; -const SyncLoopHookTest = require("../lib/SyncLoopHook"); +const SyncLoopHook = require("../lib/SyncLoopHook"); +const HookTester = require("./HookTester.test"); describe("SyncLoopHook", () => { it("should throw on tapAsync", () => { - const hook = new SyncLoopHookTest(["a"]); + const hook = new SyncLoopHook(["a"]); expect(() => hook.tapAsync("A", () => {})).toThrow( /tapAsync is not supported on a SyncLoopHook/ ); }); it("should throw on tapPromise", () => { - const hook = new SyncLoopHookTest(["a"]); + const hook = new SyncLoopHook(["a"]); expect(() => hook.tapPromise("A", () => {})).toThrow( /tapPromise is not supported on a SyncLoopHook/ ); }); + it("should have to correct behavior", async () => { + const tester = new HookTester((args) => new SyncLoopHook(args)); + + const result = await tester.runForLoop(true); + + expect(result).toMatchSnapshot(); + }, 15000); + it("should loop through taps until all return undefined", () => { - const hook = new SyncLoopHookTest(["counter"]); + const hook = new SyncLoopHook(["counter"]); let firstCalls = 0; let secondCalls = 0; hook.tap("first", () => { @@ -36,7 +45,7 @@ describe("SyncLoopHook", () => { }); it("should be callable without arguments using default args", () => { - const hook = new SyncLoopHookTest(); + const hook = new SyncLoopHook(); const mock = jest.fn(); hook.tap("A", mock); hook.call(); diff --git a/test/SyncWaterfallHook.test.js b/test/SyncWaterfallHook.test.js index 1098570..975770f 100644 --- a/test/SyncWaterfallHook.test.js +++ b/test/SyncWaterfallHook.test.js @@ -4,7 +4,8 @@ */ "use strict"; -const SyncWaterfallHookTest = require("../lib/SyncWaterfallHook"); +const SyncWaterfallHook = require("../lib/SyncWaterfallHook"); +const HookTester = require("./HookTester.test"); function pify(fn) { return new Promise((resolve, reject) => { @@ -17,13 +18,21 @@ function pify(fn) { describe("SyncWaterfallHook", () => { it("should throw an error when hook has no argument", () => { - expect(() => new SyncWaterfallHookTest()).toThrow( + expect(() => new SyncWaterfallHook()).toThrow( "Waterfall hooks must have at least one argument" ); }); + it("should have to correct behavior", async () => { + const tester = new HookTester((args) => new SyncWaterfallHook(args)); + + const result = await tester.run(true); + + expect(result).toMatchSnapshot(); + }, 15000); + it("should work", () => { - const hook = new SyncWaterfallHookTest(["x"]); + const hook = new SyncWaterfallHook(["x"]); hook.tap("number", () => 42); hook.tap("string", () => "str"); hook.tap("false", () => false); @@ -31,21 +40,21 @@ describe("SyncWaterfallHook", () => { }); it("should work with undefined", async () => { - const hook = new SyncWaterfallHookTest(["x"]); + const hook = new SyncWaterfallHook(["x"]); hook.tap("number", () => 42); hook.tap("undefined", () => undefined); return expect(hook.call()).toBe(42); }); it("should work with void", async () => { - const hook = new SyncWaterfallHookTest(["x"]); + const hook = new SyncWaterfallHook(["x"]); hook.tap("number", () => 42); hook.tap("undefined", () => {}); return expect(hook.call()).toBe(42); }); it("should work with undefined and number again", async () => { - const hook = new SyncWaterfallHookTest(["x"]); + const hook = new SyncWaterfallHook(["x"]); hook.tap("number", () => 42); hook.tap("undefined", () => {}); hook.tap("number-again", () => 43); @@ -53,21 +62,21 @@ describe("SyncWaterfallHook", () => { }); it("should work with null", async () => { - const hook = new SyncWaterfallHookTest(["x"]); + const hook = new SyncWaterfallHook(["x"]); hook.tap("number", () => 42); hook.tap("undefined", () => null); return expect(hook.call()).toBeNull(); }); it("should work with different types", async () => { - const hook = new SyncWaterfallHookTest(["x"]); + const hook = new SyncWaterfallHook(["x"]); hook.tap("number", () => 42); hook.tap("string", () => "string"); return expect(hook.call()).toBe("string"); }); it("should allow to create sync hooks", async () => { - const hook = new SyncWaterfallHookTest(["arg1", "arg2"]); + const hook = new SyncWaterfallHook(["arg1", "arg2"]); const mock0 = jest.fn((arg) => `${arg},0`); const mock1 = jest.fn((arg) => `${arg},1`); @@ -100,7 +109,7 @@ describe("SyncWaterfallHook", () => { }); it("should allow to intercept calls", () => { - const hook = new SyncWaterfallHookTest(["arg1", "arg2"]); + const hook = new SyncWaterfallHook(["arg1", "arg2"]); const mockCall = jest.fn(); const mock0 = jest.fn(() => "mock0"); @@ -139,8 +148,8 @@ describe("SyncWaterfallHook", () => { }); it("should allow to create waterfall hooks", async () => { - const h1 = new SyncWaterfallHookTest(["a"]); - const h2 = new SyncWaterfallHookTest(["a", "b"]); + const h1 = new SyncWaterfallHook(["a"]); + const h2 = new SyncWaterfallHook(["a", "b"]); expect(h1.call(1)).toBe(1); @@ -164,12 +173,12 @@ describe("SyncWaterfallHook", () => { it("should throw when args have length less than 1", () => { expect(() => { // eslint-disable-next-line no-new - new SyncWaterfallHookTest([]); + new SyncWaterfallHook([]); }).toThrow(/Waterfall/); }); it("should allow to intercept calls #2", () => { - const hook = new SyncWaterfallHookTest(["x"]); + const hook = new SyncWaterfallHook(["x"]); const mockCall = jest.fn(); const mockTap = jest.fn((x) => x); @@ -193,12 +202,12 @@ describe("SyncWaterfallHook", () => { }); it("should throw on tapAsync", () => { - const hook = new SyncWaterfallHookTest(["x"]); + const hook = new SyncWaterfallHook(["x"]); expect(() => hook.tapAsync()).toThrow(/tapAsync/); }); it("should throw on tapPromise", () => { - const hook = new SyncWaterfallHookTest(["x"]); + const hook = new SyncWaterfallHook(["x"]); expect(() => hook.tapPromise()).toThrow(/tapPromise/); }); }); diff --git a/test/__snapshots__/AsyncParallelBailHook.test.js.snap b/test/__snapshots__/AsyncParallelBailHook.test.js.snap new file mode 100644 index 0000000..ee732b7 --- /dev/null +++ b/test/__snapshots__/AsyncParallelBailHook.test.js.snap @@ -0,0 +1,798 @@ +// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing + +exports[`AsyncParallelBailHook should have to correct behavior 1`] = ` +Object { + "async": Object { + "callAsyncMultipleAsyncEarlyError": Object { + "error": "Error in async2", + "type": "async", + }, + "callAsyncMultipleAsyncEarlyErrorCalled1": true, + "callAsyncMultipleAsyncError": Object { + "error": "Error in async2", + "type": "async", + }, + "callAsyncMultipleAsyncErrorCalled1": true, + "callAsyncMultipleAsyncLateError": Object { + "error": "Error in async2", + "type": "async", + }, + "callAsyncMultipleAsyncLateErrorCalled1": true, + "callAsyncMultipleAsyncLateErrorCalled3": true, + "callAsyncMultipleAsyncLateErrorEarlyResult1": Object { + "error": "Error in async2", + "type": "async", + }, + "callAsyncMultipleAsyncLateErrorEarlyResult1Called1": true, + "callAsyncMultipleAsyncLateErrorEarlyResult1Called3": true, + "callAsyncMultipleAsyncLateErrorEarlyResult2": Object { + "type": "async", + "value": 42, + }, + "callAsyncMultipleAsyncLateErrorEarlyResult2Called1": true, + "callAsyncMultipleAsyncLateErrorEarlyResult2Called3": true, + "callAsyncMultipleAsyncWithArg": Object { + "type": "async", + "value": 43, + }, + "callAsyncMultipleAsyncWithArgCalled1": 42, + "callAsyncMultipleAsyncWithArgFirstReturn": Object { + "type": "async", + "value": 43, + }, + "callAsyncMultipleAsyncWithArgFirstReturnCalled1": 42, + "callAsyncMultipleAsyncWithArgLastReturn": Object { + "type": "async", + "value": 44, + }, + "callAsyncMultipleAsyncWithArgLastReturnCalled1": 42, + "callAsyncMultipleAsyncWithArgLastReturnCalled2": 42, + "callAsyncMultipleAsyncWithArgNoReturn": Object { + "type": "async", + "value": undefined, + }, + "callAsyncMultipleAsyncWithArgNoReturnCalled1": 42, + "callAsyncMultipleAsyncWithArgNoReturnCalled2": 42, + "callAsyncMultipleMixed1WithArg": Object { + "type": "async", + "value": 43, + }, + "callAsyncMultipleMixed1WithArgCalled1": 42, + "callAsyncMultipleMixed2WithArg": Object { + "type": "async", + "value": 43, + }, + "callAsyncMultipleMixed2WithArgCalled1": 42, + "callAsyncMultipleMixed2WithArgCalled2": 42, + "callAsyncMultipleMixed3WithArg": Object { + "type": "async", + "value": 43, + }, + "callAsyncMultipleMixed3WithArgCalled1": 42, + "callAsyncMultipleMixedError1WithArg": Object { + "type": "async", + "value": 42, + }, + "callAsyncMultipleMixedError1WithArgCalled1": 42, + "callAsyncMultipleMixedError2WithArg": Object { + "type": "async", + "value": 42, + }, + "callAsyncMultipleMixedError2WithArgCalled1": 42, + "callAsyncMultipleMixedError3WithArg": Object { + "error": "Error in async", + "type": "async", + }, + "callAsyncMultipleMixedError3WithArgCalled1": 42, + "callAsyncMultipleMixedLateError": Object { + "error": "Error in async", + "type": "async", + }, + "callAsyncMultipleMixedLateErrorCalled1": true, + "callAsyncMultipleMixedLateErrorCalled2": true, + "callAsyncMultipleMixedLateErrorCalled3": true, + "callAsyncMultiplePromiseEarlyError": Object { + "error": "Error in async2", + "type": "async", + }, + "callAsyncMultiplePromiseEarlyErrorCalled1": true, + "callAsyncMultiplePromiseEarlyErrorCalled3": true, + "callAsyncMultiplePromiseError": Object { + "error": "Error in async2", + "type": "async", + }, + "callAsyncMultiplePromiseErrorCalled1": true, + "callAsyncMultiplePromiseErrorCalled3": true, + "callAsyncMultiplePromiseLateError": Object { + "error": "Error in async2", + "type": "async", + }, + "callAsyncMultiplePromiseLateErrorCalled1": true, + "callAsyncMultiplePromiseLateErrorCalled3": true, + "callAsyncMultiplePromiseWithArg": Object { + "type": "async", + "value": 43, + }, + "callAsyncMultiplePromiseWithArgCalled1": 42, + "callAsyncMultiplePromiseWithArgCalled2": 42, + "callAsyncMultiplePromiseWithArgFirstReturn": Object { + "type": "async", + "value": 43, + }, + "callAsyncMultiplePromiseWithArgFirstReturnCalled1": 42, + "callAsyncMultiplePromiseWithArgFirstReturnCalled2": 42, + "callAsyncMultiplePromiseWithArgLastReturn": Object { + "type": "async", + "value": 44, + }, + "callAsyncMultiplePromiseWithArgLastReturnCalled1": 42, + "callAsyncMultiplePromiseWithArgLastReturnCalled2": 42, + "callAsyncMultiplePromiseWithArgNoReturn": Object { + "type": "async", + "value": undefined, + }, + "callAsyncMultiplePromiseWithArgNoReturnCalled1": 42, + "callAsyncMultiplePromiseWithArgNoReturnCalled2": 42, + "callAsyncMultipleSync": Object { + "type": "async", + "value": 42, + }, + "callAsyncMultipleSyncCalled1": true, + "callAsyncMultipleSyncError": Object { + "error": "Error in sync2", + "type": "async", + }, + "callAsyncMultipleSyncErrorCalled1": true, + "callAsyncMultipleSyncLastReturn": Object { + "type": "async", + "value": 43, + }, + "callAsyncMultipleSyncLastReturnCalled1": true, + "callAsyncMultipleSyncLastReturnCalled2": true, + "callAsyncMultipleSyncNoReturn": Object { + "type": "async", + "value": undefined, + }, + "callAsyncMultipleSyncNoReturnCalled1": true, + "callAsyncMultipleSyncNoReturnCalled2": true, + "callAsyncMultipleSyncWithArg": Object { + "type": "async", + "value": 43, + }, + "callAsyncMultipleSyncWithArgCalled1": 42, + "callAsyncMultipleSyncWithArgFirstReturn": Object { + "type": "async", + "value": 43, + }, + "callAsyncMultipleSyncWithArgFirstReturnCalled1": 42, + "callAsyncMultipleSyncWithArgLastReturn": Object { + "type": "async", + "value": 44, + }, + "callAsyncMultipleSyncWithArgLastReturnCalled1": 42, + "callAsyncMultipleSyncWithArgLastReturnCalled2": 42, + "callAsyncMultipleSyncWithArgNoReturn": Object { + "type": "async", + "value": undefined, + }, + "callAsyncMultipleSyncWithArgNoReturnCalled1": 42, + "callAsyncMultipleSyncWithArgNoReturnCalled2": 42, + "callAsyncNone": Object { + "type": "async", + "value": undefined, + }, + "callAsyncNoneWithArg": Object { + "type": "async", + "value": undefined, + }, + "callAsyncSingleAsyncWithArg": Object { + "type": "async", + "value": 42, + }, + "callAsyncSingleAsyncWithArgCalled1": 42, + "callAsyncSinglePromiseWithArg": Object { + "type": "async", + "value": 43, + }, + "callAsyncSinglePromiseWithArgCalled1": 42, + "callAsyncSinglePromiseWithEmptyReject": Object { + "error": "Tap function (tapPromise) rejects \\"\\" value", + "type": "async", + }, + "callAsyncSinglePromiseWithEmptyStringArg": Object { + "type": "async", + "value": "", + }, + "callAsyncSinglePromiseWithEmptyStringArgCalled1": 42, + "callAsyncSinglePromiseWithFalseReject": Object { + "error": "Tap function (tapPromise) rejects \\"false\\" value", + "type": "async", + }, + "callAsyncSinglePromiseWithNullArg": Object { + "type": "async", + "value": null, + }, + "callAsyncSinglePromiseWithNullArgCalled1": 42, + "callAsyncSinglePromiseWithNullReject": Object { + "error": "Tap function (tapPromise) rejects \\"null\\" value", + "type": "async", + }, + "callAsyncSinglePromiseWithUndefined": Object { + "type": "async", + "value": undefined, + }, + "callAsyncSinglePromiseWithUndefinedCalled1": 42, + "callAsyncSinglePromiseWithUndefinedReject": Object { + "error": "Tap function (tapPromise) rejects \\"undefined\\" value", + "type": "async", + }, + "callAsyncSinglePromiseWithZeroArg": Object { + "type": "async", + "value": 0, + }, + "callAsyncSinglePromiseWithZeroArgCalled1": 42, + "callAsyncSinglePromiseWithZeroReject": Object { + "error": "Tap function (tapPromise) rejects \\"0\\" value", + "type": "async", + }, + "callAsyncSingleSync": Object { + "type": "async", + "value": 42, + }, + "callAsyncSingleSyncCalled1": true, + "callAsyncSingleSyncWithArg": Object { + "type": "async", + "value": 43, + }, + "callAsyncSingleSyncWithArgCalled1": 42, + "callAsyncSingleSyncWithArgNoReturn": Object { + "type": "async", + "value": undefined, + }, + "callAsyncSingleSyncWithArgNoReturnCalled1": 42, + "promiseMultipleAsyncEarlyError": Object { + "error": "Error in async2", + "type": "promise", + }, + "promiseMultipleAsyncEarlyErrorCalled1": true, + "promiseMultipleAsyncError": Object { + "error": "Error in async2", + "type": "promise", + }, + "promiseMultipleAsyncErrorCalled1": true, + "promiseMultipleAsyncLateError": Object { + "error": "Error in async2", + "type": "promise", + }, + "promiseMultipleAsyncLateErrorCalled1": true, + "promiseMultipleAsyncLateErrorCalled3": true, + "promiseMultipleAsyncLateErrorEarlyResult1": Object { + "error": "Error in async2", + "type": "promise", + }, + "promiseMultipleAsyncLateErrorEarlyResult1Called1": true, + "promiseMultipleAsyncLateErrorEarlyResult1Called3": true, + "promiseMultipleAsyncLateErrorEarlyResult2": Object { + "type": "promise", + "value": 42, + }, + "promiseMultipleAsyncLateErrorEarlyResult2Called1": true, + "promiseMultipleAsyncLateErrorEarlyResult2Called3": true, + "promiseMultipleAsyncWithArg": Object { + "type": "promise", + "value": 43, + }, + "promiseMultipleAsyncWithArgCalled1": 42, + "promiseMultipleAsyncWithArgFirstReturn": Object { + "type": "promise", + "value": 43, + }, + "promiseMultipleAsyncWithArgFirstReturnCalled1": 42, + "promiseMultipleAsyncWithArgLastReturn": Object { + "type": "promise", + "value": 44, + }, + "promiseMultipleAsyncWithArgLastReturnCalled1": 42, + "promiseMultipleAsyncWithArgLastReturnCalled2": 42, + "promiseMultipleAsyncWithArgNoReturn": Object { + "type": "promise", + "value": undefined, + }, + "promiseMultipleAsyncWithArgNoReturnCalled1": 42, + "promiseMultipleAsyncWithArgNoReturnCalled2": 42, + "promiseMultipleMixed1WithArg": Object { + "type": "promise", + "value": 43, + }, + "promiseMultipleMixed1WithArgCalled1": 42, + "promiseMultipleMixed2WithArg": Object { + "type": "promise", + "value": 43, + }, + "promiseMultipleMixed2WithArgCalled1": 42, + "promiseMultipleMixed2WithArgCalled2": 42, + "promiseMultipleMixed3WithArg": Object { + "type": "promise", + "value": 43, + }, + "promiseMultipleMixed3WithArgCalled1": 42, + "promiseMultipleMixedError1WithArg": Object { + "type": "promise", + "value": 42, + }, + "promiseMultipleMixedError1WithArgCalled1": 42, + "promiseMultipleMixedError2WithArg": Object { + "type": "promise", + "value": 42, + }, + "promiseMultipleMixedError2WithArgCalled1": 42, + "promiseMultipleMixedError3WithArg": Object { + "error": "Error in async", + "type": "promise", + }, + "promiseMultipleMixedError3WithArgCalled1": 42, + "promiseMultipleMixedLateError": Object { + "error": "Error in async", + "type": "promise", + }, + "promiseMultipleMixedLateErrorCalled1": true, + "promiseMultipleMixedLateErrorCalled2": true, + "promiseMultipleMixedLateErrorCalled3": true, + "promiseMultiplePromiseEarlyError": Object { + "error": "Error in async2", + "type": "promise", + }, + "promiseMultiplePromiseEarlyErrorCalled1": true, + "promiseMultiplePromiseEarlyErrorCalled3": true, + "promiseMultiplePromiseError": Object { + "error": "Error in async2", + "type": "promise", + }, + "promiseMultiplePromiseErrorCalled1": true, + "promiseMultiplePromiseErrorCalled3": true, + "promiseMultiplePromiseLateError": Object { + "error": "Error in async2", + "type": "promise", + }, + "promiseMultiplePromiseLateErrorCalled1": true, + "promiseMultiplePromiseLateErrorCalled3": true, + "promiseMultiplePromiseWithArg": Object { + "type": "promise", + "value": 43, + }, + "promiseMultiplePromiseWithArgCalled1": 42, + "promiseMultiplePromiseWithArgCalled2": 42, + "promiseMultiplePromiseWithArgFirstReturn": Object { + "type": "promise", + "value": 43, + }, + "promiseMultiplePromiseWithArgFirstReturnCalled1": 42, + "promiseMultiplePromiseWithArgFirstReturnCalled2": 42, + "promiseMultiplePromiseWithArgLastReturn": Object { + "type": "promise", + "value": 44, + }, + "promiseMultiplePromiseWithArgLastReturnCalled1": 42, + "promiseMultiplePromiseWithArgLastReturnCalled2": 42, + "promiseMultiplePromiseWithArgNoReturn": Object { + "type": "promise", + "value": undefined, + }, + "promiseMultiplePromiseWithArgNoReturnCalled1": 42, + "promiseMultiplePromiseWithArgNoReturnCalled2": 42, + "promiseMultipleSync": Object { + "type": "promise", + "value": 42, + }, + "promiseMultipleSyncCalled1": true, + "promiseMultipleSyncError": Object { + "error": "Error in sync2", + "type": "promise", + }, + "promiseMultipleSyncErrorCalled1": true, + "promiseMultipleSyncLastReturn": Object { + "type": "promise", + "value": 43, + }, + "promiseMultipleSyncLastReturnCalled1": true, + "promiseMultipleSyncLastReturnCalled2": true, + "promiseMultipleSyncNoReturn": Object { + "type": "promise", + "value": undefined, + }, + "promiseMultipleSyncNoReturnCalled1": true, + "promiseMultipleSyncNoReturnCalled2": true, + "promiseMultipleSyncWithArg": Object { + "type": "promise", + "value": 43, + }, + "promiseMultipleSyncWithArgCalled1": 42, + "promiseMultipleSyncWithArgFirstReturn": Object { + "type": "promise", + "value": 43, + }, + "promiseMultipleSyncWithArgFirstReturnCalled1": 42, + "promiseMultipleSyncWithArgLastReturn": Object { + "type": "promise", + "value": 44, + }, + "promiseMultipleSyncWithArgLastReturnCalled1": 42, + "promiseMultipleSyncWithArgLastReturnCalled2": 42, + "promiseMultipleSyncWithArgNoReturn": Object { + "type": "promise", + "value": undefined, + }, + "promiseMultipleSyncWithArgNoReturnCalled1": 42, + "promiseMultipleSyncWithArgNoReturnCalled2": 42, + "promiseNone": Object { + "type": "promise", + "value": undefined, + }, + "promiseNoneWithArg": Object { + "type": "promise", + "value": undefined, + }, + "promiseSingleAsyncWithArg": Object { + "type": "promise", + "value": 42, + }, + "promiseSingleAsyncWithArgCalled1": 42, + "promiseSinglePromiseWithArg": Object { + "type": "promise", + "value": 43, + }, + "promiseSinglePromiseWithArgCalled1": 42, + "promiseSinglePromiseWithEmptyReject": Object { + "error": "Tap function (tapPromise) rejects \\"\\" value", + "type": "promise", + }, + "promiseSinglePromiseWithEmptyStringArg": Object { + "type": "promise", + "value": "", + }, + "promiseSinglePromiseWithEmptyStringArgCalled1": 42, + "promiseSinglePromiseWithFalseReject": Object { + "error": "Tap function (tapPromise) rejects \\"false\\" value", + "type": "promise", + }, + "promiseSinglePromiseWithNullArg": Object { + "type": "promise", + "value": null, + }, + "promiseSinglePromiseWithNullArgCalled1": 42, + "promiseSinglePromiseWithNullReject": Object { + "error": "Tap function (tapPromise) rejects \\"null\\" value", + "type": "promise", + }, + "promiseSinglePromiseWithUndefined": Object { + "type": "promise", + "value": undefined, + }, + "promiseSinglePromiseWithUndefinedCalled1": 42, + "promiseSinglePromiseWithUndefinedReject": Object { + "error": "Tap function (tapPromise) rejects \\"undefined\\" value", + "type": "promise", + }, + "promiseSinglePromiseWithZeroArg": Object { + "type": "promise", + "value": 0, + }, + "promiseSinglePromiseWithZeroArgCalled1": 42, + "promiseSinglePromiseWithZeroReject": Object { + "error": "Tap function (tapPromise) rejects \\"0\\" value", + "type": "promise", + }, + "promiseSingleSync": Object { + "type": "promise", + "value": 42, + }, + "promiseSingleSyncCalled1": true, + "promiseSingleSyncWithArg": Object { + "type": "promise", + "value": 43, + }, + "promiseSingleSyncWithArgCalled1": 42, + "promiseSingleSyncWithArgNoReturn": Object { + "type": "promise", + "value": undefined, + }, + "promiseSingleSyncWithArgNoReturnCalled1": 42, + }, + "intercept": Object { + "callAsyncContextIntercepted": Object { + "type": "async", + "value": 48, + }, + "callAsyncContextInterceptedCall1": Array [ + Object { + "number": 42, + }, + 1, + 2, + 3, + ], + "callAsyncContextInterceptedCall2": Array [ + 1, + 2, + 3, + ], + "callAsyncContextInterceptedTap1": Object { + "number": 42, + }, + "callAsyncIntercepted": Object { + "type": "async", + "value": 6, + }, + "callAsyncInterceptedCall1": Array [ + 1, + 2, + 3, + ], + "callAsyncInterceptedCall2": Array [ + 1, + 2, + 3, + ], + "callAsyncInterceptedResult1": 6, + "callAsyncInterceptedResult2": 6, + "callAsyncInterceptedTap1": Object { + "fn": 3, + "name": "sync", + "type": "sync", + }, + "callAsyncInterceptedTap2": Object { + "fn": 3, + "name": "sync", + "type": "sync", + }, + "callAsyncUnusedContextIntercepted": Object { + "type": "async", + "value": 6, + }, + "callAsyncUnusedContextInterceptedCall1": Array [ + undefined, + 1, + 2, + 3, + ], + "callAsyncUnusedContextInterceptedCall2": Array [ + 1, + 2, + 3, + ], + "callAsyncUnusedContextInterceptedTap1": undefined, + "promiseContextIntercepted": Object { + "type": "promise", + "value": 48, + }, + "promiseContextInterceptedCall1": Array [ + Object { + "number": 42, + }, + 1, + 2, + 3, + ], + "promiseContextInterceptedCall2": Array [ + 1, + 2, + 3, + ], + "promiseContextInterceptedTap1": Object { + "number": 42, + }, + "promiseIntercepted": Object { + "type": "promise", + "value": 6, + }, + "promiseInterceptedCall1": Array [ + 1, + 2, + 3, + ], + "promiseInterceptedCall2": Array [ + 1, + 2, + 3, + ], + "promiseInterceptedResult1": 6, + "promiseInterceptedResult2": 6, + "promiseInterceptedTap1": Object { + "fn": 3, + "name": "sync", + "type": "sync", + }, + "promiseInterceptedTap2": Object { + "fn": 3, + "name": "sync", + "type": "sync", + }, + "promiseUnusedContextIntercepted": Object { + "type": "promise", + "value": 6, + }, + "promiseUnusedContextInterceptedCall1": Array [ + undefined, + 1, + 2, + 3, + ], + "promiseUnusedContextInterceptedCall2": Array [ + 1, + 2, + 3, + ], + "promiseUnusedContextInterceptedTap1": undefined, + }, + "sync": Object { + "callAsyncIntercepted": Object { + "type": "async", + "value": 6, + }, + "callAsyncInterceptedCall1": Array [ + 1, + 2, + 3, + ], + "callAsyncInterceptedCall2": Array [ + 1, + 2, + 3, + ], + "callAsyncInterceptedTap1": Object { + "fn": 3, + "name": "sync1", + "type": "sync", + }, + "callAsyncInterceptedTap2": Object { + "fn": 3, + "name": "sync1", + "type": "sync", + }, + "callAsyncMultipleSync": Object { + "type": "async", + "value": 42, + }, + "callAsyncMultipleSyncCalled1": true, + "callAsyncMultipleSyncError": Object { + "error": "Error in sync2", + "type": "async", + }, + "callAsyncMultipleSyncErrorCalled1": true, + "callAsyncMultipleSyncErrorCalled2": true, + "callAsyncMultipleSyncWithArg": Object { + "type": "async", + "value": 84, + }, + "callAsyncMultipleSyncWithArgCalled1": 42, + "callAsyncMultipleSyncWithArgFirstReturn": Object { + "type": "async", + "value": 84, + }, + "callAsyncMultipleSyncWithArgFirstReturnCalled1": 42, + "callAsyncMultipleSyncWithArgLastReturn": Object { + "type": "async", + "value": 85, + }, + "callAsyncMultipleSyncWithArgLastReturnCalled1": 42, + "callAsyncMultipleSyncWithArgLastReturnCalled2": 42, + "callAsyncMultipleSyncWithArgNoReturn": Object { + "type": "async", + "value": undefined, + }, + "callAsyncMultipleSyncWithArgNoReturnCalled1": 42, + "callAsyncMultipleSyncWithArgNoReturnCalled2": 42, + "callAsyncMultipleSyncWithArgs": Object { + "type": "async", + "value": 129, + }, + "callAsyncMultipleSyncWithArgsCalled1": Array [ + 42, + 43, + 44, + ], + "callAsyncNone": Object { + "type": "async", + "value": undefined, + }, + "callAsyncNoneWithArg": Object { + "type": "async", + "value": undefined, + }, + "callAsyncSingleSync": Object { + "type": "async", + "value": 42, + }, + "callAsyncSingleSyncCalled": true, + "callAsyncSingleSyncWithArg": Object { + "type": "async", + "value": 42, + }, + "callAsyncSingleSyncWithArgCalled": 42, + "promiseIntercepted": Object { + "type": "promise", + "value": 6, + }, + "promiseInterceptedCall1": Array [ + 1, + 2, + 3, + ], + "promiseInterceptedCall2": Array [ + 1, + 2, + 3, + ], + "promiseInterceptedTap1": Object { + "fn": 3, + "name": "sync1", + "type": "sync", + }, + "promiseInterceptedTap2": Object { + "fn": 3, + "name": "sync1", + "type": "sync", + }, + "promiseMultipleSync": Object { + "type": "promise", + "value": 42, + }, + "promiseMultipleSyncCalled1": true, + "promiseMultipleSyncError": Object { + "error": "Error in sync2", + "type": "promise", + }, + "promiseMultipleSyncErrorCalled1": true, + "promiseMultipleSyncErrorCalled2": true, + "promiseMultipleSyncWithArg": Object { + "type": "promise", + "value": 84, + }, + "promiseMultipleSyncWithArgCalled1": 42, + "promiseMultipleSyncWithArgFirstReturn": Object { + "type": "promise", + "value": 84, + }, + "promiseMultipleSyncWithArgFirstReturnCalled1": 42, + "promiseMultipleSyncWithArgLastReturn": Object { + "type": "promise", + "value": 85, + }, + "promiseMultipleSyncWithArgLastReturnCalled1": 42, + "promiseMultipleSyncWithArgLastReturnCalled2": 42, + "promiseMultipleSyncWithArgNoReturn": Object { + "type": "promise", + "value": undefined, + }, + "promiseMultipleSyncWithArgNoReturnCalled1": 42, + "promiseMultipleSyncWithArgNoReturnCalled2": 42, + "promiseMultipleSyncWithArgs": Object { + "type": "promise", + "value": 129, + }, + "promiseMultipleSyncWithArgsCalled1": Array [ + 42, + 43, + 44, + ], + "promiseNone": Object { + "type": "promise", + "value": undefined, + }, + "promiseNoneWithArg": Object { + "type": "promise", + "value": undefined, + }, + "promiseSingleSync": Object { + "type": "promise", + "value": 42, + }, + "promiseSingleSyncCalled": true, + "promiseSingleSyncWithArg": Object { + "type": "promise", + "value": 42, + }, + "promiseSingleSyncWithArgCalled": 42, + }, +} +`; diff --git a/test/__snapshots__/AsyncParallelHooks.test.js.snap b/test/__snapshots__/AsyncParallelHooks.test.js.snap index c1c3b01..fd553b5 100644 --- a/test/__snapshots__/AsyncParallelHooks.test.js.snap +++ b/test/__snapshots__/AsyncParallelHooks.test.js.snap @@ -1,802 +1,5 @@ // Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing -exports[`AsyncParallelBailHook should have to correct behavior 1`] = ` -Object { - "async": Object { - "callAsyncMultipleAsyncEarlyError": Object { - "error": "Error in async2", - "type": "async", - }, - "callAsyncMultipleAsyncEarlyErrorCalled1": true, - "callAsyncMultipleAsyncError": Object { - "error": "Error in async2", - "type": "async", - }, - "callAsyncMultipleAsyncErrorCalled1": true, - "callAsyncMultipleAsyncLateError": Object { - "error": "Error in async2", - "type": "async", - }, - "callAsyncMultipleAsyncLateErrorCalled1": true, - "callAsyncMultipleAsyncLateErrorCalled3": true, - "callAsyncMultipleAsyncLateErrorEarlyResult1": Object { - "error": "Error in async2", - "type": "async", - }, - "callAsyncMultipleAsyncLateErrorEarlyResult1Called1": true, - "callAsyncMultipleAsyncLateErrorEarlyResult1Called3": true, - "callAsyncMultipleAsyncLateErrorEarlyResult2": Object { - "type": "async", - "value": 42, - }, - "callAsyncMultipleAsyncLateErrorEarlyResult2Called1": true, - "callAsyncMultipleAsyncLateErrorEarlyResult2Called3": true, - "callAsyncMultipleAsyncWithArg": Object { - "type": "async", - "value": 43, - }, - "callAsyncMultipleAsyncWithArgCalled1": 42, - "callAsyncMultipleAsyncWithArgFirstReturn": Object { - "type": "async", - "value": 43, - }, - "callAsyncMultipleAsyncWithArgFirstReturnCalled1": 42, - "callAsyncMultipleAsyncWithArgLastReturn": Object { - "type": "async", - "value": 44, - }, - "callAsyncMultipleAsyncWithArgLastReturnCalled1": 42, - "callAsyncMultipleAsyncWithArgLastReturnCalled2": 42, - "callAsyncMultipleAsyncWithArgNoReturn": Object { - "type": "async", - "value": undefined, - }, - "callAsyncMultipleAsyncWithArgNoReturnCalled1": 42, - "callAsyncMultipleAsyncWithArgNoReturnCalled2": 42, - "callAsyncMultipleMixed1WithArg": Object { - "type": "async", - "value": 43, - }, - "callAsyncMultipleMixed1WithArgCalled1": 42, - "callAsyncMultipleMixed2WithArg": Object { - "type": "async", - "value": 43, - }, - "callAsyncMultipleMixed2WithArgCalled1": 42, - "callAsyncMultipleMixed2WithArgCalled2": 42, - "callAsyncMultipleMixed3WithArg": Object { - "type": "async", - "value": 43, - }, - "callAsyncMultipleMixed3WithArgCalled1": 42, - "callAsyncMultipleMixedError1WithArg": Object { - "type": "async", - "value": 42, - }, - "callAsyncMultipleMixedError1WithArgCalled1": 42, - "callAsyncMultipleMixedError2WithArg": Object { - "type": "async", - "value": 42, - }, - "callAsyncMultipleMixedError2WithArgCalled1": 42, - "callAsyncMultipleMixedError3WithArg": Object { - "error": "Error in async", - "type": "async", - }, - "callAsyncMultipleMixedError3WithArgCalled1": 42, - "callAsyncMultipleMixedLateError": Object { - "error": "Error in async", - "type": "async", - }, - "callAsyncMultipleMixedLateErrorCalled1": true, - "callAsyncMultipleMixedLateErrorCalled2": true, - "callAsyncMultipleMixedLateErrorCalled3": true, - "callAsyncMultiplePromiseEarlyError": Object { - "error": "Error in async2", - "type": "async", - }, - "callAsyncMultiplePromiseEarlyErrorCalled1": true, - "callAsyncMultiplePromiseEarlyErrorCalled3": true, - "callAsyncMultiplePromiseError": Object { - "error": "Error in async2", - "type": "async", - }, - "callAsyncMultiplePromiseErrorCalled1": true, - "callAsyncMultiplePromiseErrorCalled3": true, - "callAsyncMultiplePromiseLateError": Object { - "error": "Error in async2", - "type": "async", - }, - "callAsyncMultiplePromiseLateErrorCalled1": true, - "callAsyncMultiplePromiseLateErrorCalled3": true, - "callAsyncMultiplePromiseWithArg": Object { - "type": "async", - "value": 43, - }, - "callAsyncMultiplePromiseWithArgCalled1": 42, - "callAsyncMultiplePromiseWithArgCalled2": 42, - "callAsyncMultiplePromiseWithArgFirstReturn": Object { - "type": "async", - "value": 43, - }, - "callAsyncMultiplePromiseWithArgFirstReturnCalled1": 42, - "callAsyncMultiplePromiseWithArgFirstReturnCalled2": 42, - "callAsyncMultiplePromiseWithArgLastReturn": Object { - "type": "async", - "value": 44, - }, - "callAsyncMultiplePromiseWithArgLastReturnCalled1": 42, - "callAsyncMultiplePromiseWithArgLastReturnCalled2": 42, - "callAsyncMultiplePromiseWithArgNoReturn": Object { - "type": "async", - "value": undefined, - }, - "callAsyncMultiplePromiseWithArgNoReturnCalled1": 42, - "callAsyncMultiplePromiseWithArgNoReturnCalled2": 42, - "callAsyncMultipleSync": Object { - "type": "async", - "value": 42, - }, - "callAsyncMultipleSyncCalled1": true, - "callAsyncMultipleSyncError": Object { - "error": "Error in sync2", - "type": "async", - }, - "callAsyncMultipleSyncErrorCalled1": true, - "callAsyncMultipleSyncLastReturn": Object { - "type": "async", - "value": 43, - }, - "callAsyncMultipleSyncLastReturnCalled1": true, - "callAsyncMultipleSyncLastReturnCalled2": true, - "callAsyncMultipleSyncNoReturn": Object { - "type": "async", - "value": undefined, - }, - "callAsyncMultipleSyncNoReturnCalled1": true, - "callAsyncMultipleSyncNoReturnCalled2": true, - "callAsyncMultipleSyncWithArg": Object { - "type": "async", - "value": 43, - }, - "callAsyncMultipleSyncWithArgCalled1": 42, - "callAsyncMultipleSyncWithArgFirstReturn": Object { - "type": "async", - "value": 43, - }, - "callAsyncMultipleSyncWithArgFirstReturnCalled1": 42, - "callAsyncMultipleSyncWithArgLastReturn": Object { - "type": "async", - "value": 44, - }, - "callAsyncMultipleSyncWithArgLastReturnCalled1": 42, - "callAsyncMultipleSyncWithArgLastReturnCalled2": 42, - "callAsyncMultipleSyncWithArgNoReturn": Object { - "type": "async", - "value": undefined, - }, - "callAsyncMultipleSyncWithArgNoReturnCalled1": 42, - "callAsyncMultipleSyncWithArgNoReturnCalled2": 42, - "callAsyncNone": Object { - "type": "async", - "value": undefined, - }, - "callAsyncNoneWithArg": Object { - "type": "async", - "value": undefined, - }, - "callAsyncSingleAsyncWithArg": Object { - "type": "async", - "value": 42, - }, - "callAsyncSingleAsyncWithArgCalled1": 42, - "callAsyncSinglePromiseWithArg": Object { - "type": "async", - "value": 43, - }, - "callAsyncSinglePromiseWithArgCalled1": 42, - "callAsyncSinglePromiseWithEmptyReject": Object { - "error": "Tap function (tapPromise) rejects \\"\\" value", - "type": "async", - }, - "callAsyncSinglePromiseWithEmptyStringArg": Object { - "type": "async", - "value": "", - }, - "callAsyncSinglePromiseWithEmptyStringArgCalled1": 42, - "callAsyncSinglePromiseWithFalseReject": Object { - "error": "Tap function (tapPromise) rejects \\"false\\" value", - "type": "async", - }, - "callAsyncSinglePromiseWithNullArg": Object { - "type": "async", - "value": null, - }, - "callAsyncSinglePromiseWithNullArgCalled1": 42, - "callAsyncSinglePromiseWithNullReject": Object { - "error": "Tap function (tapPromise) rejects \\"null\\" value", - "type": "async", - }, - "callAsyncSinglePromiseWithUndefined": Object { - "type": "async", - "value": undefined, - }, - "callAsyncSinglePromiseWithUndefinedCalled1": 42, - "callAsyncSinglePromiseWithUndefinedReject": Object { - "error": "Tap function (tapPromise) rejects \\"undefined\\" value", - "type": "async", - }, - "callAsyncSinglePromiseWithZeroArg": Object { - "type": "async", - "value": 0, - }, - "callAsyncSinglePromiseWithZeroArgCalled1": 42, - "callAsyncSinglePromiseWithZeroReject": Object { - "error": "Tap function (tapPromise) rejects \\"0\\" value", - "type": "async", - }, - "callAsyncSingleSync": Object { - "type": "async", - "value": 42, - }, - "callAsyncSingleSyncCalled1": true, - "callAsyncSingleSyncWithArg": Object { - "type": "async", - "value": 43, - }, - "callAsyncSingleSyncWithArgCalled1": 42, - "callAsyncSingleSyncWithArgNoReturn": Object { - "type": "async", - "value": undefined, - }, - "callAsyncSingleSyncWithArgNoReturnCalled1": 42, - "promiseMultipleAsyncEarlyError": Object { - "error": "Error in async2", - "type": "promise", - }, - "promiseMultipleAsyncEarlyErrorCalled1": true, - "promiseMultipleAsyncError": Object { - "error": "Error in async2", - "type": "promise", - }, - "promiseMultipleAsyncErrorCalled1": true, - "promiseMultipleAsyncLateError": Object { - "error": "Error in async2", - "type": "promise", - }, - "promiseMultipleAsyncLateErrorCalled1": true, - "promiseMultipleAsyncLateErrorCalled3": true, - "promiseMultipleAsyncLateErrorEarlyResult1": Object { - "error": "Error in async2", - "type": "promise", - }, - "promiseMultipleAsyncLateErrorEarlyResult1Called1": true, - "promiseMultipleAsyncLateErrorEarlyResult1Called3": true, - "promiseMultipleAsyncLateErrorEarlyResult2": Object { - "type": "promise", - "value": 42, - }, - "promiseMultipleAsyncLateErrorEarlyResult2Called1": true, - "promiseMultipleAsyncLateErrorEarlyResult2Called3": true, - "promiseMultipleAsyncWithArg": Object { - "type": "promise", - "value": 43, - }, - "promiseMultipleAsyncWithArgCalled1": 42, - "promiseMultipleAsyncWithArgFirstReturn": Object { - "type": "promise", - "value": 43, - }, - "promiseMultipleAsyncWithArgFirstReturnCalled1": 42, - "promiseMultipleAsyncWithArgLastReturn": Object { - "type": "promise", - "value": 44, - }, - "promiseMultipleAsyncWithArgLastReturnCalled1": 42, - "promiseMultipleAsyncWithArgLastReturnCalled2": 42, - "promiseMultipleAsyncWithArgNoReturn": Object { - "type": "promise", - "value": undefined, - }, - "promiseMultipleAsyncWithArgNoReturnCalled1": 42, - "promiseMultipleAsyncWithArgNoReturnCalled2": 42, - "promiseMultipleMixed1WithArg": Object { - "type": "promise", - "value": 43, - }, - "promiseMultipleMixed1WithArgCalled1": 42, - "promiseMultipleMixed2WithArg": Object { - "type": "promise", - "value": 43, - }, - "promiseMultipleMixed2WithArgCalled1": 42, - "promiseMultipleMixed2WithArgCalled2": 42, - "promiseMultipleMixed3WithArg": Object { - "type": "promise", - "value": 43, - }, - "promiseMultipleMixed3WithArgCalled1": 42, - "promiseMultipleMixedError1WithArg": Object { - "type": "promise", - "value": 42, - }, - "promiseMultipleMixedError1WithArgCalled1": 42, - "promiseMultipleMixedError2WithArg": Object { - "type": "promise", - "value": 42, - }, - "promiseMultipleMixedError2WithArgCalled1": 42, - "promiseMultipleMixedError3WithArg": Object { - "error": "Error in async", - "type": "promise", - }, - "promiseMultipleMixedError3WithArgCalled1": 42, - "promiseMultipleMixedLateError": Object { - "error": "Error in async", - "type": "promise", - }, - "promiseMultipleMixedLateErrorCalled1": true, - "promiseMultipleMixedLateErrorCalled2": true, - "promiseMultipleMixedLateErrorCalled3": true, - "promiseMultiplePromiseEarlyError": Object { - "error": "Error in async2", - "type": "promise", - }, - "promiseMultiplePromiseEarlyErrorCalled1": true, - "promiseMultiplePromiseEarlyErrorCalled3": true, - "promiseMultiplePromiseError": Object { - "error": "Error in async2", - "type": "promise", - }, - "promiseMultiplePromiseErrorCalled1": true, - "promiseMultiplePromiseErrorCalled3": true, - "promiseMultiplePromiseLateError": Object { - "error": "Error in async2", - "type": "promise", - }, - "promiseMultiplePromiseLateErrorCalled1": true, - "promiseMultiplePromiseLateErrorCalled3": true, - "promiseMultiplePromiseWithArg": Object { - "type": "promise", - "value": 43, - }, - "promiseMultiplePromiseWithArgCalled1": 42, - "promiseMultiplePromiseWithArgCalled2": 42, - "promiseMultiplePromiseWithArgFirstReturn": Object { - "type": "promise", - "value": 43, - }, - "promiseMultiplePromiseWithArgFirstReturnCalled1": 42, - "promiseMultiplePromiseWithArgFirstReturnCalled2": 42, - "promiseMultiplePromiseWithArgLastReturn": Object { - "type": "promise", - "value": 44, - }, - "promiseMultiplePromiseWithArgLastReturnCalled1": 42, - "promiseMultiplePromiseWithArgLastReturnCalled2": 42, - "promiseMultiplePromiseWithArgNoReturn": Object { - "type": "promise", - "value": undefined, - }, - "promiseMultiplePromiseWithArgNoReturnCalled1": 42, - "promiseMultiplePromiseWithArgNoReturnCalled2": 42, - "promiseMultipleSync": Object { - "type": "promise", - "value": 42, - }, - "promiseMultipleSyncCalled1": true, - "promiseMultipleSyncError": Object { - "error": "Error in sync2", - "type": "promise", - }, - "promiseMultipleSyncErrorCalled1": true, - "promiseMultipleSyncLastReturn": Object { - "type": "promise", - "value": 43, - }, - "promiseMultipleSyncLastReturnCalled1": true, - "promiseMultipleSyncLastReturnCalled2": true, - "promiseMultipleSyncNoReturn": Object { - "type": "promise", - "value": undefined, - }, - "promiseMultipleSyncNoReturnCalled1": true, - "promiseMultipleSyncNoReturnCalled2": true, - "promiseMultipleSyncWithArg": Object { - "type": "promise", - "value": 43, - }, - "promiseMultipleSyncWithArgCalled1": 42, - "promiseMultipleSyncWithArgFirstReturn": Object { - "type": "promise", - "value": 43, - }, - "promiseMultipleSyncWithArgFirstReturnCalled1": 42, - "promiseMultipleSyncWithArgLastReturn": Object { - "type": "promise", - "value": 44, - }, - "promiseMultipleSyncWithArgLastReturnCalled1": 42, - "promiseMultipleSyncWithArgLastReturnCalled2": 42, - "promiseMultipleSyncWithArgNoReturn": Object { - "type": "promise", - "value": undefined, - }, - "promiseMultipleSyncWithArgNoReturnCalled1": 42, - "promiseMultipleSyncWithArgNoReturnCalled2": 42, - "promiseNone": Object { - "type": "promise", - "value": undefined, - }, - "promiseNoneWithArg": Object { - "type": "promise", - "value": undefined, - }, - "promiseSingleAsyncWithArg": Object { - "type": "promise", - "value": 42, - }, - "promiseSingleAsyncWithArgCalled1": 42, - "promiseSinglePromiseWithArg": Object { - "type": "promise", - "value": 43, - }, - "promiseSinglePromiseWithArgCalled1": 42, - "promiseSinglePromiseWithEmptyReject": Object { - "error": "Tap function (tapPromise) rejects \\"\\" value", - "type": "promise", - }, - "promiseSinglePromiseWithEmptyStringArg": Object { - "type": "promise", - "value": "", - }, - "promiseSinglePromiseWithEmptyStringArgCalled1": 42, - "promiseSinglePromiseWithFalseReject": Object { - "error": "Tap function (tapPromise) rejects \\"false\\" value", - "type": "promise", - }, - "promiseSinglePromiseWithNullArg": Object { - "type": "promise", - "value": null, - }, - "promiseSinglePromiseWithNullArgCalled1": 42, - "promiseSinglePromiseWithNullReject": Object { - "error": "Tap function (tapPromise) rejects \\"null\\" value", - "type": "promise", - }, - "promiseSinglePromiseWithUndefined": Object { - "type": "promise", - "value": undefined, - }, - "promiseSinglePromiseWithUndefinedCalled1": 42, - "promiseSinglePromiseWithUndefinedReject": Object { - "error": "Tap function (tapPromise) rejects \\"undefined\\" value", - "type": "promise", - }, - "promiseSinglePromiseWithZeroArg": Object { - "type": "promise", - "value": 0, - }, - "promiseSinglePromiseWithZeroArgCalled1": 42, - "promiseSinglePromiseWithZeroReject": Object { - "error": "Tap function (tapPromise) rejects \\"0\\" value", - "type": "promise", - }, - "promiseSingleSync": Object { - "type": "promise", - "value": 42, - }, - "promiseSingleSyncCalled1": true, - "promiseSingleSyncWithArg": Object { - "type": "promise", - "value": 43, - }, - "promiseSingleSyncWithArgCalled1": 42, - "promiseSingleSyncWithArgNoReturn": Object { - "type": "promise", - "value": undefined, - }, - "promiseSingleSyncWithArgNoReturnCalled1": 42, - }, - "intercept": Object { - "callAsyncContextIntercepted": Object { - "type": "async", - "value": 48, - }, - "callAsyncContextInterceptedCall1": Array [ - Object { - "number": 42, - }, - 1, - 2, - 3, - ], - "callAsyncContextInterceptedCall2": Array [ - 1, - 2, - 3, - ], - "callAsyncContextInterceptedTap1": Object { - "number": 42, - }, - "callAsyncIntercepted": Object { - "type": "async", - "value": 6, - }, - "callAsyncInterceptedCall1": Array [ - 1, - 2, - 3, - ], - "callAsyncInterceptedCall2": Array [ - 1, - 2, - 3, - ], - "callAsyncInterceptedResult1": 6, - "callAsyncInterceptedResult2": 6, - "callAsyncInterceptedTap1": Object { - "fn": 3, - "name": "sync", - "type": "sync", - }, - "callAsyncInterceptedTap2": Object { - "fn": 3, - "name": "sync", - "type": "sync", - }, - "callAsyncUnusedContextIntercepted": Object { - "type": "async", - "value": 6, - }, - "callAsyncUnusedContextInterceptedCall1": Array [ - undefined, - 1, - 2, - 3, - ], - "callAsyncUnusedContextInterceptedCall2": Array [ - 1, - 2, - 3, - ], - "callAsyncUnusedContextInterceptedTap1": undefined, - "promiseContextIntercepted": Object { - "type": "promise", - "value": 48, - }, - "promiseContextInterceptedCall1": Array [ - Object { - "number": 42, - }, - 1, - 2, - 3, - ], - "promiseContextInterceptedCall2": Array [ - 1, - 2, - 3, - ], - "promiseContextInterceptedTap1": Object { - "number": 42, - }, - "promiseIntercepted": Object { - "type": "promise", - "value": 6, - }, - "promiseInterceptedCall1": Array [ - 1, - 2, - 3, - ], - "promiseInterceptedCall2": Array [ - 1, - 2, - 3, - ], - "promiseInterceptedResult1": 6, - "promiseInterceptedResult2": 6, - "promiseInterceptedTap1": Object { - "fn": 3, - "name": "sync", - "type": "sync", - }, - "promiseInterceptedTap2": Object { - "fn": 3, - "name": "sync", - "type": "sync", - }, - "promiseUnusedContextIntercepted": Object { - "type": "promise", - "value": 6, - }, - "promiseUnusedContextInterceptedCall1": Array [ - undefined, - 1, - 2, - 3, - ], - "promiseUnusedContextInterceptedCall2": Array [ - 1, - 2, - 3, - ], - "promiseUnusedContextInterceptedTap1": undefined, - }, - "sync": Object { - "callAsyncIntercepted": Object { - "type": "async", - "value": 6, - }, - "callAsyncInterceptedCall1": Array [ - 1, - 2, - 3, - ], - "callAsyncInterceptedCall2": Array [ - 1, - 2, - 3, - ], - "callAsyncInterceptedTap1": Object { - "fn": 3, - "name": "sync1", - "type": "sync", - }, - "callAsyncInterceptedTap2": Object { - "fn": 3, - "name": "sync1", - "type": "sync", - }, - "callAsyncMultipleSync": Object { - "type": "async", - "value": 42, - }, - "callAsyncMultipleSyncCalled1": true, - "callAsyncMultipleSyncError": Object { - "error": "Error in sync2", - "type": "async", - }, - "callAsyncMultipleSyncErrorCalled1": true, - "callAsyncMultipleSyncErrorCalled2": true, - "callAsyncMultipleSyncWithArg": Object { - "type": "async", - "value": 84, - }, - "callAsyncMultipleSyncWithArgCalled1": 42, - "callAsyncMultipleSyncWithArgFirstReturn": Object { - "type": "async", - "value": 84, - }, - "callAsyncMultipleSyncWithArgFirstReturnCalled1": 42, - "callAsyncMultipleSyncWithArgLastReturn": Object { - "type": "async", - "value": 85, - }, - "callAsyncMultipleSyncWithArgLastReturnCalled1": 42, - "callAsyncMultipleSyncWithArgLastReturnCalled2": 42, - "callAsyncMultipleSyncWithArgNoReturn": Object { - "type": "async", - "value": undefined, - }, - "callAsyncMultipleSyncWithArgNoReturnCalled1": 42, - "callAsyncMultipleSyncWithArgNoReturnCalled2": 42, - "callAsyncMultipleSyncWithArgs": Object { - "type": "async", - "value": 129, - }, - "callAsyncMultipleSyncWithArgsCalled1": Array [ - 42, - 43, - 44, - ], - "callAsyncNone": Object { - "type": "async", - "value": undefined, - }, - "callAsyncNoneWithArg": Object { - "type": "async", - "value": undefined, - }, - "callAsyncSingleSync": Object { - "type": "async", - "value": 42, - }, - "callAsyncSingleSyncCalled": true, - "callAsyncSingleSyncWithArg": Object { - "type": "async", - "value": 42, - }, - "callAsyncSingleSyncWithArgCalled": 42, - "promiseIntercepted": Object { - "type": "promise", - "value": 6, - }, - "promiseInterceptedCall1": Array [ - 1, - 2, - 3, - ], - "promiseInterceptedCall2": Array [ - 1, - 2, - 3, - ], - "promiseInterceptedTap1": Object { - "fn": 3, - "name": "sync1", - "type": "sync", - }, - "promiseInterceptedTap2": Object { - "fn": 3, - "name": "sync1", - "type": "sync", - }, - "promiseMultipleSync": Object { - "type": "promise", - "value": 42, - }, - "promiseMultipleSyncCalled1": true, - "promiseMultipleSyncError": Object { - "error": "Error in sync2", - "type": "promise", - }, - "promiseMultipleSyncErrorCalled1": true, - "promiseMultipleSyncErrorCalled2": true, - "promiseMultipleSyncWithArg": Object { - "type": "promise", - "value": 84, - }, - "promiseMultipleSyncWithArgCalled1": 42, - "promiseMultipleSyncWithArgFirstReturn": Object { - "type": "promise", - "value": 84, - }, - "promiseMultipleSyncWithArgFirstReturnCalled1": 42, - "promiseMultipleSyncWithArgLastReturn": Object { - "type": "promise", - "value": 85, - }, - "promiseMultipleSyncWithArgLastReturnCalled1": 42, - "promiseMultipleSyncWithArgLastReturnCalled2": 42, - "promiseMultipleSyncWithArgNoReturn": Object { - "type": "promise", - "value": undefined, - }, - "promiseMultipleSyncWithArgNoReturnCalled1": 42, - "promiseMultipleSyncWithArgNoReturnCalled2": 42, - "promiseMultipleSyncWithArgs": Object { - "type": "promise", - "value": 129, - }, - "promiseMultipleSyncWithArgsCalled1": Array [ - 42, - 43, - 44, - ], - "promiseNone": Object { - "type": "promise", - "value": undefined, - }, - "promiseNoneWithArg": Object { - "type": "promise", - "value": undefined, - }, - "promiseSingleSync": Object { - "type": "promise", - "value": 42, - }, - "promiseSingleSyncCalled": true, - "promiseSingleSyncWithArg": Object { - "type": "promise", - "value": 42, - }, - "promiseSingleSyncWithArgCalled": 42, - }, -} -`; - exports[`AsyncParallelHook should have to correct behavior 1`] = ` Object { "async": Object { diff --git a/test/__snapshots__/AsyncSeriesBailHook.test.js.snap b/test/__snapshots__/AsyncSeriesBailHook.test.js.snap new file mode 100644 index 0000000..f9c4986 --- /dev/null +++ b/test/__snapshots__/AsyncSeriesBailHook.test.js.snap @@ -0,0 +1,776 @@ +// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing + +exports[`AsyncSeriesBailHook should have to correct behavior 1`] = ` +Object { + "async": Object { + "callAsyncMultipleAsyncEarlyError": Object { + "error": "Error in async2", + "type": "async", + }, + "callAsyncMultipleAsyncEarlyErrorCalled1": true, + "callAsyncMultipleAsyncError": Object { + "error": "Error in async2", + "type": "async", + }, + "callAsyncMultipleAsyncErrorCalled1": true, + "callAsyncMultipleAsyncLateError": Object { + "error": "Error in async2", + "type": "async", + }, + "callAsyncMultipleAsyncLateErrorCalled1": true, + "callAsyncMultipleAsyncLateErrorEarlyResult1": Object { + "error": "Error in async2", + "type": "async", + }, + "callAsyncMultipleAsyncLateErrorEarlyResult1Called1": true, + "callAsyncMultipleAsyncLateErrorEarlyResult2": Object { + "type": "async", + "value": 42, + }, + "callAsyncMultipleAsyncLateErrorEarlyResult2Called1": true, + "callAsyncMultipleAsyncWithArg": Object { + "type": "async", + "value": 43, + }, + "callAsyncMultipleAsyncWithArgCalled1": 42, + "callAsyncMultipleAsyncWithArgFirstReturn": Object { + "type": "async", + "value": 43, + }, + "callAsyncMultipleAsyncWithArgFirstReturnCalled1": 42, + "callAsyncMultipleAsyncWithArgLastReturn": Object { + "type": "async", + "value": 44, + }, + "callAsyncMultipleAsyncWithArgLastReturnCalled1": 42, + "callAsyncMultipleAsyncWithArgLastReturnCalled2": 42, + "callAsyncMultipleAsyncWithArgNoReturn": Object { + "type": "async", + "value": undefined, + }, + "callAsyncMultipleAsyncWithArgNoReturnCalled1": 42, + "callAsyncMultipleAsyncWithArgNoReturnCalled2": 42, + "callAsyncMultipleMixed1WithArg": Object { + "type": "async", + "value": 43, + }, + "callAsyncMultipleMixed1WithArgCalled1": 42, + "callAsyncMultipleMixed2WithArg": Object { + "type": "async", + "value": 43, + }, + "callAsyncMultipleMixed2WithArgCalled1": 42, + "callAsyncMultipleMixed3WithArg": Object { + "type": "async", + "value": 43, + }, + "callAsyncMultipleMixed3WithArgCalled1": 42, + "callAsyncMultipleMixedError1WithArg": Object { + "type": "async", + "value": 42, + }, + "callAsyncMultipleMixedError1WithArgCalled1": 42, + "callAsyncMultipleMixedError2WithArg": Object { + "type": "async", + "value": 42, + }, + "callAsyncMultipleMixedError2WithArgCalled1": 42, + "callAsyncMultipleMixedError3WithArg": Object { + "error": "Error in async", + "type": "async", + }, + "callAsyncMultipleMixedError3WithArgCalled1": 42, + "callAsyncMultipleMixedLateError": Object { + "error": "Error in async", + "type": "async", + }, + "callAsyncMultipleMixedLateErrorCalled1": true, + "callAsyncMultiplePromiseEarlyError": Object { + "error": "Error in async2", + "type": "async", + }, + "callAsyncMultiplePromiseEarlyErrorCalled1": true, + "callAsyncMultiplePromiseError": Object { + "error": "Error in async2", + "type": "async", + }, + "callAsyncMultiplePromiseErrorCalled1": true, + "callAsyncMultiplePromiseLateError": Object { + "error": "Error in async2", + "type": "async", + }, + "callAsyncMultiplePromiseLateErrorCalled1": true, + "callAsyncMultiplePromiseWithArg": Object { + "type": "async", + "value": 43, + }, + "callAsyncMultiplePromiseWithArgCalled1": 42, + "callAsyncMultiplePromiseWithArgFirstReturn": Object { + "type": "async", + "value": 43, + }, + "callAsyncMultiplePromiseWithArgFirstReturnCalled1": 42, + "callAsyncMultiplePromiseWithArgLastReturn": Object { + "type": "async", + "value": 44, + }, + "callAsyncMultiplePromiseWithArgLastReturnCalled1": 42, + "callAsyncMultiplePromiseWithArgLastReturnCalled2": 42, + "callAsyncMultiplePromiseWithArgNoReturn": Object { + "type": "async", + "value": undefined, + }, + "callAsyncMultiplePromiseWithArgNoReturnCalled1": 42, + "callAsyncMultiplePromiseWithArgNoReturnCalled2": 42, + "callAsyncMultipleSync": Object { + "type": "async", + "value": 42, + }, + "callAsyncMultipleSyncCalled1": true, + "callAsyncMultipleSyncError": Object { + "error": "Error in sync2", + "type": "async", + }, + "callAsyncMultipleSyncErrorCalled1": true, + "callAsyncMultipleSyncLastReturn": Object { + "type": "async", + "value": 43, + }, + "callAsyncMultipleSyncLastReturnCalled1": true, + "callAsyncMultipleSyncLastReturnCalled2": true, + "callAsyncMultipleSyncNoReturn": Object { + "type": "async", + "value": undefined, + }, + "callAsyncMultipleSyncNoReturnCalled1": true, + "callAsyncMultipleSyncNoReturnCalled2": true, + "callAsyncMultipleSyncWithArg": Object { + "type": "async", + "value": 43, + }, + "callAsyncMultipleSyncWithArgCalled1": 42, + "callAsyncMultipleSyncWithArgFirstReturn": Object { + "type": "async", + "value": 43, + }, + "callAsyncMultipleSyncWithArgFirstReturnCalled1": 42, + "callAsyncMultipleSyncWithArgLastReturn": Object { + "type": "async", + "value": 44, + }, + "callAsyncMultipleSyncWithArgLastReturnCalled1": 42, + "callAsyncMultipleSyncWithArgLastReturnCalled2": 42, + "callAsyncMultipleSyncWithArgNoReturn": Object { + "type": "async", + "value": undefined, + }, + "callAsyncMultipleSyncWithArgNoReturnCalled1": 42, + "callAsyncMultipleSyncWithArgNoReturnCalled2": 42, + "callAsyncNone": Object { + "type": "async", + "value": undefined, + }, + "callAsyncNoneWithArg": Object { + "type": "async", + "value": undefined, + }, + "callAsyncSingleAsyncWithArg": Object { + "type": "async", + "value": 42, + }, + "callAsyncSingleAsyncWithArgCalled1": 42, + "callAsyncSinglePromiseWithArg": Object { + "type": "async", + "value": 43, + }, + "callAsyncSinglePromiseWithArgCalled1": 42, + "callAsyncSinglePromiseWithEmptyReject": Object { + "error": "Tap function (tapPromise) rejects \\"\\" value", + "type": "async", + }, + "callAsyncSinglePromiseWithEmptyStringArg": Object { + "type": "async", + "value": "", + }, + "callAsyncSinglePromiseWithEmptyStringArgCalled1": 42, + "callAsyncSinglePromiseWithFalseReject": Object { + "error": "Tap function (tapPromise) rejects \\"false\\" value", + "type": "async", + }, + "callAsyncSinglePromiseWithNullArg": Object { + "type": "async", + "value": null, + }, + "callAsyncSinglePromiseWithNullArgCalled1": 42, + "callAsyncSinglePromiseWithNullReject": Object { + "error": "Tap function (tapPromise) rejects \\"null\\" value", + "type": "async", + }, + "callAsyncSinglePromiseWithUndefined": Object { + "type": "async", + "value": undefined, + }, + "callAsyncSinglePromiseWithUndefinedCalled1": 42, + "callAsyncSinglePromiseWithUndefinedReject": Object { + "error": "Tap function (tapPromise) rejects \\"undefined\\" value", + "type": "async", + }, + "callAsyncSinglePromiseWithZeroArg": Object { + "type": "async", + "value": 0, + }, + "callAsyncSinglePromiseWithZeroArgCalled1": 42, + "callAsyncSinglePromiseWithZeroReject": Object { + "error": "Tap function (tapPromise) rejects \\"0\\" value", + "type": "async", + }, + "callAsyncSingleSync": Object { + "type": "async", + "value": 42, + }, + "callAsyncSingleSyncCalled1": true, + "callAsyncSingleSyncWithArg": Object { + "type": "async", + "value": 43, + }, + "callAsyncSingleSyncWithArgCalled1": 42, + "callAsyncSingleSyncWithArgNoReturn": Object { + "type": "async", + "value": undefined, + }, + "callAsyncSingleSyncWithArgNoReturnCalled1": 42, + "promiseMultipleAsyncEarlyError": Object { + "error": "Error in async2", + "type": "promise", + }, + "promiseMultipleAsyncEarlyErrorCalled1": true, + "promiseMultipleAsyncError": Object { + "error": "Error in async2", + "type": "promise", + }, + "promiseMultipleAsyncErrorCalled1": true, + "promiseMultipleAsyncLateError": Object { + "error": "Error in async2", + "type": "promise", + }, + "promiseMultipleAsyncLateErrorCalled1": true, + "promiseMultipleAsyncLateErrorEarlyResult1": Object { + "error": "Error in async2", + "type": "promise", + }, + "promiseMultipleAsyncLateErrorEarlyResult1Called1": true, + "promiseMultipleAsyncLateErrorEarlyResult2": Object { + "type": "promise", + "value": 42, + }, + "promiseMultipleAsyncLateErrorEarlyResult2Called1": true, + "promiseMultipleAsyncWithArg": Object { + "type": "promise", + "value": 43, + }, + "promiseMultipleAsyncWithArgCalled1": 42, + "promiseMultipleAsyncWithArgFirstReturn": Object { + "type": "promise", + "value": 43, + }, + "promiseMultipleAsyncWithArgFirstReturnCalled1": 42, + "promiseMultipleAsyncWithArgLastReturn": Object { + "type": "promise", + "value": 44, + }, + "promiseMultipleAsyncWithArgLastReturnCalled1": 42, + "promiseMultipleAsyncWithArgLastReturnCalled2": 42, + "promiseMultipleAsyncWithArgNoReturn": Object { + "type": "promise", + "value": undefined, + }, + "promiseMultipleAsyncWithArgNoReturnCalled1": 42, + "promiseMultipleAsyncWithArgNoReturnCalled2": 42, + "promiseMultipleMixed1WithArg": Object { + "type": "promise", + "value": 43, + }, + "promiseMultipleMixed1WithArgCalled1": 42, + "promiseMultipleMixed2WithArg": Object { + "type": "promise", + "value": 43, + }, + "promiseMultipleMixed2WithArgCalled1": 42, + "promiseMultipleMixed3WithArg": Object { + "type": "promise", + "value": 43, + }, + "promiseMultipleMixed3WithArgCalled1": 42, + "promiseMultipleMixedError1WithArg": Object { + "type": "promise", + "value": 42, + }, + "promiseMultipleMixedError1WithArgCalled1": 42, + "promiseMultipleMixedError2WithArg": Object { + "type": "promise", + "value": 42, + }, + "promiseMultipleMixedError2WithArgCalled1": 42, + "promiseMultipleMixedError3WithArg": Object { + "error": "Error in async", + "type": "promise", + }, + "promiseMultipleMixedError3WithArgCalled1": 42, + "promiseMultipleMixedLateError": Object { + "error": "Error in async", + "type": "promise", + }, + "promiseMultipleMixedLateErrorCalled1": true, + "promiseMultiplePromiseEarlyError": Object { + "error": "Error in async2", + "type": "promise", + }, + "promiseMultiplePromiseEarlyErrorCalled1": true, + "promiseMultiplePromiseError": Object { + "error": "Error in async2", + "type": "promise", + }, + "promiseMultiplePromiseErrorCalled1": true, + "promiseMultiplePromiseLateError": Object { + "error": "Error in async2", + "type": "promise", + }, + "promiseMultiplePromiseLateErrorCalled1": true, + "promiseMultiplePromiseWithArg": Object { + "type": "promise", + "value": 43, + }, + "promiseMultiplePromiseWithArgCalled1": 42, + "promiseMultiplePromiseWithArgFirstReturn": Object { + "type": "promise", + "value": 43, + }, + "promiseMultiplePromiseWithArgFirstReturnCalled1": 42, + "promiseMultiplePromiseWithArgLastReturn": Object { + "type": "promise", + "value": 44, + }, + "promiseMultiplePromiseWithArgLastReturnCalled1": 42, + "promiseMultiplePromiseWithArgLastReturnCalled2": 42, + "promiseMultiplePromiseWithArgNoReturn": Object { + "type": "promise", + "value": undefined, + }, + "promiseMultiplePromiseWithArgNoReturnCalled1": 42, + "promiseMultiplePromiseWithArgNoReturnCalled2": 42, + "promiseMultipleSync": Object { + "type": "promise", + "value": 42, + }, + "promiseMultipleSyncCalled1": true, + "promiseMultipleSyncError": Object { + "error": "Error in sync2", + "type": "promise", + }, + "promiseMultipleSyncErrorCalled1": true, + "promiseMultipleSyncLastReturn": Object { + "type": "promise", + "value": 43, + }, + "promiseMultipleSyncLastReturnCalled1": true, + "promiseMultipleSyncLastReturnCalled2": true, + "promiseMultipleSyncNoReturn": Object { + "type": "promise", + "value": undefined, + }, + "promiseMultipleSyncNoReturnCalled1": true, + "promiseMultipleSyncNoReturnCalled2": true, + "promiseMultipleSyncWithArg": Object { + "type": "promise", + "value": 43, + }, + "promiseMultipleSyncWithArgCalled1": 42, + "promiseMultipleSyncWithArgFirstReturn": Object { + "type": "promise", + "value": 43, + }, + "promiseMultipleSyncWithArgFirstReturnCalled1": 42, + "promiseMultipleSyncWithArgLastReturn": Object { + "type": "promise", + "value": 44, + }, + "promiseMultipleSyncWithArgLastReturnCalled1": 42, + "promiseMultipleSyncWithArgLastReturnCalled2": 42, + "promiseMultipleSyncWithArgNoReturn": Object { + "type": "promise", + "value": undefined, + }, + "promiseMultipleSyncWithArgNoReturnCalled1": 42, + "promiseMultipleSyncWithArgNoReturnCalled2": 42, + "promiseNone": Object { + "type": "promise", + "value": undefined, + }, + "promiseNoneWithArg": Object { + "type": "promise", + "value": undefined, + }, + "promiseSingleAsyncWithArg": Object { + "type": "promise", + "value": 42, + }, + "promiseSingleAsyncWithArgCalled1": 42, + "promiseSinglePromiseWithArg": Object { + "type": "promise", + "value": 43, + }, + "promiseSinglePromiseWithArgCalled1": 42, + "promiseSinglePromiseWithEmptyReject": Object { + "error": "Tap function (tapPromise) rejects \\"\\" value", + "type": "promise", + }, + "promiseSinglePromiseWithEmptyStringArg": Object { + "type": "promise", + "value": "", + }, + "promiseSinglePromiseWithEmptyStringArgCalled1": 42, + "promiseSinglePromiseWithFalseReject": Object { + "error": "Tap function (tapPromise) rejects \\"false\\" value", + "type": "promise", + }, + "promiseSinglePromiseWithNullArg": Object { + "type": "promise", + "value": null, + }, + "promiseSinglePromiseWithNullArgCalled1": 42, + "promiseSinglePromiseWithNullReject": Object { + "error": "Tap function (tapPromise) rejects \\"null\\" value", + "type": "promise", + }, + "promiseSinglePromiseWithUndefined": Object { + "type": "promise", + "value": undefined, + }, + "promiseSinglePromiseWithUndefinedCalled1": 42, + "promiseSinglePromiseWithUndefinedReject": Object { + "error": "Tap function (tapPromise) rejects \\"undefined\\" value", + "type": "promise", + }, + "promiseSinglePromiseWithZeroArg": Object { + "type": "promise", + "value": 0, + }, + "promiseSinglePromiseWithZeroArgCalled1": 42, + "promiseSinglePromiseWithZeroReject": Object { + "error": "Tap function (tapPromise) rejects \\"0\\" value", + "type": "promise", + }, + "promiseSingleSync": Object { + "type": "promise", + "value": 42, + }, + "promiseSingleSyncCalled1": true, + "promiseSingleSyncWithArg": Object { + "type": "promise", + "value": 43, + }, + "promiseSingleSyncWithArgCalled1": 42, + "promiseSingleSyncWithArgNoReturn": Object { + "type": "promise", + "value": undefined, + }, + "promiseSingleSyncWithArgNoReturnCalled1": 42, + }, + "intercept": Object { + "callAsyncContextIntercepted": Object { + "type": "async", + "value": 48, + }, + "callAsyncContextInterceptedCall1": Array [ + Object { + "number": 42, + }, + 1, + 2, + 3, + ], + "callAsyncContextInterceptedCall2": Array [ + 1, + 2, + 3, + ], + "callAsyncContextInterceptedTap1": Object { + "number": 42, + }, + "callAsyncIntercepted": Object { + "type": "async", + "value": 6, + }, + "callAsyncInterceptedCall1": Array [ + 1, + 2, + 3, + ], + "callAsyncInterceptedCall2": Array [ + 1, + 2, + 3, + ], + "callAsyncInterceptedResult1": 6, + "callAsyncInterceptedResult2": 6, + "callAsyncInterceptedTap1": Object { + "fn": 3, + "name": "sync", + "type": "sync", + }, + "callAsyncInterceptedTap2": Object { + "fn": 3, + "name": "sync", + "type": "sync", + }, + "callAsyncUnusedContextIntercepted": Object { + "type": "async", + "value": 6, + }, + "callAsyncUnusedContextInterceptedCall1": Array [ + undefined, + 1, + 2, + 3, + ], + "callAsyncUnusedContextInterceptedCall2": Array [ + 1, + 2, + 3, + ], + "callAsyncUnusedContextInterceptedTap1": undefined, + "promiseContextIntercepted": Object { + "type": "promise", + "value": 48, + }, + "promiseContextInterceptedCall1": Array [ + Object { + "number": 42, + }, + 1, + 2, + 3, + ], + "promiseContextInterceptedCall2": Array [ + 1, + 2, + 3, + ], + "promiseContextInterceptedTap1": Object { + "number": 42, + }, + "promiseIntercepted": Object { + "type": "promise", + "value": 6, + }, + "promiseInterceptedCall1": Array [ + 1, + 2, + 3, + ], + "promiseInterceptedCall2": Array [ + 1, + 2, + 3, + ], + "promiseInterceptedResult1": 6, + "promiseInterceptedResult2": 6, + "promiseInterceptedTap1": Object { + "fn": 3, + "name": "sync", + "type": "sync", + }, + "promiseInterceptedTap2": Object { + "fn": 3, + "name": "sync", + "type": "sync", + }, + "promiseUnusedContextIntercepted": Object { + "type": "promise", + "value": 6, + }, + "promiseUnusedContextInterceptedCall1": Array [ + undefined, + 1, + 2, + 3, + ], + "promiseUnusedContextInterceptedCall2": Array [ + 1, + 2, + 3, + ], + "promiseUnusedContextInterceptedTap1": undefined, + }, + "sync": Object { + "callAsyncIntercepted": Object { + "type": "async", + "value": 6, + }, + "callAsyncInterceptedCall1": Array [ + 1, + 2, + 3, + ], + "callAsyncInterceptedCall2": Array [ + 1, + 2, + 3, + ], + "callAsyncInterceptedTap1": Object { + "fn": 3, + "name": "sync1", + "type": "sync", + }, + "callAsyncInterceptedTap2": Object { + "fn": 3, + "name": "sync1", + "type": "sync", + }, + "callAsyncMultipleSync": Object { + "type": "async", + "value": 42, + }, + "callAsyncMultipleSyncCalled1": true, + "callAsyncMultipleSyncError": Object { + "error": "Error in sync2", + "type": "async", + }, + "callAsyncMultipleSyncErrorCalled1": true, + "callAsyncMultipleSyncErrorCalled2": true, + "callAsyncMultipleSyncWithArg": Object { + "type": "async", + "value": 84, + }, + "callAsyncMultipleSyncWithArgCalled1": 42, + "callAsyncMultipleSyncWithArgFirstReturn": Object { + "type": "async", + "value": 84, + }, + "callAsyncMultipleSyncWithArgFirstReturnCalled1": 42, + "callAsyncMultipleSyncWithArgLastReturn": Object { + "type": "async", + "value": 85, + }, + "callAsyncMultipleSyncWithArgLastReturnCalled1": 42, + "callAsyncMultipleSyncWithArgLastReturnCalled2": 42, + "callAsyncMultipleSyncWithArgNoReturn": Object { + "type": "async", + "value": undefined, + }, + "callAsyncMultipleSyncWithArgNoReturnCalled1": 42, + "callAsyncMultipleSyncWithArgNoReturnCalled2": 42, + "callAsyncMultipleSyncWithArgs": Object { + "type": "async", + "value": 129, + }, + "callAsyncMultipleSyncWithArgsCalled1": Array [ + 42, + 43, + 44, + ], + "callAsyncNone": Object { + "type": "async", + "value": undefined, + }, + "callAsyncNoneWithArg": Object { + "type": "async", + "value": undefined, + }, + "callAsyncSingleSync": Object { + "type": "async", + "value": 42, + }, + "callAsyncSingleSyncCalled": true, + "callAsyncSingleSyncWithArg": Object { + "type": "async", + "value": 42, + }, + "callAsyncSingleSyncWithArgCalled": 42, + "promiseIntercepted": Object { + "type": "promise", + "value": 6, + }, + "promiseInterceptedCall1": Array [ + 1, + 2, + 3, + ], + "promiseInterceptedCall2": Array [ + 1, + 2, + 3, + ], + "promiseInterceptedTap1": Object { + "fn": 3, + "name": "sync1", + "type": "sync", + }, + "promiseInterceptedTap2": Object { + "fn": 3, + "name": "sync1", + "type": "sync", + }, + "promiseMultipleSync": Object { + "type": "promise", + "value": 42, + }, + "promiseMultipleSyncCalled1": true, + "promiseMultipleSyncError": Object { + "error": "Error in sync2", + "type": "promise", + }, + "promiseMultipleSyncErrorCalled1": true, + "promiseMultipleSyncErrorCalled2": true, + "promiseMultipleSyncWithArg": Object { + "type": "promise", + "value": 84, + }, + "promiseMultipleSyncWithArgCalled1": 42, + "promiseMultipleSyncWithArgFirstReturn": Object { + "type": "promise", + "value": 84, + }, + "promiseMultipleSyncWithArgFirstReturnCalled1": 42, + "promiseMultipleSyncWithArgLastReturn": Object { + "type": "promise", + "value": 85, + }, + "promiseMultipleSyncWithArgLastReturnCalled1": 42, + "promiseMultipleSyncWithArgLastReturnCalled2": 42, + "promiseMultipleSyncWithArgNoReturn": Object { + "type": "promise", + "value": undefined, + }, + "promiseMultipleSyncWithArgNoReturnCalled1": 42, + "promiseMultipleSyncWithArgNoReturnCalled2": 42, + "promiseMultipleSyncWithArgs": Object { + "type": "promise", + "value": 129, + }, + "promiseMultipleSyncWithArgsCalled1": Array [ + 42, + 43, + 44, + ], + "promiseNone": Object { + "type": "promise", + "value": undefined, + }, + "promiseNoneWithArg": Object { + "type": "promise", + "value": undefined, + }, + "promiseSingleSync": Object { + "type": "promise", + "value": 42, + }, + "promiseSingleSyncCalled": true, + "promiseSingleSyncWithArg": Object { + "type": "promise", + "value": 42, + }, + "promiseSingleSyncWithArgCalled": 42, + }, +} +`; diff --git a/test/__snapshots__/AsyncSeriesHooks.test.js.snap b/test/__snapshots__/AsyncSeriesHooks.test.js.snap index 8f68dc3..03a11bf 100644 --- a/test/__snapshots__/AsyncSeriesHooks.test.js.snap +++ b/test/__snapshots__/AsyncSeriesHooks.test.js.snap @@ -1,6 +1,6 @@ // Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing -exports[`AsyncSeriesBailHook should have to correct behavior 1`] = ` +exports[`AsyncSeriesHook should have to correct behavior 1`] = ` Object { "async": Object { "callAsyncMultipleAsyncEarlyError": Object { @@ -24,23 +24,25 @@ Object { }, "callAsyncMultipleAsyncLateErrorEarlyResult1Called1": true, "callAsyncMultipleAsyncLateErrorEarlyResult2": Object { + "error": "Error in async2", "type": "async", - "value": 42, }, "callAsyncMultipleAsyncLateErrorEarlyResult2Called1": true, "callAsyncMultipleAsyncWithArg": Object { "type": "async", - "value": 43, + "value": undefined, }, "callAsyncMultipleAsyncWithArgCalled1": 42, + "callAsyncMultipleAsyncWithArgCalled2": 42, "callAsyncMultipleAsyncWithArgFirstReturn": Object { "type": "async", - "value": 43, + "value": undefined, }, "callAsyncMultipleAsyncWithArgFirstReturnCalled1": 42, + "callAsyncMultipleAsyncWithArgFirstReturnCalled2": 42, "callAsyncMultipleAsyncWithArgLastReturn": Object { "type": "async", - "value": 44, + "value": undefined, }, "callAsyncMultipleAsyncWithArgLastReturnCalled1": 42, "callAsyncMultipleAsyncWithArgLastReturnCalled2": 42, @@ -52,29 +54,37 @@ Object { "callAsyncMultipleAsyncWithArgNoReturnCalled2": 42, "callAsyncMultipleMixed1WithArg": Object { "type": "async", - "value": 43, + "value": undefined, }, "callAsyncMultipleMixed1WithArgCalled1": 42, + "callAsyncMultipleMixed1WithArgCalled2": 42, + "callAsyncMultipleMixed1WithArgCalled3": 42, "callAsyncMultipleMixed2WithArg": Object { "type": "async", - "value": 43, + "value": undefined, }, "callAsyncMultipleMixed2WithArgCalled1": 42, + "callAsyncMultipleMixed2WithArgCalled2": 42, "callAsyncMultipleMixed3WithArg": Object { "type": "async", - "value": 43, + "value": undefined, }, "callAsyncMultipleMixed3WithArgCalled1": 42, + "callAsyncMultipleMixed3WithArgCalled2": 42, + "callAsyncMultipleMixed3WithArgCalled3": 42, "callAsyncMultipleMixedError1WithArg": Object { + "error": "Error in sync", "type": "async", - "value": 42, }, "callAsyncMultipleMixedError1WithArgCalled1": 42, + "callAsyncMultipleMixedError1WithArgCalled2": 42, + "callAsyncMultipleMixedError1WithArgCalled3": 42, "callAsyncMultipleMixedError2WithArg": Object { + "error": "Error in promise", "type": "async", - "value": 42, }, "callAsyncMultipleMixedError2WithArgCalled1": 42, + "callAsyncMultipleMixedError2WithArgCalled2": 42, "callAsyncMultipleMixedError3WithArg": Object { "error": "Error in async", "type": "async", @@ -102,17 +112,19 @@ Object { "callAsyncMultiplePromiseLateErrorCalled1": true, "callAsyncMultiplePromiseWithArg": Object { "type": "async", - "value": 43, + "value": undefined, }, "callAsyncMultiplePromiseWithArgCalled1": 42, + "callAsyncMultiplePromiseWithArgCalled2": 42, "callAsyncMultiplePromiseWithArgFirstReturn": Object { "type": "async", - "value": 43, + "value": undefined, }, "callAsyncMultiplePromiseWithArgFirstReturnCalled1": 42, + "callAsyncMultiplePromiseWithArgFirstReturnCalled2": 42, "callAsyncMultiplePromiseWithArgLastReturn": Object { "type": "async", - "value": 44, + "value": undefined, }, "callAsyncMultiplePromiseWithArgLastReturnCalled1": 42, "callAsyncMultiplePromiseWithArgLastReturnCalled2": 42, @@ -124,9 +136,10 @@ Object { "callAsyncMultiplePromiseWithArgNoReturnCalled2": 42, "callAsyncMultipleSync": Object { "type": "async", - "value": 42, + "value": undefined, }, "callAsyncMultipleSyncCalled1": true, + "callAsyncMultipleSyncCalled2": true, "callAsyncMultipleSyncError": Object { "error": "Error in sync2", "type": "async", @@ -134,7 +147,7 @@ Object { "callAsyncMultipleSyncErrorCalled1": true, "callAsyncMultipleSyncLastReturn": Object { "type": "async", - "value": 43, + "value": undefined, }, "callAsyncMultipleSyncLastReturnCalled1": true, "callAsyncMultipleSyncLastReturnCalled2": true, @@ -146,17 +159,19 @@ Object { "callAsyncMultipleSyncNoReturnCalled2": true, "callAsyncMultipleSyncWithArg": Object { "type": "async", - "value": 43, + "value": undefined, }, "callAsyncMultipleSyncWithArgCalled1": 42, + "callAsyncMultipleSyncWithArgCalled2": 42, "callAsyncMultipleSyncWithArgFirstReturn": Object { "type": "async", - "value": 43, + "value": undefined, }, "callAsyncMultipleSyncWithArgFirstReturnCalled1": 42, + "callAsyncMultipleSyncWithArgFirstReturnCalled2": 42, "callAsyncMultipleSyncWithArgLastReturn": Object { "type": "async", - "value": 44, + "value": undefined, }, "callAsyncMultipleSyncWithArgLastReturnCalled1": 42, "callAsyncMultipleSyncWithArgLastReturnCalled2": 42, @@ -176,12 +191,12 @@ Object { }, "callAsyncSingleAsyncWithArg": Object { "type": "async", - "value": 42, + "value": undefined, }, "callAsyncSingleAsyncWithArgCalled1": 42, "callAsyncSinglePromiseWithArg": Object { "type": "async", - "value": 43, + "value": undefined, }, "callAsyncSinglePromiseWithArgCalled1": 42, "callAsyncSinglePromiseWithEmptyReject": Object { @@ -190,7 +205,7 @@ Object { }, "callAsyncSinglePromiseWithEmptyStringArg": Object { "type": "async", - "value": "", + "value": undefined, }, "callAsyncSinglePromiseWithEmptyStringArgCalled1": 42, "callAsyncSinglePromiseWithFalseReject": Object { @@ -199,7 +214,7 @@ Object { }, "callAsyncSinglePromiseWithNullArg": Object { "type": "async", - "value": null, + "value": undefined, }, "callAsyncSinglePromiseWithNullArgCalled1": 42, "callAsyncSinglePromiseWithNullReject": Object { @@ -217,7 +232,7 @@ Object { }, "callAsyncSinglePromiseWithZeroArg": Object { "type": "async", - "value": 0, + "value": undefined, }, "callAsyncSinglePromiseWithZeroArgCalled1": 42, "callAsyncSinglePromiseWithZeroReject": Object { @@ -226,12 +241,12 @@ Object { }, "callAsyncSingleSync": Object { "type": "async", - "value": 42, + "value": undefined, }, "callAsyncSingleSyncCalled1": true, "callAsyncSingleSyncWithArg": Object { "type": "async", - "value": 43, + "value": undefined, }, "callAsyncSingleSyncWithArgCalled1": 42, "callAsyncSingleSyncWithArgNoReturn": Object { @@ -260,23 +275,25 @@ Object { }, "promiseMultipleAsyncLateErrorEarlyResult1Called1": true, "promiseMultipleAsyncLateErrorEarlyResult2": Object { + "error": "Error in async2", "type": "promise", - "value": 42, }, "promiseMultipleAsyncLateErrorEarlyResult2Called1": true, "promiseMultipleAsyncWithArg": Object { "type": "promise", - "value": 43, + "value": undefined, }, "promiseMultipleAsyncWithArgCalled1": 42, + "promiseMultipleAsyncWithArgCalled2": 42, "promiseMultipleAsyncWithArgFirstReturn": Object { "type": "promise", - "value": 43, + "value": undefined, }, "promiseMultipleAsyncWithArgFirstReturnCalled1": 42, + "promiseMultipleAsyncWithArgFirstReturnCalled2": 42, "promiseMultipleAsyncWithArgLastReturn": Object { "type": "promise", - "value": 44, + "value": undefined, }, "promiseMultipleAsyncWithArgLastReturnCalled1": 42, "promiseMultipleAsyncWithArgLastReturnCalled2": 42, @@ -288,29 +305,37 @@ Object { "promiseMultipleAsyncWithArgNoReturnCalled2": 42, "promiseMultipleMixed1WithArg": Object { "type": "promise", - "value": 43, + "value": undefined, }, "promiseMultipleMixed1WithArgCalled1": 42, + "promiseMultipleMixed1WithArgCalled2": 42, + "promiseMultipleMixed1WithArgCalled3": 42, "promiseMultipleMixed2WithArg": Object { "type": "promise", - "value": 43, + "value": undefined, }, "promiseMultipleMixed2WithArgCalled1": 42, + "promiseMultipleMixed2WithArgCalled2": 42, "promiseMultipleMixed3WithArg": Object { "type": "promise", - "value": 43, + "value": undefined, }, "promiseMultipleMixed3WithArgCalled1": 42, + "promiseMultipleMixed3WithArgCalled2": 42, + "promiseMultipleMixed3WithArgCalled3": 42, "promiseMultipleMixedError1WithArg": Object { + "error": "Error in sync", "type": "promise", - "value": 42, }, "promiseMultipleMixedError1WithArgCalled1": 42, + "promiseMultipleMixedError1WithArgCalled2": 42, + "promiseMultipleMixedError1WithArgCalled3": 42, "promiseMultipleMixedError2WithArg": Object { + "error": "Error in promise", "type": "promise", - "value": 42, }, "promiseMultipleMixedError2WithArgCalled1": 42, + "promiseMultipleMixedError2WithArgCalled2": 42, "promiseMultipleMixedError3WithArg": Object { "error": "Error in async", "type": "promise", @@ -338,17 +363,19 @@ Object { "promiseMultiplePromiseLateErrorCalled1": true, "promiseMultiplePromiseWithArg": Object { "type": "promise", - "value": 43, + "value": undefined, }, "promiseMultiplePromiseWithArgCalled1": 42, + "promiseMultiplePromiseWithArgCalled2": 42, "promiseMultiplePromiseWithArgFirstReturn": Object { "type": "promise", - "value": 43, + "value": undefined, }, "promiseMultiplePromiseWithArgFirstReturnCalled1": 42, + "promiseMultiplePromiseWithArgFirstReturnCalled2": 42, "promiseMultiplePromiseWithArgLastReturn": Object { "type": "promise", - "value": 44, + "value": undefined, }, "promiseMultiplePromiseWithArgLastReturnCalled1": 42, "promiseMultiplePromiseWithArgLastReturnCalled2": 42, @@ -360,9 +387,10 @@ Object { "promiseMultiplePromiseWithArgNoReturnCalled2": 42, "promiseMultipleSync": Object { "type": "promise", - "value": 42, + "value": undefined, }, "promiseMultipleSyncCalled1": true, + "promiseMultipleSyncCalled2": true, "promiseMultipleSyncError": Object { "error": "Error in sync2", "type": "promise", @@ -370,7 +398,7 @@ Object { "promiseMultipleSyncErrorCalled1": true, "promiseMultipleSyncLastReturn": Object { "type": "promise", - "value": 43, + "value": undefined, }, "promiseMultipleSyncLastReturnCalled1": true, "promiseMultipleSyncLastReturnCalled2": true, @@ -382,17 +410,19 @@ Object { "promiseMultipleSyncNoReturnCalled2": true, "promiseMultipleSyncWithArg": Object { "type": "promise", - "value": 43, + "value": undefined, }, "promiseMultipleSyncWithArgCalled1": 42, + "promiseMultipleSyncWithArgCalled2": 42, "promiseMultipleSyncWithArgFirstReturn": Object { "type": "promise", - "value": 43, + "value": undefined, }, "promiseMultipleSyncWithArgFirstReturnCalled1": 42, + "promiseMultipleSyncWithArgFirstReturnCalled2": 42, "promiseMultipleSyncWithArgLastReturn": Object { "type": "promise", - "value": 44, + "value": undefined, }, "promiseMultipleSyncWithArgLastReturnCalled1": 42, "promiseMultipleSyncWithArgLastReturnCalled2": 42, @@ -412,12 +442,12 @@ Object { }, "promiseSingleAsyncWithArg": Object { "type": "promise", - "value": 42, + "value": undefined, }, "promiseSingleAsyncWithArgCalled1": 42, "promiseSinglePromiseWithArg": Object { "type": "promise", - "value": 43, + "value": undefined, }, "promiseSinglePromiseWithArgCalled1": 42, "promiseSinglePromiseWithEmptyReject": Object { @@ -426,7 +456,7 @@ Object { }, "promiseSinglePromiseWithEmptyStringArg": Object { "type": "promise", - "value": "", + "value": undefined, }, "promiseSinglePromiseWithEmptyStringArgCalled1": 42, "promiseSinglePromiseWithFalseReject": Object { @@ -435,7 +465,7 @@ Object { }, "promiseSinglePromiseWithNullArg": Object { "type": "promise", - "value": null, + "value": undefined, }, "promiseSinglePromiseWithNullArgCalled1": 42, "promiseSinglePromiseWithNullReject": Object { @@ -453,7 +483,7 @@ Object { }, "promiseSinglePromiseWithZeroArg": Object { "type": "promise", - "value": 0, + "value": undefined, }, "promiseSinglePromiseWithZeroArgCalled1": 42, "promiseSinglePromiseWithZeroReject": Object { @@ -462,12 +492,12 @@ Object { }, "promiseSingleSync": Object { "type": "promise", - "value": 42, + "value": undefined, }, "promiseSingleSyncCalled1": true, "promiseSingleSyncWithArg": Object { "type": "promise", - "value": 43, + "value": undefined, }, "promiseSingleSyncWithArgCalled1": 42, "promiseSingleSyncWithArgNoReturn": Object { @@ -479,7 +509,7 @@ Object { "intercept": Object { "callAsyncContextIntercepted": Object { "type": "async", - "value": 48, + "value": undefined, }, "callAsyncContextInterceptedCall1": Array [ Object { @@ -499,7 +529,7 @@ Object { }, "callAsyncIntercepted": Object { "type": "async", - "value": 6, + "value": undefined, }, "callAsyncInterceptedCall1": Array [ 1, @@ -511,12 +541,12 @@ Object { 2, 3, ], - "callAsyncInterceptedResult1": 6, - "callAsyncInterceptedResult2": 6, + "callAsyncInterceptedDone1": true, + "callAsyncInterceptedDone2": true, "callAsyncInterceptedTap1": Object { - "fn": 3, - "name": "sync", - "type": "sync", + "fn": 2, + "name": "promise", + "type": "promise", }, "callAsyncInterceptedTap2": Object { "fn": 3, @@ -525,7 +555,7 @@ Object { }, "callAsyncUnusedContextIntercepted": Object { "type": "async", - "value": 6, + "value": undefined, }, "callAsyncUnusedContextInterceptedCall1": Array [ undefined, @@ -541,7 +571,7 @@ Object { "callAsyncUnusedContextInterceptedTap1": undefined, "promiseContextIntercepted": Object { "type": "promise", - "value": 48, + "value": undefined, }, "promiseContextInterceptedCall1": Array [ Object { @@ -561,7 +591,7 @@ Object { }, "promiseIntercepted": Object { "type": "promise", - "value": 6, + "value": undefined, }, "promiseInterceptedCall1": Array [ 1, @@ -573,12 +603,12 @@ Object { 2, 3, ], - "promiseInterceptedResult1": 6, - "promiseInterceptedResult2": 6, + "promiseInterceptedDone1": true, + "promiseInterceptedDone2": true, "promiseInterceptedTap1": Object { - "fn": 3, - "name": "sync", - "type": "sync", + "fn": 2, + "name": "promise", + "type": "promise", }, "promiseInterceptedTap2": Object { "fn": 3, @@ -587,7 +617,7 @@ Object { }, "promiseUnusedContextIntercepted": Object { "type": "promise", - "value": 6, + "value": undefined, }, "promiseUnusedContextInterceptedCall1": Array [ undefined, @@ -605,7 +635,7 @@ Object { "sync": Object { "callAsyncIntercepted": Object { "type": "async", - "value": 6, + "value": undefined, }, "callAsyncInterceptedCall1": Array [ 1, @@ -618,8 +648,8 @@ Object { 3, ], "callAsyncInterceptedTap1": Object { - "fn": 3, - "name": "sync1", + "fn": 2, + "name": "sync2", "type": "sync", }, "callAsyncInterceptedTap2": Object { @@ -629,9 +659,10 @@ Object { }, "callAsyncMultipleSync": Object { "type": "async", - "value": 42, + "value": undefined, }, "callAsyncMultipleSyncCalled1": true, + "callAsyncMultipleSyncCalled2": true, "callAsyncMultipleSyncError": Object { "error": "Error in sync2", "type": "async", @@ -640,17 +671,19 @@ Object { "callAsyncMultipleSyncErrorCalled2": true, "callAsyncMultipleSyncWithArg": Object { "type": "async", - "value": 84, + "value": undefined, }, "callAsyncMultipleSyncWithArgCalled1": 42, + "callAsyncMultipleSyncWithArgCalled2": 42, "callAsyncMultipleSyncWithArgFirstReturn": Object { "type": "async", - "value": 84, + "value": undefined, }, "callAsyncMultipleSyncWithArgFirstReturnCalled1": 42, + "callAsyncMultipleSyncWithArgFirstReturnCalled2": 42, "callAsyncMultipleSyncWithArgLastReturn": Object { "type": "async", - "value": 85, + "value": undefined, }, "callAsyncMultipleSyncWithArgLastReturnCalled1": 42, "callAsyncMultipleSyncWithArgLastReturnCalled2": 42, @@ -662,13 +695,18 @@ Object { "callAsyncMultipleSyncWithArgNoReturnCalled2": 42, "callAsyncMultipleSyncWithArgs": Object { "type": "async", - "value": 129, + "value": undefined, }, "callAsyncMultipleSyncWithArgsCalled1": Array [ 42, 43, 44, ], + "callAsyncMultipleSyncWithArgsCalled2": Array [ + 42, + 43, + 44, + ], "callAsyncNone": Object { "type": "async", "value": undefined, @@ -679,17 +717,17 @@ Object { }, "callAsyncSingleSync": Object { "type": "async", - "value": 42, + "value": undefined, }, "callAsyncSingleSyncCalled": true, "callAsyncSingleSyncWithArg": Object { "type": "async", - "value": 42, + "value": undefined, }, "callAsyncSingleSyncWithArgCalled": 42, "promiseIntercepted": Object { "type": "promise", - "value": 6, + "value": undefined, }, "promiseInterceptedCall1": Array [ 1, @@ -702,8 +740,8 @@ Object { 3, ], "promiseInterceptedTap1": Object { - "fn": 3, - "name": "sync1", + "fn": 2, + "name": "sync2", "type": "sync", }, "promiseInterceptedTap2": Object { @@ -713,9 +751,10 @@ Object { }, "promiseMultipleSync": Object { "type": "promise", - "value": 42, + "value": undefined, }, "promiseMultipleSyncCalled1": true, + "promiseMultipleSyncCalled2": true, "promiseMultipleSyncError": Object { "error": "Error in sync2", "type": "promise", @@ -724,17 +763,19 @@ Object { "promiseMultipleSyncErrorCalled2": true, "promiseMultipleSyncWithArg": Object { "type": "promise", - "value": 84, + "value": undefined, }, "promiseMultipleSyncWithArgCalled1": 42, + "promiseMultipleSyncWithArgCalled2": 42, "promiseMultipleSyncWithArgFirstReturn": Object { "type": "promise", - "value": 84, + "value": undefined, }, "promiseMultipleSyncWithArgFirstReturnCalled1": 42, + "promiseMultipleSyncWithArgFirstReturnCalled2": 42, "promiseMultipleSyncWithArgLastReturn": Object { "type": "promise", - "value": 85, + "value": undefined, }, "promiseMultipleSyncWithArgLastReturnCalled1": 42, "promiseMultipleSyncWithArgLastReturnCalled2": 42, @@ -746,13 +787,18 @@ Object { "promiseMultipleSyncWithArgNoReturnCalled2": 42, "promiseMultipleSyncWithArgs": Object { "type": "promise", - "value": 129, + "value": undefined, }, "promiseMultipleSyncWithArgsCalled1": Array [ 42, 43, 44, ], + "promiseMultipleSyncWithArgsCalled2": Array [ + 42, + 43, + 44, + ], "promiseNone": Object { "type": "promise", "value": undefined, @@ -763,1703 +809,13 @@ Object { }, "promiseSingleSync": Object { "type": "promise", - "value": 42, + "value": undefined, }, "promiseSingleSyncCalled": true, "promiseSingleSyncWithArg": Object { "type": "promise", - "value": 42, - }, - "promiseSingleSyncWithArgCalled": 42, - }, -} -`; - -exports[`AsyncSeriesHook should have to correct behavior 1`] = ` -Object { - "async": Object { - "callAsyncMultipleAsyncEarlyError": Object { - "error": "Error in async2", - "type": "async", - }, - "callAsyncMultipleAsyncEarlyErrorCalled1": true, - "callAsyncMultipleAsyncError": Object { - "error": "Error in async2", - "type": "async", - }, - "callAsyncMultipleAsyncErrorCalled1": true, - "callAsyncMultipleAsyncLateError": Object { - "error": "Error in async2", - "type": "async", - }, - "callAsyncMultipleAsyncLateErrorCalled1": true, - "callAsyncMultipleAsyncLateErrorEarlyResult1": Object { - "error": "Error in async2", - "type": "async", - }, - "callAsyncMultipleAsyncLateErrorEarlyResult1Called1": true, - "callAsyncMultipleAsyncLateErrorEarlyResult2": Object { - "error": "Error in async2", - "type": "async", - }, - "callAsyncMultipleAsyncLateErrorEarlyResult2Called1": true, - "callAsyncMultipleAsyncWithArg": Object { - "type": "async", - "value": undefined, - }, - "callAsyncMultipleAsyncWithArgCalled1": 42, - "callAsyncMultipleAsyncWithArgCalled2": 42, - "callAsyncMultipleAsyncWithArgFirstReturn": Object { - "type": "async", - "value": undefined, - }, - "callAsyncMultipleAsyncWithArgFirstReturnCalled1": 42, - "callAsyncMultipleAsyncWithArgFirstReturnCalled2": 42, - "callAsyncMultipleAsyncWithArgLastReturn": Object { - "type": "async", - "value": undefined, - }, - "callAsyncMultipleAsyncWithArgLastReturnCalled1": 42, - "callAsyncMultipleAsyncWithArgLastReturnCalled2": 42, - "callAsyncMultipleAsyncWithArgNoReturn": Object { - "type": "async", - "value": undefined, - }, - "callAsyncMultipleAsyncWithArgNoReturnCalled1": 42, - "callAsyncMultipleAsyncWithArgNoReturnCalled2": 42, - "callAsyncMultipleMixed1WithArg": Object { - "type": "async", - "value": undefined, - }, - "callAsyncMultipleMixed1WithArgCalled1": 42, - "callAsyncMultipleMixed1WithArgCalled2": 42, - "callAsyncMultipleMixed1WithArgCalled3": 42, - "callAsyncMultipleMixed2WithArg": Object { - "type": "async", - "value": undefined, - }, - "callAsyncMultipleMixed2WithArgCalled1": 42, - "callAsyncMultipleMixed2WithArgCalled2": 42, - "callAsyncMultipleMixed3WithArg": Object { - "type": "async", "value": undefined, }, - "callAsyncMultipleMixed3WithArgCalled1": 42, - "callAsyncMultipleMixed3WithArgCalled2": 42, - "callAsyncMultipleMixed3WithArgCalled3": 42, - "callAsyncMultipleMixedError1WithArg": Object { - "error": "Error in sync", - "type": "async", - }, - "callAsyncMultipleMixedError1WithArgCalled1": 42, - "callAsyncMultipleMixedError1WithArgCalled2": 42, - "callAsyncMultipleMixedError1WithArgCalled3": 42, - "callAsyncMultipleMixedError2WithArg": Object { - "error": "Error in promise", - "type": "async", - }, - "callAsyncMultipleMixedError2WithArgCalled1": 42, - "callAsyncMultipleMixedError2WithArgCalled2": 42, - "callAsyncMultipleMixedError3WithArg": Object { - "error": "Error in async", - "type": "async", - }, - "callAsyncMultipleMixedError3WithArgCalled1": 42, - "callAsyncMultipleMixedLateError": Object { - "error": "Error in async", - "type": "async", - }, - "callAsyncMultipleMixedLateErrorCalled1": true, - "callAsyncMultiplePromiseEarlyError": Object { - "error": "Error in async2", - "type": "async", - }, - "callAsyncMultiplePromiseEarlyErrorCalled1": true, - "callAsyncMultiplePromiseError": Object { - "error": "Error in async2", - "type": "async", - }, - "callAsyncMultiplePromiseErrorCalled1": true, - "callAsyncMultiplePromiseLateError": Object { - "error": "Error in async2", - "type": "async", - }, - "callAsyncMultiplePromiseLateErrorCalled1": true, - "callAsyncMultiplePromiseWithArg": Object { - "type": "async", - "value": undefined, - }, - "callAsyncMultiplePromiseWithArgCalled1": 42, - "callAsyncMultiplePromiseWithArgCalled2": 42, - "callAsyncMultiplePromiseWithArgFirstReturn": Object { - "type": "async", - "value": undefined, - }, - "callAsyncMultiplePromiseWithArgFirstReturnCalled1": 42, - "callAsyncMultiplePromiseWithArgFirstReturnCalled2": 42, - "callAsyncMultiplePromiseWithArgLastReturn": Object { - "type": "async", - "value": undefined, - }, - "callAsyncMultiplePromiseWithArgLastReturnCalled1": 42, - "callAsyncMultiplePromiseWithArgLastReturnCalled2": 42, - "callAsyncMultiplePromiseWithArgNoReturn": Object { - "type": "async", - "value": undefined, - }, - "callAsyncMultiplePromiseWithArgNoReturnCalled1": 42, - "callAsyncMultiplePromiseWithArgNoReturnCalled2": 42, - "callAsyncMultipleSync": Object { - "type": "async", - "value": undefined, - }, - "callAsyncMultipleSyncCalled1": true, - "callAsyncMultipleSyncCalled2": true, - "callAsyncMultipleSyncError": Object { - "error": "Error in sync2", - "type": "async", - }, - "callAsyncMultipleSyncErrorCalled1": true, - "callAsyncMultipleSyncLastReturn": Object { - "type": "async", - "value": undefined, - }, - "callAsyncMultipleSyncLastReturnCalled1": true, - "callAsyncMultipleSyncLastReturnCalled2": true, - "callAsyncMultipleSyncNoReturn": Object { - "type": "async", - "value": undefined, - }, - "callAsyncMultipleSyncNoReturnCalled1": true, - "callAsyncMultipleSyncNoReturnCalled2": true, - "callAsyncMultipleSyncWithArg": Object { - "type": "async", - "value": undefined, - }, - "callAsyncMultipleSyncWithArgCalled1": 42, - "callAsyncMultipleSyncWithArgCalled2": 42, - "callAsyncMultipleSyncWithArgFirstReturn": Object { - "type": "async", - "value": undefined, - }, - "callAsyncMultipleSyncWithArgFirstReturnCalled1": 42, - "callAsyncMultipleSyncWithArgFirstReturnCalled2": 42, - "callAsyncMultipleSyncWithArgLastReturn": Object { - "type": "async", - "value": undefined, - }, - "callAsyncMultipleSyncWithArgLastReturnCalled1": 42, - "callAsyncMultipleSyncWithArgLastReturnCalled2": 42, - "callAsyncMultipleSyncWithArgNoReturn": Object { - "type": "async", - "value": undefined, - }, - "callAsyncMultipleSyncWithArgNoReturnCalled1": 42, - "callAsyncMultipleSyncWithArgNoReturnCalled2": 42, - "callAsyncNone": Object { - "type": "async", - "value": undefined, - }, - "callAsyncNoneWithArg": Object { - "type": "async", - "value": undefined, - }, - "callAsyncSingleAsyncWithArg": Object { - "type": "async", - "value": undefined, - }, - "callAsyncSingleAsyncWithArgCalled1": 42, - "callAsyncSinglePromiseWithArg": Object { - "type": "async", - "value": undefined, - }, - "callAsyncSinglePromiseWithArgCalled1": 42, - "callAsyncSinglePromiseWithEmptyReject": Object { - "error": "Tap function (tapPromise) rejects \\"\\" value", - "type": "async", - }, - "callAsyncSinglePromiseWithEmptyStringArg": Object { - "type": "async", - "value": undefined, - }, - "callAsyncSinglePromiseWithEmptyStringArgCalled1": 42, - "callAsyncSinglePromiseWithFalseReject": Object { - "error": "Tap function (tapPromise) rejects \\"false\\" value", - "type": "async", - }, - "callAsyncSinglePromiseWithNullArg": Object { - "type": "async", - "value": undefined, - }, - "callAsyncSinglePromiseWithNullArgCalled1": 42, - "callAsyncSinglePromiseWithNullReject": Object { - "error": "Tap function (tapPromise) rejects \\"null\\" value", - "type": "async", - }, - "callAsyncSinglePromiseWithUndefined": Object { - "type": "async", - "value": undefined, - }, - "callAsyncSinglePromiseWithUndefinedCalled1": 42, - "callAsyncSinglePromiseWithUndefinedReject": Object { - "error": "Tap function (tapPromise) rejects \\"undefined\\" value", - "type": "async", - }, - "callAsyncSinglePromiseWithZeroArg": Object { - "type": "async", - "value": undefined, - }, - "callAsyncSinglePromiseWithZeroArgCalled1": 42, - "callAsyncSinglePromiseWithZeroReject": Object { - "error": "Tap function (tapPromise) rejects \\"0\\" value", - "type": "async", - }, - "callAsyncSingleSync": Object { - "type": "async", - "value": undefined, - }, - "callAsyncSingleSyncCalled1": true, - "callAsyncSingleSyncWithArg": Object { - "type": "async", - "value": undefined, - }, - "callAsyncSingleSyncWithArgCalled1": 42, - "callAsyncSingleSyncWithArgNoReturn": Object { - "type": "async", - "value": undefined, - }, - "callAsyncSingleSyncWithArgNoReturnCalled1": 42, - "promiseMultipleAsyncEarlyError": Object { - "error": "Error in async2", - "type": "promise", - }, - "promiseMultipleAsyncEarlyErrorCalled1": true, - "promiseMultipleAsyncError": Object { - "error": "Error in async2", - "type": "promise", - }, - "promiseMultipleAsyncErrorCalled1": true, - "promiseMultipleAsyncLateError": Object { - "error": "Error in async2", - "type": "promise", - }, - "promiseMultipleAsyncLateErrorCalled1": true, - "promiseMultipleAsyncLateErrorEarlyResult1": Object { - "error": "Error in async2", - "type": "promise", - }, - "promiseMultipleAsyncLateErrorEarlyResult1Called1": true, - "promiseMultipleAsyncLateErrorEarlyResult2": Object { - "error": "Error in async2", - "type": "promise", - }, - "promiseMultipleAsyncLateErrorEarlyResult2Called1": true, - "promiseMultipleAsyncWithArg": Object { - "type": "promise", - "value": undefined, - }, - "promiseMultipleAsyncWithArgCalled1": 42, - "promiseMultipleAsyncWithArgCalled2": 42, - "promiseMultipleAsyncWithArgFirstReturn": Object { - "type": "promise", - "value": undefined, - }, - "promiseMultipleAsyncWithArgFirstReturnCalled1": 42, - "promiseMultipleAsyncWithArgFirstReturnCalled2": 42, - "promiseMultipleAsyncWithArgLastReturn": Object { - "type": "promise", - "value": undefined, - }, - "promiseMultipleAsyncWithArgLastReturnCalled1": 42, - "promiseMultipleAsyncWithArgLastReturnCalled2": 42, - "promiseMultipleAsyncWithArgNoReturn": Object { - "type": "promise", - "value": undefined, - }, - "promiseMultipleAsyncWithArgNoReturnCalled1": 42, - "promiseMultipleAsyncWithArgNoReturnCalled2": 42, - "promiseMultipleMixed1WithArg": Object { - "type": "promise", - "value": undefined, - }, - "promiseMultipleMixed1WithArgCalled1": 42, - "promiseMultipleMixed1WithArgCalled2": 42, - "promiseMultipleMixed1WithArgCalled3": 42, - "promiseMultipleMixed2WithArg": Object { - "type": "promise", - "value": undefined, - }, - "promiseMultipleMixed2WithArgCalled1": 42, - "promiseMultipleMixed2WithArgCalled2": 42, - "promiseMultipleMixed3WithArg": Object { - "type": "promise", - "value": undefined, - }, - "promiseMultipleMixed3WithArgCalled1": 42, - "promiseMultipleMixed3WithArgCalled2": 42, - "promiseMultipleMixed3WithArgCalled3": 42, - "promiseMultipleMixedError1WithArg": Object { - "error": "Error in sync", - "type": "promise", - }, - "promiseMultipleMixedError1WithArgCalled1": 42, - "promiseMultipleMixedError1WithArgCalled2": 42, - "promiseMultipleMixedError1WithArgCalled3": 42, - "promiseMultipleMixedError2WithArg": Object { - "error": "Error in promise", - "type": "promise", - }, - "promiseMultipleMixedError2WithArgCalled1": 42, - "promiseMultipleMixedError2WithArgCalled2": 42, - "promiseMultipleMixedError3WithArg": Object { - "error": "Error in async", - "type": "promise", - }, - "promiseMultipleMixedError3WithArgCalled1": 42, - "promiseMultipleMixedLateError": Object { - "error": "Error in async", - "type": "promise", - }, - "promiseMultipleMixedLateErrorCalled1": true, - "promiseMultiplePromiseEarlyError": Object { - "error": "Error in async2", - "type": "promise", - }, - "promiseMultiplePromiseEarlyErrorCalled1": true, - "promiseMultiplePromiseError": Object { - "error": "Error in async2", - "type": "promise", - }, - "promiseMultiplePromiseErrorCalled1": true, - "promiseMultiplePromiseLateError": Object { - "error": "Error in async2", - "type": "promise", - }, - "promiseMultiplePromiseLateErrorCalled1": true, - "promiseMultiplePromiseWithArg": Object { - "type": "promise", - "value": undefined, - }, - "promiseMultiplePromiseWithArgCalled1": 42, - "promiseMultiplePromiseWithArgCalled2": 42, - "promiseMultiplePromiseWithArgFirstReturn": Object { - "type": "promise", - "value": undefined, - }, - "promiseMultiplePromiseWithArgFirstReturnCalled1": 42, - "promiseMultiplePromiseWithArgFirstReturnCalled2": 42, - "promiseMultiplePromiseWithArgLastReturn": Object { - "type": "promise", - "value": undefined, - }, - "promiseMultiplePromiseWithArgLastReturnCalled1": 42, - "promiseMultiplePromiseWithArgLastReturnCalled2": 42, - "promiseMultiplePromiseWithArgNoReturn": Object { - "type": "promise", - "value": undefined, - }, - "promiseMultiplePromiseWithArgNoReturnCalled1": 42, - "promiseMultiplePromiseWithArgNoReturnCalled2": 42, - "promiseMultipleSync": Object { - "type": "promise", - "value": undefined, - }, - "promiseMultipleSyncCalled1": true, - "promiseMultipleSyncCalled2": true, - "promiseMultipleSyncError": Object { - "error": "Error in sync2", - "type": "promise", - }, - "promiseMultipleSyncErrorCalled1": true, - "promiseMultipleSyncLastReturn": Object { - "type": "promise", - "value": undefined, - }, - "promiseMultipleSyncLastReturnCalled1": true, - "promiseMultipleSyncLastReturnCalled2": true, - "promiseMultipleSyncNoReturn": Object { - "type": "promise", - "value": undefined, - }, - "promiseMultipleSyncNoReturnCalled1": true, - "promiseMultipleSyncNoReturnCalled2": true, - "promiseMultipleSyncWithArg": Object { - "type": "promise", - "value": undefined, - }, - "promiseMultipleSyncWithArgCalled1": 42, - "promiseMultipleSyncWithArgCalled2": 42, - "promiseMultipleSyncWithArgFirstReturn": Object { - "type": "promise", - "value": undefined, - }, - "promiseMultipleSyncWithArgFirstReturnCalled1": 42, - "promiseMultipleSyncWithArgFirstReturnCalled2": 42, - "promiseMultipleSyncWithArgLastReturn": Object { - "type": "promise", - "value": undefined, - }, - "promiseMultipleSyncWithArgLastReturnCalled1": 42, - "promiseMultipleSyncWithArgLastReturnCalled2": 42, - "promiseMultipleSyncWithArgNoReturn": Object { - "type": "promise", - "value": undefined, - }, - "promiseMultipleSyncWithArgNoReturnCalled1": 42, - "promiseMultipleSyncWithArgNoReturnCalled2": 42, - "promiseNone": Object { - "type": "promise", - "value": undefined, - }, - "promiseNoneWithArg": Object { - "type": "promise", - "value": undefined, - }, - "promiseSingleAsyncWithArg": Object { - "type": "promise", - "value": undefined, - }, - "promiseSingleAsyncWithArgCalled1": 42, - "promiseSinglePromiseWithArg": Object { - "type": "promise", - "value": undefined, - }, - "promiseSinglePromiseWithArgCalled1": 42, - "promiseSinglePromiseWithEmptyReject": Object { - "error": "Tap function (tapPromise) rejects \\"\\" value", - "type": "promise", - }, - "promiseSinglePromiseWithEmptyStringArg": Object { - "type": "promise", - "value": undefined, - }, - "promiseSinglePromiseWithEmptyStringArgCalled1": 42, - "promiseSinglePromiseWithFalseReject": Object { - "error": "Tap function (tapPromise) rejects \\"false\\" value", - "type": "promise", - }, - "promiseSinglePromiseWithNullArg": Object { - "type": "promise", - "value": undefined, - }, - "promiseSinglePromiseWithNullArgCalled1": 42, - "promiseSinglePromiseWithNullReject": Object { - "error": "Tap function (tapPromise) rejects \\"null\\" value", - "type": "promise", - }, - "promiseSinglePromiseWithUndefined": Object { - "type": "promise", - "value": undefined, - }, - "promiseSinglePromiseWithUndefinedCalled1": 42, - "promiseSinglePromiseWithUndefinedReject": Object { - "error": "Tap function (tapPromise) rejects \\"undefined\\" value", - "type": "promise", - }, - "promiseSinglePromiseWithZeroArg": Object { - "type": "promise", - "value": undefined, - }, - "promiseSinglePromiseWithZeroArgCalled1": 42, - "promiseSinglePromiseWithZeroReject": Object { - "error": "Tap function (tapPromise) rejects \\"0\\" value", - "type": "promise", - }, - "promiseSingleSync": Object { - "type": "promise", - "value": undefined, - }, - "promiseSingleSyncCalled1": true, - "promiseSingleSyncWithArg": Object { - "type": "promise", - "value": undefined, - }, - "promiseSingleSyncWithArgCalled1": 42, - "promiseSingleSyncWithArgNoReturn": Object { - "type": "promise", - "value": undefined, - }, - "promiseSingleSyncWithArgNoReturnCalled1": 42, - }, - "intercept": Object { - "callAsyncContextIntercepted": Object { - "type": "async", - "value": undefined, - }, - "callAsyncContextInterceptedCall1": Array [ - Object { - "number": 42, - }, - 1, - 2, - 3, - ], - "callAsyncContextInterceptedCall2": Array [ - 1, - 2, - 3, - ], - "callAsyncContextInterceptedTap1": Object { - "number": 42, - }, - "callAsyncIntercepted": Object { - "type": "async", - "value": undefined, - }, - "callAsyncInterceptedCall1": Array [ - 1, - 2, - 3, - ], - "callAsyncInterceptedCall2": Array [ - 1, - 2, - 3, - ], - "callAsyncInterceptedDone1": true, - "callAsyncInterceptedDone2": true, - "callAsyncInterceptedTap1": Object { - "fn": 2, - "name": "promise", - "type": "promise", - }, - "callAsyncInterceptedTap2": Object { - "fn": 3, - "name": "sync", - "type": "sync", - }, - "callAsyncUnusedContextIntercepted": Object { - "type": "async", - "value": undefined, - }, - "callAsyncUnusedContextInterceptedCall1": Array [ - undefined, - 1, - 2, - 3, - ], - "callAsyncUnusedContextInterceptedCall2": Array [ - 1, - 2, - 3, - ], - "callAsyncUnusedContextInterceptedTap1": undefined, - "promiseContextIntercepted": Object { - "type": "promise", - "value": undefined, - }, - "promiseContextInterceptedCall1": Array [ - Object { - "number": 42, - }, - 1, - 2, - 3, - ], - "promiseContextInterceptedCall2": Array [ - 1, - 2, - 3, - ], - "promiseContextInterceptedTap1": Object { - "number": 42, - }, - "promiseIntercepted": Object { - "type": "promise", - "value": undefined, - }, - "promiseInterceptedCall1": Array [ - 1, - 2, - 3, - ], - "promiseInterceptedCall2": Array [ - 1, - 2, - 3, - ], - "promiseInterceptedDone1": true, - "promiseInterceptedDone2": true, - "promiseInterceptedTap1": Object { - "fn": 2, - "name": "promise", - "type": "promise", - }, - "promiseInterceptedTap2": Object { - "fn": 3, - "name": "sync", - "type": "sync", - }, - "promiseUnusedContextIntercepted": Object { - "type": "promise", - "value": undefined, - }, - "promiseUnusedContextInterceptedCall1": Array [ - undefined, - 1, - 2, - 3, - ], - "promiseUnusedContextInterceptedCall2": Array [ - 1, - 2, - 3, - ], - "promiseUnusedContextInterceptedTap1": undefined, - }, - "sync": Object { - "callAsyncIntercepted": Object { - "type": "async", - "value": undefined, - }, - "callAsyncInterceptedCall1": Array [ - 1, - 2, - 3, - ], - "callAsyncInterceptedCall2": Array [ - 1, - 2, - 3, - ], - "callAsyncInterceptedTap1": Object { - "fn": 2, - "name": "sync2", - "type": "sync", - }, - "callAsyncInterceptedTap2": Object { - "fn": 3, - "name": "sync1", - "type": "sync", - }, - "callAsyncMultipleSync": Object { - "type": "async", - "value": undefined, - }, - "callAsyncMultipleSyncCalled1": true, - "callAsyncMultipleSyncCalled2": true, - "callAsyncMultipleSyncError": Object { - "error": "Error in sync2", - "type": "async", - }, - "callAsyncMultipleSyncErrorCalled1": true, - "callAsyncMultipleSyncErrorCalled2": true, - "callAsyncMultipleSyncWithArg": Object { - "type": "async", - "value": undefined, - }, - "callAsyncMultipleSyncWithArgCalled1": 42, - "callAsyncMultipleSyncWithArgCalled2": 42, - "callAsyncMultipleSyncWithArgFirstReturn": Object { - "type": "async", - "value": undefined, - }, - "callAsyncMultipleSyncWithArgFirstReturnCalled1": 42, - "callAsyncMultipleSyncWithArgFirstReturnCalled2": 42, - "callAsyncMultipleSyncWithArgLastReturn": Object { - "type": "async", - "value": undefined, - }, - "callAsyncMultipleSyncWithArgLastReturnCalled1": 42, - "callAsyncMultipleSyncWithArgLastReturnCalled2": 42, - "callAsyncMultipleSyncWithArgNoReturn": Object { - "type": "async", - "value": undefined, - }, - "callAsyncMultipleSyncWithArgNoReturnCalled1": 42, - "callAsyncMultipleSyncWithArgNoReturnCalled2": 42, - "callAsyncMultipleSyncWithArgs": Object { - "type": "async", - "value": undefined, - }, - "callAsyncMultipleSyncWithArgsCalled1": Array [ - 42, - 43, - 44, - ], - "callAsyncMultipleSyncWithArgsCalled2": Array [ - 42, - 43, - 44, - ], - "callAsyncNone": Object { - "type": "async", - "value": undefined, - }, - "callAsyncNoneWithArg": Object { - "type": "async", - "value": undefined, - }, - "callAsyncSingleSync": Object { - "type": "async", - "value": undefined, - }, - "callAsyncSingleSyncCalled": true, - "callAsyncSingleSyncWithArg": Object { - "type": "async", - "value": undefined, - }, - "callAsyncSingleSyncWithArgCalled": 42, - "promiseIntercepted": Object { - "type": "promise", - "value": undefined, - }, - "promiseInterceptedCall1": Array [ - 1, - 2, - 3, - ], - "promiseInterceptedCall2": Array [ - 1, - 2, - 3, - ], - "promiseInterceptedTap1": Object { - "fn": 2, - "name": "sync2", - "type": "sync", - }, - "promiseInterceptedTap2": Object { - "fn": 3, - "name": "sync1", - "type": "sync", - }, - "promiseMultipleSync": Object { - "type": "promise", - "value": undefined, - }, - "promiseMultipleSyncCalled1": true, - "promiseMultipleSyncCalled2": true, - "promiseMultipleSyncError": Object { - "error": "Error in sync2", - "type": "promise", - }, - "promiseMultipleSyncErrorCalled1": true, - "promiseMultipleSyncErrorCalled2": true, - "promiseMultipleSyncWithArg": Object { - "type": "promise", - "value": undefined, - }, - "promiseMultipleSyncWithArgCalled1": 42, - "promiseMultipleSyncWithArgCalled2": 42, - "promiseMultipleSyncWithArgFirstReturn": Object { - "type": "promise", - "value": undefined, - }, - "promiseMultipleSyncWithArgFirstReturnCalled1": 42, - "promiseMultipleSyncWithArgFirstReturnCalled2": 42, - "promiseMultipleSyncWithArgLastReturn": Object { - "type": "promise", - "value": undefined, - }, - "promiseMultipleSyncWithArgLastReturnCalled1": 42, - "promiseMultipleSyncWithArgLastReturnCalled2": 42, - "promiseMultipleSyncWithArgNoReturn": Object { - "type": "promise", - "value": undefined, - }, - "promiseMultipleSyncWithArgNoReturnCalled1": 42, - "promiseMultipleSyncWithArgNoReturnCalled2": 42, - "promiseMultipleSyncWithArgs": Object { - "type": "promise", - "value": undefined, - }, - "promiseMultipleSyncWithArgsCalled1": Array [ - 42, - 43, - 44, - ], - "promiseMultipleSyncWithArgsCalled2": Array [ - 42, - 43, - 44, - ], - "promiseNone": Object { - "type": "promise", - "value": undefined, - }, - "promiseNoneWithArg": Object { - "type": "promise", - "value": undefined, - }, - "promiseSingleSync": Object { - "type": "promise", - "value": undefined, - }, - "promiseSingleSyncCalled": true, - "promiseSingleSyncWithArg": Object { - "type": "promise", - "value": undefined, - }, - "promiseSingleSyncWithArgCalled": 42, - }, -} -`; - -exports[`AsyncSeriesLoopHook should have to correct behavior 1`] = ` -Object { - "async": Object { - "callAsyncBrokenPromise": Object { - "error": "Tap function (tapPromise) did not return promise (returned this is not a promise)", - }, - "callAsyncMixed": Object { - "type": "async", - "value": undefined, - }, - "callAsyncMixedCalled1": 124, - "callAsyncMixedCalled2": 83, - "callAsyncMixedCalled3": 42, - "callAsyncMultipleAsync": Object { - "type": "async", - "value": undefined, - }, - "callAsyncMultipleAsyncCalled1": 83, - "callAsyncMultipleAsyncCalled2": 42, - "callAsyncMultiplePromise": Object { - "type": "async", - "value": undefined, - }, - "callAsyncMultiplePromiseCalled1": 83, - "callAsyncMultiplePromiseCalled2": 42, - "callAsyncSingleAsync": Object { - "type": "async", - "value": undefined, - }, - "callAsyncSingleAsyncCalled": 42, - "callAsyncSinglePromise": Object { - "type": "async", - "value": undefined, - }, - "callAsyncSinglePromiseCalled": 42, - "promiseBrokenPromise": Object { - "error": "Tap function (tapPromise) did not return promise (returned this is not a promise)", - "type": "promise", - }, - "promiseMixed": Object { - "type": "promise", - "value": undefined, - }, - "promiseMixedCalled1": 124, - "promiseMixedCalled2": 83, - "promiseMixedCalled3": 42, - "promiseMultipleAsync": Object { - "type": "promise", - "value": undefined, - }, - "promiseMultipleAsyncCalled1": 83, - "promiseMultipleAsyncCalled2": 42, - "promiseMultiplePromise": Object { - "type": "promise", - "value": undefined, - }, - "promiseMultiplePromiseCalled1": 83, - "promiseMultiplePromiseCalled2": 42, - "promiseSingleAsync": Object { - "type": "promise", - "value": undefined, - }, - "promiseSingleAsyncCalled": 42, - "promiseSinglePromise": Object { - "type": "promise", - "value": undefined, - }, - "promiseSinglePromiseCalled": 42, - }, - "sync": Object { - "callAsyncInterceptedSync": Object { - "type": "async", - "value": undefined, - }, - "callAsyncInterceptedSyncCalled1": 83, - "callAsyncInterceptedSyncCalled2": 42, - "callAsyncInterceptedSyncCalledCall": 1, - "callAsyncInterceptedSyncCalledLoop": 83, - "callAsyncInterceptedSyncCalledTap": 125, - "callAsyncMultipleSync": Object { - "type": "async", - "value": undefined, - }, - "callAsyncMultipleSyncCalled1": 83, - "callAsyncMultipleSyncCalled2": 42, - "callAsyncNone": Object { - "type": "async", - "value": undefined, - }, - "callAsyncNoneWithArg": Object { - "type": "async", - "value": undefined, - }, - "callAsyncSingleSync": Object { - "type": "async", - "value": undefined, - }, - "callAsyncSingleSyncCalled": 42, - "promiseInterceptedSync": Object { - "type": "promise", - "value": undefined, - }, - "promiseInterceptedSyncCalled1": 83, - "promiseInterceptedSyncCalled2": 42, - "promiseInterceptedSyncCalledCall": 1, - "promiseInterceptedSyncCalledLoop": 83, - "promiseInterceptedSyncCalledTap": 125, - "promiseMultipleSync": Object { - "type": "promise", - "value": undefined, - }, - "promiseMultipleSyncCalled1": 83, - "promiseMultipleSyncCalled2": 42, - "promiseNone": Object { - "type": "promise", - "value": undefined, - }, - "promiseNoneWithArg": Object { - "type": "promise", - "value": undefined, - }, - "promiseSingleSync": Object { - "type": "promise", - "value": undefined, - }, - "promiseSingleSyncCalled": 42, - }, -} -`; - -exports[`AsyncSeriesWaterfallHook should have to correct behavior 1`] = ` -Object { - "async": Object { - "callAsyncMultipleAsyncEarlyError": Object { - "error": "Waterfall hooks must have at least one argument", - }, - "callAsyncMultipleAsyncError": Object { - "error": "Waterfall hooks must have at least one argument", - }, - "callAsyncMultipleAsyncLateError": Object { - "error": "Waterfall hooks must have at least one argument", - }, - "callAsyncMultipleAsyncLateErrorEarlyResult1": Object { - "error": "Waterfall hooks must have at least one argument", - }, - "callAsyncMultipleAsyncLateErrorEarlyResult2": Object { - "error": "Waterfall hooks must have at least one argument", - }, - "callAsyncMultipleAsyncWithArg": Object { - "type": "async", - "value": 45, - }, - "callAsyncMultipleAsyncWithArgCalled1": 42, - "callAsyncMultipleAsyncWithArgCalled2": 43, - "callAsyncMultipleAsyncWithArgFirstReturn": Object { - "type": "async", - "value": 43, - }, - "callAsyncMultipleAsyncWithArgFirstReturnCalled1": 42, - "callAsyncMultipleAsyncWithArgFirstReturnCalled2": 43, - "callAsyncMultipleAsyncWithArgLastReturn": Object { - "type": "async", - "value": 44, - }, - "callAsyncMultipleAsyncWithArgLastReturnCalled1": 42, - "callAsyncMultipleAsyncWithArgLastReturnCalled2": 42, - "callAsyncMultipleAsyncWithArgNoReturn": Object { - "type": "async", - "value": 42, - }, - "callAsyncMultipleAsyncWithArgNoReturnCalled1": 42, - "callAsyncMultipleAsyncWithArgNoReturnCalled2": 42, - "callAsyncMultipleMixed1WithArg": Object { - "type": "async", - "value": 48, - }, - "callAsyncMultipleMixed1WithArgCalled1": 42, - "callAsyncMultipleMixed1WithArgCalled2": 43, - "callAsyncMultipleMixed1WithArgCalled3": 45, - "callAsyncMultipleMixed2WithArg": Object { - "type": "async", - "value": 45, - }, - "callAsyncMultipleMixed2WithArgCalled1": 42, - "callAsyncMultipleMixed2WithArgCalled2": 43, - "callAsyncMultipleMixed3WithArg": Object { - "type": "async", - "value": 48, - }, - "callAsyncMultipleMixed3WithArgCalled1": 42, - "callAsyncMultipleMixed3WithArgCalled2": 43, - "callAsyncMultipleMixed3WithArgCalled3": 45, - "callAsyncMultipleMixedError1WithArg": Object { - "error": "Error in sync", - "type": "async", - }, - "callAsyncMultipleMixedError1WithArgCalled1": 42, - "callAsyncMultipleMixedError1WithArgCalled2": 42, - "callAsyncMultipleMixedError1WithArgCalled3": 43, - "callAsyncMultipleMixedError2WithArg": Object { - "error": "Error in promise", - "type": "async", - }, - "callAsyncMultipleMixedError2WithArgCalled1": 42, - "callAsyncMultipleMixedError2WithArgCalled2": 42, - "callAsyncMultipleMixedError3WithArg": Object { - "error": "Error in async", - "type": "async", - }, - "callAsyncMultipleMixedError3WithArgCalled1": 42, - "callAsyncMultipleMixedLateError": Object { - "error": "Waterfall hooks must have at least one argument", - }, - "callAsyncMultiplePromiseEarlyError": Object { - "error": "Waterfall hooks must have at least one argument", - }, - "callAsyncMultiplePromiseError": Object { - "error": "Waterfall hooks must have at least one argument", - }, - "callAsyncMultiplePromiseLateError": Object { - "error": "Waterfall hooks must have at least one argument", - }, - "callAsyncMultiplePromiseWithArg": Object { - "type": "async", - "value": 45, - }, - "callAsyncMultiplePromiseWithArgCalled1": 42, - "callAsyncMultiplePromiseWithArgCalled2": 43, - "callAsyncMultiplePromiseWithArgFirstReturn": Object { - "type": "async", - "value": 43, - }, - "callAsyncMultiplePromiseWithArgFirstReturnCalled1": 42, - "callAsyncMultiplePromiseWithArgFirstReturnCalled2": 43, - "callAsyncMultiplePromiseWithArgLastReturn": Object { - "type": "async", - "value": 44, - }, - "callAsyncMultiplePromiseWithArgLastReturnCalled1": 42, - "callAsyncMultiplePromiseWithArgLastReturnCalled2": 42, - "callAsyncMultiplePromiseWithArgNoReturn": Object { - "type": "async", - "value": 42, - }, - "callAsyncMultiplePromiseWithArgNoReturnCalled1": 42, - "callAsyncMultiplePromiseWithArgNoReturnCalled2": 42, - "callAsyncMultipleSync": Object { - "error": "Waterfall hooks must have at least one argument", - }, - "callAsyncMultipleSyncError": Object { - "error": "Waterfall hooks must have at least one argument", - }, - "callAsyncMultipleSyncLastReturn": Object { - "error": "Waterfall hooks must have at least one argument", - }, - "callAsyncMultipleSyncNoReturn": Object { - "error": "Waterfall hooks must have at least one argument", - }, - "callAsyncMultipleSyncWithArg": Object { - "type": "async", - "value": 45, - }, - "callAsyncMultipleSyncWithArgCalled1": 42, - "callAsyncMultipleSyncWithArgCalled2": 43, - "callAsyncMultipleSyncWithArgFirstReturn": Object { - "type": "async", - "value": 43, - }, - "callAsyncMultipleSyncWithArgFirstReturnCalled1": 42, - "callAsyncMultipleSyncWithArgFirstReturnCalled2": 43, - "callAsyncMultipleSyncWithArgLastReturn": Object { - "type": "async", - "value": 44, - }, - "callAsyncMultipleSyncWithArgLastReturnCalled1": 42, - "callAsyncMultipleSyncWithArgLastReturnCalled2": 42, - "callAsyncMultipleSyncWithArgNoReturn": Object { - "type": "async", - "value": 42, - }, - "callAsyncMultipleSyncWithArgNoReturnCalled1": 42, - "callAsyncMultipleSyncWithArgNoReturnCalled2": 42, - "callAsyncNone": Object { - "error": "Waterfall hooks must have at least one argument", - }, - "callAsyncNoneWithArg": Object { - "type": "async", - "value": 42, - }, - "callAsyncSingleAsyncWithArg": Object { - "type": "async", - "value": 42, - }, - "callAsyncSingleAsyncWithArgCalled1": 42, - "callAsyncSinglePromiseWithArg": Object { - "type": "async", - "value": 43, - }, - "callAsyncSinglePromiseWithArgCalled1": 42, - "callAsyncSinglePromiseWithEmptyReject": Object { - "error": "Tap function (tapPromise) rejects \\"\\" value", - "type": "async", - }, - "callAsyncSinglePromiseWithEmptyStringArg": Object { - "type": "async", - "value": "", - }, - "callAsyncSinglePromiseWithEmptyStringArgCalled1": 42, - "callAsyncSinglePromiseWithFalseReject": Object { - "error": "Tap function (tapPromise) rejects \\"false\\" value", - "type": "async", - }, - "callAsyncSinglePromiseWithNullArg": Object { - "type": "async", - "value": null, - }, - "callAsyncSinglePromiseWithNullArgCalled1": 42, - "callAsyncSinglePromiseWithNullReject": Object { - "error": "Tap function (tapPromise) rejects \\"null\\" value", - "type": "async", - }, - "callAsyncSinglePromiseWithUndefined": Object { - "type": "async", - "value": 42, - }, - "callAsyncSinglePromiseWithUndefinedCalled1": 42, - "callAsyncSinglePromiseWithUndefinedReject": Object { - "error": "Tap function (tapPromise) rejects \\"undefined\\" value", - "type": "async", - }, - "callAsyncSinglePromiseWithZeroArg": Object { - "type": "async", - "value": 0, - }, - "callAsyncSinglePromiseWithZeroArgCalled1": 42, - "callAsyncSinglePromiseWithZeroReject": Object { - "error": "Tap function (tapPromise) rejects \\"0\\" value", - "type": "async", - }, - "callAsyncSingleSync": Object { - "error": "Waterfall hooks must have at least one argument", - }, - "callAsyncSingleSyncWithArg": Object { - "type": "async", - "value": 43, - }, - "callAsyncSingleSyncWithArgCalled1": 42, - "callAsyncSingleSyncWithArgNoReturn": Object { - "type": "async", - "value": 42, - }, - "callAsyncSingleSyncWithArgNoReturnCalled1": 42, - "promiseMultipleAsyncEarlyError": Object { - "error": "Waterfall hooks must have at least one argument", - }, - "promiseMultipleAsyncError": Object { - "error": "Waterfall hooks must have at least one argument", - }, - "promiseMultipleAsyncLateError": Object { - "error": "Waterfall hooks must have at least one argument", - }, - "promiseMultipleAsyncLateErrorEarlyResult1": Object { - "error": "Waterfall hooks must have at least one argument", - }, - "promiseMultipleAsyncLateErrorEarlyResult2": Object { - "error": "Waterfall hooks must have at least one argument", - }, - "promiseMultipleAsyncWithArg": Object { - "type": "promise", - "value": 45, - }, - "promiseMultipleAsyncWithArgCalled1": 42, - "promiseMultipleAsyncWithArgCalled2": 43, - "promiseMultipleAsyncWithArgFirstReturn": Object { - "type": "promise", - "value": 43, - }, - "promiseMultipleAsyncWithArgFirstReturnCalled1": 42, - "promiseMultipleAsyncWithArgFirstReturnCalled2": 43, - "promiseMultipleAsyncWithArgLastReturn": Object { - "type": "promise", - "value": 44, - }, - "promiseMultipleAsyncWithArgLastReturnCalled1": 42, - "promiseMultipleAsyncWithArgLastReturnCalled2": 42, - "promiseMultipleAsyncWithArgNoReturn": Object { - "type": "promise", - "value": 42, - }, - "promiseMultipleAsyncWithArgNoReturnCalled1": 42, - "promiseMultipleAsyncWithArgNoReturnCalled2": 42, - "promiseMultipleMixed1WithArg": Object { - "type": "promise", - "value": 48, - }, - "promiseMultipleMixed1WithArgCalled1": 42, - "promiseMultipleMixed1WithArgCalled2": 43, - "promiseMultipleMixed1WithArgCalled3": 45, - "promiseMultipleMixed2WithArg": Object { - "type": "promise", - "value": 45, - }, - "promiseMultipleMixed2WithArgCalled1": 42, - "promiseMultipleMixed2WithArgCalled2": 43, - "promiseMultipleMixed3WithArg": Object { - "type": "promise", - "value": 48, - }, - "promiseMultipleMixed3WithArgCalled1": 42, - "promiseMultipleMixed3WithArgCalled2": 43, - "promiseMultipleMixed3WithArgCalled3": 45, - "promiseMultipleMixedError1WithArg": Object { - "error": "Error in sync", - "type": "promise", - }, - "promiseMultipleMixedError1WithArgCalled1": 42, - "promiseMultipleMixedError1WithArgCalled2": 42, - "promiseMultipleMixedError1WithArgCalled3": 43, - "promiseMultipleMixedError2WithArg": Object { - "error": "Error in promise", - "type": "promise", - }, - "promiseMultipleMixedError2WithArgCalled1": 42, - "promiseMultipleMixedError2WithArgCalled2": 42, - "promiseMultipleMixedError3WithArg": Object { - "error": "Error in async", - "type": "promise", - }, - "promiseMultipleMixedError3WithArgCalled1": 42, - "promiseMultipleMixedLateError": Object { - "error": "Waterfall hooks must have at least one argument", - }, - "promiseMultiplePromiseEarlyError": Object { - "error": "Waterfall hooks must have at least one argument", - }, - "promiseMultiplePromiseError": Object { - "error": "Waterfall hooks must have at least one argument", - }, - "promiseMultiplePromiseLateError": Object { - "error": "Waterfall hooks must have at least one argument", - }, - "promiseMultiplePromiseWithArg": Object { - "type": "promise", - "value": 45, - }, - "promiseMultiplePromiseWithArgCalled1": 42, - "promiseMultiplePromiseWithArgCalled2": 43, - "promiseMultiplePromiseWithArgFirstReturn": Object { - "type": "promise", - "value": 43, - }, - "promiseMultiplePromiseWithArgFirstReturnCalled1": 42, - "promiseMultiplePromiseWithArgFirstReturnCalled2": 43, - "promiseMultiplePromiseWithArgLastReturn": Object { - "type": "promise", - "value": 44, - }, - "promiseMultiplePromiseWithArgLastReturnCalled1": 42, - "promiseMultiplePromiseWithArgLastReturnCalled2": 42, - "promiseMultiplePromiseWithArgNoReturn": Object { - "type": "promise", - "value": 42, - }, - "promiseMultiplePromiseWithArgNoReturnCalled1": 42, - "promiseMultiplePromiseWithArgNoReturnCalled2": 42, - "promiseMultipleSync": Object { - "error": "Waterfall hooks must have at least one argument", - }, - "promiseMultipleSyncError": Object { - "error": "Waterfall hooks must have at least one argument", - }, - "promiseMultipleSyncLastReturn": Object { - "error": "Waterfall hooks must have at least one argument", - }, - "promiseMultipleSyncNoReturn": Object { - "error": "Waterfall hooks must have at least one argument", - }, - "promiseMultipleSyncWithArg": Object { - "type": "promise", - "value": 45, - }, - "promiseMultipleSyncWithArgCalled1": 42, - "promiseMultipleSyncWithArgCalled2": 43, - "promiseMultipleSyncWithArgFirstReturn": Object { - "type": "promise", - "value": 43, - }, - "promiseMultipleSyncWithArgFirstReturnCalled1": 42, - "promiseMultipleSyncWithArgFirstReturnCalled2": 43, - "promiseMultipleSyncWithArgLastReturn": Object { - "type": "promise", - "value": 44, - }, - "promiseMultipleSyncWithArgLastReturnCalled1": 42, - "promiseMultipleSyncWithArgLastReturnCalled2": 42, - "promiseMultipleSyncWithArgNoReturn": Object { - "type": "promise", - "value": 42, - }, - "promiseMultipleSyncWithArgNoReturnCalled1": 42, - "promiseMultipleSyncWithArgNoReturnCalled2": 42, - "promiseNone": Object { - "error": "Waterfall hooks must have at least one argument", - }, - "promiseNoneWithArg": Object { - "type": "promise", - "value": 42, - }, - "promiseSingleAsyncWithArg": Object { - "type": "promise", - "value": 42, - }, - "promiseSingleAsyncWithArgCalled1": 42, - "promiseSinglePromiseWithArg": Object { - "type": "promise", - "value": 43, - }, - "promiseSinglePromiseWithArgCalled1": 42, - "promiseSinglePromiseWithEmptyReject": Object { - "error": "Tap function (tapPromise) rejects \\"\\" value", - "type": "promise", - }, - "promiseSinglePromiseWithEmptyStringArg": Object { - "type": "promise", - "value": "", - }, - "promiseSinglePromiseWithEmptyStringArgCalled1": 42, - "promiseSinglePromiseWithFalseReject": Object { - "error": "Tap function (tapPromise) rejects \\"false\\" value", - "type": "promise", - }, - "promiseSinglePromiseWithNullArg": Object { - "type": "promise", - "value": null, - }, - "promiseSinglePromiseWithNullArgCalled1": 42, - "promiseSinglePromiseWithNullReject": Object { - "error": "Tap function (tapPromise) rejects \\"null\\" value", - "type": "promise", - }, - "promiseSinglePromiseWithUndefined": Object { - "type": "promise", - "value": 42, - }, - "promiseSinglePromiseWithUndefinedCalled1": 42, - "promiseSinglePromiseWithUndefinedReject": Object { - "error": "Tap function (tapPromise) rejects \\"undefined\\" value", - "type": "promise", - }, - "promiseSinglePromiseWithZeroArg": Object { - "type": "promise", - "value": 0, - }, - "promiseSinglePromiseWithZeroArgCalled1": 42, - "promiseSinglePromiseWithZeroReject": Object { - "error": "Tap function (tapPromise) rejects \\"0\\" value", - "type": "promise", - }, - "promiseSingleSync": Object { - "error": "Waterfall hooks must have at least one argument", - }, - "promiseSingleSyncWithArg": Object { - "type": "promise", - "value": 43, - }, - "promiseSingleSyncWithArgCalled1": 42, - "promiseSingleSyncWithArgNoReturn": Object { - "type": "promise", - "value": 42, - }, - "promiseSingleSyncWithArgNoReturnCalled1": 42, - }, - "intercept": Object { - "callAsyncContextIntercepted": Object { - "type": "async", - "value": 48, - }, - "callAsyncContextInterceptedCall1": Array [ - Object { - "number": 42, - }, - 1, - 2, - 3, - ], - "callAsyncContextInterceptedCall2": Array [ - 1, - 2, - 3, - ], - "callAsyncContextInterceptedTap1": Object { - "number": 42, - }, - "callAsyncIntercepted": Object { - "type": "async", - "value": 9, - }, - "callAsyncInterceptedCall1": Array [ - 1, - 2, - 3, - ], - "callAsyncInterceptedCall2": Array [ - 1, - 2, - 3, - ], - "callAsyncInterceptedResult1": 9, - "callAsyncInterceptedResult2": 9, - "callAsyncInterceptedTap1": Object { - "fn": 2, - "name": "promise", - "type": "promise", - }, - "callAsyncInterceptedTap2": Object { - "fn": 3, - "name": "sync", - "type": "sync", - }, - "callAsyncUnusedContextIntercepted": Object { - "type": "async", - "value": 6, - }, - "callAsyncUnusedContextInterceptedCall1": Array [ - undefined, - 1, - 2, - 3, - ], - "callAsyncUnusedContextInterceptedCall2": Array [ - 1, - 2, - 3, - ], - "callAsyncUnusedContextInterceptedTap1": undefined, - "promiseContextIntercepted": Object { - "type": "promise", - "value": 48, - }, - "promiseContextInterceptedCall1": Array [ - Object { - "number": 42, - }, - 1, - 2, - 3, - ], - "promiseContextInterceptedCall2": Array [ - 1, - 2, - 3, - ], - "promiseContextInterceptedTap1": Object { - "number": 42, - }, - "promiseIntercepted": Object { - "type": "promise", - "value": 9, - }, - "promiseInterceptedCall1": Array [ - 1, - 2, - 3, - ], - "promiseInterceptedCall2": Array [ - 1, - 2, - 3, - ], - "promiseInterceptedResult1": 9, - "promiseInterceptedResult2": 9, - "promiseInterceptedTap1": Object { - "fn": 2, - "name": "promise", - "type": "promise", - }, - "promiseInterceptedTap2": Object { - "fn": 3, - "name": "sync", - "type": "sync", - }, - "promiseUnusedContextIntercepted": Object { - "type": "promise", - "value": 6, - }, - "promiseUnusedContextInterceptedCall1": Array [ - undefined, - 1, - 2, - 3, - ], - "promiseUnusedContextInterceptedCall2": Array [ - 1, - 2, - 3, - ], - "promiseUnusedContextInterceptedTap1": undefined, - }, - "sync": Object { - "callAsyncIntercepted": Object { - "type": "async", - "value": 9, - }, - "callAsyncInterceptedCall1": Array [ - 1, - 2, - 3, - ], - "callAsyncInterceptedCall2": Array [ - 1, - 2, - 3, - ], - "callAsyncInterceptedTap1": Object { - "fn": 2, - "name": "sync2", - "type": "sync", - }, - "callAsyncInterceptedTap2": Object { - "fn": 3, - "name": "sync1", - "type": "sync", - }, - "callAsyncMultipleSync": Object { - "error": "Waterfall hooks must have at least one argument", - }, - "callAsyncMultipleSyncError": Object { - "error": "Waterfall hooks must have at least one argument", - }, - "callAsyncMultipleSyncWithArg": Object { - "type": "async", - "value": 127, - }, - "callAsyncMultipleSyncWithArgCalled1": 42, - "callAsyncMultipleSyncWithArgCalled2": 84, - "callAsyncMultipleSyncWithArgFirstReturn": Object { - "type": "async", - "value": 84, - }, - "callAsyncMultipleSyncWithArgFirstReturnCalled1": 42, - "callAsyncMultipleSyncWithArgFirstReturnCalled2": 84, - "callAsyncMultipleSyncWithArgLastReturn": Object { - "type": "async", - "value": 85, - }, - "callAsyncMultipleSyncWithArgLastReturnCalled1": 42, - "callAsyncMultipleSyncWithArgLastReturnCalled2": 42, - "callAsyncMultipleSyncWithArgNoReturn": Object { - "type": "async", - "value": 42, - }, - "callAsyncMultipleSyncWithArgNoReturnCalled1": 42, - "callAsyncMultipleSyncWithArgNoReturnCalled2": 42, - "callAsyncMultipleSyncWithArgs": Object { - "type": "async", - "value": 217, - }, - "callAsyncMultipleSyncWithArgsCalled1": Array [ - 42, - 43, - 44, - ], - "callAsyncMultipleSyncWithArgsCalled2": Array [ - 129, - 43, - 44, - ], - "callAsyncNone": Object { - "error": "Waterfall hooks must have at least one argument", - }, - "callAsyncNoneWithArg": Object { - "type": "async", - "value": 42, - }, - "callAsyncSingleSync": Object { - "error": "Waterfall hooks must have at least one argument", - }, - "callAsyncSingleSyncWithArg": Object { - "type": "async", - "value": 42, - }, - "callAsyncSingleSyncWithArgCalled": 42, - "promiseIntercepted": Object { - "type": "promise", - "value": 9, - }, - "promiseInterceptedCall1": Array [ - 1, - 2, - 3, - ], - "promiseInterceptedCall2": Array [ - 1, - 2, - 3, - ], - "promiseInterceptedTap1": Object { - "fn": 2, - "name": "sync2", - "type": "sync", - }, - "promiseInterceptedTap2": Object { - "fn": 3, - "name": "sync1", - "type": "sync", - }, - "promiseMultipleSync": Object { - "error": "Waterfall hooks must have at least one argument", - }, - "promiseMultipleSyncError": Object { - "error": "Waterfall hooks must have at least one argument", - }, - "promiseMultipleSyncWithArg": Object { - "type": "promise", - "value": 127, - }, - "promiseMultipleSyncWithArgCalled1": 42, - "promiseMultipleSyncWithArgCalled2": 84, - "promiseMultipleSyncWithArgFirstReturn": Object { - "type": "promise", - "value": 84, - }, - "promiseMultipleSyncWithArgFirstReturnCalled1": 42, - "promiseMultipleSyncWithArgFirstReturnCalled2": 84, - "promiseMultipleSyncWithArgLastReturn": Object { - "type": "promise", - "value": 85, - }, - "promiseMultipleSyncWithArgLastReturnCalled1": 42, - "promiseMultipleSyncWithArgLastReturnCalled2": 42, - "promiseMultipleSyncWithArgNoReturn": Object { - "type": "promise", - "value": 42, - }, - "promiseMultipleSyncWithArgNoReturnCalled1": 42, - "promiseMultipleSyncWithArgNoReturnCalled2": 42, - "promiseMultipleSyncWithArgs": Object { - "type": "promise", - "value": 217, - }, - "promiseMultipleSyncWithArgsCalled1": Array [ - 42, - 43, - 44, - ], - "promiseMultipleSyncWithArgsCalled2": Array [ - 129, - 43, - 44, - ], - "promiseNone": Object { - "error": "Waterfall hooks must have at least one argument", - }, - "promiseNoneWithArg": Object { - "type": "promise", - "value": 42, - }, - "promiseSingleSync": Object { - "error": "Waterfall hooks must have at least one argument", - }, - "promiseSingleSyncWithArg": Object { - "type": "promise", - "value": 42, - }, "promiseSingleSyncWithArgCalled": 42, }, } diff --git a/test/__snapshots__/AsyncSeriesLoopHook.test.js.snap b/test/__snapshots__/AsyncSeriesLoopHook.test.js.snap new file mode 100644 index 0000000..f7e9579 --- /dev/null +++ b/test/__snapshots__/AsyncSeriesLoopHook.test.js.snap @@ -0,0 +1,131 @@ +// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing + +exports[`AsyncSeriesLoopHook should have to correct behavior 1`] = ` +Object { + "async": Object { + "callAsyncBrokenPromise": Object { + "error": "Tap function (tapPromise) did not return promise (returned this is not a promise)", + }, + "callAsyncMixed": Object { + "type": "async", + "value": undefined, + }, + "callAsyncMixedCalled1": 124, + "callAsyncMixedCalled2": 83, + "callAsyncMixedCalled3": 42, + "callAsyncMultipleAsync": Object { + "type": "async", + "value": undefined, + }, + "callAsyncMultipleAsyncCalled1": 83, + "callAsyncMultipleAsyncCalled2": 42, + "callAsyncMultiplePromise": Object { + "type": "async", + "value": undefined, + }, + "callAsyncMultiplePromiseCalled1": 83, + "callAsyncMultiplePromiseCalled2": 42, + "callAsyncSingleAsync": Object { + "type": "async", + "value": undefined, + }, + "callAsyncSingleAsyncCalled": 42, + "callAsyncSinglePromise": Object { + "type": "async", + "value": undefined, + }, + "callAsyncSinglePromiseCalled": 42, + "promiseBrokenPromise": Object { + "error": "Tap function (tapPromise) did not return promise (returned this is not a promise)", + "type": "promise", + }, + "promiseMixed": Object { + "type": "promise", + "value": undefined, + }, + "promiseMixedCalled1": 124, + "promiseMixedCalled2": 83, + "promiseMixedCalled3": 42, + "promiseMultipleAsync": Object { + "type": "promise", + "value": undefined, + }, + "promiseMultipleAsyncCalled1": 83, + "promiseMultipleAsyncCalled2": 42, + "promiseMultiplePromise": Object { + "type": "promise", + "value": undefined, + }, + "promiseMultiplePromiseCalled1": 83, + "promiseMultiplePromiseCalled2": 42, + "promiseSingleAsync": Object { + "type": "promise", + "value": undefined, + }, + "promiseSingleAsyncCalled": 42, + "promiseSinglePromise": Object { + "type": "promise", + "value": undefined, + }, + "promiseSinglePromiseCalled": 42, + }, + "sync": Object { + "callAsyncInterceptedSync": Object { + "type": "async", + "value": undefined, + }, + "callAsyncInterceptedSyncCalled1": 83, + "callAsyncInterceptedSyncCalled2": 42, + "callAsyncInterceptedSyncCalledCall": 1, + "callAsyncInterceptedSyncCalledLoop": 83, + "callAsyncInterceptedSyncCalledTap": 125, + "callAsyncMultipleSync": Object { + "type": "async", + "value": undefined, + }, + "callAsyncMultipleSyncCalled1": 83, + "callAsyncMultipleSyncCalled2": 42, + "callAsyncNone": Object { + "type": "async", + "value": undefined, + }, + "callAsyncNoneWithArg": Object { + "type": "async", + "value": undefined, + }, + "callAsyncSingleSync": Object { + "type": "async", + "value": undefined, + }, + "callAsyncSingleSyncCalled": 42, + "promiseInterceptedSync": Object { + "type": "promise", + "value": undefined, + }, + "promiseInterceptedSyncCalled1": 83, + "promiseInterceptedSyncCalled2": 42, + "promiseInterceptedSyncCalledCall": 1, + "promiseInterceptedSyncCalledLoop": 83, + "promiseInterceptedSyncCalledTap": 125, + "promiseMultipleSync": Object { + "type": "promise", + "value": undefined, + }, + "promiseMultipleSyncCalled1": 83, + "promiseMultipleSyncCalled2": 42, + "promiseNone": Object { + "type": "promise", + "value": undefined, + }, + "promiseNoneWithArg": Object { + "type": "promise", + "value": undefined, + }, + "promiseSingleSync": Object { + "type": "promise", + "value": undefined, + }, + "promiseSingleSyncCalled": 42, + }, +} +`; diff --git a/test/__snapshots__/AsyncSeriesWaterfallHook.test.js.snap b/test/__snapshots__/AsyncSeriesWaterfallHook.test.js.snap new file mode 100644 index 0000000..7b84832 --- /dev/null +++ b/test/__snapshots__/AsyncSeriesWaterfallHook.test.js.snap @@ -0,0 +1,740 @@ +// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing + +exports[`AsyncSeriesWaterfallHook should have to correct behavior 1`] = ` +Object { + "async": Object { + "callAsyncMultipleAsyncEarlyError": Object { + "error": "Waterfall hooks must have at least one argument", + }, + "callAsyncMultipleAsyncError": Object { + "error": "Waterfall hooks must have at least one argument", + }, + "callAsyncMultipleAsyncLateError": Object { + "error": "Waterfall hooks must have at least one argument", + }, + "callAsyncMultipleAsyncLateErrorEarlyResult1": Object { + "error": "Waterfall hooks must have at least one argument", + }, + "callAsyncMultipleAsyncLateErrorEarlyResult2": Object { + "error": "Waterfall hooks must have at least one argument", + }, + "callAsyncMultipleAsyncWithArg": Object { + "type": "async", + "value": 45, + }, + "callAsyncMultipleAsyncWithArgCalled1": 42, + "callAsyncMultipleAsyncWithArgCalled2": 43, + "callAsyncMultipleAsyncWithArgFirstReturn": Object { + "type": "async", + "value": 43, + }, + "callAsyncMultipleAsyncWithArgFirstReturnCalled1": 42, + "callAsyncMultipleAsyncWithArgFirstReturnCalled2": 43, + "callAsyncMultipleAsyncWithArgLastReturn": Object { + "type": "async", + "value": 44, + }, + "callAsyncMultipleAsyncWithArgLastReturnCalled1": 42, + "callAsyncMultipleAsyncWithArgLastReturnCalled2": 42, + "callAsyncMultipleAsyncWithArgNoReturn": Object { + "type": "async", + "value": 42, + }, + "callAsyncMultipleAsyncWithArgNoReturnCalled1": 42, + "callAsyncMultipleAsyncWithArgNoReturnCalled2": 42, + "callAsyncMultipleMixed1WithArg": Object { + "type": "async", + "value": 48, + }, + "callAsyncMultipleMixed1WithArgCalled1": 42, + "callAsyncMultipleMixed1WithArgCalled2": 43, + "callAsyncMultipleMixed1WithArgCalled3": 45, + "callAsyncMultipleMixed2WithArg": Object { + "type": "async", + "value": 45, + }, + "callAsyncMultipleMixed2WithArgCalled1": 42, + "callAsyncMultipleMixed2WithArgCalled2": 43, + "callAsyncMultipleMixed3WithArg": Object { + "type": "async", + "value": 48, + }, + "callAsyncMultipleMixed3WithArgCalled1": 42, + "callAsyncMultipleMixed3WithArgCalled2": 43, + "callAsyncMultipleMixed3WithArgCalled3": 45, + "callAsyncMultipleMixedError1WithArg": Object { + "error": "Error in sync", + "type": "async", + }, + "callAsyncMultipleMixedError1WithArgCalled1": 42, + "callAsyncMultipleMixedError1WithArgCalled2": 42, + "callAsyncMultipleMixedError1WithArgCalled3": 43, + "callAsyncMultipleMixedError2WithArg": Object { + "error": "Error in promise", + "type": "async", + }, + "callAsyncMultipleMixedError2WithArgCalled1": 42, + "callAsyncMultipleMixedError2WithArgCalled2": 42, + "callAsyncMultipleMixedError3WithArg": Object { + "error": "Error in async", + "type": "async", + }, + "callAsyncMultipleMixedError3WithArgCalled1": 42, + "callAsyncMultipleMixedLateError": Object { + "error": "Waterfall hooks must have at least one argument", + }, + "callAsyncMultiplePromiseEarlyError": Object { + "error": "Waterfall hooks must have at least one argument", + }, + "callAsyncMultiplePromiseError": Object { + "error": "Waterfall hooks must have at least one argument", + }, + "callAsyncMultiplePromiseLateError": Object { + "error": "Waterfall hooks must have at least one argument", + }, + "callAsyncMultiplePromiseWithArg": Object { + "type": "async", + "value": 45, + }, + "callAsyncMultiplePromiseWithArgCalled1": 42, + "callAsyncMultiplePromiseWithArgCalled2": 43, + "callAsyncMultiplePromiseWithArgFirstReturn": Object { + "type": "async", + "value": 43, + }, + "callAsyncMultiplePromiseWithArgFirstReturnCalled1": 42, + "callAsyncMultiplePromiseWithArgFirstReturnCalled2": 43, + "callAsyncMultiplePromiseWithArgLastReturn": Object { + "type": "async", + "value": 44, + }, + "callAsyncMultiplePromiseWithArgLastReturnCalled1": 42, + "callAsyncMultiplePromiseWithArgLastReturnCalled2": 42, + "callAsyncMultiplePromiseWithArgNoReturn": Object { + "type": "async", + "value": 42, + }, + "callAsyncMultiplePromiseWithArgNoReturnCalled1": 42, + "callAsyncMultiplePromiseWithArgNoReturnCalled2": 42, + "callAsyncMultipleSync": Object { + "error": "Waterfall hooks must have at least one argument", + }, + "callAsyncMultipleSyncError": Object { + "error": "Waterfall hooks must have at least one argument", + }, + "callAsyncMultipleSyncLastReturn": Object { + "error": "Waterfall hooks must have at least one argument", + }, + "callAsyncMultipleSyncNoReturn": Object { + "error": "Waterfall hooks must have at least one argument", + }, + "callAsyncMultipleSyncWithArg": Object { + "type": "async", + "value": 45, + }, + "callAsyncMultipleSyncWithArgCalled1": 42, + "callAsyncMultipleSyncWithArgCalled2": 43, + "callAsyncMultipleSyncWithArgFirstReturn": Object { + "type": "async", + "value": 43, + }, + "callAsyncMultipleSyncWithArgFirstReturnCalled1": 42, + "callAsyncMultipleSyncWithArgFirstReturnCalled2": 43, + "callAsyncMultipleSyncWithArgLastReturn": Object { + "type": "async", + "value": 44, + }, + "callAsyncMultipleSyncWithArgLastReturnCalled1": 42, + "callAsyncMultipleSyncWithArgLastReturnCalled2": 42, + "callAsyncMultipleSyncWithArgNoReturn": Object { + "type": "async", + "value": 42, + }, + "callAsyncMultipleSyncWithArgNoReturnCalled1": 42, + "callAsyncMultipleSyncWithArgNoReturnCalled2": 42, + "callAsyncNone": Object { + "error": "Waterfall hooks must have at least one argument", + }, + "callAsyncNoneWithArg": Object { + "type": "async", + "value": 42, + }, + "callAsyncSingleAsyncWithArg": Object { + "type": "async", + "value": 42, + }, + "callAsyncSingleAsyncWithArgCalled1": 42, + "callAsyncSinglePromiseWithArg": Object { + "type": "async", + "value": 43, + }, + "callAsyncSinglePromiseWithArgCalled1": 42, + "callAsyncSinglePromiseWithEmptyReject": Object { + "error": "Tap function (tapPromise) rejects \\"\\" value", + "type": "async", + }, + "callAsyncSinglePromiseWithEmptyStringArg": Object { + "type": "async", + "value": "", + }, + "callAsyncSinglePromiseWithEmptyStringArgCalled1": 42, + "callAsyncSinglePromiseWithFalseReject": Object { + "error": "Tap function (tapPromise) rejects \\"false\\" value", + "type": "async", + }, + "callAsyncSinglePromiseWithNullArg": Object { + "type": "async", + "value": null, + }, + "callAsyncSinglePromiseWithNullArgCalled1": 42, + "callAsyncSinglePromiseWithNullReject": Object { + "error": "Tap function (tapPromise) rejects \\"null\\" value", + "type": "async", + }, + "callAsyncSinglePromiseWithUndefined": Object { + "type": "async", + "value": 42, + }, + "callAsyncSinglePromiseWithUndefinedCalled1": 42, + "callAsyncSinglePromiseWithUndefinedReject": Object { + "error": "Tap function (tapPromise) rejects \\"undefined\\" value", + "type": "async", + }, + "callAsyncSinglePromiseWithZeroArg": Object { + "type": "async", + "value": 0, + }, + "callAsyncSinglePromiseWithZeroArgCalled1": 42, + "callAsyncSinglePromiseWithZeroReject": Object { + "error": "Tap function (tapPromise) rejects \\"0\\" value", + "type": "async", + }, + "callAsyncSingleSync": Object { + "error": "Waterfall hooks must have at least one argument", + }, + "callAsyncSingleSyncWithArg": Object { + "type": "async", + "value": 43, + }, + "callAsyncSingleSyncWithArgCalled1": 42, + "callAsyncSingleSyncWithArgNoReturn": Object { + "type": "async", + "value": 42, + }, + "callAsyncSingleSyncWithArgNoReturnCalled1": 42, + "promiseMultipleAsyncEarlyError": Object { + "error": "Waterfall hooks must have at least one argument", + }, + "promiseMultipleAsyncError": Object { + "error": "Waterfall hooks must have at least one argument", + }, + "promiseMultipleAsyncLateError": Object { + "error": "Waterfall hooks must have at least one argument", + }, + "promiseMultipleAsyncLateErrorEarlyResult1": Object { + "error": "Waterfall hooks must have at least one argument", + }, + "promiseMultipleAsyncLateErrorEarlyResult2": Object { + "error": "Waterfall hooks must have at least one argument", + }, + "promiseMultipleAsyncWithArg": Object { + "type": "promise", + "value": 45, + }, + "promiseMultipleAsyncWithArgCalled1": 42, + "promiseMultipleAsyncWithArgCalled2": 43, + "promiseMultipleAsyncWithArgFirstReturn": Object { + "type": "promise", + "value": 43, + }, + "promiseMultipleAsyncWithArgFirstReturnCalled1": 42, + "promiseMultipleAsyncWithArgFirstReturnCalled2": 43, + "promiseMultipleAsyncWithArgLastReturn": Object { + "type": "promise", + "value": 44, + }, + "promiseMultipleAsyncWithArgLastReturnCalled1": 42, + "promiseMultipleAsyncWithArgLastReturnCalled2": 42, + "promiseMultipleAsyncWithArgNoReturn": Object { + "type": "promise", + "value": 42, + }, + "promiseMultipleAsyncWithArgNoReturnCalled1": 42, + "promiseMultipleAsyncWithArgNoReturnCalled2": 42, + "promiseMultipleMixed1WithArg": Object { + "type": "promise", + "value": 48, + }, + "promiseMultipleMixed1WithArgCalled1": 42, + "promiseMultipleMixed1WithArgCalled2": 43, + "promiseMultipleMixed1WithArgCalled3": 45, + "promiseMultipleMixed2WithArg": Object { + "type": "promise", + "value": 45, + }, + "promiseMultipleMixed2WithArgCalled1": 42, + "promiseMultipleMixed2WithArgCalled2": 43, + "promiseMultipleMixed3WithArg": Object { + "type": "promise", + "value": 48, + }, + "promiseMultipleMixed3WithArgCalled1": 42, + "promiseMultipleMixed3WithArgCalled2": 43, + "promiseMultipleMixed3WithArgCalled3": 45, + "promiseMultipleMixedError1WithArg": Object { + "error": "Error in sync", + "type": "promise", + }, + "promiseMultipleMixedError1WithArgCalled1": 42, + "promiseMultipleMixedError1WithArgCalled2": 42, + "promiseMultipleMixedError1WithArgCalled3": 43, + "promiseMultipleMixedError2WithArg": Object { + "error": "Error in promise", + "type": "promise", + }, + "promiseMultipleMixedError2WithArgCalled1": 42, + "promiseMultipleMixedError2WithArgCalled2": 42, + "promiseMultipleMixedError3WithArg": Object { + "error": "Error in async", + "type": "promise", + }, + "promiseMultipleMixedError3WithArgCalled1": 42, + "promiseMultipleMixedLateError": Object { + "error": "Waterfall hooks must have at least one argument", + }, + "promiseMultiplePromiseEarlyError": Object { + "error": "Waterfall hooks must have at least one argument", + }, + "promiseMultiplePromiseError": Object { + "error": "Waterfall hooks must have at least one argument", + }, + "promiseMultiplePromiseLateError": Object { + "error": "Waterfall hooks must have at least one argument", + }, + "promiseMultiplePromiseWithArg": Object { + "type": "promise", + "value": 45, + }, + "promiseMultiplePromiseWithArgCalled1": 42, + "promiseMultiplePromiseWithArgCalled2": 43, + "promiseMultiplePromiseWithArgFirstReturn": Object { + "type": "promise", + "value": 43, + }, + "promiseMultiplePromiseWithArgFirstReturnCalled1": 42, + "promiseMultiplePromiseWithArgFirstReturnCalled2": 43, + "promiseMultiplePromiseWithArgLastReturn": Object { + "type": "promise", + "value": 44, + }, + "promiseMultiplePromiseWithArgLastReturnCalled1": 42, + "promiseMultiplePromiseWithArgLastReturnCalled2": 42, + "promiseMultiplePromiseWithArgNoReturn": Object { + "type": "promise", + "value": 42, + }, + "promiseMultiplePromiseWithArgNoReturnCalled1": 42, + "promiseMultiplePromiseWithArgNoReturnCalled2": 42, + "promiseMultipleSync": Object { + "error": "Waterfall hooks must have at least one argument", + }, + "promiseMultipleSyncError": Object { + "error": "Waterfall hooks must have at least one argument", + }, + "promiseMultipleSyncLastReturn": Object { + "error": "Waterfall hooks must have at least one argument", + }, + "promiseMultipleSyncNoReturn": Object { + "error": "Waterfall hooks must have at least one argument", + }, + "promiseMultipleSyncWithArg": Object { + "type": "promise", + "value": 45, + }, + "promiseMultipleSyncWithArgCalled1": 42, + "promiseMultipleSyncWithArgCalled2": 43, + "promiseMultipleSyncWithArgFirstReturn": Object { + "type": "promise", + "value": 43, + }, + "promiseMultipleSyncWithArgFirstReturnCalled1": 42, + "promiseMultipleSyncWithArgFirstReturnCalled2": 43, + "promiseMultipleSyncWithArgLastReturn": Object { + "type": "promise", + "value": 44, + }, + "promiseMultipleSyncWithArgLastReturnCalled1": 42, + "promiseMultipleSyncWithArgLastReturnCalled2": 42, + "promiseMultipleSyncWithArgNoReturn": Object { + "type": "promise", + "value": 42, + }, + "promiseMultipleSyncWithArgNoReturnCalled1": 42, + "promiseMultipleSyncWithArgNoReturnCalled2": 42, + "promiseNone": Object { + "error": "Waterfall hooks must have at least one argument", + }, + "promiseNoneWithArg": Object { + "type": "promise", + "value": 42, + }, + "promiseSingleAsyncWithArg": Object { + "type": "promise", + "value": 42, + }, + "promiseSingleAsyncWithArgCalled1": 42, + "promiseSinglePromiseWithArg": Object { + "type": "promise", + "value": 43, + }, + "promiseSinglePromiseWithArgCalled1": 42, + "promiseSinglePromiseWithEmptyReject": Object { + "error": "Tap function (tapPromise) rejects \\"\\" value", + "type": "promise", + }, + "promiseSinglePromiseWithEmptyStringArg": Object { + "type": "promise", + "value": "", + }, + "promiseSinglePromiseWithEmptyStringArgCalled1": 42, + "promiseSinglePromiseWithFalseReject": Object { + "error": "Tap function (tapPromise) rejects \\"false\\" value", + "type": "promise", + }, + "promiseSinglePromiseWithNullArg": Object { + "type": "promise", + "value": null, + }, + "promiseSinglePromiseWithNullArgCalled1": 42, + "promiseSinglePromiseWithNullReject": Object { + "error": "Tap function (tapPromise) rejects \\"null\\" value", + "type": "promise", + }, + "promiseSinglePromiseWithUndefined": Object { + "type": "promise", + "value": 42, + }, + "promiseSinglePromiseWithUndefinedCalled1": 42, + "promiseSinglePromiseWithUndefinedReject": Object { + "error": "Tap function (tapPromise) rejects \\"undefined\\" value", + "type": "promise", + }, + "promiseSinglePromiseWithZeroArg": Object { + "type": "promise", + "value": 0, + }, + "promiseSinglePromiseWithZeroArgCalled1": 42, + "promiseSinglePromiseWithZeroReject": Object { + "error": "Tap function (tapPromise) rejects \\"0\\" value", + "type": "promise", + }, + "promiseSingleSync": Object { + "error": "Waterfall hooks must have at least one argument", + }, + "promiseSingleSyncWithArg": Object { + "type": "promise", + "value": 43, + }, + "promiseSingleSyncWithArgCalled1": 42, + "promiseSingleSyncWithArgNoReturn": Object { + "type": "promise", + "value": 42, + }, + "promiseSingleSyncWithArgNoReturnCalled1": 42, + }, + "intercept": Object { + "callAsyncContextIntercepted": Object { + "type": "async", + "value": 48, + }, + "callAsyncContextInterceptedCall1": Array [ + Object { + "number": 42, + }, + 1, + 2, + 3, + ], + "callAsyncContextInterceptedCall2": Array [ + 1, + 2, + 3, + ], + "callAsyncContextInterceptedTap1": Object { + "number": 42, + }, + "callAsyncIntercepted": Object { + "type": "async", + "value": 9, + }, + "callAsyncInterceptedCall1": Array [ + 1, + 2, + 3, + ], + "callAsyncInterceptedCall2": Array [ + 1, + 2, + 3, + ], + "callAsyncInterceptedResult1": 9, + "callAsyncInterceptedResult2": 9, + "callAsyncInterceptedTap1": Object { + "fn": 2, + "name": "promise", + "type": "promise", + }, + "callAsyncInterceptedTap2": Object { + "fn": 3, + "name": "sync", + "type": "sync", + }, + "callAsyncUnusedContextIntercepted": Object { + "type": "async", + "value": 6, + }, + "callAsyncUnusedContextInterceptedCall1": Array [ + undefined, + 1, + 2, + 3, + ], + "callAsyncUnusedContextInterceptedCall2": Array [ + 1, + 2, + 3, + ], + "callAsyncUnusedContextInterceptedTap1": undefined, + "promiseContextIntercepted": Object { + "type": "promise", + "value": 48, + }, + "promiseContextInterceptedCall1": Array [ + Object { + "number": 42, + }, + 1, + 2, + 3, + ], + "promiseContextInterceptedCall2": Array [ + 1, + 2, + 3, + ], + "promiseContextInterceptedTap1": Object { + "number": 42, + }, + "promiseIntercepted": Object { + "type": "promise", + "value": 9, + }, + "promiseInterceptedCall1": Array [ + 1, + 2, + 3, + ], + "promiseInterceptedCall2": Array [ + 1, + 2, + 3, + ], + "promiseInterceptedResult1": 9, + "promiseInterceptedResult2": 9, + "promiseInterceptedTap1": Object { + "fn": 2, + "name": "promise", + "type": "promise", + }, + "promiseInterceptedTap2": Object { + "fn": 3, + "name": "sync", + "type": "sync", + }, + "promiseUnusedContextIntercepted": Object { + "type": "promise", + "value": 6, + }, + "promiseUnusedContextInterceptedCall1": Array [ + undefined, + 1, + 2, + 3, + ], + "promiseUnusedContextInterceptedCall2": Array [ + 1, + 2, + 3, + ], + "promiseUnusedContextInterceptedTap1": undefined, + }, + "sync": Object { + "callAsyncIntercepted": Object { + "type": "async", + "value": 9, + }, + "callAsyncInterceptedCall1": Array [ + 1, + 2, + 3, + ], + "callAsyncInterceptedCall2": Array [ + 1, + 2, + 3, + ], + "callAsyncInterceptedTap1": Object { + "fn": 2, + "name": "sync2", + "type": "sync", + }, + "callAsyncInterceptedTap2": Object { + "fn": 3, + "name": "sync1", + "type": "sync", + }, + "callAsyncMultipleSync": Object { + "error": "Waterfall hooks must have at least one argument", + }, + "callAsyncMultipleSyncError": Object { + "error": "Waterfall hooks must have at least one argument", + }, + "callAsyncMultipleSyncWithArg": Object { + "type": "async", + "value": 127, + }, + "callAsyncMultipleSyncWithArgCalled1": 42, + "callAsyncMultipleSyncWithArgCalled2": 84, + "callAsyncMultipleSyncWithArgFirstReturn": Object { + "type": "async", + "value": 84, + }, + "callAsyncMultipleSyncWithArgFirstReturnCalled1": 42, + "callAsyncMultipleSyncWithArgFirstReturnCalled2": 84, + "callAsyncMultipleSyncWithArgLastReturn": Object { + "type": "async", + "value": 85, + }, + "callAsyncMultipleSyncWithArgLastReturnCalled1": 42, + "callAsyncMultipleSyncWithArgLastReturnCalled2": 42, + "callAsyncMultipleSyncWithArgNoReturn": Object { + "type": "async", + "value": 42, + }, + "callAsyncMultipleSyncWithArgNoReturnCalled1": 42, + "callAsyncMultipleSyncWithArgNoReturnCalled2": 42, + "callAsyncMultipleSyncWithArgs": Object { + "type": "async", + "value": 217, + }, + "callAsyncMultipleSyncWithArgsCalled1": Array [ + 42, + 43, + 44, + ], + "callAsyncMultipleSyncWithArgsCalled2": Array [ + 129, + 43, + 44, + ], + "callAsyncNone": Object { + "error": "Waterfall hooks must have at least one argument", + }, + "callAsyncNoneWithArg": Object { + "type": "async", + "value": 42, + }, + "callAsyncSingleSync": Object { + "error": "Waterfall hooks must have at least one argument", + }, + "callAsyncSingleSyncWithArg": Object { + "type": "async", + "value": 42, + }, + "callAsyncSingleSyncWithArgCalled": 42, + "promiseIntercepted": Object { + "type": "promise", + "value": 9, + }, + "promiseInterceptedCall1": Array [ + 1, + 2, + 3, + ], + "promiseInterceptedCall2": Array [ + 1, + 2, + 3, + ], + "promiseInterceptedTap1": Object { + "fn": 2, + "name": "sync2", + "type": "sync", + }, + "promiseInterceptedTap2": Object { + "fn": 3, + "name": "sync1", + "type": "sync", + }, + "promiseMultipleSync": Object { + "error": "Waterfall hooks must have at least one argument", + }, + "promiseMultipleSyncError": Object { + "error": "Waterfall hooks must have at least one argument", + }, + "promiseMultipleSyncWithArg": Object { + "type": "promise", + "value": 127, + }, + "promiseMultipleSyncWithArgCalled1": 42, + "promiseMultipleSyncWithArgCalled2": 84, + "promiseMultipleSyncWithArgFirstReturn": Object { + "type": "promise", + "value": 84, + }, + "promiseMultipleSyncWithArgFirstReturnCalled1": 42, + "promiseMultipleSyncWithArgFirstReturnCalled2": 84, + "promiseMultipleSyncWithArgLastReturn": Object { + "type": "promise", + "value": 85, + }, + "promiseMultipleSyncWithArgLastReturnCalled1": 42, + "promiseMultipleSyncWithArgLastReturnCalled2": 42, + "promiseMultipleSyncWithArgNoReturn": Object { + "type": "promise", + "value": 42, + }, + "promiseMultipleSyncWithArgNoReturnCalled1": 42, + "promiseMultipleSyncWithArgNoReturnCalled2": 42, + "promiseMultipleSyncWithArgs": Object { + "type": "promise", + "value": 217, + }, + "promiseMultipleSyncWithArgsCalled1": Array [ + 42, + 43, + 44, + ], + "promiseMultipleSyncWithArgsCalled2": Array [ + 129, + 43, + 44, + ], + "promiseNone": Object { + "error": "Waterfall hooks must have at least one argument", + }, + "promiseNoneWithArg": Object { + "type": "promise", + "value": 42, + }, + "promiseSingleSync": Object { + "error": "Waterfall hooks must have at least one argument", + }, + "promiseSingleSyncWithArg": Object { + "type": "promise", + "value": 42, + }, + "promiseSingleSyncWithArgCalled": 42, + }, +} +`; diff --git a/test/__snapshots__/SyncBailHook.test.js.snap b/test/__snapshots__/SyncBailHook.test.js.snap new file mode 100644 index 0000000..e614d36 --- /dev/null +++ b/test/__snapshots__/SyncBailHook.test.js.snap @@ -0,0 +1,258 @@ +// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing + +exports[`SyncBailHook should have to correct behavior 1`] = ` +Object { + "async": Object {}, + "intercept": Object {}, + "sync": Object { + "callAsyncIntercepted": Object { + "type": "async", + "value": 6, + }, + "callAsyncInterceptedCall1": Array [ + 1, + 2, + 3, + ], + "callAsyncInterceptedCall2": Array [ + 1, + 2, + 3, + ], + "callAsyncInterceptedTap1": Object { + "fn": 3, + "name": "sync1", + "type": "sync", + }, + "callAsyncInterceptedTap2": Object { + "fn": 3, + "name": "sync1", + "type": "sync", + }, + "callAsyncMultipleSync": Object { + "type": "async", + "value": 42, + }, + "callAsyncMultipleSyncCalled1": true, + "callAsyncMultipleSyncError": Object { + "error": "Error in sync2", + "type": "async", + }, + "callAsyncMultipleSyncErrorCalled1": true, + "callAsyncMultipleSyncErrorCalled2": true, + "callAsyncMultipleSyncWithArg": Object { + "type": "async", + "value": 84, + }, + "callAsyncMultipleSyncWithArgCalled1": 42, + "callAsyncMultipleSyncWithArgFirstReturn": Object { + "type": "async", + "value": 84, + }, + "callAsyncMultipleSyncWithArgFirstReturnCalled1": 42, + "callAsyncMultipleSyncWithArgLastReturn": Object { + "type": "async", + "value": 85, + }, + "callAsyncMultipleSyncWithArgLastReturnCalled1": 42, + "callAsyncMultipleSyncWithArgLastReturnCalled2": 42, + "callAsyncMultipleSyncWithArgNoReturn": Object { + "type": "async", + "value": undefined, + }, + "callAsyncMultipleSyncWithArgNoReturnCalled1": 42, + "callAsyncMultipleSyncWithArgNoReturnCalled2": 42, + "callAsyncMultipleSyncWithArgs": Object { + "type": "async", + "value": 129, + }, + "callAsyncMultipleSyncWithArgsCalled1": Array [ + 42, + 43, + 44, + ], + "callAsyncNone": Object { + "type": "async", + "value": undefined, + }, + "callAsyncNoneWithArg": Object { + "type": "async", + "value": undefined, + }, + "callAsyncSingleSync": Object { + "type": "async", + "value": 42, + }, + "callAsyncSingleSyncCalled": true, + "callAsyncSingleSyncWithArg": Object { + "type": "async", + "value": 42, + }, + "callAsyncSingleSyncWithArgCalled": 42, + "callIntercepted": Object { + "type": "return", + "value": 6, + }, + "callInterceptedCall1": Array [ + 1, + 2, + 3, + ], + "callInterceptedCall2": Array [ + 1, + 2, + 3, + ], + "callInterceptedTap1": Object { + "fn": 3, + "name": "sync1", + "type": "sync", + }, + "callInterceptedTap2": Object { + "fn": 3, + "name": "sync1", + "type": "sync", + }, + "callMultipleSync": Object { + "type": "return", + "value": 42, + }, + "callMultipleSyncCalled1": true, + "callMultipleSyncError": Object { + "error": "Error in sync2", + }, + "callMultipleSyncErrorCalled1": true, + "callMultipleSyncErrorCalled2": true, + "callMultipleSyncWithArg": Object { + "type": "return", + "value": 84, + }, + "callMultipleSyncWithArgCalled1": 42, + "callMultipleSyncWithArgFirstReturn": Object { + "type": "return", + "value": 84, + }, + "callMultipleSyncWithArgFirstReturnCalled1": 42, + "callMultipleSyncWithArgLastReturn": Object { + "type": "return", + "value": 85, + }, + "callMultipleSyncWithArgLastReturnCalled1": 42, + "callMultipleSyncWithArgLastReturnCalled2": 42, + "callMultipleSyncWithArgNoReturn": Object { + "type": "no result", + }, + "callMultipleSyncWithArgNoReturnCalled1": 42, + "callMultipleSyncWithArgNoReturnCalled2": 42, + "callMultipleSyncWithArgs": Object { + "type": "return", + "value": 129, + }, + "callMultipleSyncWithArgsCalled1": Array [ + 42, + 43, + 44, + ], + "callNone": Object { + "type": "no result", + }, + "callNoneWithArg": Object { + "type": "no result", + }, + "callSingleSync": Object { + "type": "return", + "value": 42, + }, + "callSingleSyncCalled": true, + "callSingleSyncWithArg": Object { + "type": "return", + "value": 42, + }, + "callSingleSyncWithArgCalled": 42, + "promiseIntercepted": Object { + "type": "promise", + "value": 6, + }, + "promiseInterceptedCall1": Array [ + 1, + 2, + 3, + ], + "promiseInterceptedCall2": Array [ + 1, + 2, + 3, + ], + "promiseInterceptedTap1": Object { + "fn": 3, + "name": "sync1", + "type": "sync", + }, + "promiseInterceptedTap2": Object { + "fn": 3, + "name": "sync1", + "type": "sync", + }, + "promiseMultipleSync": Object { + "type": "promise", + "value": 42, + }, + "promiseMultipleSyncCalled1": true, + "promiseMultipleSyncError": Object { + "error": "Error in sync2", + "type": "promise", + }, + "promiseMultipleSyncErrorCalled1": true, + "promiseMultipleSyncErrorCalled2": true, + "promiseMultipleSyncWithArg": Object { + "type": "promise", + "value": 84, + }, + "promiseMultipleSyncWithArgCalled1": 42, + "promiseMultipleSyncWithArgFirstReturn": Object { + "type": "promise", + "value": 84, + }, + "promiseMultipleSyncWithArgFirstReturnCalled1": 42, + "promiseMultipleSyncWithArgLastReturn": Object { + "type": "promise", + "value": 85, + }, + "promiseMultipleSyncWithArgLastReturnCalled1": 42, + "promiseMultipleSyncWithArgLastReturnCalled2": 42, + "promiseMultipleSyncWithArgNoReturn": Object { + "type": "promise", + "value": undefined, + }, + "promiseMultipleSyncWithArgNoReturnCalled1": 42, + "promiseMultipleSyncWithArgNoReturnCalled2": 42, + "promiseMultipleSyncWithArgs": Object { + "type": "promise", + "value": 129, + }, + "promiseMultipleSyncWithArgsCalled1": Array [ + 42, + 43, + 44, + ], + "promiseNone": Object { + "type": "promise", + "value": undefined, + }, + "promiseNoneWithArg": Object { + "type": "promise", + "value": undefined, + }, + "promiseSingleSync": Object { + "type": "promise", + "value": 42, + }, + "promiseSingleSyncCalled": true, + "promiseSingleSyncWithArg": Object { + "type": "promise", + "value": 42, + }, + "promiseSingleSyncWithArgCalled": 42, + }, +} +`; diff --git a/test/__snapshots__/SyncHooks.test.js.snap b/test/__snapshots__/SyncHooks.test.js.snap index 5a2bac5..c182098 100644 --- a/test/__snapshots__/SyncHooks.test.js.snap +++ b/test/__snapshots__/SyncHooks.test.js.snap @@ -1,262 +1,5 @@ // Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing -exports[`SyncBailHook should have to correct behavior 1`] = ` -Object { - "async": Object {}, - "intercept": Object {}, - "sync": Object { - "callAsyncIntercepted": Object { - "type": "async", - "value": 6, - }, - "callAsyncInterceptedCall1": Array [ - 1, - 2, - 3, - ], - "callAsyncInterceptedCall2": Array [ - 1, - 2, - 3, - ], - "callAsyncInterceptedTap1": Object { - "fn": 3, - "name": "sync1", - "type": "sync", - }, - "callAsyncInterceptedTap2": Object { - "fn": 3, - "name": "sync1", - "type": "sync", - }, - "callAsyncMultipleSync": Object { - "type": "async", - "value": 42, - }, - "callAsyncMultipleSyncCalled1": true, - "callAsyncMultipleSyncError": Object { - "error": "Error in sync2", - "type": "async", - }, - "callAsyncMultipleSyncErrorCalled1": true, - "callAsyncMultipleSyncErrorCalled2": true, - "callAsyncMultipleSyncWithArg": Object { - "type": "async", - "value": 84, - }, - "callAsyncMultipleSyncWithArgCalled1": 42, - "callAsyncMultipleSyncWithArgFirstReturn": Object { - "type": "async", - "value": 84, - }, - "callAsyncMultipleSyncWithArgFirstReturnCalled1": 42, - "callAsyncMultipleSyncWithArgLastReturn": Object { - "type": "async", - "value": 85, - }, - "callAsyncMultipleSyncWithArgLastReturnCalled1": 42, - "callAsyncMultipleSyncWithArgLastReturnCalled2": 42, - "callAsyncMultipleSyncWithArgNoReturn": Object { - "type": "async", - "value": undefined, - }, - "callAsyncMultipleSyncWithArgNoReturnCalled1": 42, - "callAsyncMultipleSyncWithArgNoReturnCalled2": 42, - "callAsyncMultipleSyncWithArgs": Object { - "type": "async", - "value": 129, - }, - "callAsyncMultipleSyncWithArgsCalled1": Array [ - 42, - 43, - 44, - ], - "callAsyncNone": Object { - "type": "async", - "value": undefined, - }, - "callAsyncNoneWithArg": Object { - "type": "async", - "value": undefined, - }, - "callAsyncSingleSync": Object { - "type": "async", - "value": 42, - }, - "callAsyncSingleSyncCalled": true, - "callAsyncSingleSyncWithArg": Object { - "type": "async", - "value": 42, - }, - "callAsyncSingleSyncWithArgCalled": 42, - "callIntercepted": Object { - "type": "return", - "value": 6, - }, - "callInterceptedCall1": Array [ - 1, - 2, - 3, - ], - "callInterceptedCall2": Array [ - 1, - 2, - 3, - ], - "callInterceptedTap1": Object { - "fn": 3, - "name": "sync1", - "type": "sync", - }, - "callInterceptedTap2": Object { - "fn": 3, - "name": "sync1", - "type": "sync", - }, - "callMultipleSync": Object { - "type": "return", - "value": 42, - }, - "callMultipleSyncCalled1": true, - "callMultipleSyncError": Object { - "error": "Error in sync2", - }, - "callMultipleSyncErrorCalled1": true, - "callMultipleSyncErrorCalled2": true, - "callMultipleSyncWithArg": Object { - "type": "return", - "value": 84, - }, - "callMultipleSyncWithArgCalled1": 42, - "callMultipleSyncWithArgFirstReturn": Object { - "type": "return", - "value": 84, - }, - "callMultipleSyncWithArgFirstReturnCalled1": 42, - "callMultipleSyncWithArgLastReturn": Object { - "type": "return", - "value": 85, - }, - "callMultipleSyncWithArgLastReturnCalled1": 42, - "callMultipleSyncWithArgLastReturnCalled2": 42, - "callMultipleSyncWithArgNoReturn": Object { - "type": "no result", - }, - "callMultipleSyncWithArgNoReturnCalled1": 42, - "callMultipleSyncWithArgNoReturnCalled2": 42, - "callMultipleSyncWithArgs": Object { - "type": "return", - "value": 129, - }, - "callMultipleSyncWithArgsCalled1": Array [ - 42, - 43, - 44, - ], - "callNone": Object { - "type": "no result", - }, - "callNoneWithArg": Object { - "type": "no result", - }, - "callSingleSync": Object { - "type": "return", - "value": 42, - }, - "callSingleSyncCalled": true, - "callSingleSyncWithArg": Object { - "type": "return", - "value": 42, - }, - "callSingleSyncWithArgCalled": 42, - "promiseIntercepted": Object { - "type": "promise", - "value": 6, - }, - "promiseInterceptedCall1": Array [ - 1, - 2, - 3, - ], - "promiseInterceptedCall2": Array [ - 1, - 2, - 3, - ], - "promiseInterceptedTap1": Object { - "fn": 3, - "name": "sync1", - "type": "sync", - }, - "promiseInterceptedTap2": Object { - "fn": 3, - "name": "sync1", - "type": "sync", - }, - "promiseMultipleSync": Object { - "type": "promise", - "value": 42, - }, - "promiseMultipleSyncCalled1": true, - "promiseMultipleSyncError": Object { - "error": "Error in sync2", - "type": "promise", - }, - "promiseMultipleSyncErrorCalled1": true, - "promiseMultipleSyncErrorCalled2": true, - "promiseMultipleSyncWithArg": Object { - "type": "promise", - "value": 84, - }, - "promiseMultipleSyncWithArgCalled1": 42, - "promiseMultipleSyncWithArgFirstReturn": Object { - "type": "promise", - "value": 84, - }, - "promiseMultipleSyncWithArgFirstReturnCalled1": 42, - "promiseMultipleSyncWithArgLastReturn": Object { - "type": "promise", - "value": 85, - }, - "promiseMultipleSyncWithArgLastReturnCalled1": 42, - "promiseMultipleSyncWithArgLastReturnCalled2": 42, - "promiseMultipleSyncWithArgNoReturn": Object { - "type": "promise", - "value": undefined, - }, - "promiseMultipleSyncWithArgNoReturnCalled1": 42, - "promiseMultipleSyncWithArgNoReturnCalled2": 42, - "promiseMultipleSyncWithArgs": Object { - "type": "promise", - "value": 129, - }, - "promiseMultipleSyncWithArgsCalled1": Array [ - 42, - 43, - 44, - ], - "promiseNone": Object { - "type": "promise", - "value": undefined, - }, - "promiseNoneWithArg": Object { - "type": "promise", - "value": undefined, - }, - "promiseSingleSync": Object { - "type": "promise", - "value": 42, - }, - "promiseSingleSyncCalled": true, - "promiseSingleSyncWithArg": Object { - "type": "promise", - "value": 42, - }, - "promiseSingleSyncWithArgCalled": 42, - }, -} -`; - exports[`SyncHook should have to correct behavior 1`] = ` Object { "async": Object {}, @@ -529,348 +272,3 @@ Object { }, } `; - -exports[`SyncLoopHook should have to correct behavior 1`] = ` -Object { - "async": Object {}, - "sync": Object { - "callAsyncInterceptedSync": Object { - "type": "async", - "value": undefined, - }, - "callAsyncInterceptedSyncCalled1": 83, - "callAsyncInterceptedSyncCalled2": 42, - "callAsyncInterceptedSyncCalledCall": 1, - "callAsyncInterceptedSyncCalledLoop": 83, - "callAsyncInterceptedSyncCalledTap": 125, - "callAsyncMultipleSync": Object { - "type": "async", - "value": undefined, - }, - "callAsyncMultipleSyncCalled1": 83, - "callAsyncMultipleSyncCalled2": 42, - "callAsyncNone": Object { - "type": "async", - "value": undefined, - }, - "callAsyncNoneWithArg": Object { - "type": "async", - "value": undefined, - }, - "callAsyncSingleSync": Object { - "type": "async", - "value": undefined, - }, - "callAsyncSingleSyncCalled": 42, - "callInterceptedSync": Object { - "type": "no result", - }, - "callInterceptedSyncCalled1": 83, - "callInterceptedSyncCalled2": 42, - "callInterceptedSyncCalledCall": 1, - "callInterceptedSyncCalledLoop": 83, - "callInterceptedSyncCalledTap": 125, - "callMultipleSync": Object { - "type": "no result", - }, - "callMultipleSyncCalled1": 83, - "callMultipleSyncCalled2": 42, - "callNone": Object { - "type": "no result", - }, - "callNoneWithArg": Object { - "type": "no result", - }, - "callSingleSync": Object { - "type": "no result", - }, - "callSingleSyncCalled": 42, - "promiseInterceptedSync": Object { - "type": "promise", - "value": undefined, - }, - "promiseInterceptedSyncCalled1": 83, - "promiseInterceptedSyncCalled2": 42, - "promiseInterceptedSyncCalledCall": 1, - "promiseInterceptedSyncCalledLoop": 83, - "promiseInterceptedSyncCalledTap": 125, - "promiseMultipleSync": Object { - "type": "promise", - "value": undefined, - }, - "promiseMultipleSyncCalled1": 83, - "promiseMultipleSyncCalled2": 42, - "promiseNone": Object { - "type": "promise", - "value": undefined, - }, - "promiseNoneWithArg": Object { - "type": "promise", - "value": undefined, - }, - "promiseSingleSync": Object { - "type": "promise", - "value": undefined, - }, - "promiseSingleSyncCalled": 42, - }, -} -`; - -exports[`SyncWaterfallHook should have to correct behavior 1`] = ` -Object { - "async": Object {}, - "intercept": Object {}, - "sync": Object { - "callAsyncIntercepted": Object { - "type": "async", - "value": 9, - }, - "callAsyncInterceptedCall1": Array [ - 1, - 2, - 3, - ], - "callAsyncInterceptedCall2": Array [ - 1, - 2, - 3, - ], - "callAsyncInterceptedTap1": Object { - "fn": 2, - "name": "sync2", - "type": "sync", - }, - "callAsyncInterceptedTap2": Object { - "fn": 3, - "name": "sync1", - "type": "sync", - }, - "callAsyncMultipleSync": Object { - "error": "Waterfall hooks must have at least one argument", - }, - "callAsyncMultipleSyncError": Object { - "error": "Waterfall hooks must have at least one argument", - }, - "callAsyncMultipleSyncWithArg": Object { - "type": "async", - "value": 127, - }, - "callAsyncMultipleSyncWithArgCalled1": 42, - "callAsyncMultipleSyncWithArgCalled2": 84, - "callAsyncMultipleSyncWithArgFirstReturn": Object { - "type": "async", - "value": 84, - }, - "callAsyncMultipleSyncWithArgFirstReturnCalled1": 42, - "callAsyncMultipleSyncWithArgFirstReturnCalled2": 84, - "callAsyncMultipleSyncWithArgLastReturn": Object { - "type": "async", - "value": 85, - }, - "callAsyncMultipleSyncWithArgLastReturnCalled1": 42, - "callAsyncMultipleSyncWithArgLastReturnCalled2": 42, - "callAsyncMultipleSyncWithArgNoReturn": Object { - "type": "async", - "value": 42, - }, - "callAsyncMultipleSyncWithArgNoReturnCalled1": 42, - "callAsyncMultipleSyncWithArgNoReturnCalled2": 42, - "callAsyncMultipleSyncWithArgs": Object { - "type": "async", - "value": 217, - }, - "callAsyncMultipleSyncWithArgsCalled1": Array [ - 42, - 43, - 44, - ], - "callAsyncMultipleSyncWithArgsCalled2": Array [ - 129, - 43, - 44, - ], - "callAsyncNone": Object { - "error": "Waterfall hooks must have at least one argument", - }, - "callAsyncNoneWithArg": Object { - "type": "async", - "value": 42, - }, - "callAsyncSingleSync": Object { - "error": "Waterfall hooks must have at least one argument", - }, - "callAsyncSingleSyncWithArg": Object { - "type": "async", - "value": 42, - }, - "callAsyncSingleSyncWithArgCalled": 42, - "callIntercepted": Object { - "type": "return", - "value": 9, - }, - "callInterceptedCall1": Array [ - 1, - 2, - 3, - ], - "callInterceptedCall2": Array [ - 1, - 2, - 3, - ], - "callInterceptedTap1": Object { - "fn": 2, - "name": "sync2", - "type": "sync", - }, - "callInterceptedTap2": Object { - "fn": 3, - "name": "sync1", - "type": "sync", - }, - "callMultipleSync": Object { - "error": "Waterfall hooks must have at least one argument", - }, - "callMultipleSyncError": Object { - "error": "Waterfall hooks must have at least one argument", - }, - "callMultipleSyncWithArg": Object { - "type": "return", - "value": 127, - }, - "callMultipleSyncWithArgCalled1": 42, - "callMultipleSyncWithArgCalled2": 84, - "callMultipleSyncWithArgFirstReturn": Object { - "type": "return", - "value": 84, - }, - "callMultipleSyncWithArgFirstReturnCalled1": 42, - "callMultipleSyncWithArgFirstReturnCalled2": 84, - "callMultipleSyncWithArgLastReturn": Object { - "type": "return", - "value": 85, - }, - "callMultipleSyncWithArgLastReturnCalled1": 42, - "callMultipleSyncWithArgLastReturnCalled2": 42, - "callMultipleSyncWithArgNoReturn": Object { - "type": "return", - "value": 42, - }, - "callMultipleSyncWithArgNoReturnCalled1": 42, - "callMultipleSyncWithArgNoReturnCalled2": 42, - "callMultipleSyncWithArgs": Object { - "type": "return", - "value": 217, - }, - "callMultipleSyncWithArgsCalled1": Array [ - 42, - 43, - 44, - ], - "callMultipleSyncWithArgsCalled2": Array [ - 129, - 43, - 44, - ], - "callNone": Object { - "error": "Waterfall hooks must have at least one argument", - }, - "callNoneWithArg": Object { - "type": "return", - "value": 42, - }, - "callSingleSync": Object { - "error": "Waterfall hooks must have at least one argument", - }, - "callSingleSyncWithArg": Object { - "type": "return", - "value": 42, - }, - "callSingleSyncWithArgCalled": 42, - "promiseIntercepted": Object { - "type": "promise", - "value": 9, - }, - "promiseInterceptedCall1": Array [ - 1, - 2, - 3, - ], - "promiseInterceptedCall2": Array [ - 1, - 2, - 3, - ], - "promiseInterceptedTap1": Object { - "fn": 2, - "name": "sync2", - "type": "sync", - }, - "promiseInterceptedTap2": Object { - "fn": 3, - "name": "sync1", - "type": "sync", - }, - "promiseMultipleSync": Object { - "error": "Waterfall hooks must have at least one argument", - }, - "promiseMultipleSyncError": Object { - "error": "Waterfall hooks must have at least one argument", - }, - "promiseMultipleSyncWithArg": Object { - "type": "promise", - "value": 127, - }, - "promiseMultipleSyncWithArgCalled1": 42, - "promiseMultipleSyncWithArgCalled2": 84, - "promiseMultipleSyncWithArgFirstReturn": Object { - "type": "promise", - "value": 84, - }, - "promiseMultipleSyncWithArgFirstReturnCalled1": 42, - "promiseMultipleSyncWithArgFirstReturnCalled2": 84, - "promiseMultipleSyncWithArgLastReturn": Object { - "type": "promise", - "value": 85, - }, - "promiseMultipleSyncWithArgLastReturnCalled1": 42, - "promiseMultipleSyncWithArgLastReturnCalled2": 42, - "promiseMultipleSyncWithArgNoReturn": Object { - "type": "promise", - "value": 42, - }, - "promiseMultipleSyncWithArgNoReturnCalled1": 42, - "promiseMultipleSyncWithArgNoReturnCalled2": 42, - "promiseMultipleSyncWithArgs": Object { - "type": "promise", - "value": 217, - }, - "promiseMultipleSyncWithArgsCalled1": Array [ - 42, - 43, - 44, - ], - "promiseMultipleSyncWithArgsCalled2": Array [ - 129, - 43, - 44, - ], - "promiseNone": Object { - "error": "Waterfall hooks must have at least one argument", - }, - "promiseNoneWithArg": Object { - "type": "promise", - "value": 42, - }, - "promiseSingleSync": Object { - "error": "Waterfall hooks must have at least one argument", - }, - "promiseSingleSyncWithArg": Object { - "type": "promise", - "value": 42, - }, - "promiseSingleSyncWithArgCalled": 42, - }, -} -`; diff --git a/test/__snapshots__/SyncLoopHook.test.js.snap b/test/__snapshots__/SyncLoopHook.test.js.snap new file mode 100644 index 0000000..7f8d61b --- /dev/null +++ b/test/__snapshots__/SyncLoopHook.test.js.snap @@ -0,0 +1,88 @@ +// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing + +exports[`SyncLoopHook should have to correct behavior 1`] = ` +Object { + "async": Object {}, + "sync": Object { + "callAsyncInterceptedSync": Object { + "type": "async", + "value": undefined, + }, + "callAsyncInterceptedSyncCalled1": 83, + "callAsyncInterceptedSyncCalled2": 42, + "callAsyncInterceptedSyncCalledCall": 1, + "callAsyncInterceptedSyncCalledLoop": 83, + "callAsyncInterceptedSyncCalledTap": 125, + "callAsyncMultipleSync": Object { + "type": "async", + "value": undefined, + }, + "callAsyncMultipleSyncCalled1": 83, + "callAsyncMultipleSyncCalled2": 42, + "callAsyncNone": Object { + "type": "async", + "value": undefined, + }, + "callAsyncNoneWithArg": Object { + "type": "async", + "value": undefined, + }, + "callAsyncSingleSync": Object { + "type": "async", + "value": undefined, + }, + "callAsyncSingleSyncCalled": 42, + "callInterceptedSync": Object { + "type": "no result", + }, + "callInterceptedSyncCalled1": 83, + "callInterceptedSyncCalled2": 42, + "callInterceptedSyncCalledCall": 1, + "callInterceptedSyncCalledLoop": 83, + "callInterceptedSyncCalledTap": 125, + "callMultipleSync": Object { + "type": "no result", + }, + "callMultipleSyncCalled1": 83, + "callMultipleSyncCalled2": 42, + "callNone": Object { + "type": "no result", + }, + "callNoneWithArg": Object { + "type": "no result", + }, + "callSingleSync": Object { + "type": "no result", + }, + "callSingleSyncCalled": 42, + "promiseInterceptedSync": Object { + "type": "promise", + "value": undefined, + }, + "promiseInterceptedSyncCalled1": 83, + "promiseInterceptedSyncCalled2": 42, + "promiseInterceptedSyncCalledCall": 1, + "promiseInterceptedSyncCalledLoop": 83, + "promiseInterceptedSyncCalledTap": 125, + "promiseMultipleSync": Object { + "type": "promise", + "value": undefined, + }, + "promiseMultipleSyncCalled1": 83, + "promiseMultipleSyncCalled2": 42, + "promiseNone": Object { + "type": "promise", + "value": undefined, + }, + "promiseNoneWithArg": Object { + "type": "promise", + "value": undefined, + }, + "promiseSingleSync": Object { + "type": "promise", + "value": undefined, + }, + "promiseSingleSyncCalled": 42, + }, +} +`; diff --git a/test/__snapshots__/SyncWaterfallHook.test.js.snap b/test/__snapshots__/SyncWaterfallHook.test.js.snap new file mode 100644 index 0000000..fa5240a --- /dev/null +++ b/test/__snapshots__/SyncWaterfallHook.test.js.snap @@ -0,0 +1,259 @@ +// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing + +exports[`SyncWaterfallHook should have to correct behavior 1`] = ` +Object { + "async": Object {}, + "intercept": Object {}, + "sync": Object { + "callAsyncIntercepted": Object { + "type": "async", + "value": 9, + }, + "callAsyncInterceptedCall1": Array [ + 1, + 2, + 3, + ], + "callAsyncInterceptedCall2": Array [ + 1, + 2, + 3, + ], + "callAsyncInterceptedTap1": Object { + "fn": 2, + "name": "sync2", + "type": "sync", + }, + "callAsyncInterceptedTap2": Object { + "fn": 3, + "name": "sync1", + "type": "sync", + }, + "callAsyncMultipleSync": Object { + "error": "Waterfall hooks must have at least one argument", + }, + "callAsyncMultipleSyncError": Object { + "error": "Waterfall hooks must have at least one argument", + }, + "callAsyncMultipleSyncWithArg": Object { + "type": "async", + "value": 127, + }, + "callAsyncMultipleSyncWithArgCalled1": 42, + "callAsyncMultipleSyncWithArgCalled2": 84, + "callAsyncMultipleSyncWithArgFirstReturn": Object { + "type": "async", + "value": 84, + }, + "callAsyncMultipleSyncWithArgFirstReturnCalled1": 42, + "callAsyncMultipleSyncWithArgFirstReturnCalled2": 84, + "callAsyncMultipleSyncWithArgLastReturn": Object { + "type": "async", + "value": 85, + }, + "callAsyncMultipleSyncWithArgLastReturnCalled1": 42, + "callAsyncMultipleSyncWithArgLastReturnCalled2": 42, + "callAsyncMultipleSyncWithArgNoReturn": Object { + "type": "async", + "value": 42, + }, + "callAsyncMultipleSyncWithArgNoReturnCalled1": 42, + "callAsyncMultipleSyncWithArgNoReturnCalled2": 42, + "callAsyncMultipleSyncWithArgs": Object { + "type": "async", + "value": 217, + }, + "callAsyncMultipleSyncWithArgsCalled1": Array [ + 42, + 43, + 44, + ], + "callAsyncMultipleSyncWithArgsCalled2": Array [ + 129, + 43, + 44, + ], + "callAsyncNone": Object { + "error": "Waterfall hooks must have at least one argument", + }, + "callAsyncNoneWithArg": Object { + "type": "async", + "value": 42, + }, + "callAsyncSingleSync": Object { + "error": "Waterfall hooks must have at least one argument", + }, + "callAsyncSingleSyncWithArg": Object { + "type": "async", + "value": 42, + }, + "callAsyncSingleSyncWithArgCalled": 42, + "callIntercepted": Object { + "type": "return", + "value": 9, + }, + "callInterceptedCall1": Array [ + 1, + 2, + 3, + ], + "callInterceptedCall2": Array [ + 1, + 2, + 3, + ], + "callInterceptedTap1": Object { + "fn": 2, + "name": "sync2", + "type": "sync", + }, + "callInterceptedTap2": Object { + "fn": 3, + "name": "sync1", + "type": "sync", + }, + "callMultipleSync": Object { + "error": "Waterfall hooks must have at least one argument", + }, + "callMultipleSyncError": Object { + "error": "Waterfall hooks must have at least one argument", + }, + "callMultipleSyncWithArg": Object { + "type": "return", + "value": 127, + }, + "callMultipleSyncWithArgCalled1": 42, + "callMultipleSyncWithArgCalled2": 84, + "callMultipleSyncWithArgFirstReturn": Object { + "type": "return", + "value": 84, + }, + "callMultipleSyncWithArgFirstReturnCalled1": 42, + "callMultipleSyncWithArgFirstReturnCalled2": 84, + "callMultipleSyncWithArgLastReturn": Object { + "type": "return", + "value": 85, + }, + "callMultipleSyncWithArgLastReturnCalled1": 42, + "callMultipleSyncWithArgLastReturnCalled2": 42, + "callMultipleSyncWithArgNoReturn": Object { + "type": "return", + "value": 42, + }, + "callMultipleSyncWithArgNoReturnCalled1": 42, + "callMultipleSyncWithArgNoReturnCalled2": 42, + "callMultipleSyncWithArgs": Object { + "type": "return", + "value": 217, + }, + "callMultipleSyncWithArgsCalled1": Array [ + 42, + 43, + 44, + ], + "callMultipleSyncWithArgsCalled2": Array [ + 129, + 43, + 44, + ], + "callNone": Object { + "error": "Waterfall hooks must have at least one argument", + }, + "callNoneWithArg": Object { + "type": "return", + "value": 42, + }, + "callSingleSync": Object { + "error": "Waterfall hooks must have at least one argument", + }, + "callSingleSyncWithArg": Object { + "type": "return", + "value": 42, + }, + "callSingleSyncWithArgCalled": 42, + "promiseIntercepted": Object { + "type": "promise", + "value": 9, + }, + "promiseInterceptedCall1": Array [ + 1, + 2, + 3, + ], + "promiseInterceptedCall2": Array [ + 1, + 2, + 3, + ], + "promiseInterceptedTap1": Object { + "fn": 2, + "name": "sync2", + "type": "sync", + }, + "promiseInterceptedTap2": Object { + "fn": 3, + "name": "sync1", + "type": "sync", + }, + "promiseMultipleSync": Object { + "error": "Waterfall hooks must have at least one argument", + }, + "promiseMultipleSyncError": Object { + "error": "Waterfall hooks must have at least one argument", + }, + "promiseMultipleSyncWithArg": Object { + "type": "promise", + "value": 127, + }, + "promiseMultipleSyncWithArgCalled1": 42, + "promiseMultipleSyncWithArgCalled2": 84, + "promiseMultipleSyncWithArgFirstReturn": Object { + "type": "promise", + "value": 84, + }, + "promiseMultipleSyncWithArgFirstReturnCalled1": 42, + "promiseMultipleSyncWithArgFirstReturnCalled2": 84, + "promiseMultipleSyncWithArgLastReturn": Object { + "type": "promise", + "value": 85, + }, + "promiseMultipleSyncWithArgLastReturnCalled1": 42, + "promiseMultipleSyncWithArgLastReturnCalled2": 42, + "promiseMultipleSyncWithArgNoReturn": Object { + "type": "promise", + "value": 42, + }, + "promiseMultipleSyncWithArgNoReturnCalled1": 42, + "promiseMultipleSyncWithArgNoReturnCalled2": 42, + "promiseMultipleSyncWithArgs": Object { + "type": "promise", + "value": 217, + }, + "promiseMultipleSyncWithArgsCalled1": Array [ + 42, + 43, + 44, + ], + "promiseMultipleSyncWithArgsCalled2": Array [ + 129, + 43, + 44, + ], + "promiseNone": Object { + "error": "Waterfall hooks must have at least one argument", + }, + "promiseNoneWithArg": Object { + "type": "promise", + "value": 42, + }, + "promiseSingleSync": Object { + "error": "Waterfall hooks must have at least one argument", + }, + "promiseSingleSyncWithArg": Object { + "type": "promise", + "value": 42, + }, + "promiseSingleSyncWithArgCalled": 42, + }, +} +`; diff --git a/tsconfig.json b/tsconfig.json index 7a4d88f..e14b866 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,17 +1,26 @@ { "compilerOptions": { - "target": "ES2020", - "module": "CommonJS", - "moduleResolution": "node", + "target": "esnext", + "module": "nodenext", + + "resolveJsonModule": true, + "allowSyntheticDefaultImports": true, + + "erasableSyntaxOnly": true, + "verbatimModuleSyntax": true, + "rewriteRelativeImportExtensions": true, + + "types": ["node"], + + "rootDir": "./lib", + "outDir": "./types", + "allowJs": true, - "checkJs": false, - "declaration": true, - "emitDeclarationOnly": true, + "checkJs": true, "strict": true, - "esModuleInterop": true, - "skipLibCheck": true, - "outDir": "./types", - "rootDir": "./lib" + + "declaration": true, + "emitDeclarationOnly": true }, - "include": ["lib/**/*.js"] + "include": ["./lib/**/*"] } From 7eccacf6e5ef326cba59429812270f56b351199c Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 28 Apr 2026 00:14:01 +0000 Subject: [PATCH 3/8] fix(types): resolve TypeScript errors flagged by lint:types - Pass generic args to CompileOptions in all hook subclasses (needs 2-3 type args after upstream made it generic). - Default args parameter to a properly typed cast (via unknown -> ArgumentNames) instead of bare [] in Hook constructor and every subclass factory function. - Cast subclass factory return values to the declared Hook return type (via unknown), since `new Hook(...)` produces the default-parameter variance that does not assign to the generic return. - Fix typo in Hook.CompileOptions where `args` was incorrectly typed as `ArgumentNames>[]` (an array of arg-arrays); it should be `ArgumentNames>` to match the constructor signature. - Cast _createCall results inside CALL_DELEGATE / CALL_ASYNC_DELEGATE / PROMISE_DELEGATE so the `EXPECTED_FUNCTION` return is assignable to the delegate fields. - Widen mergeOptions parameter to `string | (TapOptions & IfSet<...>)` so the wrapped withOptions can recurse through it. - Cast `taps[i]` to `FullTap & IfSet` when calling `interceptor.register` in Hook#intercept. - Add MultiHook tap/tapAsync/tapPromise @template T,R declarations so the JSDoc types resolve, and cast withOptions / tapPromise call sites where the underlying hook contract is wider than the local generics. - Initialize `fn` as `EXPECTED_FUNCTION | undefined` and cast on return in HookCodeFactory#create; type the `every` callback param explicitly; cast options.args when assigning to the local `_args: string[]`. --- lib/AsyncParallelBailHook.js | 8 +++++--- lib/AsyncParallelHook.js | 11 ++++++++--- lib/AsyncSeriesBailHook.js | 11 ++++++++--- lib/AsyncSeriesHook.js | 11 ++++++++--- lib/AsyncSeriesLoopHook.js | 11 ++++++++--- lib/AsyncSeriesWaterfallHook.js | 11 ++++++++--- lib/Hook.js | 33 +++++++++++++++++++++++++-------- lib/HookCodeFactory.js | 14 +++++++++----- lib/MultiHook.js | 18 ++++++++++++++---- lib/SyncBailHook.js | 11 ++++++++--- lib/SyncHook.js | 13 +++++++++---- lib/SyncLoopHook.js | 11 ++++++++--- lib/SyncWaterfallHook.js | 11 ++++++++--- 13 files changed, 126 insertions(+), 48 deletions(-) diff --git a/lib/AsyncParallelBailHook.js b/lib/AsyncParallelBailHook.js index 907cfb6..788f5cd 100644 --- a/lib/AsyncParallelBailHook.js +++ b/lib/AsyncParallelBailHook.js @@ -10,7 +10,7 @@ const HookCodeFactory = require("./HookCodeFactory"); /** @typedef {import("./Hook").EXPECTED_ANY} EXPECTED_ANY */ /** @typedef {import("./Hook").EXPECTED_FUNCTION} EXPECTED_FUNCTION */ /** @typedef {import("./Hook").UnsetAdditionalOptions} UnsetAdditionalOptions */ -/** @typedef {import("./Hook").CompileOptions} CompileOptions */ +/** @typedef {import("./Hook").CompileOptions} CompileOptions */ /** @typedef {import("./HookCodeFactory").ContentOptions} ContentOptions */ /** * @template {EXPECTED_ANY[]} T @@ -110,7 +110,7 @@ function COMPILE(options) { * @returns {Hook} a new AsyncParallelBailHook instance */ function AsyncParallelBailHook( - args = /** @type {ArgumentNames>} */ ([]), + args = /** @type {ArgumentNames>} */ (/** @type {unknown} */ ([])), name = undefined ) { const hook = new Hook(args, name); @@ -118,7 +118,9 @@ function AsyncParallelBailHook( hook.compile = COMPILE; hook._call = undefined; hook.call = undefined; - return hook; + return /** @type {Hook} */ ( + /** @type {unknown} */ (hook) + ); } /** @type {EXPECTED_ANY} */ diff --git a/lib/AsyncParallelHook.js b/lib/AsyncParallelHook.js index 288930d..8d5ebe4 100644 --- a/lib/AsyncParallelHook.js +++ b/lib/AsyncParallelHook.js @@ -9,7 +9,7 @@ const HookCodeFactory = require("./HookCodeFactory"); /** @typedef {import("./Hook").EXPECTED_ANY} EXPECTED_ANY */ /** @typedef {import("./Hook").EXPECTED_FUNCTION} EXPECTED_FUNCTION */ -/** @typedef {import("./Hook").CompileOptions} CompileOptions */ +/** @typedef {import("./Hook").CompileOptions} CompileOptions */ /** @typedef {import("./Hook").UnsetAdditionalOptions} UnsetAdditionalOptions */ /** @typedef {import("./HookCodeFactory").ContentOptions} ContentOptions */ /** @@ -54,13 +54,18 @@ function COMPILE(options) { * @param {string=} name name of the hook * @returns {Hook} a new AsyncParallelBailHook instance */ -function AsyncParallelHook(args = [], name = undefined) { +function AsyncParallelHook( + args = /** @type {ArgumentNames>} */ (/** @type {unknown} */ ([])), + name = undefined +) { const hook = new Hook(args, name); hook.constructor = AsyncParallelHook; hook.compile = COMPILE; hook._call = undefined; hook.call = undefined; - return hook; + return /** @type {Hook} */ ( + /** @type {unknown} */ (hook) + ); } /** @type {EXPECTED_ANY} */ diff --git a/lib/AsyncSeriesBailHook.js b/lib/AsyncSeriesBailHook.js index 3bd105a..3756a54 100644 --- a/lib/AsyncSeriesBailHook.js +++ b/lib/AsyncSeriesBailHook.js @@ -9,7 +9,7 @@ const HookCodeFactory = require("./HookCodeFactory"); /** @typedef {import("./Hook").EXPECTED_ANY} EXPECTED_ANY */ /** @typedef {import("./Hook").EXPECTED_FUNCTION} EXPECTED_FUNCTION */ -/** @typedef {import("./Hook").CompileOptions} CompileOptions */ +/** @typedef {import("./Hook").CompileOptions} CompileOptions */ /** @typedef {import("./Hook").UnsetAdditionalOptions} UnsetAdditionalOptions */ /** @typedef {import("./HookCodeFactory").ContentOptions} ContentOptions */ /** @@ -60,13 +60,18 @@ function COMPILE(options) { * @param {string=} name name of the hook * @returns {Hook} a new AsyncParallelBailHook instance */ -function AsyncSeriesBailHook(args = [], name = undefined) { +function AsyncSeriesBailHook( + args = /** @type {ArgumentNames>} */ (/** @type {unknown} */ ([])), + name = undefined +) { const hook = new Hook(args, name); hook.constructor = AsyncSeriesBailHook; hook.compile = COMPILE; hook._call = undefined; hook.call = undefined; - return hook; + return /** @type {Hook} */ ( + /** @type {unknown} */ (hook) + ); } /** @type {EXPECTED_ANY} */ diff --git a/lib/AsyncSeriesHook.js b/lib/AsyncSeriesHook.js index 6a118b6..6fcffd4 100644 --- a/lib/AsyncSeriesHook.js +++ b/lib/AsyncSeriesHook.js @@ -9,7 +9,7 @@ const HookCodeFactory = require("./HookCodeFactory"); /** @typedef {import("./Hook").EXPECTED_ANY} EXPECTED_ANY */ /** @typedef {import("./Hook").EXPECTED_FUNCTION} EXPECTED_FUNCTION */ -/** @typedef {import("./Hook").CompileOptions} CompileOptions */ +/** @typedef {import("./Hook").CompileOptions} CompileOptions */ /** @typedef {import("./Hook").UnsetAdditionalOptions} UnsetAdditionalOptions */ /** @typedef {import("./HookCodeFactory").ContentOptions} ContentOptions */ /** @@ -54,13 +54,18 @@ function COMPILE(options) { * @param {string=} name name of the hook * @returns {Hook} a new AsyncParallelBailHook instance */ -function AsyncSeriesHook(args = [], name = undefined) { +function AsyncSeriesHook( + args = /** @type {ArgumentNames>} */ (/** @type {unknown} */ ([])), + name = undefined +) { const hook = new Hook(args, name); hook.constructor = AsyncSeriesHook; hook.compile = COMPILE; hook._call = undefined; hook.call = undefined; - return hook; + return /** @type {Hook} */ ( + /** @type {unknown} */ (hook) + ); } /** @type {EXPECTED_ANY} */ diff --git a/lib/AsyncSeriesLoopHook.js b/lib/AsyncSeriesLoopHook.js index b795d46..156c873 100644 --- a/lib/AsyncSeriesLoopHook.js +++ b/lib/AsyncSeriesLoopHook.js @@ -9,7 +9,7 @@ const HookCodeFactory = require("./HookCodeFactory"); /** @typedef {import("./Hook").EXPECTED_ANY} EXPECTED_ANY */ /** @typedef {import("./Hook").EXPECTED_FUNCTION} EXPECTED_FUNCTION */ -/** @typedef {import("./Hook").CompileOptions} CompileOptions */ +/** @typedef {import("./Hook").CompileOptions} CompileOptions */ /** @typedef {import("./Hook").UnsetAdditionalOptions} UnsetAdditionalOptions */ /** @typedef {import("./HookCodeFactory").ContentOptions} ContentOptions */ /** @@ -54,13 +54,18 @@ function COMPILE(options) { * @param {string=} name name of the hook * @returns {Hook} a new AsyncParallelBailHook instance */ -function AsyncSeriesLoopHook(args = [], name = undefined) { +function AsyncSeriesLoopHook( + args = /** @type {ArgumentNames>} */ (/** @type {unknown} */ ([])), + name = undefined +) { const hook = new Hook(args, name); hook.constructor = AsyncSeriesLoopHook; hook.compile = COMPILE; hook._call = undefined; hook.call = undefined; - return hook; + return /** @type {Hook} */ ( + /** @type {unknown} */ (hook) + ); } /** @type {EXPECTED_ANY} */ diff --git a/lib/AsyncSeriesWaterfallHook.js b/lib/AsyncSeriesWaterfallHook.js index aba298d..3eb302e 100644 --- a/lib/AsyncSeriesWaterfallHook.js +++ b/lib/AsyncSeriesWaterfallHook.js @@ -9,7 +9,7 @@ const HookCodeFactory = require("./HookCodeFactory"); /** @typedef {import("./Hook").EXPECTED_ANY} EXPECTED_ANY */ /** @typedef {import("./Hook").EXPECTED_FUNCTION} EXPECTED_FUNCTION */ -/** @typedef {import("./Hook").CompileOptions} CompileOptions */ +/** @typedef {import("./Hook").CompileOptions} CompileOptions */ /** @typedef {import("./Hook").UnsetAdditionalOptions} UnsetAdditionalOptions */ /** @typedef {import("./HookCodeFactory").ContentOptions} ContentOptions */ /** @@ -63,7 +63,10 @@ function COMPILE(options) { * @param {string=} name name of the hook * @returns {Hook} a new AsyncParallelBailHook instance */ -function AsyncSeriesWaterfallHook(args = [], name = undefined) { +function AsyncSeriesWaterfallHook( + args = /** @type {ArgumentNames>} */ (/** @type {unknown} */ ([])), + name = undefined +) { if (args.length < 1) { throw new Error("Waterfall hooks must have at least one argument"); } @@ -72,7 +75,9 @@ function AsyncSeriesWaterfallHook(args = [], name = undefined) { hook.compile = COMPILE; hook._call = undefined; hook.call = undefined; - return hook; + return /** @type {Hook} */ ( + /** @type {unknown} */ (hook) + ); } /** @type {EXPECTED_ANY} */ diff --git a/lib/Hook.js b/lib/Hook.js index c1b7b2c..5b39a32 100644 --- a/lib/Hook.js +++ b/lib/Hook.js @@ -108,7 +108,7 @@ const util = require("util"); * @typedef {object} CompileOptions * @property {FullTap[]} taps the registered taps * @property {HookInterceptor[]} interceptors the registered interceptors - * @property {ArgumentNames>[]} args names of the hook arguments (used for code generation) + * @property {ArgumentNames>} args names of the hook arguments (used for code generation) * @property {"sync" | "async" | "promise"} type call type */ @@ -130,7 +130,7 @@ const deprecateContext = util.deprecate( * @this {Hook} */ function CALL_DELEGATE(...args) { - this.call = this._createCall("sync"); + this.call = /** @type {CallDelegate} */ (this._createCall("sync")); return this.call(...args); } @@ -147,7 +147,9 @@ function CALL_DELEGATE(...args) { * @this {Hook} */ function CALL_ASYNC_DELEGATE(...args) { - this.callAsync = this._createCall("async"); + this.callAsync = /** @type {CallAsyncDelegate} */ ( + this._createCall("async") + ); return this.callAsync(...args); } @@ -164,7 +166,9 @@ function CALL_ASYNC_DELEGATE(...args) { * @this {Hook} */ function PROMISE_DELEGATE(...args) { - this.promise = this._createCall("promise"); + this.promise = /** @type {PromiseDeledate} */ ( + this._createCall("promise") + ); return this.promise(...args); } @@ -178,7 +182,12 @@ class Hook { * @param {ArgumentNames>=} args argument names of the hook (used for code generation) * @param {string=} name name of the hook */ - constructor(args = [], name = undefined) { + constructor( + args = /** @type {ArgumentNames>} */ ( + /** @type {unknown} */ ([]) + ), + name = undefined + ) { /** @type {ArgumentNames>} */ this._args = args; /** @type {string | undefined} */ @@ -356,11 +365,17 @@ class Hook { */ withOptions(options) { /** - * @param {string | (Tap & IfSet)} opt options + * @param {string | (TapOptions & IfSet)} opt options * @returns {Tap & IfSet} merged options */ const mergeOptions = (opt) => - Object.assign({}, options, typeof opt === "string" ? { name: opt } : opt); + /** @type {Tap & IfSet} */ ( + Object.assign( + {}, + options, + typeof opt === "string" ? { name: opt } : opt + ) + ); return /** @type {Omit} */ ({ name: this.name, @@ -389,7 +404,9 @@ class Hook { this.interceptors.push(Object.assign({}, interceptor)); if (interceptor.register) { for (let i = 0; i < this.taps.length; i++) { - this.taps[i] = interceptor.register(this.taps[i]); + this.taps[i] = interceptor.register( + /** @type {FullTap & IfSet} */ (this.taps[i]) + ); } } } diff --git a/lib/HookCodeFactory.js b/lib/HookCodeFactory.js index f089924..5961d41 100644 --- a/lib/HookCodeFactory.js +++ b/lib/HookCodeFactory.js @@ -8,7 +8,7 @@ /** @typedef {import("./Hook").EXPECTED_OBJECT} EXPECTED_OBJECT */ /** @typedef {import("./Hook").EXPECTED_FUNCTION} EXPECTED_FUNCTION */ /** @typedef {import("./Hook").FullTap} FullTap */ -/** @typedef {import("./Hook").CompileOptions} CompileOptions */ +/** @typedef {import("./Hook").CompileOptions} CompileOptions */ /** * @template T, R, AdditionalOptions @@ -83,7 +83,7 @@ class HookCodeFactory { */ create(options) { this.init(options); - /** @type {EXPECTED_FUNCTION} */ + /** @type {EXPECTED_FUNCTION | undefined} */ let fn; switch (options.type) { case "sync": @@ -144,7 +144,7 @@ class HookCodeFactory { } } this.deinit(); - return fn; + return /** @type {EXPECTED_FUNCTION} */ (fn); } /** @@ -181,7 +181,9 @@ class HookCodeFactory { // `_args` is only read (length / join / [0]) - never mutated - so we // can share the caller's array directly instead of paying for a copy // on every compile. - this._args = options.args; + this._args = /** @type {string[]} */ ( + /** @type {unknown} */ (options.args) + ); /** @type {string | undefined} */ this._joinedArgs = undefined; } @@ -468,7 +470,9 @@ class HookCodeFactory { callTapsLooping({ onError, onDone, rethrowIfPossible }) { const opts = /** @type {CompileOptions} */ (this.options); if (opts.taps.length === 0) return onDone(); - const syncOnly = opts.taps.every((t) => t.type === "sync"); + const syncOnly = opts.taps.every( + (/** @type {FullTap} */ t) => t.type === "sync" + ); let code = ""; if (!syncOnly) { code += "var _looper = (function() {\n"; diff --git a/lib/MultiHook.js b/lib/MultiHook.js index 78cdd74..051dbd9 100644 --- a/lib/MultiHook.js +++ b/lib/MultiHook.js @@ -53,6 +53,7 @@ class MultiHook { } /** + * @template T, R * @param {string | Tap} options tap name or full tap options * @param {(...args: AsArray) => R} fn the function to register * @returns {void} @@ -65,6 +66,7 @@ class MultiHook { } /** + * @template T, R * @param {string | Tap} options tap name or full tap options * @param {(...args: Append, InnerCallback>) => void} fn the function to register * @returns {void} @@ -77,6 +79,7 @@ class MultiHook { } /** + * @template T, R * @param {string | Tap} options tap name or full tap options * @param {(...args: AsArray) => Promise} fn the function to register * @returns {void} @@ -84,7 +87,7 @@ class MultiHook { tapPromise(options, fn) { const { hooks } = this; for (let i = 0; i < hooks.length; i++) { - hooks[i].tapPromise(options, fn); + hooks[i].tapPromise(options, /** @type {EXPECTED_ANY} */ (fn)); } } @@ -117,9 +120,16 @@ class MultiHook { * @returns {MultiHook} a new MultiHook wrapping each underlying hook with the options */ withOptions(options) { - return new MultiHook( - this.hooks.map((hook) => hook.withOptions(options)), - this.name + return /** @type {MultiHook} */ ( + new MultiHook( + this.hooks.map( + (hook) => + /** @type {H} */ ( + /** @type {unknown} */ (hook.withOptions(options)) + ) + ), + this.name + ) ); } } diff --git a/lib/SyncBailHook.js b/lib/SyncBailHook.js index efdc0fb..b25325f 100644 --- a/lib/SyncBailHook.js +++ b/lib/SyncBailHook.js @@ -10,7 +10,7 @@ const HookCodeFactory = require("./HookCodeFactory"); /** @typedef {import("./Hook").EXPECTED_ANY} EXPECTED_ANY */ /** @typedef {import("./Hook").EXPECTED_FUNCTION} EXPECTED_FUNCTION */ /** @typedef {import("./Hook").UnsetAdditionalOptions} UnsetAdditionalOptions */ -/** @typedef {import("./Hook").CompileOptions} CompileOptions */ +/** @typedef {import("./Hook").CompileOptions} CompileOptions */ /** @typedef {import("./HookCodeFactory").ContentOptions} ContentOptions */ /** @@ -70,13 +70,18 @@ function COMPILE(options) { * @param {string=} name name of the hook * @returns {Hook} a new AsyncParallelBailHook instance */ -function SyncBailHook(args = [], name = undefined) { +function SyncBailHook( + args = /** @type {ArgumentNames>} */ (/** @type {unknown} */ ([])), + name = undefined +) { const hook = new Hook(args, name); hook.constructor = SyncBailHook; hook.tapAsync = TAP_ASYNC; hook.tapPromise = TAP_PROMISE; hook.compile = COMPILE; - return hook; + return /** @type {Hook} */ ( + /** @type {unknown} */ (hook) + ); } /** @type {EXPECTED_ANY} */ diff --git a/lib/SyncHook.js b/lib/SyncHook.js index 0a9485a..fecdbaf 100644 --- a/lib/SyncHook.js +++ b/lib/SyncHook.js @@ -10,7 +10,7 @@ const HookCodeFactory = require("./HookCodeFactory"); /** @typedef {import("./Hook").EXPECTED_ANY} EXPECTED_ANY */ /** @typedef {import("./Hook").EXPECTED_FUNCTION} EXPECTED_FUNCTION */ /** @typedef {import("./Hook").UnsetAdditionalOptions} UnsetAdditionalOptions */ -/** @typedef {import("./Hook").CompileOptions} CompileOptions */ +/** @typedef {import("./Hook").CompileOptions} CompileOptions */ /** @typedef {import("./HookCodeFactory").ContentOptions} ContentOptions */ /** @@ -63,15 +63,20 @@ function COMPILE(options) { * @template [AdditionalOptions=UnsetAdditionalOptions] * @param {ArgumentNames>=} args argument names of the hook * @param {string=} name name of the hook - * @returns {Hook} a new AsyncParallelBailHook instance + * @returns {Hook} a new SyncHook instance */ -function SyncHook(args = [], name = undefined) { +function SyncHook( + args = /** @type {ArgumentNames>} */ (/** @type {unknown} */ ([])), + name = undefined +) { const hook = new Hook(args, name); hook.constructor = SyncHook; hook.tapAsync = TAP_ASYNC; hook.tapPromise = TAP_PROMISE; hook.compile = COMPILE; - return hook; + return /** @type {Hook} */ ( + /** @type {unknown} */ (hook) + ); } /** @type {EXPECTED_ANY} */ diff --git a/lib/SyncLoopHook.js b/lib/SyncLoopHook.js index 245136d..0dbd95f 100644 --- a/lib/SyncLoopHook.js +++ b/lib/SyncLoopHook.js @@ -9,7 +9,7 @@ const HookCodeFactory = require("./HookCodeFactory"); /** @typedef {import("./Hook").EXPECTED_ANY} EXPECTED_ANY */ /** @typedef {import("./Hook").EXPECTED_FUNCTION} EXPECTED_FUNCTION */ -/** @typedef {import("./Hook").CompileOptions} CompileOptions */ +/** @typedef {import("./Hook").CompileOptions} CompileOptions */ /** @typedef {import("./Hook").UnsetAdditionalOptions} UnsetAdditionalOptions */ /** @typedef {import("./HookCodeFactory").ContentOptions} ContentOptions */ /** @@ -63,13 +63,18 @@ function COMPILE(options) { * @param {string=} name name of the hook * @returns {Hook} a new AsyncParallelBailHook instance */ -function SyncLoopHook(args = [], name = undefined) { +function SyncLoopHook( + args = /** @type {ArgumentNames>} */ (/** @type {unknown} */ ([])), + name = undefined +) { const hook = new Hook(args, name); hook.constructor = SyncLoopHook; hook.tapAsync = TAP_ASYNC; hook.tapPromise = TAP_PROMISE; hook.compile = COMPILE; - return hook; + return /** @type {Hook} */ ( + /** @type {unknown} */ (hook) + ); } /** @type {EXPECTED_ANY} */ diff --git a/lib/SyncWaterfallHook.js b/lib/SyncWaterfallHook.js index 556eef8..f4e6a52 100644 --- a/lib/SyncWaterfallHook.js +++ b/lib/SyncWaterfallHook.js @@ -9,7 +9,7 @@ const HookCodeFactory = require("./HookCodeFactory"); /** @typedef {import("./Hook").EXPECTED_ANY} EXPECTED_ANY */ /** @typedef {import("./Hook").EXPECTED_FUNCTION} EXPECTED_FUNCTION */ -/** @typedef {import("./Hook").CompileOptions} CompileOptions */ +/** @typedef {import("./Hook").CompileOptions} CompileOptions */ /** @typedef {import("./Hook").UnsetAdditionalOptions} UnsetAdditionalOptions */ /** @typedef {import("./HookCodeFactory").ContentOptions} ContentOptions */ /** @@ -73,7 +73,10 @@ function COMPILE(options) { * @param {string=} name name of the hook * @returns {Hook} a new AsyncParallelBailHook instance */ -function SyncWaterfallHook(args = [], name = undefined) { +function SyncWaterfallHook( + args = /** @type {ArgumentNames>} */ (/** @type {unknown} */ ([])), + name = undefined +) { if (args.length < 1) { throw new Error("Waterfall hooks must have at least one argument"); } @@ -82,7 +85,9 @@ function SyncWaterfallHook(args = [], name = undefined) { hook.tapAsync = TAP_ASYNC; hook.tapPromise = TAP_PROMISE; hook.compile = COMPILE; - return hook; + return /** @type {Hook} */ ( + /** @type {unknown} */ (hook) + ); } /** @type {EXPECTED_ANY} */ From 3fc13ff7cb922440685dc41b57d0b5eb9d242549 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 28 Apr 2026 12:50:38 +0000 Subject: [PATCH 4/8] test(Hook): pin V8 hidden-class layout invariants Lock down the optimization that lives in `Hook.js`: the `Object.setPrototypeOf(Hook.prototype, null)` call and the trailing `this.compile = this.compile` (and friends) self-assignments in the constructor. Together they force `compile`/`tap`/`tapAsync`/`tapPromise` to be own properties in a fixed insertion order so that subclass overrides (`SyncHook`, `AsyncSeriesHook`, ...) overwrite existing slots instead of triggering a hidden-class transition - keeping shared call sites monomorphic. The new tests assert: - Hook.prototype has a null prototype. - compile / tap / tapAsync / tapPromise and the call/_call, callAsync/_callAsync, promise/_promise pairs are own properties. - The base Hook layout is the documented 15-key sequence. - Every subclass instance shares the same 16-key layout (base + the trailing `constructor` slot the factories add) - across all 10 subclass families. - Exercising a hook (intercept/tap/call) does not introduce new own properties or change ordering. - Async* hooks keep `call`/`_call` as own properties holding `undefined` rather than deleting them, so the layout still matches. A future "cleanup" that removes the self-assignments or rearranges the constructor will now fail the suite instead of silently regressing hot-path performance. --- test/Hook.test.js | 139 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 139 insertions(+) diff --git a/test/Hook.test.js b/test/Hook.test.js index 6b551d4..eb677b2 100644 --- a/test/Hook.test.js +++ b/test/Hook.test.js @@ -4,8 +4,17 @@ */ "use strict"; +const AsyncParallelBailHook = require("../lib/AsyncParallelBailHook"); +const AsyncParallelHook = require("../lib/AsyncParallelHook"); +const AsyncSeriesBailHook = require("../lib/AsyncSeriesBailHook"); +const AsyncSeriesHook = require("../lib/AsyncSeriesHook"); +const AsyncSeriesLoopHook = require("../lib/AsyncSeriesLoopHook"); +const AsyncSeriesWaterfallHook = require("../lib/AsyncSeriesWaterfallHook"); const HookTest = require("../lib/Hook"); +const SyncBailHook = require("../lib/SyncBailHook"); const SyncHook = require("../lib/SyncHook"); +const SyncLoopHook = require("../lib/SyncLoopHook"); +const SyncWaterfallHook = require("../lib/SyncWaterfallHook"); describe("Hook", () => { it("should throw when compile is not overridden", () => { @@ -200,6 +209,136 @@ describe("Hook", () => { expect(hook.taps[1].extra).toBe("value"); }); + describe("instance shape (V8 hidden-class layout)", () => { + // `Hook.js` ends with `Object.setPrototypeOf(Hook.prototype, null)` and + // the constructor does `this.compile = this.compile` etc. Both are + // load-bearing performance optimizations - the self-assignments force + // the methods that subclasses overwrite (`compile`, `tap`, `tapAsync`, + // `tapPromise`) to be own properties in a fixed insertion order, so + // every Hook/SyncHook/AsyncSeriesHook/... lands in the same V8 hidden + // class. These tests pin the contract so a future "cleanup" cannot + // silently regress it. + + // Layout produced by the base `Hook` constructor. + const baseOwnKeys = [ + "_args", + "name", + "taps", + "interceptors", + "_call", + "call", + "_callAsync", + "callAsync", + "_promise", + "promise", + "_x", + "compile", + "tap", + "tapAsync", + "tapPromise" + ]; + + // Subclass factories (`SyncHook(...)` etc.) tack `constructor` onto the + // instance *after* the base layout is established, then overwrite a + // few of the existing slots in place. So every subclass instance ends + // up with the same shape, distinct from the bare `new Hook(...)` shape + // but identical across all subclass families - which is the case that + // matters in practice (users instantiate subclasses, not Hook). + const subclassOwnKeys = [...baseOwnKeys, "constructor"]; + + it("hook.prototype has a null prototype", () => { + // `Object.setPrototypeOf(Hook.prototype, null)` keeps property + // lookup at one hop and protects against prototype pollution. + expect(Object.getPrototypeOf(HookTest.prototype)).toBeNull(); + }); + + it("makes compile/tap/tapAsync/tapPromise own properties on every Hook instance", () => { + const hook = new HookTest(["arg"]); + // Self-assignments in the constructor must produce own props, + // not inherited ones - otherwise subclass overwrites would + // trigger a hidden-class transition on every instance. + expect(Object.prototype.hasOwnProperty.call(hook, "compile")).toBe(true); + expect(Object.prototype.hasOwnProperty.call(hook, "tap")).toBe(true); + expect(Object.prototype.hasOwnProperty.call(hook, "tapAsync")).toBe(true); + expect(Object.prototype.hasOwnProperty.call(hook, "tapPromise")).toBe( + true + ); + }); + + it("makes the call/_call/callAsync/_callAsync/promise/_promise pairs own properties", () => { + const hook = new HookTest(["arg"]); + // The split is the lazy-compile reset pattern: `_xxx` is the + // delegate, `xxx` is the live slot that gets replaced with the + // compiled function on first invocation. + for (const key of [ + "_call", + "call", + "_callAsync", + "callAsync", + "_promise", + "promise" + ]) { + expect(Object.prototype.hasOwnProperty.call(hook, key)).toBe(true); + } + }); + + it("preserves the own-property insertion order on a base Hook", () => { + const hook = new HookTest(["arg"]); + expect(Object.keys(hook)).toEqual(baseOwnKeys); + }); + + it("preserves the same own-property layout across every Hook subclass", () => { + // Subclasses overwrite `compile`/`tapAsync`/`tapPromise` (and some + // wipe `_call`/`call` to undefined), but they must not introduce + // new own properties or change their order beyond the trailing + // `constructor` assignment. Otherwise instances of different + // subclasses end up in different hidden classes and shared call + // sites turn polymorphic. + const subclasses = [ + new SyncHook(["arg"]), + new SyncBailHook(["arg"]), + new SyncLoopHook(["arg"]), + new SyncWaterfallHook(["arg"]), + new AsyncParallelHook(["arg"]), + new AsyncParallelBailHook(["arg"]), + new AsyncSeriesHook(["arg"]), + new AsyncSeriesBailHook(["arg"]), + new AsyncSeriesLoopHook(["arg"]), + new AsyncSeriesWaterfallHook(["arg"]) + ]; + + for (const hook of subclasses) { + expect(Object.keys(hook)).toEqual(subclassOwnKeys); + } + }); + + it("does not change the own-property layout after taps/interceptors/calls", () => { + // Once a hook is exercised end-to-end (tap, intercept, call) the + // own-property set must still match the layout established by the + // constructor. Anything new added by `_resetCompilation`, + // `intercept`, the lazy compile, etc. would change the hidden + // class for every hook that has ever been used. + const hook = new SyncHook(["arg"]); + hook.intercept({ call: () => {} }); + hook.tap("A", () => {}); + hook.call(1); + + expect(Object.keys(hook)).toEqual(subclassOwnKeys); + }); + + it("keeps Async* hooks in the same layout even with call/_call set to undefined", () => { + // Async* hooks set `hook.call = undefined; hook._call = undefined` + // to disable the sync entrypoint. The slots must still exist as + // own properties (just holding `undefined`) so the hidden class + // matches the rest of the family. + const hook = new AsyncSeriesHook(["arg"]); + expect(Object.prototype.hasOwnProperty.call(hook, "call")).toBe(true); + expect(Object.prototype.hasOwnProperty.call(hook, "_call")).toBe(true); + expect(hook.call).toBeUndefined(); + expect(hook._call).toBeUndefined(); + }); + }); + it("should not ignore invalid before values", () => { // A plugin may use a hook that will never be executed const hook = new SyncHook(); From f47cc10ea201209a0848db3e07b38c2928c40082 Mon Sep 17 00:00:00 2001 From: alexander-akait Date: Tue, 28 Apr 2026 16:00:17 +0300 Subject: [PATCH 5/8] refactor: code --- lib/AsyncParallelBailHook.js | 1 + lib/AsyncParallelHook.js | 3 ++- lib/AsyncSeriesBailHook.js | 3 ++- lib/AsyncSeriesHook.js | 3 ++- lib/AsyncSeriesLoopHook.js | 3 ++- lib/AsyncSeriesWaterfallHook.js | 3 ++- lib/Hook.js | 42 +++++++++++++++++++++++---------- lib/HookCodeFactory.js | 8 +++---- 8 files changed, 44 insertions(+), 22 deletions(-) diff --git a/lib/AsyncParallelBailHook.js b/lib/AsyncParallelBailHook.js index 788f5cd..138e4ea 100644 --- a/lib/AsyncParallelBailHook.js +++ b/lib/AsyncParallelBailHook.js @@ -116,6 +116,7 @@ function AsyncParallelBailHook( const hook = new Hook(args, name); hook.constructor = AsyncParallelBailHook; hook.compile = COMPILE; + // @ts-expect-error for performance reasons hook._call = undefined; hook.call = undefined; return /** @type {Hook} */ ( diff --git a/lib/AsyncParallelHook.js b/lib/AsyncParallelHook.js index 8d5ebe4..b34da11 100644 --- a/lib/AsyncParallelHook.js +++ b/lib/AsyncParallelHook.js @@ -52,7 +52,7 @@ function COMPILE(options) { * @template [AdditionalOptions=UnsetAdditionalOptions] * @param {ArgumentNames>=} args argument names of the hook * @param {string=} name name of the hook - * @returns {Hook} a new AsyncParallelBailHook instance + * @returns {Hook} a new AsyncParallelHook instance */ function AsyncParallelHook( args = /** @type {ArgumentNames>} */ (/** @type {unknown} */ ([])), @@ -61,6 +61,7 @@ function AsyncParallelHook( const hook = new Hook(args, name); hook.constructor = AsyncParallelHook; hook.compile = COMPILE; + // @ts-expect-error for performance reasons hook._call = undefined; hook.call = undefined; return /** @type {Hook} */ ( diff --git a/lib/AsyncSeriesBailHook.js b/lib/AsyncSeriesBailHook.js index 3756a54..3732dba 100644 --- a/lib/AsyncSeriesBailHook.js +++ b/lib/AsyncSeriesBailHook.js @@ -58,7 +58,7 @@ function COMPILE(options) { * @template [AdditionalOptions=UnsetAdditionalOptions] * @param {ArgumentNames>=} args argument names of the hook * @param {string=} name name of the hook - * @returns {Hook} a new AsyncParallelBailHook instance + * @returns {Hook} a new AsyncSeriesBailHook instance */ function AsyncSeriesBailHook( args = /** @type {ArgumentNames>} */ (/** @type {unknown} */ ([])), @@ -67,6 +67,7 @@ function AsyncSeriesBailHook( const hook = new Hook(args, name); hook.constructor = AsyncSeriesBailHook; hook.compile = COMPILE; + // @ts-expect-error for performance reasons hook._call = undefined; hook.call = undefined; return /** @type {Hook} */ ( diff --git a/lib/AsyncSeriesHook.js b/lib/AsyncSeriesHook.js index 6fcffd4..8b6d2e8 100644 --- a/lib/AsyncSeriesHook.js +++ b/lib/AsyncSeriesHook.js @@ -52,7 +52,7 @@ function COMPILE(options) { * @template [AdditionalOptions=UnsetAdditionalOptions] * @param {ArgumentNames>=} args argument names of the hook * @param {string=} name name of the hook - * @returns {Hook} a new AsyncParallelBailHook instance + * @returns {Hook} a new AsyncSeriesHook instance */ function AsyncSeriesHook( args = /** @type {ArgumentNames>} */ (/** @type {unknown} */ ([])), @@ -61,6 +61,7 @@ function AsyncSeriesHook( const hook = new Hook(args, name); hook.constructor = AsyncSeriesHook; hook.compile = COMPILE; + // @ts-expect-error for performance reasons hook._call = undefined; hook.call = undefined; return /** @type {Hook} */ ( diff --git a/lib/AsyncSeriesLoopHook.js b/lib/AsyncSeriesLoopHook.js index 156c873..78fb7b3 100644 --- a/lib/AsyncSeriesLoopHook.js +++ b/lib/AsyncSeriesLoopHook.js @@ -52,7 +52,7 @@ function COMPILE(options) { * @template [AdditionalOptions=UnsetAdditionalOptions] * @param {ArgumentNames>=} args argument names of the hook * @param {string=} name name of the hook - * @returns {Hook} a new AsyncParallelBailHook instance + * @returns {Hook} a new AsyncSeriesLoopHook instance */ function AsyncSeriesLoopHook( args = /** @type {ArgumentNames>} */ (/** @type {unknown} */ ([])), @@ -61,6 +61,7 @@ function AsyncSeriesLoopHook( const hook = new Hook(args, name); hook.constructor = AsyncSeriesLoopHook; hook.compile = COMPILE; + // @ts-expect-error for performance reasons hook._call = undefined; hook.call = undefined; return /** @type {Hook} */ ( diff --git a/lib/AsyncSeriesWaterfallHook.js b/lib/AsyncSeriesWaterfallHook.js index 3eb302e..4134bf1 100644 --- a/lib/AsyncSeriesWaterfallHook.js +++ b/lib/AsyncSeriesWaterfallHook.js @@ -61,7 +61,7 @@ function COMPILE(options) { * @template [AdditionalOptions=UnsetAdditionalOptions] * @param {ArgumentNames>=} args argument names of the hook * @param {string=} name name of the hook - * @returns {Hook} a new AsyncParallelBailHook instance + * @returns {Hook} a new AsyncSeriesWaterfallHookCodeFactory instance */ function AsyncSeriesWaterfallHook( args = /** @type {ArgumentNames>} */ (/** @type {unknown} */ ([])), @@ -73,6 +73,7 @@ function AsyncSeriesWaterfallHook( const hook = new Hook(args, name); hook.constructor = AsyncSeriesWaterfallHook; hook.compile = COMPILE; + // @ts-expect-error for performance reasons hook._call = undefined; hook.call = undefined; return /** @type {Hook} */ ( diff --git a/lib/Hook.js b/lib/Hook.js index 5b39a32..851fb3c 100644 --- a/lib/Hook.js +++ b/lib/Hook.js @@ -80,6 +80,7 @@ const util = require("util"); * @typedef {(error?: E | null | false, result?: T) => void} InnerCallback */ +// TODO remove context in the next major release, deprecated /** * @template T * @template R @@ -130,7 +131,9 @@ const deprecateContext = util.deprecate( * @this {Hook} */ function CALL_DELEGATE(...args) { - this.call = /** @type {CallDelegate} */ (this._createCall("sync")); + // @ts-expect-error for performance reasons + this.call = this._createCall("sync"); + // @ts-expect-error for performance reasons return this.call(...args); } @@ -147,9 +150,8 @@ function CALL_DELEGATE(...args) { * @this {Hook} */ function CALL_ASYNC_DELEGATE(...args) { - this.callAsync = /** @type {CallAsyncDelegate} */ ( - this._createCall("async") - ); + // @ts-expect-error for performance reasons + this.callAsync = this._createCall("async"); return this.callAsync(...args); } @@ -166,15 +168,14 @@ function CALL_ASYNC_DELEGATE(...args) { * @this {Hook} */ function PROMISE_DELEGATE(...args) { - this.promise = /** @type {PromiseDeledate} */ ( - this._createCall("promise") - ); + // @ts-expect-error for performance reasons + this.promise = this._createCall("promise"); return this.promise(...args); } /** * @template T - * @template [R=void] + * @template R * @template [AdditionalOptions=UnsetAdditionalOptions] */ class Hook { @@ -188,7 +189,10 @@ class Hook { ), name = undefined ) { - /** @type {ArgumentNames>} */ + /** + * @private + * @type {ArgumentNames>} + */ this._args = args; /** @type {string | undefined} */ this.name = name; @@ -196,15 +200,24 @@ class Hook { this.taps = []; /** @type {HookInterceptor[]} */ this.interceptors = []; - /** @type {CallDelegate | undefined} */ + /** + * @private + * @type {CallDelegate | undefined} + */ this._call = CALL_DELEGATE; /** @type {CallDelegate | undefined} */ this.call = CALL_DELEGATE; - /** @type {CallAsyncDelegate} */ + /** + * @private + * @type {CallAsyncDelegate} + */ this._callAsync = CALL_ASYNC_DELEGATE; /** @type {CallAsyncDelegate} */ this.callAsync = CALL_ASYNC_DELEGATE; - /** @type {PromiseDeledate} */ + /** + * @private + * @type {PromiseDeledate} + */ this._promise = PROMISE_DELEGATE; /** @type {PromiseDeledate} */ this.promise = PROMISE_DELEGATE; @@ -231,6 +244,7 @@ class Hook { } /** + * @private * @param {"sync" | "async" | "promise"} type the call type * @returns {EXPECTED_FUNCTION} the compiled call function */ @@ -244,6 +258,7 @@ class Hook { } /** + * @private * @param {"sync" | "async" | "promise"} type the tap type * @param {string | (Tap & IfSet)} options name or full tap options * @param {EXPECTED_FUNCTION} fn callback registered with the tap @@ -339,6 +354,7 @@ class Hook { } /** + * @private * @param {FullTap & IfSet} options the tap descriptor * @returns {FullTap & IfSet} possibly transformed options */ @@ -412,6 +428,7 @@ class Hook { } /** + * @private * @returns {void} */ _resetCompilation() { @@ -421,6 +438,7 @@ class Hook { } /** + * @private * @param {FullTap & IfSet} item the tap to insert into the ordered taps list * @returns {void} */ diff --git a/lib/HookCodeFactory.js b/lib/HookCodeFactory.js index 5961d41..8089f54 100644 --- a/lib/HookCodeFactory.js +++ b/lib/HookCodeFactory.js @@ -83,7 +83,7 @@ class HookCodeFactory { */ create(options) { this.init(options); - /** @type {EXPECTED_FUNCTION | undefined} */ + /** @type {EXPECTED_FUNCTION} */ let fn; switch (options.type) { case "sync": @@ -144,7 +144,7 @@ class HookCodeFactory { } } this.deinit(); - return /** @type {EXPECTED_FUNCTION} */ (fn); + return fn; } /** @@ -470,9 +470,7 @@ class HookCodeFactory { callTapsLooping({ onError, onDone, rethrowIfPossible }) { const opts = /** @type {CompileOptions} */ (this.options); if (opts.taps.length === 0) return onDone(); - const syncOnly = opts.taps.every( - (/** @type {FullTap} */ t) => t.type === "sync" - ); + const syncOnly = opts.taps.every((t) => t.type === "sync"); let code = ""; if (!syncOnly) { code += "var _looper = (function() {\n"; From f8fb87aea145906ced4259a25f0a0c5d08cba41c Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 28 Apr 2026 13:03:13 +0000 Subject: [PATCH 6/8] perf(HookCodeFactory): drop runtime content stub, restore monomorphism The base `content` placeholder shadowed the subclass overrides on the prototype chain - every `this.content(options)` lookup in `contentWithInterceptors` had to walk past `HookCodeFactory.prototype` before hitting the concrete `SyncHookCodeFactory`/`AsyncSeriesHookCodeFactory` implementation. On the hot compile path that's a real cost in webpack where `compile()` runs for every hook on every plugin registration. Remove the stub so `content` exists only on subclass prototypes - V8 sees a single, monomorphic shape for the lookup. Use the `@ts-expect-error abstract method ... for performance reasons` pattern already established on `Hook.js` (CALL_DELEGATE etc.) to keep `lint:types` green at the two call sites. The trade-off: instantiating `HookCodeFactory` directly and calling `content` now throws `TypeError: this.content is not a function` instead of the prior friendlier `Error: Abstract: should be overridden`. The class is internal and never exposed; this is acceptable. --- lib/HookCodeFactory.js | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/lib/HookCodeFactory.js b/lib/HookCodeFactory.js index 8089f54..598ceab 100644 --- a/lib/HookCodeFactory.js +++ b/lib/HookCodeFactory.js @@ -147,15 +147,6 @@ class HookCodeFactory { return fn; } - /** - * @abstract - * @param {ContentOptions} _options content generation options - * @returns {string} generated body code - */ - content(_options) { - throw new Error("Abstract: should be overridden"); - } - /** * @param {Hook} instance the hook instance to attach the resolved tap function array to * @param {CompileOptions} options compile options containing the taps @@ -214,6 +205,11 @@ class HookCodeFactory { })});\n`; } } + // `content` is intentionally not declared on the base class - it's + // abstract and provided by every subclass. Skipping the runtime + // stub keeps the prototype chain mononomorphic on the hot compile + // path: subclass `content` is the only one V8 sees, no shadowing. + // @ts-expect-error abstract method, provided by subclasses for performance reasons code += this.content( Object.assign(options, { onError: @@ -268,6 +264,7 @@ class HookCodeFactory { ); return code; } + // @ts-expect-error abstract method, provided by subclasses for performance reasons return this.content(options); } From 73889c0300f52bc1a01cf4b9fac26a24f8f250c7 Mon Sep 17 00:00:00 2001 From: alexander-akait Date: Tue, 28 Apr 2026 16:31:58 +0300 Subject: [PATCH 7/8] refactor: avoid build types --- package.json | 1 - 1 file changed, 1 deletion(-) diff --git a/package.json b/package.json index 47c9096..2945b89 100644 --- a/package.json +++ b/package.json @@ -32,7 +32,6 @@ "fix": "npm run fix:code && npm run fmt", "fix:code": "npm run lint:code -- --fix", "test": "jest", - "build:types": "tsc", "benchmark": "node --max-old-space-size=4096 --hash-seed=1 --random-seed=1 --no-opt --predictable --predictable-gc-schedule --interpreted-frames-native-stack --allow-natives-syntax --expose-gc --no-concurrent-sweeping ./benchmark/run.mjs", "version": "changeset version", "release": "changeset publish" From 49bf9b48f10c167641dafd1f32b39f8286455be0 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 28 Apr 2026 13:47:40 +0000 Subject: [PATCH 8/8] fix(types): resolve subclass factory return types to specific hook types Each subclass factory (SyncHook, AsyncParallelHook, ...) was returning the generic `Hook` type, so consumers calling `new SyncHook()` got `Hook<...>` from JSDoc-generated types instead of the specific `SyncHook<...>` declared in the public `tapable.d.ts`. Mirror the public class declarations: each subclass file gets a typedef that re-exports the corresponding class from `tapable.d.ts` (with a `Type` suffix to avoid colliding with the factory function name in scope), then wires it as the factory's `@returns` and inner cast target. This keeps the V8 hidden-class optimization intact (still factory functions, no real `class extends Hook`) while aligning the JSDoc types with what tapable.d.ts already promises to consumers. --- lib/AsyncParallelBailHook.js | 14 ++++++++++++-- lib/AsyncParallelHook.js | 13 +++++++++++-- lib/AsyncSeriesBailHook.js | 14 ++++++++++++-- lib/AsyncSeriesHook.js | 13 +++++++++++-- lib/AsyncSeriesLoopHook.js | 13 +++++++++++-- lib/AsyncSeriesWaterfallHook.js | 15 +++++++++++++-- lib/SyncBailHook.js | 14 ++++++++++++-- lib/SyncHook.js | 14 ++++++++++++-- lib/SyncLoopHook.js | 13 +++++++++++-- lib/SyncWaterfallHook.js | 14 ++++++++++++-- 10 files changed, 117 insertions(+), 20 deletions(-) diff --git a/lib/AsyncParallelBailHook.js b/lib/AsyncParallelBailHook.js index 138e4ea..d5f1bad 100644 --- a/lib/AsyncParallelBailHook.js +++ b/lib/AsyncParallelBailHook.js @@ -21,6 +21,16 @@ const HookCodeFactory = require("./HookCodeFactory"); * @typedef {import("./Hook").AsArray} AsArray */ +/** + * Mirror of the `AsyncParallelBailHook` class declared in `tapable.d.ts` for + * use as the factory function's return type, so `new AsyncParallelBailHook(...)` + * resolves to the specific subclass type instead of the generic `Hook`. + * @template T + * @template R + * @template [AdditionalOptions=UnsetAdditionalOptions] + * @typedef {import("../tapable").AsyncParallelBailHook} AsyncParallelBailHookType + */ + class AsyncParallelBailHookCodeFactory extends HookCodeFactory { /** * @param {ContentOptions} options content generation options @@ -107,7 +117,7 @@ function COMPILE(options) { * @template [AdditionalOptions=UnsetAdditionalOptions] * @param {ArgumentNames>=} args argument names of the hook * @param {string=} name name of the hook - * @returns {Hook} a new AsyncParallelBailHook instance + * @returns {AsyncParallelBailHookType} a new AsyncParallelBailHook instance */ function AsyncParallelBailHook( args = /** @type {ArgumentNames>} */ (/** @type {unknown} */ ([])), @@ -119,7 +129,7 @@ function AsyncParallelBailHook( // @ts-expect-error for performance reasons hook._call = undefined; hook.call = undefined; - return /** @type {Hook} */ ( + return /** @type {AsyncParallelBailHookType} */ ( /** @type {unknown} */ (hook) ); } diff --git a/lib/AsyncParallelHook.js b/lib/AsyncParallelHook.js index b34da11..34327b5 100644 --- a/lib/AsyncParallelHook.js +++ b/lib/AsyncParallelHook.js @@ -21,6 +21,15 @@ const HookCodeFactory = require("./HookCodeFactory"); * @typedef {import("./Hook").AsArray} AsArray */ +/** + * Mirror of the `AsyncParallelHook` class declared in `tapable.d.ts` for use + * as the factory function's return type, so `new AsyncParallelHook(...)` + * resolves to the specific subclass type instead of the generic `Hook`. + * @template T + * @template [AdditionalOptions=UnsetAdditionalOptions] + * @typedef {import("../tapable").AsyncParallelHook} AsyncParallelHookType + */ + class AsyncParallelHookCodeFactory extends HookCodeFactory { /** * @param {ContentOptions} options content generation options @@ -52,7 +61,7 @@ function COMPILE(options) { * @template [AdditionalOptions=UnsetAdditionalOptions] * @param {ArgumentNames>=} args argument names of the hook * @param {string=} name name of the hook - * @returns {Hook} a new AsyncParallelHook instance + * @returns {AsyncParallelHookType} a new AsyncParallelHook instance */ function AsyncParallelHook( args = /** @type {ArgumentNames>} */ (/** @type {unknown} */ ([])), @@ -64,7 +73,7 @@ function AsyncParallelHook( // @ts-expect-error for performance reasons hook._call = undefined; hook.call = undefined; - return /** @type {Hook} */ ( + return /** @type {AsyncParallelHookType} */ ( /** @type {unknown} */ (hook) ); } diff --git a/lib/AsyncSeriesBailHook.js b/lib/AsyncSeriesBailHook.js index 3732dba..f247b43 100644 --- a/lib/AsyncSeriesBailHook.js +++ b/lib/AsyncSeriesBailHook.js @@ -21,6 +21,16 @@ const HookCodeFactory = require("./HookCodeFactory"); * @typedef {import("./Hook").AsArray} AsArray */ +/** + * Mirror of the `AsyncSeriesBailHook` class declared in `tapable.d.ts` for + * use as the factory function's return type, so `new AsyncSeriesBailHook(...)` + * resolves to the specific subclass type instead of the generic `Hook`. + * @template T + * @template R + * @template [AdditionalOptions=UnsetAdditionalOptions] + * @typedef {import("../tapable").AsyncSeriesBailHook} AsyncSeriesBailHookType + */ + class AsyncSeriesBailHookCodeFactory extends HookCodeFactory { /** * @param {ContentOptions} options content generation options @@ -58,7 +68,7 @@ function COMPILE(options) { * @template [AdditionalOptions=UnsetAdditionalOptions] * @param {ArgumentNames>=} args argument names of the hook * @param {string=} name name of the hook - * @returns {Hook} a new AsyncSeriesBailHook instance + * @returns {AsyncSeriesBailHookType} a new AsyncSeriesBailHook instance */ function AsyncSeriesBailHook( args = /** @type {ArgumentNames>} */ (/** @type {unknown} */ ([])), @@ -70,7 +80,7 @@ function AsyncSeriesBailHook( // @ts-expect-error for performance reasons hook._call = undefined; hook.call = undefined; - return /** @type {Hook} */ ( + return /** @type {AsyncSeriesBailHookType} */ ( /** @type {unknown} */ (hook) ); } diff --git a/lib/AsyncSeriesHook.js b/lib/AsyncSeriesHook.js index 8b6d2e8..d23ff9a 100644 --- a/lib/AsyncSeriesHook.js +++ b/lib/AsyncSeriesHook.js @@ -21,6 +21,15 @@ const HookCodeFactory = require("./HookCodeFactory"); * @typedef {import("./Hook").AsArray} AsArray */ +/** + * Mirror of the `AsyncSeriesHook` class declared in `tapable.d.ts` for use + * as the factory function's return type, so `new AsyncSeriesHook(...)` + * resolves to the specific subclass type instead of the generic `Hook`. + * @template T + * @template [AdditionalOptions=UnsetAdditionalOptions] + * @typedef {import("../tapable").AsyncSeriesHook} AsyncSeriesHookType + */ + class AsyncSeriesHookCodeFactory extends HookCodeFactory { /** * @param {ContentOptions} options content generation options @@ -52,7 +61,7 @@ function COMPILE(options) { * @template [AdditionalOptions=UnsetAdditionalOptions] * @param {ArgumentNames>=} args argument names of the hook * @param {string=} name name of the hook - * @returns {Hook} a new AsyncSeriesHook instance + * @returns {AsyncSeriesHookType} a new AsyncSeriesHook instance */ function AsyncSeriesHook( args = /** @type {ArgumentNames>} */ (/** @type {unknown} */ ([])), @@ -64,7 +73,7 @@ function AsyncSeriesHook( // @ts-expect-error for performance reasons hook._call = undefined; hook.call = undefined; - return /** @type {Hook} */ ( + return /** @type {AsyncSeriesHookType} */ ( /** @type {unknown} */ (hook) ); } diff --git a/lib/AsyncSeriesLoopHook.js b/lib/AsyncSeriesLoopHook.js index 78fb7b3..5765eb3 100644 --- a/lib/AsyncSeriesLoopHook.js +++ b/lib/AsyncSeriesLoopHook.js @@ -21,6 +21,15 @@ const HookCodeFactory = require("./HookCodeFactory"); * @typedef {import("./Hook").AsArray} AsArray */ +/** + * Mirror of the `AsyncSeriesLoopHook` class declared in `tapable.d.ts` for + * use as the factory function's return type, so `new AsyncSeriesLoopHook(...)` + * resolves to the specific subclass type instead of the generic `Hook`. + * @template T + * @template [AdditionalOptions=UnsetAdditionalOptions] + * @typedef {import("../tapable").AsyncSeriesLoopHook} AsyncSeriesLoopHookType + */ + class AsyncSeriesLoopHookCodeFactory extends HookCodeFactory { /** * @param {ContentOptions} options content generation options @@ -52,7 +61,7 @@ function COMPILE(options) { * @template [AdditionalOptions=UnsetAdditionalOptions] * @param {ArgumentNames>=} args argument names of the hook * @param {string=} name name of the hook - * @returns {Hook} a new AsyncSeriesLoopHook instance + * @returns {AsyncSeriesLoopHookType} a new AsyncSeriesLoopHook instance */ function AsyncSeriesLoopHook( args = /** @type {ArgumentNames>} */ (/** @type {unknown} */ ([])), @@ -64,7 +73,7 @@ function AsyncSeriesLoopHook( // @ts-expect-error for performance reasons hook._call = undefined; hook.call = undefined; - return /** @type {Hook} */ ( + return /** @type {AsyncSeriesLoopHookType} */ ( /** @type {unknown} */ (hook) ); } diff --git a/lib/AsyncSeriesWaterfallHook.js b/lib/AsyncSeriesWaterfallHook.js index 4134bf1..4cc48c0 100644 --- a/lib/AsyncSeriesWaterfallHook.js +++ b/lib/AsyncSeriesWaterfallHook.js @@ -21,6 +21,17 @@ const HookCodeFactory = require("./HookCodeFactory"); * @typedef {import("./Hook").AsArray} AsArray */ +/** + * Mirror of the `AsyncSeriesWaterfallHook` class declared in `tapable.d.ts` + * for use as the factory function's return type, so + * `new AsyncSeriesWaterfallHook(...)` resolves to the specific subclass type + * instead of the generic `Hook`. + * @template T + * @template [R=AsArray[0]] + * @template [AdditionalOptions=UnsetAdditionalOptions] + * @typedef {import("../tapable").AsyncSeriesWaterfallHook} AsyncSeriesWaterfallHookType + */ + class AsyncSeriesWaterfallHookCodeFactory extends HookCodeFactory { /** * @param {ContentOptions} options content generation options @@ -61,7 +72,7 @@ function COMPILE(options) { * @template [AdditionalOptions=UnsetAdditionalOptions] * @param {ArgumentNames>=} args argument names of the hook * @param {string=} name name of the hook - * @returns {Hook} a new AsyncSeriesWaterfallHookCodeFactory instance + * @returns {AsyncSeriesWaterfallHookType} a new AsyncSeriesWaterfallHook instance */ function AsyncSeriesWaterfallHook( args = /** @type {ArgumentNames>} */ (/** @type {unknown} */ ([])), @@ -76,7 +87,7 @@ function AsyncSeriesWaterfallHook( // @ts-expect-error for performance reasons hook._call = undefined; hook.call = undefined; - return /** @type {Hook} */ ( + return /** @type {AsyncSeriesWaterfallHookType} */ ( /** @type {unknown} */ (hook) ); } diff --git a/lib/SyncBailHook.js b/lib/SyncBailHook.js index b25325f..4e970e9 100644 --- a/lib/SyncBailHook.js +++ b/lib/SyncBailHook.js @@ -22,6 +22,16 @@ const HookCodeFactory = require("./HookCodeFactory"); * @typedef {import("./Hook").ArgumentNames} ArgumentNames */ +/** + * Mirror of the `SyncBailHook` class declared in `tapable.d.ts` for use as + * the factory function's return type, so `new SyncBailHook(...)` resolves to + * the specific subclass type instead of the generic `Hook`. + * @template T + * @template R + * @template [AdditionalOptions=UnsetAdditionalOptions] + * @typedef {import("../tapable").SyncBailHook} SyncBailHookType + */ + class SyncBailHookCodeFactory extends HookCodeFactory { /** * @param {ContentOptions} options content generation options @@ -68,7 +78,7 @@ function COMPILE(options) { * @template [AdditionalOptions=UnsetAdditionalOptions] * @param {ArgumentNames>=} args argument names of the hook * @param {string=} name name of the hook - * @returns {Hook} a new AsyncParallelBailHook instance + * @returns {SyncBailHookType} a new SyncBailHook instance */ function SyncBailHook( args = /** @type {ArgumentNames>} */ (/** @type {unknown} */ ([])), @@ -79,7 +89,7 @@ function SyncBailHook( hook.tapAsync = TAP_ASYNC; hook.tapPromise = TAP_PROMISE; hook.compile = COMPILE; - return /** @type {Hook} */ ( + return /** @type {SyncBailHookType} */ ( /** @type {unknown} */ (hook) ); } diff --git a/lib/SyncHook.js b/lib/SyncHook.js index fecdbaf..9260fc1 100644 --- a/lib/SyncHook.js +++ b/lib/SyncHook.js @@ -22,6 +22,16 @@ const HookCodeFactory = require("./HookCodeFactory"); * @typedef {import("./Hook").ArgumentNames} ArgumentNames */ +/** + * Mirror of the `SyncHook` class declared in `tapable.d.ts` for use as the + * factory function's return type, so `new SyncHook(...)` resolves to the + * specific subclass type instead of the generic `Hook`. + * @template T + * @template [R=void] + * @template [AdditionalOptions=UnsetAdditionalOptions] + * @typedef {import("../tapable").SyncHook} SyncHookType + */ + class SyncHookCodeFactory extends HookCodeFactory { /** * @param {ContentOptions} options content generation options @@ -63,7 +73,7 @@ function COMPILE(options) { * @template [AdditionalOptions=UnsetAdditionalOptions] * @param {ArgumentNames>=} args argument names of the hook * @param {string=} name name of the hook - * @returns {Hook} a new SyncHook instance + * @returns {SyncHookType} a new SyncHook instance */ function SyncHook( args = /** @type {ArgumentNames>} */ (/** @type {unknown} */ ([])), @@ -74,7 +84,7 @@ function SyncHook( hook.tapAsync = TAP_ASYNC; hook.tapPromise = TAP_PROMISE; hook.compile = COMPILE; - return /** @type {Hook} */ ( + return /** @type {SyncHookType} */ ( /** @type {unknown} */ (hook) ); } diff --git a/lib/SyncLoopHook.js b/lib/SyncLoopHook.js index 0dbd95f..86e769b 100644 --- a/lib/SyncLoopHook.js +++ b/lib/SyncLoopHook.js @@ -21,6 +21,15 @@ const HookCodeFactory = require("./HookCodeFactory"); * @typedef {import("./Hook").ArgumentNames} ArgumentNames */ +/** + * Mirror of the `SyncLoopHook` class declared in `tapable.d.ts` for use as + * the factory function's return type, so `new SyncLoopHook(...)` resolves + * to the specific subclass type instead of the generic `Hook`. + * @template T + * @template [AdditionalOptions=UnsetAdditionalOptions] + * @typedef {import("../tapable").SyncLoopHook} SyncLoopHookType + */ + class SyncLoopHookCodeFactory extends HookCodeFactory { /** * @param {ContentOptions} options content generation options @@ -61,7 +70,7 @@ function COMPILE(options) { * @template [AdditionalOptions=UnsetAdditionalOptions] * @param {ArgumentNames>=} args argument names of the hook * @param {string=} name name of the hook - * @returns {Hook} a new AsyncParallelBailHook instance + * @returns {SyncLoopHookType} a new SyncLoopHook instance */ function SyncLoopHook( args = /** @type {ArgumentNames>} */ (/** @type {unknown} */ ([])), @@ -72,7 +81,7 @@ function SyncLoopHook( hook.tapAsync = TAP_ASYNC; hook.tapPromise = TAP_PROMISE; hook.compile = COMPILE; - return /** @type {Hook} */ ( + return /** @type {SyncLoopHookType} */ ( /** @type {unknown} */ (hook) ); } diff --git a/lib/SyncWaterfallHook.js b/lib/SyncWaterfallHook.js index f4e6a52..de4f2a8 100644 --- a/lib/SyncWaterfallHook.js +++ b/lib/SyncWaterfallHook.js @@ -21,6 +21,16 @@ const HookCodeFactory = require("./HookCodeFactory"); * @typedef {import("./Hook").ArgumentNames} ArgumentNames */ +/** + * Mirror of the `SyncWaterfallHook` class declared in `tapable.d.ts` for use + * as the factory function's return type, so `new SyncWaterfallHook(...)` + * resolves to the specific subclass type instead of the generic `Hook`. + * @template T + * @template [R=AsArray[0]] + * @template [AdditionalOptions=UnsetAdditionalOptions] + * @typedef {import("../tapable").SyncWaterfallHook} SyncWaterfallHookType + */ + class SyncWaterfallHookCodeFactory extends HookCodeFactory { /** * @param {ContentOptions} options content generation options @@ -71,7 +81,7 @@ function COMPILE(options) { * @template [AdditionalOptions=UnsetAdditionalOptions] * @param {ArgumentNames>=} args argument names of the hook * @param {string=} name name of the hook - * @returns {Hook} a new AsyncParallelBailHook instance + * @returns {SyncWaterfallHookType} a new SyncWaterfallHook instance */ function SyncWaterfallHook( args = /** @type {ArgumentNames>} */ (/** @type {unknown} */ ([])), @@ -85,7 +95,7 @@ function SyncWaterfallHook( hook.tapAsync = TAP_ASYNC; hook.tapPromise = TAP_PROMISE; hook.compile = COMPILE; - return /** @type {Hook} */ ( + return /** @type {SyncWaterfallHookType} */ ( /** @type {unknown} */ (hook) ); }