mirror of
https://github.com/angular/angular
synced 2026-05-24 09:28:37 +00:00
75 lines
2.5 KiB
JavaScript
75 lines
2.5 KiB
JavaScript
/**
|
|
* @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.dev/license
|
|
*/
|
|
|
|
/**
|
|
* @fileoverview
|
|
*
|
|
* Module loader that augments NodeJS's execution to:
|
|
*
|
|
* - support native execution of Angular JavaScript output
|
|
* that isn't strict ESM at this point (lack of explicit extensions).
|
|
* - support path mappings at runtime. This allows us to natively execute ESM
|
|
* without having to pre-bundle for testing, or use the slow full npm linked packages
|
|
*/
|
|
|
|
import {parseTsconfig, createPathsMatcher} from 'get-tsconfig';
|
|
|
|
import path from 'node:path';
|
|
|
|
const explicitExtensionRe = /\.[mc]?js$/;
|
|
const nonModuleImportRe = /^[.\/]/;
|
|
|
|
const runfilesRoot = process.env.JS_BINARY__RUNFILES;
|
|
|
|
const tsconfigPath = path.join(runfilesRoot, '_main/packages/tsconfig-build.json');
|
|
const tsconfig = parseTsconfig(tsconfigPath);
|
|
const pathMappingMatcher = createPathsMatcher({config: tsconfig, path: tsconfigPath});
|
|
|
|
/** @type {import('module').ResolveHook} */
|
|
export const resolve = async (specifier, context, nextResolve) => {
|
|
// True when it's a non-module import without explicit extensions.
|
|
const isNonModuleExtensionlessImport =
|
|
nonModuleImportRe.test(specifier) && !explicitExtensionRe.test(specifier);
|
|
const pathMappings = !nonModuleImportRe.test(specifier) ? pathMappingMatcher(specifier) : [];
|
|
|
|
// If it's neither path mapped, nor an extension-less import that may be fixed up, exit early.
|
|
if (!isNonModuleExtensionlessImport && pathMappings.length === 0) {
|
|
return nextResolve(specifier, context);
|
|
}
|
|
|
|
if (pathMappings.length > 0) {
|
|
for (const mapping of pathMappings) {
|
|
const res = await catchError(() => resolve(mapping, context, nextResolve));
|
|
if (res !== null) {
|
|
return res;
|
|
}
|
|
}
|
|
} else {
|
|
const fixedResult =
|
|
(await catchError(() => nextResolve(`${specifier}.js`, context))) ||
|
|
(await catchError(() => nextResolve(`${specifier}/index.js`, context))) ||
|
|
// Legacy variants for the `zone.js` variant using still `ts_library`.
|
|
// TODO(rules_js migration): Remove this.
|
|
(await catchError(() => nextResolve(`${specifier}.mjs`, context))) ||
|
|
(await catchError(() => nextResolve(`${specifier}/index.mjs`, context)));
|
|
|
|
if (fixedResult !== null) {
|
|
return fixedResult;
|
|
}
|
|
}
|
|
|
|
return await nextResolve(specifier, context);
|
|
};
|
|
|
|
async function catchError(fn) {
|
|
try {
|
|
return await fn();
|
|
} catch {
|
|
return null;
|
|
}
|
|
}
|