From 73cf7d5cb4a6068dc2fe27d923f69565b9302a23 Mon Sep 17 00:00:00 2001 From: Pete Bacon Darwin Date: Thu, 27 Feb 2020 19:50:14 +0000 Subject: [PATCH] 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 --- .../ngcc/src/sourcemaps/source_file.ts | 13 +++++++--- .../ngcc/test/rendering/renderer_spec.ts | 8 ++---- .../ngcc/test/sourcemaps/source_file_spec.ts | 26 +++++++++++++++++++ 3 files changed, 37 insertions(+), 10 deletions(-) diff --git a/packages/compiler-cli/ngcc/src/sourcemaps/source_file.ts b/packages/compiler-cli/ngcc/src/sourcemaps/source_file.ts index 09f1feae7c..e18d94ff80 100644 --- a/packages/compiler-cli/ngcc/src/sourcemaps/source_file.ts +++ b/packages/compiler-cli/ngcc/src/sourcemaps/source_file.ts @@ -49,11 +49,9 @@ export class SourceFile { const sources: SourceFile[] = []; const names: string[] = []; - // Ensure a mapping line array for each line in the generated source. - const mappings: SourceMapMappings = this.lineLengths.map(() => []); + const mappings: SourceMapMappings = []; for (const mapping of this.flattenedMappings) { - const mappingLine = mappings[mapping.generatedSegment.line]; const sourceIndex = findIndexOrAdd(sources, mapping.originalSource); const mappingArray: SourceMapSegment = [ mapping.generatedSegment.column, @@ -65,7 +63,14 @@ export class SourceFile { const nameIndex = findIndexOrAdd(names, mapping.name); 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); diff --git a/packages/compiler-cli/ngcc/test/rendering/renderer_spec.ts b/packages/compiler-cli/ngcc/test/rendering/renderer_spec.ts index c8d9dd523c..dc3d144d18 100644 --- a/packages/compiler-cli/ngcc/test/rendering/renderer_spec.ts +++ b/packages/compiler-cli/ngcc/test/rendering/renderer_spec.ts @@ -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], [9, 0, 2, 13], [10, 0, 2, 14] ], - [], ]; JS_CONTENT_MAP = fromObject({ @@ -196,15 +195,12 @@ runInEachFileSystem(() => { 'file': 'file.js', 'sources': ['file.js'], 'names': [], - 'mappings': encode([ - [], [], [], [], [], [], [], [], [], [], [], [], [[0, 0, 0, 0]], - [], [], [], [], [], [], [], [], [] - ]), + 'mappings': encode([[], [], [], [], [], [], [], [], [], [], [], [], [[0, 0, 0, 0]]]), 'sourcesContent': [JS_CONTENT.contents], }); const MERGED_OUTPUT_PROGRAM_MAPPINGS: SourceMapMappings = - [[], [], [], [], [], [], [], [], [], [], [], [], ...JS_CONTENT_MAPPINGS, []]; + [[], [], [], [], [], [], [], [], [], [], [], [], ...JS_CONTENT_MAPPINGS]; MERGED_OUTPUT_PROGRAM_MAP = fromObject({ 'version': 3, diff --git a/packages/compiler-cli/ngcc/test/sourcemaps/source_file_spec.ts b/packages/compiler-cli/ngcc/test/sourcemaps/source_file_spec.ts index 3a3df16d7b..4cc7dcb277 100644 --- a/packages/compiler-cli/ngcc/test/sourcemaps/source_file_spec.ts +++ b/packages/compiler-cli/ngcc/test/sourcemaps/source_file_spec.ts @@ -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]] ])); }); + + 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); + }); }); });