@@ -80,7 +80,6 @@ let debug = require('internal/util/debuglog').debuglog('esm', (fn) => {
80
80
81
81
// [2] `validate...()`s throw the wrong error
82
82
83
-
84
83
class Hooks {
85
84
#chains = {
86
85
/**
@@ -126,16 +125,18 @@ class Hooks {
126
125
*/
127
126
async register ( urlOrSpecifier , parentURL ) {
128
127
const moduleLoader = require ( 'internal/process/esm_loader' ) . esmLoader ;
129
-
130
128
const keyedExports = await moduleLoader . import (
131
129
urlOrSpecifier ,
132
130
parentURL ,
133
131
kEmptyObject ,
134
132
) ;
135
-
136
133
this . addCustomLoader ( urlOrSpecifier , keyedExports ) ;
137
134
}
138
135
136
+ allowImportMetaResolve ( ) {
137
+ return false ;
138
+ }
139
+
139
140
/**
140
141
* Collect custom/user-defined module loader hook(s).
141
142
* After all hooks have been collected, the global preload hook(s) must be initialized.
@@ -150,13 +151,16 @@ class Hooks {
150
151
} = pluckHooks ( exports ) ;
151
152
152
153
if ( globalPreload ) {
153
- ArrayPrototypePush ( this . #chains. globalPreload , { fn : globalPreload , url } ) ;
154
+ const next = this . #chains. globalPreload [ this . #chains. globalPreload . length - 1 ] ;
155
+ ArrayPrototypePush ( this . #chains. globalPreload , { fn : globalPreload , url, next } ) ;
154
156
}
155
157
if ( resolve ) {
156
- ArrayPrototypePush ( this . #chains. resolve , { fn : resolve , url } ) ;
158
+ const next = this . #chains. resolve [ this . #chains. resolve . length - 1 ] ;
159
+ ArrayPrototypePush ( this . #chains. resolve , { fn : resolve , url, next } ) ;
157
160
}
158
161
if ( load ) {
159
- ArrayPrototypePush ( this . #chains. load , { fn : load , url } ) ;
162
+ const next = this . #chains. load [ this . #chains. load . length - 1 ] ;
163
+ ArrayPrototypePush ( this . #chains. load , { fn : load , url, next } ) ;
160
164
}
161
165
}
162
166
@@ -233,7 +237,6 @@ class Hooks {
233
237
chainFinished : null ,
234
238
context,
235
239
hookErrIdentifier : '' ,
236
- hookIndex : chain . length - 1 ,
237
240
hookName : 'resolve' ,
238
241
shortCircuited : false ,
239
242
} ;
@@ -256,7 +259,7 @@ class Hooks {
256
259
}
257
260
} ;
258
261
259
- const nextResolve = nextHookFactory ( chain , meta , { validateArgs, validateOutput } ) ;
262
+ const nextResolve = nextHookFactory ( chain [ chain . length - 1 ] , meta , { validateArgs, validateOutput } ) ;
260
263
261
264
const resolution = await nextResolve ( originalSpecifier , context ) ;
262
265
const { hookErrIdentifier } = meta ; // Retrieve the value after all settled
@@ -349,7 +352,6 @@ class Hooks {
349
352
chainFinished : null ,
350
353
context,
351
354
hookErrIdentifier : '' ,
352
- hookIndex : chain . length - 1 ,
353
355
hookName : 'load' ,
354
356
shortCircuited : false ,
355
357
} ;
@@ -391,7 +393,7 @@ class Hooks {
391
393
}
392
394
} ;
393
395
394
- const nextLoad = nextHookFactory ( chain , meta , { validateArgs, validateOutput } ) ;
396
+ const nextLoad = nextHookFactory ( chain [ chain . length - 1 ] , meta , { validateArgs, validateOutput } ) ;
395
397
396
398
const loaded = await nextLoad ( url , context ) ;
397
399
const { hookErrIdentifier } = meta ; // Retrieve the value after all settled
@@ -528,7 +530,17 @@ class HooksProxy {
528
530
debug ( 'wait for signal from worker' ) ;
529
531
AtomicsWait ( this . #lock, WORKER_TO_MAIN_THREAD_NOTIFICATION , 0 ) ;
530
532
const response = this . #worker. receiveMessageSync ( ) ;
531
- if ( response . message . status === 'exit' ) { return ; }
533
+ if ( response . message . status === 'exit' ) {
534
+ // TODO: I do not understand why this is necessary.
535
+ // node \
536
+ // --no-warnings --experimental-loader 'data:text/javascript,process.exit(42)'
537
+ // ./test/fixtures/empty.js
538
+ // Does not trigger `this.#worker.on('exit', process.exit);`.
539
+ // I think it is because `makeSyncRequest` keeps waiting to see another
540
+ // message and blocks the thread from ANY other activity including the exit.
541
+ process . exit ( response . message . body ) ;
542
+ return ;
543
+ }
532
544
const { preloadScripts } = this . #unwrapMessage( response ) ;
533
545
this . #executePreloadScripts( preloadScripts ) ;
534
546
}
@@ -684,46 +696,34 @@ function pluckHooks({
684
696
* A utility function to iterate through a hook chain, track advancement in the
685
697
* chain, and generate and supply the `next<HookName>` argument to the custom
686
698
* hook.
687
- * @param {KeyedHook[] } chain The whole hook chain.
699
+ * @param {Hook } hook The first hook in the chain.
688
700
* @param {object } meta Properties that change as the current hook advances
689
701
* along the chain.
690
702
* @param {boolean } meta.chainFinished Whether the end of the chain has been
691
703
* reached AND invoked.
692
704
* @param {string } meta.hookErrIdentifier A user-facing identifier to help
693
705
* 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.
696
706
* @param {string } meta.hookName The kind of hook the chain is (ex 'resolve')
697
707
* @param {boolean } meta.shortCircuited Whether a hook signaled a short-circuit.
698
708
* @param {(hookErrIdentifier, hookArgs) => void } validate A wrapper function
699
709
* containing all validation of a custom loader hook's intermediary output. Any
700
710
* validation within MUST throw.
701
711
* @returns {function next<HookName>(...hookArgs) } The next hook in the chain.
702
712
*/
703
- function nextHookFactory ( chain , meta , { validateArgs, validateOutput } ) {
713
+ function nextHookFactory ( hook , meta , { validateArgs, validateOutput } ) {
704
714
// First, prepare the current
705
715
const { hookName } = meta ;
706
- const {
707
- fn : hook ,
708
- url : hookFilePath ,
709
- } = chain [ meta . hookIndex ] ;
716
+ const { fn, url, next } = hook ;
710
717
711
718
// ex 'nextResolve'
712
719
const nextHookName = `next${
713
720
StringPrototypeToUpperCase ( hookName [ 0 ] ) +
714
721
StringPrototypeSlice ( hookName , 1 )
715
722
} `;
716
723
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 ;
720
724
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 } ) ;
725
+ if ( next ) {
726
+ nextNextHook = nextHookFactory ( next , meta , { validateArgs, validateOutput } ) ;
727
727
} else {
728
728
// eslint-disable-next-line func-name-matching
729
729
nextNextHook = function chainAdvancedTooFar ( ) {
@@ -736,21 +736,20 @@ function nextHookFactory(chain, meta, { validateArgs, validateOutput }) {
736
736
return ObjectDefineProperty (
737
737
async ( arg0 = undefined , context ) => {
738
738
// Update only when hook is invoked to avoid fingering the wrong filePath
739
- meta . hookErrIdentifier = `${ hookFilePath } '${ hookName } '` ;
739
+ meta . hookErrIdentifier = `${ url } '${ hookName } '` ;
740
740
741
741
validateArgs ( `${ meta . hookErrIdentifier } hook's ${ nextHookName } ()` , arg0 , context ) ;
742
742
743
- const outputErrIdentifier = `${ chain [ generatedHookIndex ] . url } '${ hookName } ' hook's ${ nextHookName } ()` ;
743
+ const outputErrIdentifier = `${ url } '${ hookName } ' hook's ${ nextHookName } ()` ;
744
744
745
745
// Set when next<HookName> is actually called, not just generated.
746
- if ( generatedHookIndex === 0 ) { meta . chainFinished = true ; }
746
+ if ( ! next ) { meta . chainFinished = true ; }
747
747
748
748
if ( context ) { // `context` has already been validated, so no fancy check needed.
749
749
ObjectAssign ( meta . context , context ) ;
750
750
}
751
751
752
- const output = await hook ( arg0 , meta . context , nextNextHook ) ;
753
-
752
+ const output = await fn ( arg0 , meta . context , nextNextHook ) ;
754
753
validateOutput ( outputErrIdentifier , output ) ;
755
754
756
755
if ( output ?. shortCircuit === true ) { meta . shortCircuited = true ; }
0 commit comments