mirror of
https://github.com/angular/angular.git
synced 2026-09-14 13:54:52 +08:00
fix(compiler-cli): handle pseudo cycles in inline source-maps (#40435)
When a source-map has an inline source, any source-map linked from that source should only be loaded if itself is also inline; it should not attempt to load a source-map from the file-system. Otherwise we can find ourselves with inadvertent infinite cyclic dependencies. For example, if a transpiler takes a file (e.g. index.js) and generates a new file overwriting the original file - capturing the original source inline in the new source-map (index.js.map) - the source file loader might read the inline original file (also index.js) and then try to load the `index.js.map` file from disk - ad infinitum. Note that the first call to `loadSourceFile()` is special, since you can pass in the source-file and source-map contents directly as in-memory strrngs. This is common if the transpiler has just generated these and has not yet written them to disk. When the contents are passed into `loadSourceFile()` directly, they are not treated as "inline" for the purposes described above since there is no chance of these "in-memory" source and source-map contents being caught up in a cyclic dependency. Fixes #40408 PR Close #40435
This commit is contained in:
committed by
Jessica Janiuk
parent
d482f5cdd3
commit
dc06873c72
@@ -11,7 +11,7 @@ import * as ts from 'typescript';
|
||||
|
||||
import {absoluteFrom, absoluteFromSourceFile, ReadonlyFileSystem} from '../../../src/ngtsc/file_system';
|
||||
import {Logger} from '../../../src/ngtsc/logging';
|
||||
import {RawSourceMap, SourceFileLoader} from '../../../src/ngtsc/sourcemaps';
|
||||
import {ContentOrigin, RawSourceMap, SourceFileLoader} from '../../../src/ngtsc/sourcemaps';
|
||||
|
||||
import {FileToWrite} from './utils';
|
||||
|
||||
@@ -28,22 +28,22 @@ export interface SourceMapInfo {
|
||||
export function renderSourceAndMap(
|
||||
logger: Logger, fs: ReadonlyFileSystem, sourceFile: ts.SourceFile,
|
||||
generatedMagicString: MagicString): FileToWrite[] {
|
||||
const generatedPath = absoluteFromSourceFile(sourceFile);
|
||||
const generatedMapPath = absoluteFrom(`${generatedPath}.map`);
|
||||
const sourceFilePath = absoluteFromSourceFile(sourceFile);
|
||||
const sourceMapPath = absoluteFrom(`${sourceFilePath}.map`);
|
||||
const generatedContent = generatedMagicString.toString();
|
||||
const generatedMap: RawSourceMap = generatedMagicString.generateMap(
|
||||
{file: generatedPath, source: generatedPath, includeContent: true});
|
||||
{file: sourceFilePath, source: sourceFilePath, includeContent: true});
|
||||
|
||||
try {
|
||||
const loader = new SourceFileLoader(fs, logger, {});
|
||||
const generatedFile = loader.loadSourceFile(
|
||||
generatedPath, generatedContent, {map: generatedMap, mapPath: generatedMapPath});
|
||||
sourceFilePath, generatedContent, {map: generatedMap, mapPath: sourceMapPath});
|
||||
|
||||
const rawMergedMap: RawSourceMap = generatedFile.renderFlattenedSourceMap();
|
||||
const mergedMap = fromObject(rawMergedMap);
|
||||
const firstSource = generatedFile.sources[0];
|
||||
if (firstSource && (firstSource.rawMap !== null || !sourceFile.isDeclarationFile) &&
|
||||
firstSource.inline) {
|
||||
const originalFile = loader.loadSourceFile(sourceFilePath, generatedMagicString.original);
|
||||
if (originalFile.rawMap === null && !sourceFile.isDeclarationFile ||
|
||||
originalFile.rawMap?.origin === ContentOrigin.Inline) {
|
||||
// We render an inline source map if one of:
|
||||
// * there was no input source map and this is not a typings file;
|
||||
// * the input source map exists and was inline.
|
||||
@@ -52,21 +52,21 @@ export function renderSourceAndMap(
|
||||
// the input file because these inline source maps can be very large and it impacts on the
|
||||
// performance of IDEs that need to read them to provide intellisense etc.
|
||||
return [
|
||||
{path: generatedPath, contents: `${generatedFile.contents}\n${mergedMap.toComment()}`}
|
||||
];
|
||||
} else {
|
||||
const sourceMapComment = generateMapFileComment(`${fs.basename(generatedPath)}.map`);
|
||||
return [
|
||||
{path: generatedPath, contents: `${generatedFile.contents}\n${sourceMapComment}`},
|
||||
{path: generatedMapPath, contents: mergedMap.toJSON()}
|
||||
{path: sourceFilePath, contents: `${generatedFile.contents}\n${mergedMap.toComment()}`}
|
||||
];
|
||||
}
|
||||
} catch (e) {
|
||||
logger.error(`Error when flattening the source-map "${generatedMapPath}" for "${
|
||||
generatedPath}": ${e.toString()}`);
|
||||
|
||||
const sourceMapComment = generateMapFileComment(`${fs.basename(sourceFilePath)}.map`);
|
||||
return [
|
||||
{path: generatedPath, contents: generatedContent},
|
||||
{path: generatedMapPath, contents: fromObject(generatedMap).toJSON()},
|
||||
{path: sourceFilePath, contents: `${generatedFile.contents}\n${sourceMapComment}`},
|
||||
{path: sourceMapPath, contents: mergedMap.toJSON()}
|
||||
];
|
||||
} catch (e) {
|
||||
logger.error(`Error when flattening the source-map "${sourceMapPath}" for "${
|
||||
sourceFilePath}": ${e.toString()}`);
|
||||
return [
|
||||
{path: sourceFilePath, contents: generatedContent},
|
||||
{path: sourceMapPath, contents: fromObject(generatedMap).toJSON()},
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user