forked from angular/angular
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathesm-extension-loader.mjs
58 lines (53 loc) · 2.31 KB
/
esm-extension-loader.mjs
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
51
52
53
54
55
56
57
58
/**
* @license
* Copyright Google LLC All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
const explicitExtensionRe = /\.[mc]?js$/;
const explicitJsExtensionRe = /\.js$/;
const builtinNamespaceImportRe = /^node:/;
/*
* NodeJS resolver that enables the interop with the current Bazel setup.
*
* The loader will attempt resolution by replacing explicit extension with
* their ESM variants. It also tries completing import specifiers in case no
* extension of explicit file is specified.
*
* There are a few cases:
*
* * Relative imports without an extension. This happens because our
* source files cannot use explicit `.mjs` extensions yet.
* * Relative imports with an explicit extension to `.js`. This may
* be generated by TypeScript as we have `.ts` source files.
* * Local module imports. In NPM, extensions are not needed as the
* `package.json` `exports` help resolving. In Bazel when dealing with
* 1st-party packages- `package.json` is not consulted in resolution.
* 1. The NPM artifacts differ from the source compilation output.
* 2. It results in additional churn, having to put `package.json` into `bin`.
*/
export async function resolve(specifier, context, nextResolve) {
const interopAttempts = [];
if (explicitJsExtensionRe.test(specifier)) {
interopAttempts.push(specifier.replace(explicitJsExtensionRe, '.mjs'));
}
// If there is no explicit extension and we are not dealing with a
// builtin namespace module, attempt various subpaths to prioritize ESM.
if (!explicitExtensionRe.test(specifier) && !builtinNamespaceImportRe.test(specifier)) {
interopAttempts.push(`${specifier}.mjs`);
interopAttempts.push(`${specifier}/index.mjs`);
// Last attempts are normal `.js` extensions. These could still
// be valid ESM when there is an type:module `package.json` file
interopAttempts.push(`${specifier}.js`);
interopAttempts.push(`${specifier}/index.js`);
}
for (const attempt of interopAttempts) {
try {
return await nextResolve(attempt, context);
} catch {}
}
// Original specifier is attempted at the end because
// we want to prioritize the ESM variants first.
return await nextResolve(specifier, context);
}