mirror of
https://github.com/angular/angular
synced 2026-05-24 09:28:37 +00:00
As outlined in the previous commit which enabled the `esModuleInterop` TypeScript compiler option, we need to update all namespace imports for `typescript` to default imports. This is needed to allow for TypeScript to be imported at runtime from an ES module. Similar changes are needed for modules like `semver` where the types incorrectly suggest named exports that will not exist at runtime when imported from ESM. This commit refactors all imports to match with the lint rule we have configured in the previous commit. See the previous commit for more details on why certain imports have been changed. A special case are the imports to `@babel/core` and `@babel/types`. For these a special interop is needed as both default imports, or named imports break the other module format. e.g default imports would work well for ESM, but it breaks for CJS. For CJS, the named imports would only work, but in ESM, only the default export exist. We work around this for now until the devmode is using ESM as well (which would be consistent with prodmode and gives us more valuable test results). More details on the interop can be found in the `babel_core.ts` files (two interops are needed for both localize/or the compiler-cli). PR Close #43431
114 lines
4.6 KiB
TypeScript
114 lines
4.6 KiB
TypeScript
/**
|
|
* @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
|
|
*/
|
|
import {needsLinking} from '../../../linker';
|
|
import {createEs2015LinkerPlugin} from '../../../linker/babel';
|
|
import {PluginObj, transformSync} from '../../../linker/babel/src/babel_core';
|
|
import {AbsoluteFsPath, FileSystem} from '../../../src/ngtsc/file_system';
|
|
import {ConsoleLogger, LogLevel} from '../../../src/ngtsc/logging';
|
|
import {MapAndPath, RawSourceMap, SourceFileLoader} from '../../../src/ngtsc/sourcemaps';
|
|
import {CompileResult, getBuildOutputDirectory} from '../test_helpers/compile_test';
|
|
import {ComplianceTest} from '../test_helpers/get_compliance_tests';
|
|
import {parseGoldenPartial} from '../test_helpers/golden_partials';
|
|
import {runTests} from '../test_helpers/test_runner';
|
|
|
|
runTests('linked compile', linkPartials);
|
|
|
|
/**
|
|
* Link all the partials specified in the given `test`.
|
|
*
|
|
* @param fileSystem The mock file-system to use for linking the partials.
|
|
* @param test The compliance test whose partials will be linked.
|
|
*/
|
|
function linkPartials(fileSystem: FileSystem, test: ComplianceTest): CompileResult {
|
|
const logger = new ConsoleLogger(LogLevel.debug);
|
|
const loader = new SourceFileLoader(fileSystem, logger, {});
|
|
const builtDirectory = getBuildOutputDirectory(fileSystem);
|
|
const linkerPlugin = createEs2015LinkerPlugin({
|
|
fileSystem,
|
|
logger,
|
|
sourceMapping: test.compilerOptions?.sourceMap === true,
|
|
...test.angularCompilerOptions
|
|
});
|
|
const goldenPartialPath = fileSystem.resolve('/GOLDEN_PARTIAL.js');
|
|
if (!fileSystem.exists(goldenPartialPath)) {
|
|
throw new Error(
|
|
'Golden partial does not exist for this test\n' +
|
|
'Try generating it by running:\n' +
|
|
`bazel run //packages/compiler-cli/test/compliance/test_cases:${
|
|
test.relativePath}.golden.update`);
|
|
}
|
|
const partialFile = fileSystem.readFile(goldenPartialPath);
|
|
const partialFiles = parseGoldenPartial(partialFile);
|
|
|
|
partialFiles.forEach(
|
|
f => safeWrite(fileSystem, fileSystem.resolve(builtDirectory, f.path), f.content));
|
|
|
|
for (const expectation of test.expectations) {
|
|
for (const {generated} of expectation.files) {
|
|
const fileName = fileSystem.resolve(builtDirectory, generated);
|
|
if (!fileSystem.exists(fileName)) {
|
|
continue;
|
|
}
|
|
const source = fileSystem.readFile(fileName);
|
|
const sourceMapPath = fileSystem.resolve(fileName + '.map');
|
|
const sourceMap = fileSystem.exists(sourceMapPath) ?
|
|
JSON.parse(fileSystem.readFile(sourceMapPath)) as RawSourceMap :
|
|
undefined;
|
|
const {linkedSource, linkedSourceMap} =
|
|
applyLinker(builtDirectory, fileName, source, sourceMap, linkerPlugin);
|
|
|
|
if (linkedSourceMap !== undefined) {
|
|
const mapAndPath: MapAndPath = {map: linkedSourceMap, mapPath: sourceMapPath};
|
|
const sourceFile = loader.loadSourceFile(fileName, linkedSource, mapAndPath);
|
|
safeWrite(fileSystem, sourceMapPath, JSON.stringify(sourceFile.renderFlattenedSourceMap()));
|
|
}
|
|
safeWrite(fileSystem, fileName, linkedSource);
|
|
}
|
|
}
|
|
return {emittedFiles: [], errors: []};
|
|
}
|
|
|
|
/**
|
|
* Run the file through the Babel linker plugin.
|
|
*
|
|
* It will ignore files that do not have a `.js` extension.
|
|
*
|
|
* @param file The absolute file path and its source to be transformed using the linker.
|
|
* @param linkerPlugin The linker plugin to apply.
|
|
* @returns The file's source content, which has been transformed using the linker if necessary.
|
|
*/
|
|
function applyLinker(
|
|
cwd: string, filename: string, source: string, sourceMap: RawSourceMap|undefined,
|
|
linkerPlugin: PluginObj): {linkedSource: string, linkedSourceMap: RawSourceMap|undefined} {
|
|
if (!filename.endsWith('.js') || !needsLinking(filename, source)) {
|
|
return {linkedSource: source, linkedSourceMap: sourceMap};
|
|
}
|
|
const result = transformSync(source, {
|
|
cwd,
|
|
filename,
|
|
sourceMaps: !!sourceMap,
|
|
plugins: [linkerPlugin],
|
|
parserOpts: {sourceType: 'unambiguous'},
|
|
});
|
|
if (result === null) {
|
|
throw fail('Babel transform did not have output');
|
|
}
|
|
if (result.code == null) {
|
|
throw fail('Babel transform result does not have any code');
|
|
}
|
|
return {linkedSource: result.code, linkedSourceMap: result.map || undefined};
|
|
}
|
|
|
|
/**
|
|
* Write the `content` to the `path` on the `fs` file-system, first ensuring that the containing
|
|
* directory exists.
|
|
*/
|
|
function safeWrite(fs: FileSystem, path: AbsoluteFsPath, content: string): void {
|
|
fs.ensureDir(fs.dirname(path));
|
|
fs.writeFile(path, content);
|
|
}
|