@@ -32,6 +32,7 @@ const {
32
32
ERR_INVALID_RETURN_VALUE ,
33
33
ERR_LOADER_CHAIN_INCOMPLETE ,
34
34
ERR_UNKNOWN_BUILTIN_MODULE ,
35
+ ERR_METHOD_NOT_IMPLEMENTED ,
35
36
ERR_WORKER_UNSERIALIZABLE_ERROR ,
36
37
} = require ( 'internal/errors' ) . codes ;
37
38
const { exitCodes : { kUnfinishedTopLevelAwait } } = internalBinding ( 'errors' ) ;
@@ -82,7 +83,6 @@ let debug = require('internal/util/debuglog').debuglog('esm', (fn) => {
82
83
83
84
// [2] `validate...()`s throw the wrong error
84
85
85
-
86
86
class Hooks {
87
87
#chains = {
88
88
/**
@@ -121,20 +121,20 @@ class Hooks {
121
121
// Cache URLs we've already validated to avoid repeated validation
122
122
#validatedUrls = new SafeSet ( ) ;
123
123
124
+ allowImportMetaResolve = false ;
125
+
124
126
/**
125
127
* Import and register custom/user-defined module loader hook(s).
126
128
* @param {string } urlOrSpecifier
127
129
* @param {string } parentURL
128
130
*/
129
131
async register ( urlOrSpecifier , parentURL ) {
130
132
const moduleLoader = require ( 'internal/process/esm_loader' ) . esmLoader ;
131
-
132
133
const keyedExports = await moduleLoader . import (
133
134
urlOrSpecifier ,
134
135
parentURL ,
135
136
kEmptyObject ,
136
137
) ;
137
-
138
138
this . addCustomLoader ( urlOrSpecifier , keyedExports ) ;
139
139
}
140
140
@@ -152,13 +152,16 @@ class Hooks {
152
152
} = pluckHooks ( exports ) ;
153
153
154
154
if ( globalPreload ) {
155
- 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 } ) ;
156
157
}
157
158
if ( resolve ) {
158
- 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 } ) ;
159
161
}
160
162
if ( load ) {
161
- 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 } ) ;
162
165
}
163
166
}
164
167
@@ -235,7 +238,6 @@ class Hooks {
235
238
chainFinished : null ,
236
239
context,
237
240
hookErrIdentifier : '' ,
238
- hookIndex : chain . length - 1 ,
239
241
hookName : 'resolve' ,
240
242
shortCircuited : false ,
241
243
} ;
@@ -258,7 +260,7 @@ class Hooks {
258
260
}
259
261
} ;
260
262
261
- const nextResolve = nextHookFactory ( chain , meta , { validateArgs, validateOutput } ) ;
263
+ const nextResolve = nextHookFactory ( chain [ chain . length - 1 ] , meta , { validateArgs, validateOutput } ) ;
262
264
263
265
const resolution = await nextResolve ( originalSpecifier , context ) ;
264
266
const { hookErrIdentifier } = meta ; // Retrieve the value after all settled
@@ -335,6 +337,10 @@ class Hooks {
335
337
} ;
336
338
}
337
339
340
+ resolveSync ( _originalSpecifier , _parentURL , _importAssertions ) {
341
+ throw new ERR_METHOD_NOT_IMPLEMENTED ( 'resolveSync()' ) ;
342
+ }
343
+
338
344
/**
339
345
* Provide source that is understood by one of Node's translators.
340
346
*
@@ -351,7 +357,6 @@ class Hooks {
351
357
chainFinished : null ,
352
358
context,
353
359
hookErrIdentifier : '' ,
354
- hookIndex : chain . length - 1 ,
355
360
hookName : 'load' ,
356
361
shortCircuited : false ,
357
362
} ;
@@ -393,7 +398,7 @@ class Hooks {
393
398
}
394
399
} ;
395
400
396
- const nextLoad = nextHookFactory ( chain , meta , { validateArgs, validateOutput } ) ;
401
+ const nextLoad = nextHookFactory ( chain [ chain . length - 1 ] , meta , { validateArgs, validateOutput } ) ;
397
402
398
403
const loaded = await nextLoad ( url , context ) ;
399
404
const { hookErrIdentifier } = meta ; // Retrieve the value after all settled
@@ -717,46 +722,39 @@ function pluckHooks({
717
722
* A utility function to iterate through a hook chain, track advancement in the
718
723
* chain, and generate and supply the `next<HookName>` argument to the custom
719
724
* hook.
720
- * @param {KeyedHook[] } chain The whole hook chain.
725
+ * @param {Hook } current The (currently) first hook in the chain (this shifts
726
+ * on every call).
721
727
* @param {object } meta Properties that change as the current hook advances
722
728
* along the chain.
723
729
* @param {boolean } meta.chainFinished Whether the end of the chain has been
724
730
* reached AND invoked.
725
731
* @param {string } meta.hookErrIdentifier A user-facing identifier to help
726
732
* pinpoint where an error occurred. Ex "file:///foo.mjs 'resolve'".
727
- * @param {number } meta.hookIndex A non-negative integer tracking the current
728
- * position in the hook chain.
729
733
* @param {string } meta.hookName The kind of hook the chain is (ex 'resolve')
730
734
* @param {boolean } meta.shortCircuited Whether a hook signaled a short-circuit.
731
735
* @param {(hookErrIdentifier, hookArgs) => void } validate A wrapper function
732
736
* containing all validation of a custom loader hook's intermediary output. Any
733
737
* validation within MUST throw.
734
738
* @returns {function next<HookName>(...hookArgs) } The next hook in the chain.
735
739
*/
736
- function nextHookFactory ( chain , meta , { validateArgs, validateOutput } ) {
740
+ function nextHookFactory ( current , meta , { validateArgs, validateOutput } ) {
737
741
// First, prepare the current
738
742
const { hookName } = meta ;
739
743
const {
740
744
fn : hook ,
741
745
url : hookFilePath ,
742
- } = chain [ meta . hookIndex ] ;
746
+ next,
747
+ } = current ;
743
748
744
749
// ex 'nextResolve'
745
750
const nextHookName = `next${
746
751
StringPrototypeToUpperCase ( hookName [ 0 ] ) +
747
752
StringPrototypeSlice ( hookName , 1 )
748
753
} `;
749
754
750
- // When hookIndex is 0, it's reached the default, which does not call next()
751
- // so feed it a noop that blows up if called, so the problem is obvious.
752
- const generatedHookIndex = meta . hookIndex ;
753
755
let nextNextHook ;
754
- if ( meta . hookIndex > 0 ) {
755
- // Now, prepare the next: decrement the pointer so the next call to the
756
- // factory generates the next link in the chain.
757
- meta . hookIndex -- ;
758
-
759
- nextNextHook = nextHookFactory ( chain , meta , { validateArgs, validateOutput } ) ;
756
+ if ( next ) {
757
+ nextNextHook = nextHookFactory ( next , meta , { validateArgs, validateOutput } ) ;
760
758
} else {
761
759
// eslint-disable-next-line func-name-matching
762
760
nextNextHook = function chainAdvancedTooFar ( ) {
@@ -773,17 +771,16 @@ function nextHookFactory(chain, meta, { validateArgs, validateOutput }) {
773
771
774
772
validateArgs ( `${ meta . hookErrIdentifier } hook's ${ nextHookName } ()` , arg0 , context ) ;
775
773
776
- const outputErrIdentifier = `${ chain [ generatedHookIndex ] . url } '${ hookName } ' hook's ${ nextHookName } ()` ;
774
+ const outputErrIdentifier = `${ hookFilePath } '${ hookName } ' hook's ${ nextHookName } ()` ;
777
775
778
776
// Set when next<HookName> is actually called, not just generated.
779
- if ( generatedHookIndex === 0 ) { meta . chainFinished = true ; }
777
+ if ( ! next ) { meta . chainFinished = true ; }
780
778
781
779
if ( context ) { // `context` has already been validated, so no fancy check needed.
782
780
ObjectAssign ( meta . context , context ) ;
783
781
}
784
782
785
783
const output = await hook ( arg0 , meta . context , nextNextHook ) ;
786
-
787
784
validateOutput ( outputErrIdentifier , output ) ;
788
785
789
786
if ( output ?. shortCircuit === true ) { meta . shortCircuited = true ; }
0 commit comments