@@ -69,7 +69,11 @@ export namespace NodeLoaderHooksAPI2 {
69
69
parentURL : string ;
70
70
} ,
71
71
defaultResolve : ResolveHook
72
- ) => Promise < { url : string ; format ?: NodeLoaderHooksFormat } > ;
72
+ ) => Promise < {
73
+ url : string ;
74
+ format ?: NodeLoaderHooksFormat ;
75
+ shortCircuit ?: boolean ;
76
+ } > ;
73
77
export type LoadHook = (
74
78
url : string ,
75
79
context : {
@@ -80,6 +84,7 @@ export namespace NodeLoaderHooksAPI2 {
80
84
) => Promise < {
81
85
format : NodeLoaderHooksFormat ;
82
86
source : string | Buffer | undefined ;
87
+ shortCircuit ?: boolean ;
83
88
} > ;
84
89
export type NodeImportConditions = unknown ;
85
90
export interface NodeImportAssertions {
@@ -205,32 +210,34 @@ export function createEsmHooks(tsNodeService: Service) {
205
210
}
206
211
}
207
212
208
- const parsed = parseUrl ( specifier ) ;
209
- const { pathname, protocol, hostname } = parsed ;
213
+ return addShortCircuitFlag ( async ( ) => {
214
+ const parsed = parseUrl ( specifier ) ;
215
+ const { pathname, protocol, hostname } = parsed ;
210
216
211
- if ( ! isFileUrlOrNodeStyleSpecifier ( parsed ) ) {
212
- return entrypointFallback ( defer ) ;
213
- }
217
+ if ( ! isFileUrlOrNodeStyleSpecifier ( parsed ) ) {
218
+ return entrypointFallback ( defer ) ;
219
+ }
214
220
215
- if ( protocol !== null && protocol !== 'file:' ) {
216
- return entrypointFallback ( defer ) ;
217
- }
221
+ if ( protocol !== null && protocol !== 'file:' ) {
222
+ return entrypointFallback ( defer ) ;
223
+ }
218
224
219
- // Malformed file:// URL? We should always see `null` or `''`
220
- if ( hostname ) {
221
- // TODO file://./foo sets `hostname` to `'.'`. Perhaps we should special-case this.
222
- return entrypointFallback ( defer ) ;
223
- }
225
+ // Malformed file:// URL? We should always see `null` or `''`
226
+ if ( hostname ) {
227
+ // TODO file://./foo sets `hostname` to `'.'`. Perhaps we should special-case this.
228
+ return entrypointFallback ( defer ) ;
229
+ }
224
230
225
- // pathname is the path to be resolved
231
+ // pathname is the path to be resolved
226
232
227
- return entrypointFallback ( ( ) =>
228
- nodeResolveImplementation . defaultResolve (
229
- specifier ,
230
- context ,
231
- defaultResolve
232
- )
233
- ) ;
233
+ return entrypointFallback ( ( ) =>
234
+ nodeResolveImplementation . defaultResolve (
235
+ specifier ,
236
+ context ,
237
+ defaultResolve
238
+ )
239
+ ) ;
240
+ } ) ;
234
241
}
235
242
236
243
// `load` from new loader hook API (See description at the top of this file)
@@ -245,47 +252,49 @@ export function createEsmHooks(tsNodeService: Service) {
245
252
format : NodeLoaderHooksFormat ;
246
253
source : string | Buffer | undefined ;
247
254
} > {
248
- // If we get a format hint from resolve() on the context then use it
249
- // otherwise call the old getFormat() hook using node's old built-in defaultGetFormat() that ships with ts-node
250
- const format =
251
- context . format ??
252
- ( await getFormat ( url , context , defaultGetFormat ) ) . format ;
253
-
254
- let source = undefined ;
255
- if ( format !== 'builtin' && format !== 'commonjs' ) {
256
- // Call the new defaultLoad() to get the source
257
- const { source : rawSource } = await defaultLoad (
258
- url ,
259
- {
260
- ...context ,
261
- format,
262
- } ,
263
- defaultLoad
264
- ) ;
255
+ return addShortCircuitFlag ( async ( ) => {
256
+ // If we get a format hint from resolve() on the context then use it
257
+ // otherwise call the old getFormat() hook using node's old built-in defaultGetFormat() that ships with ts-node
258
+ const format =
259
+ context . format ??
260
+ ( await getFormat ( url , context , defaultGetFormat ) ) . format ;
261
+
262
+ let source = undefined ;
263
+ if ( format !== 'builtin' && format !== 'commonjs' ) {
264
+ // Call the new defaultLoad() to get the source
265
+ const { source : rawSource } = await defaultLoad (
266
+ url ,
267
+ {
268
+ ...context ,
269
+ format,
270
+ } ,
271
+ defaultLoad
272
+ ) ;
273
+
274
+ if ( rawSource === undefined || rawSource === null ) {
275
+ throw new Error (
276
+ `Failed to load raw source: Format was '${ format } ' and url was '${ url } ''.`
277
+ ) ;
278
+ }
265
279
266
- if ( rawSource === undefined || rawSource === null ) {
267
- throw new Error (
268
- `Failed to load raw source: Format was '${ format } ' and url was '${ url } ''.`
280
+ // Emulate node's built-in old defaultTransformSource() so we can re-use the old transformSource() hook
281
+ const defaultTransformSource : typeof transformSource = async (
282
+ source ,
283
+ _context ,
284
+ _defaultTransformSource
285
+ ) => ( { source } ) ;
286
+
287
+ // Call the old hook
288
+ const { source : transformedSource } = await transformSource (
289
+ rawSource ,
290
+ { url, format } ,
291
+ defaultTransformSource
269
292
) ;
293
+ source = transformedSource ;
270
294
}
271
295
272
- // Emulate node's built-in old defaultTransformSource() so we can re-use the old transformSource() hook
273
- const defaultTransformSource : typeof transformSource = async (
274
- source ,
275
- _context ,
276
- _defaultTransformSource
277
- ) => ( { source } ) ;
278
-
279
- // Call the old hook
280
- const { source : transformedSource } = await transformSource (
281
- rawSource ,
282
- { url, format } ,
283
- defaultTransformSource
284
- ) ;
285
- source = transformedSource ;
286
- }
287
-
288
- return { format, source } ;
296
+ return { format, source } ;
297
+ } ) ;
289
298
}
290
299
291
300
async function getFormat (
@@ -384,3 +393,13 @@ export function createEsmHooks(tsNodeService: Service) {
384
393
385
394
return hooksAPI ;
386
395
}
396
+
397
+ async function addShortCircuitFlag < T > ( fn : ( ) => Promise < T > ) {
398
+ const ret = await fn ( ) ;
399
+ // Not sure if this is necessary; being lazy. Can revisit in the future.
400
+ if ( ret == null ) return ret ;
401
+ return {
402
+ ...ret ,
403
+ shortCircuit : true ,
404
+ } ;
405
+ }
0 commit comments