@@ -30,6 +30,7 @@ const {
3030 ERR_INVALID_RETURN_PROPERTY_VALUE ,
3131 ERR_INVALID_RETURN_VALUE ,
3232 ERR_LOADER_CHAIN_INCOMPLETE ,
33+ ERR_METHOD_NOT_IMPLEMENTED ,
3334 ERR_WORKER_UNSERIALIZABLE_ERROR ,
3435} = require ( 'internal/errors' ) . codes ;
3536const { exitCodes : { kUnfinishedTopLevelAwait } } = internalBinding ( 'errors' ) ;
@@ -80,7 +81,6 @@ let debug = require('internal/util/debuglog').debuglog('esm', (fn) => {
8081
8182// [2] `validate...()`s throw the wrong error
8283
83-
8484class Hooks {
8585 #chains = {
8686 /**
@@ -126,16 +126,18 @@ class Hooks {
126126 */
127127 async register ( urlOrSpecifier , parentURL ) {
128128 const moduleLoader = require ( 'internal/process/esm_loader' ) . esmLoader ;
129-
130129 const keyedExports = await moduleLoader . import (
131130 urlOrSpecifier ,
132131 parentURL ,
133132 kEmptyObject ,
134133 ) ;
135-
136134 this . addCustomLoader ( urlOrSpecifier , keyedExports ) ;
137135 }
138136
137+ allowImportMetaResolve ( ) {
138+ return false ;
139+ }
140+
139141 /**
140142 * Collect custom/user-defined module loader hook(s).
141143 * After all hooks have been collected, the global preload hook(s) must be initialized.
@@ -150,13 +152,16 @@ class Hooks {
150152 } = pluckHooks ( exports ) ;
151153
152154 if ( globalPreload ) {
153- ArrayPrototypePush ( this . #chains. globalPreload , { fn : globalPreload , url } ) ;
155+ const next = this . #chains. globalPreload [ this . #chains. globalPreload . length - 1 ] ;
156+ ArrayPrototypePush ( this . #chains. globalPreload , { fn : globalPreload , url, next } ) ;
154157 }
155158 if ( resolve ) {
156- ArrayPrototypePush ( this . #chains. resolve , { fn : resolve , url } ) ;
159+ const next = this . #chains. resolve [ this . #chains. resolve . length - 1 ] ;
160+ ArrayPrototypePush ( this . #chains. resolve , { fn : resolve , url, next } ) ;
157161 }
158162 if ( load ) {
159- ArrayPrototypePush ( this . #chains. load , { fn : load , url } ) ;
163+ const next = this . #chains. load [ this . #chains. load . length - 1 ] ;
164+ ArrayPrototypePush ( this . #chains. load , { fn : load , url, next } ) ;
160165 }
161166 }
162167
@@ -233,7 +238,6 @@ class Hooks {
233238 chainFinished : null ,
234239 context,
235240 hookErrIdentifier : '' ,
236- hookIndex : chain . length - 1 ,
237241 hookName : 'resolve' ,
238242 shortCircuited : false ,
239243 } ;
@@ -256,7 +260,7 @@ class Hooks {
256260 }
257261 } ;
258262
259- const nextResolve = nextHookFactory ( chain , meta , { validateArgs, validateOutput } ) ;
263+ const nextResolve = nextHookFactory ( chain [ chain . length - 1 ] , meta , { validateArgs, validateOutput } ) ;
260264
261265 const resolution = await nextResolve ( originalSpecifier , context ) ;
262266 const { hookErrIdentifier } = meta ; // Retrieve the value after all settled
@@ -333,6 +337,10 @@ class Hooks {
333337 } ;
334338 }
335339
340+ resolveSync ( _originalSpecifier , _parentURL , _importAssertions ) {
341+ throw new ERR_METHOD_NOT_IMPLEMENTED ( 'resolveSync()' ) ;
342+ }
343+
336344 /**
337345 * Provide source that is understood by one of Node's translators.
338346 *
@@ -349,7 +357,6 @@ class Hooks {
349357 chainFinished : null ,
350358 context,
351359 hookErrIdentifier : '' ,
352- hookIndex : chain . length - 1 ,
353360 hookName : 'load' ,
354361 shortCircuited : false ,
355362 } ;
@@ -391,7 +398,7 @@ class Hooks {
391398 }
392399 } ;
393400
394- const nextLoad = nextHookFactory ( chain , meta , { validateArgs, validateOutput } ) ;
401+ const nextLoad = nextHookFactory ( chain [ chain . length - 1 ] , meta , { validateArgs, validateOutput } ) ;
395402
396403 const loaded = await nextLoad ( url , context ) ;
397404 const { hookErrIdentifier } = meta ; // Retrieve the value after all settled
@@ -528,7 +535,10 @@ class HooksProxy {
528535 debug ( 'wait for signal from worker' ) ;
529536 AtomicsWait ( this . #lock, WORKER_TO_MAIN_THREAD_NOTIFICATION , 0 ) ;
530537 const response = this . #worker. receiveMessageSync ( ) ;
531- if ( response . message . status === 'exit' ) { return ; }
538+ if ( response . message . status === 'exit' ) {
539+ process . exit ( response . message . body ) ;
540+ return ;
541+ }
532542 const { preloadScripts } = this . #unwrapMessage( response ) ;
533543 this . #executePreloadScripts( preloadScripts ) ;
534544 }
@@ -684,46 +694,38 @@ function pluckHooks({
684694 * A utility function to iterate through a hook chain, track advancement in the
685695 * chain, and generate and supply the `next<HookName>` argument to the custom
686696 * hook.
687- * @param {KeyedHook[] } chain The whole hook chain.
697+ * @param {Hook } current The first hook in the chain.
688698 * @param {object } meta Properties that change as the current hook advances
689699 * along the chain.
690700 * @param {boolean } meta.chainFinished Whether the end of the chain has been
691701 * reached AND invoked.
692702 * @param {string } meta.hookErrIdentifier A user-facing identifier to help
693703 * pinpoint where an error occurred. Ex "file:///foo.mjs 'resolve'".
694- * @param {number } meta.hookIndex A non-negative integer tracking the current
695- * position in the hook chain.
696704 * @param {string } meta.hookName The kind of hook the chain is (ex 'resolve')
697705 * @param {boolean } meta.shortCircuited Whether a hook signaled a short-circuit.
698706 * @param {(hookErrIdentifier, hookArgs) => void } validate A wrapper function
699707 * containing all validation of a custom loader hook's intermediary output. Any
700708 * validation within MUST throw.
701709 * @returns {function next<HookName>(...hookArgs) } The next hook in the chain.
702710 */
703- function nextHookFactory ( chain , meta , { validateArgs, validateOutput } ) {
711+ function nextHookFactory ( current , meta , { validateArgs, validateOutput } ) {
704712 // First, prepare the current
705713 const { hookName } = meta ;
706714 const {
707715 fn : hook ,
708716 url : hookFilePath ,
709- } = chain [ meta . hookIndex ] ;
717+ next,
718+ } = current ;
710719
711720 // ex 'nextResolve'
712721 const nextHookName = `next${
713722 StringPrototypeToUpperCase ( hookName [ 0 ] ) +
714723 StringPrototypeSlice ( hookName , 1 )
715724 } `;
716725
717- // When hookIndex is 0, it's reached the default, which does not call next()
718- // so feed it a noop that blows up if called, so the problem is obvious.
719- const generatedHookIndex = meta . hookIndex ;
720726 let nextNextHook ;
721- if ( meta . hookIndex > 0 ) {
722- // Now, prepare the next: decrement the pointer so the next call to the
723- // factory generates the next link in the chain.
724- meta . hookIndex -- ;
725-
726- nextNextHook = nextHookFactory ( chain , meta , { validateArgs, validateOutput } ) ;
727+ if ( next ) {
728+ nextNextHook = nextHookFactory ( next , meta , { validateArgs, validateOutput } ) ;
727729 } else {
728730 // eslint-disable-next-line func-name-matching
729731 nextNextHook = function chainAdvancedTooFar ( ) {
@@ -740,17 +742,16 @@ function nextHookFactory(chain, meta, { validateArgs, validateOutput }) {
740742
741743 validateArgs ( `${ meta . hookErrIdentifier } hook's ${ nextHookName } ()` , arg0 , context ) ;
742744
743- const outputErrIdentifier = `${ chain [ generatedHookIndex ] . url } '${ hookName } ' hook's ${ nextHookName } ()` ;
745+ const outputErrIdentifier = `${ hookFilePath } '${ hookName } ' hook's ${ nextHookName } ()` ;
744746
745747 // Set when next<HookName> is actually called, not just generated.
746- if ( generatedHookIndex === 0 ) { meta . chainFinished = true ; }
748+ if ( ! next ) { meta . chainFinished = true ; }
747749
748750 if ( context ) { // `context` has already been validated, so no fancy check needed.
749751 ObjectAssign ( meta . context , context ) ;
750752 }
751753
752754 const output = await hook ( arg0 , meta . context , nextNextHook ) ;
753-
754755 validateOutput ( outputErrIdentifier , output ) ;
755756
756757 if ( output ?. shortCircuit === true ) { meta . shortCircuited = true ; }
0 commit comments