fix(ngcc): handle mappings outside the content when flattening source-maps (#35718)
Previously when rendering flattened source-maps, it was assumed that no mapping would come from a line that is outside the lines of the actual source content. It turns out this is not a valid assumption. Now the code that renders flattened source-maps will handle such mappings, with the additional benefit that the rendered source-map will only contain mapping lines up to the last mapping, rather than a mapping line for every content line. Fixes #35709 PR Close #35718
This commit is contained in:
parent
72c4fda613
commit
73cf7d5cb4
|
@ -49,11 +49,9 @@ export class SourceFile {
|
||||||
const sources: SourceFile[] = [];
|
const sources: SourceFile[] = [];
|
||||||
const names: string[] = [];
|
const names: string[] = [];
|
||||||
|
|
||||||
// Ensure a mapping line array for each line in the generated source.
|
const mappings: SourceMapMappings = [];
|
||||||
const mappings: SourceMapMappings = this.lineLengths.map(() => []);
|
|
||||||
|
|
||||||
for (const mapping of this.flattenedMappings) {
|
for (const mapping of this.flattenedMappings) {
|
||||||
const mappingLine = mappings[mapping.generatedSegment.line];
|
|
||||||
const sourceIndex = findIndexOrAdd(sources, mapping.originalSource);
|
const sourceIndex = findIndexOrAdd(sources, mapping.originalSource);
|
||||||
const mappingArray: SourceMapSegment = [
|
const mappingArray: SourceMapSegment = [
|
||||||
mapping.generatedSegment.column,
|
mapping.generatedSegment.column,
|
||||||
|
@ -65,7 +63,14 @@ export class SourceFile {
|
||||||
const nameIndex = findIndexOrAdd(names, mapping.name);
|
const nameIndex = findIndexOrAdd(names, mapping.name);
|
||||||
mappingArray.push(nameIndex);
|
mappingArray.push(nameIndex);
|
||||||
}
|
}
|
||||||
mappingLine.push(mappingArray);
|
|
||||||
|
// Ensure a mapping line array for this mapping.
|
||||||
|
const line = mapping.generatedSegment.line;
|
||||||
|
while (line >= mappings.length) {
|
||||||
|
mappings.push([]);
|
||||||
|
}
|
||||||
|
// Add this mapping to the line
|
||||||
|
mappings[line].push(mappingArray);
|
||||||
}
|
}
|
||||||
|
|
||||||
const sourcePathDir = dirname(this.sourcePath);
|
const sourcePathDir = dirname(this.sourcePath);
|
||||||
|
|
|
@ -174,7 +174,6 @@ runInEachFileSystem(() => {
|
||||||
[5, 0, 1, 20], [7, 0, 1, 22], [12, 0, 1, 27], [14, 0, 1, 28], [15, 0, 1, 29],
|
[5, 0, 1, 20], [7, 0, 1, 22], [12, 0, 1, 27], [14, 0, 1, 28], [15, 0, 1, 29],
|
||||||
[9, 0, 2, 13], [10, 0, 2, 14]
|
[9, 0, 2, 13], [10, 0, 2, 14]
|
||||||
],
|
],
|
||||||
[],
|
|
||||||
];
|
];
|
||||||
|
|
||||||
JS_CONTENT_MAP = fromObject({
|
JS_CONTENT_MAP = fromObject({
|
||||||
|
@ -196,15 +195,12 @@ runInEachFileSystem(() => {
|
||||||
'file': 'file.js',
|
'file': 'file.js',
|
||||||
'sources': ['file.js'],
|
'sources': ['file.js'],
|
||||||
'names': [],
|
'names': [],
|
||||||
'mappings': encode([
|
'mappings': encode([[], [], [], [], [], [], [], [], [], [], [], [], [[0, 0, 0, 0]]]),
|
||||||
[], [], [], [], [], [], [], [], [], [], [], [], [[0, 0, 0, 0]],
|
|
||||||
[], [], [], [], [], [], [], [], []
|
|
||||||
]),
|
|
||||||
'sourcesContent': [JS_CONTENT.contents],
|
'sourcesContent': [JS_CONTENT.contents],
|
||||||
});
|
});
|
||||||
|
|
||||||
const MERGED_OUTPUT_PROGRAM_MAPPINGS: SourceMapMappings =
|
const MERGED_OUTPUT_PROGRAM_MAPPINGS: SourceMapMappings =
|
||||||
[[], [], [], [], [], [], [], [], [], [], [], [], ...JS_CONTENT_MAPPINGS, []];
|
[[], [], [], [], [], [], [], [], [], [], [], [], ...JS_CONTENT_MAPPINGS];
|
||||||
|
|
||||||
MERGED_OUTPUT_PROGRAM_MAP = fromObject({
|
MERGED_OUTPUT_PROGRAM_MAP = fromObject({
|
||||||
'version': 3,
|
'version': 3,
|
||||||
|
|
|
@ -229,6 +229,32 @@ runInEachFileSystem(() => {
|
||||||
[[1, 0, 0, 0], [2, 0, 0, 2], [3, 0, 0, 3], [3, 0, 0, 6], [4, 0, 0, 1], [5, 0, 0, 7]]
|
[[1, 0, 0, 0], [2, 0, 0, 2], [3, 0, 0, 3], [3, 0, 0, 6], [4, 0, 0, 1], [5, 0, 0, 7]]
|
||||||
]));
|
]));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should handle mappings that map from lines outside of the actual content lines', () => {
|
||||||
|
const bSource = new SourceFile(_('/foo/src/b.js'), 'abcdef', null, false, []);
|
||||||
|
const aToBSourceMap: RawSourceMap = {
|
||||||
|
mappings: encode([
|
||||||
|
[[0, 0, 0, 0], [2, 0, 0, 3], [4, 0, 0, 2], [5, 0, 0, 5]],
|
||||||
|
[
|
||||||
|
[0, 0, 0, 0], // Extra mapping from a non-existent line
|
||||||
|
]
|
||||||
|
]),
|
||||||
|
names: [],
|
||||||
|
sources: ['b.js'],
|
||||||
|
version: 3
|
||||||
|
};
|
||||||
|
const aSource =
|
||||||
|
new SourceFile(_('/foo/src/a.js'), 'abdecf', aToBSourceMap, false, [bSource]);
|
||||||
|
|
||||||
|
const aTocSourceMap = aSource.renderFlattenedSourceMap();
|
||||||
|
expect(aTocSourceMap.version).toEqual(3);
|
||||||
|
expect(aTocSourceMap.file).toEqual('a.js');
|
||||||
|
expect(aTocSourceMap.names).toEqual([]);
|
||||||
|
expect(aTocSourceMap.sourceRoot).toBeUndefined();
|
||||||
|
expect(aTocSourceMap.sources).toEqual(['b.js']);
|
||||||
|
expect(aTocSourceMap.sourcesContent).toEqual(['abcdef']);
|
||||||
|
expect(aTocSourceMap.mappings).toEqual(aToBSourceMap.mappings);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue