Skip to content

Commit

Permalink
Fix bug with SectionedSourceMaps
Browse files Browse the repository at this point in the history
We incorrectly counted the stopping index when a section runs over into the range defined by the next section.
  • Loading branch information
jridgewell committed Apr 20, 2022
1 parent bb535b5 commit 9f52472
Show file tree
Hide file tree
Showing 3 changed files with 142 additions and 115 deletions.
26 changes: 13 additions & 13 deletions src/any-map.ts
Expand Up @@ -33,7 +33,7 @@ export const AnyMap: AnyMap = function (map, mapUrl) {
addSection(sections[i], mapUrl, mappings, sources, sourcesContent, names, no.line, no.column);
}
if (sections.length > 0) {
addSection(sections[i], mapUrl, mappings, sources, sourcesContent, names, -1, -1);
addSection(sections[i], mapUrl, mappings, sources, sourcesContent, names, Infinity, Infinity);
}

const joined: DecodedSourceMap = {
Expand All @@ -58,25 +58,25 @@ function addSection(
stopLine: number,
stopColumn: number,
) {
const { offset, map } = section;
const { line: lineOffset, column: columnOffset } = offset;
const map = AnyMap(section.map, mapUrl);
const { line: lineOffset, column: columnOffset } = section.offset;

// If this section jumps forwards several lines, we need to add lines to the output mappings catch up.
for (let i = mappings.length; i <= lineOffset; i++) mappings.push([]);

const trace = AnyMap(map, mapUrl);
const sourcesOffset = sources.length;
const namesOffset = names.length;
const decoded = decodedMappings(trace);
const { resolvedSources } = trace;
const decoded = decodedMappings(map);
const { resolvedSources } = map;
append(sources, resolvedSources);
append(sourcesContent, trace.sourcesContent || fillSourcesContent(resolvedSources.length));
append(names, trace.names);
append(sourcesContent, map.sourcesContent || fillSourcesContent(resolvedSources.length));
append(names, map.names);

// If this section jumps forwards several lines, we need to add lines to the output mappings catch up.
for (let i = mappings.length; i <= lineOffset; i++) mappings.push([]);

// We can only add so many lines before we step into the range that the next section's map
// controls. When we get to the last line, then we'll start checking the segments to see if
// they've crossed into the column range.
const len = stopLine === -1 ? decoded.length : Math.min(decoded.length, stopLine + 1);
const stopI = stopLine - lineOffset;
const len = Math.min(decoded.length, stopI + 1);

for (let i = 0; i < len; i++) {
const line = decoded[i];
Expand All @@ -93,7 +93,7 @@ function addSection(

// If this segment steps into the column range that the next section's map controls, we need
// to stop early.
if (i === stopLine && column >= stopColumn) break;
if (i === stopI && column >= stopColumn) break;

if (seg.length === 1) {
out.push([column]);
Expand Down
129 changes: 129 additions & 0 deletions test/any-map.test.ts
@@ -0,0 +1,129 @@
/// <reference lib="esnext" />

import { test, describe } from './setup';
import { AnyMap, encodedMappings, decodedMappings } from '../src/trace-mapping';

import type { SectionedSourceMap } from '../src/trace-mapping';

describe('AnyMap', () => {
const map: SectionedSourceMap = {
version: 3,
file: 'sectioned.js',
sections: [
{
offset: { line: 1, column: 1 },
map: {
version: 3,
sections: [
{
offset: { line: 0, column: 1 },
map: {
version: 3,
names: ['first'],
sources: ['first.js'],
sourcesContent: ['firstsource'],
mappings: 'AAAAA,CAAC',
},
},
{
offset: { line: 0, column: 2 },
map: {
version: 3,
names: ['second'],
sources: ['second.js'],
sourcesContent: ['secondsource'],
mappings: 'AAAAA;AAAA',
},
},
],
},
},
{
offset: { line: 2, column: 0 },
map: {
version: 3,
sections: [
{
offset: { line: 0, column: 0 },
map: {
version: 3,
names: ['third'],
sources: ['third.js'],
sourcesContent: ['thirdsource'],
sourceRoot: 'nested',
mappings: 'AAAAA,CAAA;AAAA',
},
},
{
offset: { line: 0, column: 1 },
map: {
version: 3,
names: [],
sources: ['fourth.js'],
sourcesContent: ['fourthsource'],
mappings: 'AAAA',
},
},
],
},
},
],
};

describe('map properties', () => {
test('version', (t) => {
const tracer = new AnyMap(map);
t.is(tracer.version, map.version);
});

test('file', (t) => {
const tracer = new AnyMap(map);
t.is(tracer.file, map.file);
});

test('sourceRoot', (t) => {
const tracer = new AnyMap(map);
t.is(tracer.sourceRoot, undefined);
});

test('sources', (t) => {
const tracer = new AnyMap(map);
t.deepEqual(tracer.sources, ['first.js', 'second.js', 'nested/third.js', 'fourth.js']);
});

test('names', (t) => {
const tracer = new AnyMap(map);
t.deepEqual(tracer.names, ['first', 'second', 'third']);
});

test('encodedMappings', (t) => {
const tracer = new AnyMap(map);
t.is(encodedMappings(tracer), ';GCAAC;AAAA,ACAAC,CCAA');
});

test.only('decodedMappings', (t) => {
const tracer = new AnyMap(map);
t.deepEqual(decodedMappings(tracer), [
[],
[
[2, 0, 0, 0, 0],
[3, 1, 0, 0, 1],
],
[
[0, 2, 0, 0, 2],
[1, 3, 0, 0],
],
]);
});

test('sourcesContent', (t) => {
const tracer = new AnyMap(map);
t.deepEqual(tracer.sourcesContent, [
'firstsource',
'secondsource',
'thirdsource',
'fourthsource',
]);
});
});
});
102 changes: 0 additions & 102 deletions test/trace-mapping.test.ts
Expand Up @@ -5,7 +5,6 @@ import { encode, decode } from '@jridgewell/sourcemap-codec';
import { test, describe } from './setup';
import {
TraceMap,
AnyMap,
encodedMappings,
decodedMappings,
traceSegment,
Expand All @@ -23,7 +22,6 @@ import type {
EncodedSourceMap,
DecodedSourceMap,
EachMapping,
SectionedSourceMap,
} from '../src/trace-mapping';

describe('TraceMap', () => {
Expand Down Expand Up @@ -375,103 +373,3 @@ describe('TraceMap', () => {
});
});
});

describe('AnyMap', () => {
const map: SectionedSourceMap = {
version: 3,
file: 'sectioned.js',
sections: [
{
offset: { line: 1, column: 1 },
map: {
version: 3,
names: ['first'],
sources: ['first.js'],
sourcesContent: ['firstsource'],
mappings: 'AAAAA,CAAC',
},
},
{
offset: { line: 2, column: 0 },
map: {
version: 3,
sections: [
{
offset: { line: 0, column: 0 },
map: {
version: 3,
names: ['second'],
sources: ['second.js'],
sourcesContent: ['secondsource'],
sourceRoot: 'nested',
mappings: 'AAAAA,CAAA;AAAA',
},
},
{
offset: { line: 0, column: 1 },
map: {
version: 3,
names: [],
sources: ['third.js'],
sourcesContent: ['thirdsource'],
mappings: 'AAAA',
},
},
],
},
},
],
};

describe('map properties', () => {
test('version', (t) => {
const tracer = new AnyMap(map);
t.is(tracer.version, map.version);
});

test('file', (t) => {
const tracer = new AnyMap(map);
t.is(tracer.file, map.file);
});

test('sourceRoot', (t) => {
const tracer = new AnyMap(map);
t.is(tracer.sourceRoot, undefined);
});

test('sources', (t) => {
const tracer = new AnyMap(map);
t.deepEqual(tracer.sources, ['first.js', 'nested/second.js', 'third.js']);
});

test('names', (t) => {
const tracer = new AnyMap(map);
t.deepEqual(tracer.names, ['first', 'second']);
});

test('encodedMappings', (t) => {
const tracer = new AnyMap(map);
t.is(encodedMappings(tracer), ';CAAAA,CAAC;ACADC,CCAA');
});

test('decodedMappings', (t) => {
const tracer = new AnyMap(map);
t.deepEqual(decodedMappings(tracer), [
[],
[
[1, 0, 0, 0, 0],
[2, 0, 0, 1],
],
[
[0, 1, 0, 0, 1],
[1, 2, 0, 0],
],
]);
});

test('sourcesContent', (t) => {
const tracer = new AnyMap(map);
t.deepEqual(tracer.sourcesContent, ['firstsource', 'secondsource', 'thirdsource']);
});
});
});

0 comments on commit 9f52472

Please sign in to comment.