@@ -31,6 +31,7 @@ const {
31
31
ERR_INVALID_RETURN_PROPERTY_VALUE ,
32
32
ERR_INVALID_RETURN_VALUE ,
33
33
ERR_LOADER_CHAIN_INCOMPLETE ,
34
+ ERR_METHOD_NOT_IMPLEMENTED ,
34
35
ERR_UNKNOWN_BUILTIN_MODULE ,
35
36
ERR_WORKER_UNSERIALIZABLE_ERROR ,
36
37
} = require ( 'internal/errors' ) . codes ;
@@ -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 , { __proto__ : null , fn : globalPreload , url } ) ;
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 , { __proto__ : null , 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 , { __proto__ : null , 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
@@ -468,6 +473,10 @@ class Hooks {
468
473
source,
469
474
} ;
470
475
}
476
+
477
+ forceLoadHooks ( ) {
478
+ // No-op
479
+ }
471
480
}
472
481
ObjectSetPrototypeOf ( Hooks . prototype , null ) ;
473
482
@@ -717,46 +726,39 @@ function pluckHooks({
717
726
* A utility function to iterate through a hook chain, track advancement in the
718
727
* chain, and generate and supply the `next<HookName>` argument to the custom
719
728
* hook.
720
- * @param {KeyedHook[] } chain The whole hook chain.
729
+ * @param {Hook } current The (currently) first hook in the chain (this shifts
730
+ * on every call).
721
731
* @param {object } meta Properties that change as the current hook advances
722
732
* along the chain.
723
733
* @param {boolean } meta.chainFinished Whether the end of the chain has been
724
734
* reached AND invoked.
725
735
* @param {string } meta.hookErrIdentifier A user-facing identifier to help
726
736
* 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
737
* @param {string } meta.hookName The kind of hook the chain is (ex 'resolve')
730
738
* @param {boolean } meta.shortCircuited Whether a hook signaled a short-circuit.
731
739
* @param {(hookErrIdentifier, hookArgs) => void } validate A wrapper function
732
740
* containing all validation of a custom loader hook's intermediary output. Any
733
741
* validation within MUST throw.
734
742
* @returns {function next<HookName>(...hookArgs) } The next hook in the chain.
735
743
*/
736
- function nextHookFactory ( chain , meta , { validateArgs, validateOutput } ) {
744
+ function nextHookFactory ( current , meta , { validateArgs, validateOutput } ) {
737
745
// First, prepare the current
738
746
const { hookName } = meta ;
739
747
const {
740
748
fn : hook ,
741
749
url : hookFilePath ,
742
- } = chain [ meta . hookIndex ] ;
750
+ next,
751
+ } = current ;
743
752
744
753
// ex 'nextResolve'
745
754
const nextHookName = `next${
746
755
StringPrototypeToUpperCase ( hookName [ 0 ] ) +
747
756
StringPrototypeSlice ( hookName , 1 )
748
757
} `;
749
758
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
759
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 } ) ;
760
+ if ( next ) {
761
+ nextNextHook = nextHookFactory ( next , meta , { validateArgs, validateOutput } ) ;
760
762
} else {
761
763
// eslint-disable-next-line func-name-matching
762
764
nextNextHook = function chainAdvancedTooFar ( ) {
@@ -773,17 +775,16 @@ function nextHookFactory(chain, meta, { validateArgs, validateOutput }) {
773
775
774
776
validateArgs ( `${ meta . hookErrIdentifier } hook's ${ nextHookName } ()` , arg0 , context ) ;
775
777
776
- const outputErrIdentifier = `${ chain [ generatedHookIndex ] . url } '${ hookName } ' hook's ${ nextHookName } ()` ;
778
+ const outputErrIdentifier = `${ hookFilePath } '${ hookName } ' hook's ${ nextHookName } ()` ;
777
779
778
780
// Set when next<HookName> is actually called, not just generated.
779
- if ( generatedHookIndex === 0 ) { meta . chainFinished = true ; }
781
+ if ( ! next ) { meta . chainFinished = true ; }
780
782
781
783
if ( context ) { // `context` has already been validated, so no fancy check needed.
782
784
ObjectAssign ( meta . context , context ) ;
783
785
}
784
786
785
787
const output = await hook ( arg0 , meta . context , nextNextHook ) ;
786
-
787
788
validateOutput ( outputErrIdentifier , output ) ;
788
789
789
790
if ( output ?. shortCircuit === true ) { meta . shortCircuited = true ; }
0 commit comments