Skip to content

Commit

Permalink
fixup: change async/thenable detection
Browse files Browse the repository at this point in the history
  • Loading branch information
JakobJingleheimer committed Jun 12, 2022
1 parent 8bf7965 commit c3b979c
Showing 1 changed file with 40 additions and 41 deletions.
81 changes: 40 additions & 41 deletions lib/internal/modules/esm/loader.js
Expand Up @@ -15,6 +15,8 @@ const {
ObjectDefineProperty,
ObjectSetPrototypeOf,
PromiseAll,
PromiseResolve,
PromisePrototypeThen,
ReflectApply,
RegExpPrototypeExec,
SafeArrayIterator,
Expand Down Expand Up @@ -114,7 +116,7 @@ let emittedSpecifierResolutionWarning = false;
* validation within MUST throw.
* @returns {function next<HookName>(...hookArgs)} The next hook in the chain.
*/
function nextHookFactory(chain, meta, validate) {
function nextHookFactory(chain, meta, { validateArgs, validateOutput }) {
// First, prepare the current
const { hookName } = meta;
const {
Expand All @@ -137,7 +139,7 @@ function nextHookFactory(chain, meta, validate) {
// factory generates the next link in the chain.
meta.hookIndex--;

nextNextHook = nextHookFactory(chain, meta, validate);
nextNextHook = nextHookFactory(chain, meta, { validateArgs, validateOutput });
} else {
// eslint-disable-next-line func-name-matching
nextNextHook = function chainAdvancedTooFar() {
Expand All @@ -152,34 +154,25 @@ function nextHookFactory(chain, meta, validate) {
// Update only when hook is invoked to avoid fingering the wrong filePath
meta.hookErrIdentifier = `${hookFilePath} '${hookName}'`;

validate(`${meta.hookErrIdentifier} hook's ${nextHookName}()`, args);
validateArgs(`${meta.hookErrIdentifier} hook's ${nextHookName}()`, args);

const outputErrIdentifier = `${chain[generatedHookIndex].url} '${hookName}' hook's ${nextHookName}()`;

// Set when next<HookName> is actually called, not just generated.
if (generatedHookIndex === 0) { meta.chainFinished = true; }

ArrayPrototypePush(args, nextNextHook);
const output = ReflectApply(hook, undefined, args);
let output = ReflectApply(hook, undefined, args);

validateOutput(output, outputErrIdentifier);

function checkShortCircuited(output) {
if (output?.shortCircuit === true) { meta.shortCircuited = true; }
}

const then = output?.then;
if (typeof then === 'function') {
if (!meta.isChainAsync) {
throw ERR_INVALID_RETURN_VALUE(
'an object',
// MUST use generatedHookIndex because the chain has already advanced,
// causing meta.hookIndex to advance
`${chain[generatedHookIndex].url} '${hookName}' hook's ${nextHookName}()`,
output,
);
}

ReflectApply(then, output, [
checkShortCircuited,
// TODO: handle error case
]);
if (meta.isChainAsync) {
output = PromiseResolve(output);
PromisePrototypeThen(output, checkShortCircuited);
} else {
checkShortCircuited(output);
}
Expand Down Expand Up @@ -586,7 +579,7 @@ class ESMLoader {
shortCircuited: false,
};

const validate = (hookErrIdentifier, { 0: nextUrl, 1: ctx }) => {
const validateArgs = (hookErrIdentifier, { 0: nextUrl, 1: ctx }) => {
if (typeof nextUrl !== 'string') {
// non-strings can be coerced to a url string
// validateString() throws a less-specific error
Expand All @@ -612,19 +605,22 @@ class ESMLoader {

validateObject(ctx, `${hookErrIdentifier} context`);
};
const validateOutput = (output, hookErrIdentifier) => {
if (typeof output !== 'object') { // [2]
throw new ERR_INVALID_RETURN_VALUE(
'an object',
hookErrIdentifier,
output,
);
}
};

const nextLoad = nextHookFactory(chain, meta, validate);
const nextLoad = nextHookFactory(chain, meta, { validateArgs, validateOutput });

const loaded = await nextLoad(url, context);
const { hookErrIdentifier } = meta; // Retrieve the value after all settled

if (typeof loaded !== 'object') { // [2]
throw new ERR_INVALID_RETURN_VALUE(
'an object',
hookErrIdentifier,
loaded,
);
}
validateOutput(loaded, hookErrIdentifier);

if (loaded?.shortCircuit === true) { meta.shortCircuited = true; }

Expand Down Expand Up @@ -837,7 +833,7 @@ class ESMLoader {
parentURL,
};

const validate = (hookErrIdentifier, output) => {
const validateArgs = (hookErrIdentifier, output) => {
const { 0: suppliedSpecifier, 1: ctx } = output;

validateString(
Expand All @@ -847,22 +843,25 @@ class ESMLoader {

validateObject(ctx, `${hookErrIdentifier} context`);
};
const validateOutput = (output, hookErrIdentifier) => {
if (
typeof output !== 'object' || // [2]
typeof output.then === 'function'
) {
throw new ERR_INVALID_RETURN_VALUE(
'an object',
hookErrIdentifier,
output,
);
}
};

const nextResolve = nextHookFactory(chain, meta, validate);
const nextResolve = nextHookFactory(chain, meta, { validateArgs, validateOutput });

const resolution = nextResolve(originalSpecifier, context);
const { hookErrIdentifier } = meta; // Retrieve the value after all settled

if (
typeof resolution !== 'object' || // [2]
typeof resolution?.then === 'function'
) {
throw new ERR_INVALID_RETURN_VALUE(
'an object',
hookErrIdentifier,
resolution,
);
}
validateOutput(resolution, hookErrIdentifier);

if (resolution?.shortCircuit === true) { meta.shortCircuited = true; }

Expand Down

0 comments on commit c3b979c

Please sign in to comment.