diff --git a/src/source-map-tree.ts b/src/source-map-tree.ts index ae0687f..38bd3d5 100644 --- a/src/source-map-tree.ts +++ b/src/source-map-tree.ts @@ -75,9 +75,7 @@ export default class SourceMapTree { let lastSegmentsLine = -1; for (let i = 0; i < rootMappings.length; i++) { const segments = rootMappings[i]; - const traced = - traceUneditedLine(segments, rootSources, intoSegments) || - traceLine(segments, rootSources, rootNames, intoSegments); + const traced = traceLine(segments, rootSources, rootNames, intoSegments); if (traced.length > 0) lastSegmentsLine = i; mappings.push(traced); } @@ -105,10 +103,9 @@ export default class SourceMapTree { ): SourceMapSegment[] { if (line >= this.lines) return []; - const { sources } = this; const { mappings, names } = this.map; const segments = mappings[line]; - return traceUneditedLine(segments, sources, into) || traceLine(segments, sources, names, into); + return traceLine(segments, this.sources, names, into); } /** @@ -174,9 +171,21 @@ export default class SourceMapTree { } } -// An unedited line either contains no segments, or it contains only a line marker segment. -// Line markers are the default "lowres" segment generated by magic-string, and match [0, SOURCE, LINE, 0]. -// For these markers, we trace directly from the referenced source instead of from this map. +function traceLine( + segments: SourceMapSegment[], + sources: Source[], + names: string[], + into: (s: SourceMapSegmentObject) => SourceMapSegment +): SourceMapSegment[] { + return ( + traceUneditedLine(segments, sources, into) || traceEditedLine(segments, sources, names, into) + ); +} + +// An unedited line either contains only a line marker segment. Line markers are +// the default "lowres" segment generated by magic-string, and match [0, SOURCE, +// LINE, 0]. For these markers, we inherit the mappings from the referenced +// source directly, instead of trying to match the segments. function traceUneditedLine( segments: SourceMapSegment[], sources: Source[], @@ -194,7 +203,7 @@ function traceUneditedLine( return sources[segment[1]].traceLine(segment[2], into); } -function traceLine( +function traceEditedLine( segments: SourceMapSegment[], sources: Source[], names: string[], diff --git a/test/unit/source-map-tree.ts b/test/unit/source-map-tree.ts index c72d5ec..3b89b6b 100644 --- a/test/unit/source-map-tree.ts +++ b/test/unit/source-map-tree.ts @@ -16,7 +16,7 @@ import OriginalSource from '../../src/original-source'; import SourceMapTree from '../../src/source-map-tree'; -import type { DecodedSourceMap } from '../../src/types'; +import type { SourceMapSegment, SourceMapSegmentObject, DecodedSourceMap } from '../../src/types'; describe('SourceMapTree', () => { describe('traceMappings()', () => { @@ -215,6 +215,100 @@ describe('SourceMapTree', () => { }); }); }); + + describe('unedited line', () => { + it('inherits mappings from child map', () => { + const map: DecodedSourceMap = { + ...baseMap, + mappings: [[[0, 0, 0, 0]]], + }; + + const source = new SourceMapTree(map, [child]); + const traced = source.traceMappings(); + + expect(traced).toMatchObject({ + mappings: [ + [ + [0, 0, 0, 0], + [4, 0, 1, 1], + ], + ], + }); + }); + + it('inherits mappings from any child map', () => { + const map: DecodedSourceMap = { + ...baseMap, + mappings: [[[0, 1, 0, 0]]], + }; + + const source = new SourceMapTree(map, [new OriginalSource('foo.js', ''), child]); + const traced = source.traceMappings(); + + expect(traced).toMatchObject({ + sources: [`${sourceRoot}/original.js`], + mappings: [ + [ + [0, 0, 0, 0], + [4, 0, 1, 1], + ], + ], + }); + }); + }); + }); + + describe('traceLine()', () => { + const map: DecodedSourceMap = { + mappings: [ + [[0, 0, 0, 0]], + [ + [0, 0, 0, 0], + [1, 0, 1, 2], + ], + ], + names: [], + sources: ['middle.js'], + version: 3, + }; + const middle: DecodedSourceMap = { + mappings: [ + [ + [0, 0, 0, 0], + [1, 0, 0, 0], + [2, 0, 0, 0], + [4, 0, 1, 1], + ], // line 0 + [[2, 0, 1, 1]], // line 1 - maps to line 0 col 0 + ], + names: ['name'], + sources: ['child.js'], + version: 3, + }; + const source = new SourceMapTree(map, [ + new SourceMapTree(middle, [new OriginalSource('child.js', '')]), + ]); + function into(s: SourceMapSegmentObject): SourceMapSegment { + return [s.outputColumn, 0, s.line, s.column]; + } + + it('inherits segments from unedited line', () => { + const traced = source.traceLine(0, into); + + expect(traced).toEqual([ + [0, 0, 0, 0], + [4, 0, 1, 1], + ]); + }); + + it('traces segments from an edited line', () => { + const traced = source.traceLine(1, into); + + expect(traced).toEqual([ + [0, 0, 0, 0], + [1, 0, 1, 1], + ]); + }); }); describe('traceSegment()', () => {