@@ -31,6 +31,7 @@ const {
3131 ERR_INVALID_RETURN_PROPERTY_VALUE ,
3232 ERR_INVALID_RETURN_VALUE ,
3333 ERR_LOADER_CHAIN_INCOMPLETE ,
34+ ERR_METHOD_NOT_IMPLEMENTED ,
3435 ERR_UNKNOWN_BUILTIN_MODULE ,
3536 ERR_WORKER_UNSERIALIZABLE_ERROR ,
3637} = require ( 'internal/errors' ) . codes ;
@@ -64,7 +65,7 @@ const {
6465let debug = require ( 'internal/util/debuglog' ) . debuglog ( 'esm' , ( fn ) => {
6566 debug = fn ;
6667} ) ;
67-
68+ let importMetaInitializer ;
6869
6970/**
7071 * @typedef {object } ExportedHooks
@@ -81,7 +82,6 @@ let debug = require('internal/util/debuglog').debuglog('esm', (fn) => {
8182
8283// [2] `validate...()`s throw the wrong error
8384
84-
8585class Hooks {
8686 #chains = {
8787 /**
@@ -120,20 +120,20 @@ class Hooks {
120120 // Cache URLs we've already validated to avoid repeated validation
121121 #validatedUrls = new SafeSet ( ) ;
122122
123+ allowImportMetaResolve = false ;
124+
123125 /**
124126 * Import and register custom/user-defined module loader hook(s).
125127 * @param {string } urlOrSpecifier
126128 * @param {string } parentURL
127129 */
128130 async register ( urlOrSpecifier , parentURL ) {
129131 const moduleLoader = require ( 'internal/process/esm_loader' ) . esmLoader ;
130-
131132 const keyedExports = await moduleLoader . import (
132133 urlOrSpecifier ,
133134 parentURL ,
134135 kEmptyObject ,
135136 ) ;
136-
137137 this . addCustomLoader ( urlOrSpecifier , keyedExports ) ;
138138 }
139139
@@ -151,13 +151,15 @@ class Hooks {
151151 } = pluckHooks ( exports ) ;
152152
153153 if ( globalPreload ) {
154- ArrayPrototypePush ( this . #chains. globalPreload , { fn : globalPreload , url } ) ;
154+ ArrayPrototypePush ( this . #chains. globalPreload , { __proto__ : null , fn : globalPreload , url } ) ;
155155 }
156156 if ( resolve ) {
157- ArrayPrototypePush ( this . #chains. resolve , { fn : resolve , url } ) ;
157+ const next = this . #chains. resolve [ this . #chains. resolve . length - 1 ] ;
158+ ArrayPrototypePush ( this . #chains. resolve , { __proto__ : null , fn : resolve , url, next } ) ;
158159 }
159160 if ( load ) {
160- ArrayPrototypePush ( this . #chains. load , { fn : load , url } ) ;
161+ const next = this . #chains. load [ this . #chains. load . length - 1 ] ;
162+ ArrayPrototypePush ( this . #chains. load , { __proto__ : null , fn : load , url, next } ) ;
161163 }
162164 }
163165
@@ -234,7 +236,6 @@ class Hooks {
234236 chainFinished : null ,
235237 context,
236238 hookErrIdentifier : '' ,
237- hookIndex : chain . length - 1 ,
238239 hookName : 'resolve' ,
239240 shortCircuited : false ,
240241 } ;
@@ -257,7 +258,7 @@ class Hooks {
257258 }
258259 } ;
259260
260- const nextResolve = nextHookFactory ( chain , meta , { validateArgs, validateOutput } ) ;
261+ const nextResolve = nextHookFactory ( chain [ chain . length - 1 ] , meta , { validateArgs, validateOutput } ) ;
261262
262263 const resolution = await nextResolve ( originalSpecifier , context ) ;
263264 const { hookErrIdentifier } = meta ; // Retrieve the value after all settled
@@ -334,6 +335,10 @@ class Hooks {
334335 } ;
335336 }
336337
338+ resolveSync ( _originalSpecifier , _parentURL , _importAssertions ) {
339+ throw new ERR_METHOD_NOT_IMPLEMENTED ( 'resolveSync()' ) ;
340+ }
341+
337342 /**
338343 * Provide source that is understood by one of Node's translators.
339344 *
@@ -350,7 +355,6 @@ class Hooks {
350355 chainFinished : null ,
351356 context,
352357 hookErrIdentifier : '' ,
353- hookIndex : chain . length - 1 ,
354358 hookName : 'load' ,
355359 shortCircuited : false ,
356360 } ;
@@ -392,7 +396,7 @@ class Hooks {
392396 }
393397 } ;
394398
395- const nextLoad = nextHookFactory ( chain , meta , { validateArgs, validateOutput } ) ;
399+ const nextLoad = nextHookFactory ( chain [ chain . length - 1 ] , meta , { validateArgs, validateOutput } ) ;
396400
397401 const loaded = await nextLoad ( url , context ) ;
398402 const { hookErrIdentifier } = meta ; // Retrieve the value after all settled
@@ -467,6 +471,16 @@ class Hooks {
467471 source,
468472 } ;
469473 }
474+
475+ forceLoadHooks ( ) {
476+ // No-op
477+ }
478+
479+ importMetaInitialize ( meta , context , loader ) {
480+ importMetaInitializer ??= require ( 'internal/modules/esm/initialize_import_meta' ) . initializeImportMeta ;
481+ meta = importMetaInitializer ( meta , context , loader ) ;
482+ return meta ;
483+ }
470484}
471485ObjectSetPrototypeOf ( Hooks . prototype , null ) ;
472486
@@ -716,46 +730,39 @@ function pluckHooks({
716730 * A utility function to iterate through a hook chain, track advancement in the
717731 * chain, and generate and supply the `next<HookName>` argument to the custom
718732 * hook.
719- * @param {KeyedHook[] } chain The whole hook chain.
733+ * @param {Hook } current The (currently) first hook in the chain (this shifts
734+ * on every call).
720735 * @param {object } meta Properties that change as the current hook advances
721736 * along the chain.
722737 * @param {boolean } meta.chainFinished Whether the end of the chain has been
723738 * reached AND invoked.
724739 * @param {string } meta.hookErrIdentifier A user-facing identifier to help
725740 * pinpoint where an error occurred. Ex "file:///foo.mjs 'resolve'".
726- * @param {number } meta.hookIndex A non-negative integer tracking the current
727- * position in the hook chain.
728741 * @param {string } meta.hookName The kind of hook the chain is (ex 'resolve')
729742 * @param {boolean } meta.shortCircuited Whether a hook signaled a short-circuit.
730743 * @param {(hookErrIdentifier, hookArgs) => void } validate A wrapper function
731744 * containing all validation of a custom loader hook's intermediary output. Any
732745 * validation within MUST throw.
733746 * @returns {function next<HookName>(...hookArgs) } The next hook in the chain.
734747 */
735- function nextHookFactory ( chain , meta , { validateArgs, validateOutput } ) {
748+ function nextHookFactory ( current , meta , { validateArgs, validateOutput } ) {
736749 // First, prepare the current
737750 const { hookName } = meta ;
738751 const {
739752 fn : hook ,
740753 url : hookFilePath ,
741- } = chain [ meta . hookIndex ] ;
754+ next,
755+ } = current ;
742756
743757 // ex 'nextResolve'
744758 const nextHookName = `next${
745759 StringPrototypeToUpperCase ( hookName [ 0 ] ) +
746760 StringPrototypeSlice ( hookName , 1 )
747761 } `;
748762
749- // When hookIndex is 0, it's reached the default, which does not call next()
750- // so feed it a noop that blows up if called, so the problem is obvious.
751- const generatedHookIndex = meta . hookIndex ;
752763 let nextNextHook ;
753- if ( meta . hookIndex > 0 ) {
754- // Now, prepare the next: decrement the pointer so the next call to the
755- // factory generates the next link in the chain.
756- meta . hookIndex -- ;
757-
758- nextNextHook = nextHookFactory ( chain , meta , { validateArgs, validateOutput } ) ;
764+ if ( next ) {
765+ nextNextHook = nextHookFactory ( next , meta , { validateArgs, validateOutput } ) ;
759766 } else {
760767 // eslint-disable-next-line func-name-matching
761768 nextNextHook = function chainAdvancedTooFar ( ) {
@@ -772,17 +779,16 @@ function nextHookFactory(chain, meta, { validateArgs, validateOutput }) {
772779
773780 validateArgs ( `${ meta . hookErrIdentifier } hook's ${ nextHookName } ()` , arg0 , context ) ;
774781
775- const outputErrIdentifier = `${ chain [ generatedHookIndex ] . url } '${ hookName } ' hook's ${ nextHookName } ()` ;
782+ const outputErrIdentifier = `${ hookFilePath } '${ hookName } ' hook's ${ nextHookName } ()` ;
776783
777784 // Set when next<HookName> is actually called, not just generated.
778- if ( generatedHookIndex === 0 ) { meta . chainFinished = true ; }
785+ if ( ! next ) { meta . chainFinished = true ; }
779786
780787 if ( context ) { // `context` has already been validated, so no fancy check needed.
781788 ObjectAssign ( meta . context , context ) ;
782789 }
783790
784791 const output = await hook ( arg0 , meta . context , nextNextHook ) ;
785-
786792 validateOutput ( outputErrIdentifier , output ) ;
787793
788794 if ( output ?. shortCircuit === true ) { meta . shortCircuited = true ; }
0 commit comments