* A utility function to iterate through a hook chain, track advancement in the * chain, and generate and supply the `next ` argument to the custom * hook. * @param {KeyedHook} current The (currently) first hook in the chain (this shifts * on every call). * @param {object} meta Proper
(current, meta, { validateArgs, validateOutput })
| 724 | * @returns {Function} The next hook in the chain. |
| 725 | */ |
| 726 | function nextHookFactory(current, meta, { validateArgs, validateOutput }) { |
| 727 | // First, prepare the current |
| 728 | const { hookName } = meta; |
| 729 | const { |
| 730 | fn: hook, |
| 731 | url: hookFilePath, |
| 732 | next, |
| 733 | } = current; |
| 734 | |
| 735 | // ex 'nextResolve' |
| 736 | const nextHookName = `next${ |
| 737 | StringPrototypeToUpperCase(hookName[0]) + |
| 738 | StringPrototypeSlice(hookName, 1) |
| 739 | }`; |
| 740 | |
| 741 | let nextNextHook; |
| 742 | if (next) { |
| 743 | nextNextHook = nextHookFactory(next, meta, { validateArgs, validateOutput }); |
| 744 | } else { |
| 745 | // eslint-disable-next-line func-name-matching |
| 746 | nextNextHook = function chainAdvancedTooFar() { |
| 747 | throw new ERR_INTERNAL_ASSERTION( |
| 748 | `ESM custom loader '${hookName}' advanced beyond the end of the chain.`, |
| 749 | ); |
| 750 | }; |
| 751 | } |
| 752 | |
| 753 | return ObjectDefineProperty( |
| 754 | async (arg0 = undefined, context) => { |
| 755 | // Update only when hook is invoked to avoid fingering the wrong filePath |
| 756 | meta.hookErrIdentifier = `${hookFilePath} '${hookName}'`; |
| 757 | |
| 758 | validateArgs(`${meta.hookErrIdentifier} hook's ${nextHookName}()`, arg0, context); |
| 759 | |
| 760 | const outputErrIdentifier = `${hookFilePath} '${hookName}' hook's ${nextHookName}()`; |
| 761 | |
| 762 | // Set when next<HookName> is actually called, not just generated. |
| 763 | if (!next) { meta.chainFinished = true; } |
| 764 | |
| 765 | if (context) { // `context` has already been validated, so no fancy check needed. |
| 766 | ObjectAssign(meta.context, context); |
| 767 | } |
| 768 | |
| 769 | const output = await hook(arg0, meta.context, nextNextHook); |
| 770 | validateOutput(outputErrIdentifier, output); |
| 771 | |
| 772 | if (output?.shortCircuit === true) { meta.shortCircuited = true; } |
| 773 | |
| 774 | return output; |
| 775 | }, |
| 776 | 'name', |
| 777 | { __proto__: null, value: nextHookName }, |
| 778 | ); |
| 779 | } |
| 780 | |
| 781 | /** |
| 782 | * @type {AsyncLoaderHookWorker} |
no test coverage detected
searching dependent graphs…