@@ -15,8 +15,6 @@ const {
1515 ObjectDefineProperty,
1616 ObjectSetPrototypeOf,
1717 PromiseAll,
18- PromiseResolve,
19- PromisePrototypeThen,
2018 ReflectApply,
2119 RegExpPrototypeExec,
2220 SafeArrayIterator,
@@ -111,14 +109,12 @@ let emittedSpecifierResolutionWarning = false;
111109 * position in the hook chain.
112110 * @param {string } meta.hookName The kind of hook the chain is (ex 'resolve')
113111 * @param {boolean } meta.shortCircuited Whether a hook signaled a short-circuit.
114- * @param {object } validators A wrapper function
112+ * @param {(hookErrIdentifier, hookArgs) => void } validate A wrapper function
115113 * containing all validation of a custom loader hook's intermediary output. Any
116114 * validation within MUST throw.
117- * @param {(hookErrIdentifier, hookArgs) => void } validators.validateArgs
118- * @param {(hookErrIdentifier, output) => void } validators.validateOutput
119115 * @returns {function next<HookName>(...hookArgs) } The next hook in the chain.
120116 */
121- function nextHookFactory ( chain , meta , { validateArgs , validateOutput } ) {
117+ function nextHookFactory ( chain , meta , validate ) {
122118 // First, prepare the current
123119 const { hookName } = meta ;
124120 const {
@@ -141,7 +137,7 @@ function nextHookFactory(chain, meta, { validateArgs, validateOutput }) {
141137 // factory generates the next link in the chain.
142138 meta . hookIndex -- ;
143139
144- nextNextHook = nextHookFactory ( chain , meta , { validateArgs , validateOutput } ) ;
140+ nextNextHook = nextHookFactory ( chain , meta , validate ) ;
145141 } else {
146142 // eslint-disable-next-line func-name-matching
147143 nextNextHook = function chainAdvancedTooFar ( ) {
@@ -152,36 +148,21 @@ function nextHookFactory(chain, meta, { validateArgs, validateOutput }) {
152148 }
153149
154150 return ObjectDefineProperty (
155- ( ...args ) => {
151+ async ( ...args ) => {
156152 // Update only when hook is invoked to avoid fingering the wrong filePath
157153 meta . hookErrIdentifier = `${ hookFilePath } '${ hookName } '` ;
158154
159- validateArgs ( `${ meta . hookErrIdentifier } hook's ${ nextHookName } ()` , args ) ;
160-
161- const outputErrIdentifier = `${ chain [ generatedHookIndex ] . url } '${ hookName } ' hook's ${ nextHookName } ()` ;
155+ validate ( `${ meta . hookErrIdentifier } hook's ${ nextHookName } ()` , args ) ;
162156
163157 // Set when next<HookName> is actually called, not just generated.
164158 if ( generatedHookIndex === 0 ) { meta . chainFinished = true ; }
165159
166160 ArrayPrototypePush ( args , nextNextHook ) ;
167- const output = ReflectApply ( hook , undefined , args ) ;
168-
169- validateOutput ( outputErrIdentifier , output ) ;
161+ const output = await ReflectApply ( hook , undefined , args ) ;
170162
171- function checkShortCircuited ( output ) {
172- if ( output ?. shortCircuit === true ) { meta . shortCircuited = true ; }
173-
174- return output ;
175- }
176-
177- if ( meta . isChainAsync ) {
178- return PromisePrototypeThen (
179- PromiseResolve ( output ) ,
180- checkShortCircuited ,
181- ) ;
182- }
163+ if ( output ?. shortCircuit === true ) { meta . shortCircuited = true ; }
164+ return output ;
183165
184- return checkShortCircuited ( output ) ;
185166 } ,
186167 'name' ,
187168 { __proto__ : null , value : nextHookName } ,
@@ -440,11 +421,8 @@ class ESMLoader {
440421 ) ;
441422 }
442423
443- const { format, url } = this . resolve (
444- specifier ,
445- parentURL ,
446- importAssertionsForResolve ,
447- ) ;
424+ const { format, url } =
425+ await this . resolve ( specifier , parentURL , importAssertionsForResolve ) ;
448426
449427 let job = this . moduleMap . get ( url , importAssertions . type ) ;
450428
@@ -579,11 +557,10 @@ class ESMLoader {
579557 hookErrIdentifier : '' ,
580558 hookIndex : chain . length - 1 ,
581559 hookName : 'load' ,
582- isChainAsync : true ,
583560 shortCircuited : false ,
584561 } ;
585562
586- const validateArgs = ( hookErrIdentifier , { 0 : nextUrl , 1 : ctx } ) => {
563+ const validate = ( hookErrIdentifier , { 0 : nextUrl , 1 : ctx } ) => {
587564 if ( typeof nextUrl !== 'string' ) {
588565 // non-strings can be coerced to a url string
589566 // validateString() throws a less-specific error
@@ -609,22 +586,19 @@ class ESMLoader {
609586
610587 validateObject ( ctx , `${ hookErrIdentifier } context` ) ;
611588 } ;
612- const validateOutput = ( hookErrIdentifier , output ) => {
613- if ( typeof output !== 'object' ) { // [2]
614- throw new ERR_INVALID_RETURN_VALUE (
615- 'an object' ,
616- hookErrIdentifier ,
617- output ,
618- ) ;
619- }
620- } ;
621589
622- const nextLoad = nextHookFactory ( chain , meta , { validateArgs , validateOutput } ) ;
590+ const nextLoad = nextHookFactory ( chain , meta , validate ) ;
623591
624592 const loaded = await nextLoad ( url , context ) ;
625593 const { hookErrIdentifier } = meta ; // Retrieve the value after all settled
626594
627- validateOutput ( hookErrIdentifier , loaded ) ;
595+ if ( typeof loaded !== 'object' ) { // [2]
596+ throw new ERR_INVALID_RETURN_VALUE (
597+ 'an object' ,
598+ hookErrIdentifier ,
599+ loaded ,
600+ ) ;
601+ }
628602
629603 if ( loaded ?. shortCircuit === true ) { meta . shortCircuited = true ; }
630604
@@ -804,7 +778,7 @@ class ESMLoader {
804778 * statement or expression.
805779 * @returns {{ format: string, url: URL['href'] } }
806780 */
807- resolve (
781+ async resolve (
808782 originalSpecifier ,
809783 parentURL ,
810784 importAssertions = ObjectCreate ( null )
@@ -828,43 +802,36 @@ class ESMLoader {
828802 hookErrIdentifier : '' ,
829803 hookIndex : chain . length - 1 ,
830804 hookName : 'resolve' ,
831- isChainAsync : false ,
832805 shortCircuited : false ,
833806 } ;
807+
834808 const context = {
835809 conditions : DEFAULT_CONDITIONS ,
836810 importAssertions,
837811 parentURL,
838812 } ;
813+ const validate = ( hookErrIdentifier , { 0 : suppliedSpecifier , 1 : ctx } ) => {
839814
840- const validateArgs = ( hookErrIdentifier , { 0 : suppliedSpecifier , 1 : ctx } ) => {
841815 validateString (
842816 suppliedSpecifier ,
843817 `${ hookErrIdentifier } specifier` ,
844818 ) ; // non-strings can be coerced to a url string
845819
846820 validateObject ( ctx , `${ hookErrIdentifier } context` ) ;
847821 } ;
848- const validateOutput = ( hookErrIdentifier , output ) => {
849- if (
850- typeof output !== 'object' || // [2]
851- output === null ||
852- ( output . url == null && typeof output . then === 'function' )
853- ) {
854- throw new ERR_INVALID_RETURN_VALUE (
855- 'an object' ,
856- hookErrIdentifier ,
857- output ,
858- ) ;
859- }
860- } ;
861822
862- const nextResolve = nextHookFactory ( chain , meta , { validateArgs , validateOutput } ) ;
823+ const nextResolve = nextHookFactory ( chain , meta , validate ) ;
863824
864- const resolution = nextResolve ( originalSpecifier , context ) ;
825+ const resolution = await nextResolve ( originalSpecifier , context ) ;
865826 const { hookErrIdentifier } = meta ; // Retrieve the value after all settled
866827
867- validateOutput ( hookErrIdentifier , resolution ) ;
828+ if ( typeof resolution !== 'object' ) { // [2]
829+ throw new ERR_INVALID_RETURN_VALUE (
830+ 'an object' ,
831+ hookErrIdentifier ,
832+ resolution ,
833+ ) ;
834+ }
868835
869836 if ( resolution ?. shortCircuit === true ) { meta . shortCircuited = true ; }
870837
0 commit comments