Skip to content

Commit

Permalink
add option segmentsAreSorted
Browse files Browse the repository at this point in the history
  • Loading branch information
milahu committed Sep 28, 2020
1 parent 2819f98 commit 4c25d9c
Show file tree
Hide file tree
Showing 4 changed files with 105 additions and 30 deletions.
5 changes: 3 additions & 2 deletions src/build-source-map-tree.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,10 @@ function asArray<T>(value: T | T[]): T[] {
export default function buildSourceMapTree(
input: SourceMapInput | SourceMapInput[],
loader: SourceMapLoader,
relativeRoot?: string
relativeRoot?: string,
segmentsAreSorted?: boolean
): SourceMapTree {
const maps = asArray(input).map(decodeSourceMap);
const maps = asArray(input).map((map: SourceMapInput): DecodedSourceMap => decodeSourceMap(map, segmentsAreSorted)) as DecodedSourceMap[];
const map = maps.pop()!;

for (let i = 0; i < maps.length; i++) {
Expand Down
14 changes: 8 additions & 6 deletions src/decode-source-map.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,23 +24,25 @@ import { DecodedSourceMap, RawSourceMap, SourceMapInput, SourceMapSegment } from
* Valid input maps include a `DecodedSourceMap`, a `RawSourceMap`, or JSON
* representations of either type.
*/
export default function decodeSourceMap(map: SourceMapInput): DecodedSourceMap {
export default function decodeSourceMap(map: SourceMapInput, segmentsAreSorted?: boolean): DecodedSourceMap {
if (typeof map === 'string') {
map = JSON.parse(map) as DecodedSourceMap | RawSourceMap;
}

let { mappings } = map;
if (typeof mappings === 'string') {
mappings = decode(mappings);
} else {
} else if (!segmentsAreSorted) {
// Clone the Line so that we can sort it. We don't want to mutate an array
// that we don't own directly.
mappings = mappings.map(cloneSegmentLine);
}
// Sort each Line's segments. There's no guarantee that segments are sorted for us,
// and even Chrome's implementation sorts:
// https://cs.chromium.org/chromium/src/third_party/devtools-frontend/src/front_end/sdk/SourceMap.js?l=507-508&rcl=109232bcf479c8f4ef8ead3cf56c49eb25f8c2f0
mappings.forEach(sortSegments);
if (!segmentsAreSorted) {
// Sort each Line's segments. There's no guarantee that segments are sorted for us,
// and even Chrome's implementation sorts:
// https://cs.chromium.org/chromium/src/third_party/devtools-frontend/src/front_end/sdk/SourceMap.js?l=507-508&rcl=109232bcf479c8f4ef8ead3cf56c49eb25f8c2f0
mappings.forEach(sortSegments);
}

return defaults({ mappings }, map);
}
Expand Down
5 changes: 3 additions & 2 deletions src/remapping.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,10 @@ export default function remapping(
input: SourceMapInput | SourceMapInput[],
loader: SourceMapLoader,
excludeContent?: boolean,
decodeMappings?: boolean
decodeMappings?: boolean,
segmentsAreSorted?: boolean
): SourceMap | DecodedSourceMap {
const graph = buildSourceMapTree(input, loader);
const graph = buildSourceMapTree(input, loader, '', !!segmentsAreSorted);
return decodeMappings
? graph.traceMappings()
: new SourceMap(graph.traceMappings(), !!excludeContent);
Expand Down
111 changes: 91 additions & 20 deletions test/unit/remapping.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,47 +18,89 @@ import remapping from '../../src/remapping';
import { DecodedSourceMap, RawSourceMap } from '../../src/types';

describe('remapping', () => {

// transform chain:
// 1+1 \n 1+1 \n\n 1 + 1;
// line 0 column 0 < line 1 column 1 < line 2 column 2
// transpiled.min.js < transpiled.js < helloworld.js
// v v
// rawMap transpiledMap
// v
// translatedMap

// segment = output_column [, source, line, column [, name]]
// all decoded numbers are zero-based

const rawMap: RawSourceMap = {
file: 'transpiled.min.js',
// 0th column of 1st line of output file translates into the 1st source
// file, line 2, column 1, using 1st name.
mappings: 'AACCA',
// line 0, column 0 <- source 0, line 1, column 1, name 0
mappings: 'AACCA', // [[[ 0, 0, 1, 1, 0 ]]]
names: ['add'],
sources: ['transpiled.js'],
sourcesContent: ['1+1'],
sourcesContent: ['\n 1+1'],
version: 3,
};
const transpiledMap: RawSourceMap = {
// 1st column of 2nd line of output file translates into the 1st source
// file, line 3, column 2
mappings: ';CAEE',
// line 1, column 1 <- source 0, line 2, column 2
mappings: ';CAEE', // [ [], [[ 1, 0, 2, 2 ]] ]
names: [],
sources: ['helloworld.js'],
sourcesContent: ['\n\n 1 + 1;'],
version: 3,
};
const translatedMap: RawSourceMap = {
file: 'transpiled.min.js',
// 0th column of 1st line of output file translates into the 1st source
// file, line 3, column 2, using first name
mappings: 'AAEEA',
// line 0, column 0 <- source 0, line 2, column 2, name 0
mappings: 'AAEEA', // [[[ 0, 0, 2, 2, 0 ]]]
names: ['add'],
// TODO: support sourceRoot
// sourceRoot: '',
sources: ['helloworld.js'],
sourcesContent: ['\n\n 1 + 1;'],
version: 3,
};
const decodedMap: DecodedSourceMap = {
file: 'transpiled.min.js',
mappings: [[[0, 0, 2, 2, 0]]],
names: ['add'],
// TODO: support sourceRoot
// sourceRoot: '',
sources: ['helloworld.js'],
sourcesContent: ['\n\n 1 + 1;'],
version: 3,

const rawMapDecoded: DecodedSourceMap = {
...rawMap,
mappings: [[[ 0, 0, 1, 1, 0 ]]],
};
const transpiledMapDecoded: DecodedSourceMap = {
...transpiledMap,
mappings: [ [], [[ 1, 0, 2, 2 ]] ],
};
const translatedMapDecoded: DecodedSourceMap = {
...translatedMap,
mappings: [[[ 0, 0, 2, 2, 0 ]]],
};

// segments in reverse order to test `segmentsAreSorted` option
// sort order is preserved in result
// transform chain:
// line 0 column 0 < line 1 column 1 < line 2 column 2
// line 0 column 1 < line 1 column 2 < line 2 column 1
// transpiled.min.js < transpiled.js < helloworld.js
// v v
// rawMap transpiledMap
const rawMapDecodedReversed: DecodedSourceMap = {
...rawMap,
// line 0, column 1 <- source 0, line 1, column 2, name 0
// line 0, column 0 <- source 0, line 1, column 1
mappings: [[ [ 1, 0, 1, 2, 0 ], [ 0, 0, 1, 1 ] ]],
};
const transpiledMapDecodedReversed: DecodedSourceMap = {
...transpiledMap,
// line 1, column 2 <- source 0, line 2, column 1
// line 1, column 1 <- source 0, line 2, column 2
mappings: [ [], [ [ 2, 0, 2, 1 ], [ 1, 0, 2, 2 ] ] ],
};
const translatedMapDecodedReversed: DecodedSourceMap = {
...translatedMap,
// line 0, column 1 <- source 0, line 2, column 1, name 0
// line 0, column 0 <- source 0, line 2, column 2
mappings: [[ [ 1, 0, 2, 1, 0 ], [ 0, 0, 2, 2 ] ]],
};



test('does not alter a lone sourcemap', () => {
const map = remapping(rawMap, () => null);
Expand Down Expand Up @@ -178,6 +220,35 @@ describe('remapping', () => {
true
);

expect(map).toEqual(decodedMap);
expect(map).toEqual(translatedMapDecoded);
});

test('accepts decoded mappings as input', () => {
const map = remapping(
rawMapDecoded,
(name: string) => {
if (name === 'transpiled.js') {
return transpiledMapDecoded;
}
}
);

expect(map).toEqual(translatedMap);
});

test('skips sorting of segments if `segmentsAreSorted` is set', () => {
const map = remapping(
rawMapDecodedReversed,
(name: string) => {
if (name === 'transpiled.js') {
return transpiledMapDecodedReversed;
}
},
false,
true,
true
);

expect(map).toEqual(translatedMapDecodedReversed);
});
});

0 comments on commit 4c25d9c

Please sign in to comment.