-
Notifications
You must be signed in to change notification settings - Fork 17
Expand file tree
/
Copy pathts-resolve-hooks.js
More file actions
50 lines (45 loc) · 1.74 KB
/
Copy pathts-resolve-hooks.js
File metadata and controls
50 lines (45 loc) · 1.74 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
/**
* ESM resolve/load hooks for .js → .ts fallback during gradual migration.
*
* - resolve: when a .js specifier resolves to a path that doesn't exist,
* check if a .ts version exists and redirect to it.
* - load: for .ts files, delegate to Node's native loader (works on
* Node >= 22.6 with --experimental-strip-types). On older Node versions,
* throws a clear error instead of returning unparseable TypeScript source.
*/
import { fileURLToPath } from 'node:url';
export async function resolve(specifier, context, nextResolve) {
try {
return await nextResolve(specifier, context);
} catch (err) {
// Only intercept ERR_MODULE_NOT_FOUND for .js specifiers
if (err.code === 'ERR_MODULE_NOT_FOUND' && specifier.endsWith('.js')) {
const tsSpecifier = specifier.replace(/\.js$/, '.ts');
try {
return await nextResolve(tsSpecifier, context);
} catch {
// .ts also not found — throw the original error
}
}
throw err;
}
}
export async function load(url, context, nextLoad) {
if (!url.endsWith('.ts')) return nextLoad(url, context);
// On Node >= 22.6 with --experimental-strip-types, Node handles .ts natively
try {
return await nextLoad(url, context);
} catch (err) {
if (err.code !== 'ERR_UNKNOWN_FILE_EXTENSION') throw err;
}
// Node < 22.6 cannot strip TypeScript syntax. Throw a clear error instead
// of returning raw TS source that would produce a confusing SyntaxError.
const filePath = fileURLToPath(url);
throw Object.assign(
new Error(
`Cannot load TypeScript file ${filePath} on Node ${process.versions.node}. ` +
`TypeScript type stripping requires Node >= 22.6 with --experimental-strip-types.`,
),
{ code: 'ERR_TS_UNSUPPORTED' },
);
}