refactor(ngcc): move sourcemaps
into ngtsc
(#37114)
The `SourceFile` and associated code is general and reusable in other projects (such as `@angular/localize`). Moving it to `ngtsc` makes it more easily shared. PR Close #37114
This commit is contained in:

committed by
Misko Hevery

parent
6de5a12a9d
commit
2b53b07c70
@ -1,109 +0,0 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google LLC All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
import {compareSegments, offsetSegment} from '../../src/sourcemaps/segment_marker';
|
||||
import {computeStartOfLinePositions} from '../../src/sourcemaps/source_file';
|
||||
|
||||
describe('SegmentMarker utils', () => {
|
||||
describe('compareSegments()', () => {
|
||||
it('should return 0 if the segments are the same', () => {
|
||||
expect(compareSegments(
|
||||
{line: 0, column: 0, position: 0, next: undefined},
|
||||
{line: 0, column: 0, position: 0, next: undefined}))
|
||||
.toEqual(0);
|
||||
expect(compareSegments(
|
||||
{line: 123, column: 0, position: 200, next: undefined},
|
||||
{line: 123, column: 0, position: 200, next: undefined}))
|
||||
.toEqual(0);
|
||||
expect(compareSegments(
|
||||
{line: 0, column: 45, position: 45, next: undefined},
|
||||
{line: 0, column: 45, position: 45, next: undefined}))
|
||||
.toEqual(0);
|
||||
expect(compareSegments(
|
||||
{line: 123, column: 45, position: 245, next: undefined},
|
||||
{line: 123, column: 45, position: 245, next: undefined}))
|
||||
.toEqual(0);
|
||||
});
|
||||
|
||||
it('should return a negative number if the first segment is before the second segment', () => {
|
||||
expect(compareSegments(
|
||||
{line: 0, column: 0, position: 0, next: undefined},
|
||||
{line: 0, column: 45, position: 45, next: undefined}))
|
||||
.toBeLessThan(0);
|
||||
expect(compareSegments(
|
||||
{line: 123, column: 0, position: 200, next: undefined},
|
||||
{line: 123, column: 45, position: 245, next: undefined}))
|
||||
.toBeLessThan(0);
|
||||
expect(compareSegments(
|
||||
{line: 13, column: 45, position: 75, next: undefined},
|
||||
{line: 123, column: 45, position: 245, next: undefined}))
|
||||
.toBeLessThan(0);
|
||||
expect(compareSegments(
|
||||
{line: 13, column: 45, position: 75, next: undefined},
|
||||
{line: 123, column: 9, position: 209, next: undefined}))
|
||||
.toBeLessThan(0);
|
||||
});
|
||||
|
||||
it('should return a positive number if the first segment is after the second segment', () => {
|
||||
expect(compareSegments(
|
||||
{line: 0, column: 45, position: 45, next: undefined},
|
||||
{line: 0, column: 0, position: 0, next: undefined}))
|
||||
.toBeGreaterThan(0);
|
||||
expect(compareSegments(
|
||||
{line: 123, column: 45, position: 245, next: undefined},
|
||||
{line: 123, column: 0, position: 200, next: undefined}))
|
||||
.toBeGreaterThan(0);
|
||||
expect(compareSegments(
|
||||
{line: 123, column: 45, position: 245, next: undefined},
|
||||
{line: 13, column: 45, position: 75, next: undefined}))
|
||||
.toBeGreaterThan(0);
|
||||
expect(compareSegments(
|
||||
{line: 123, column: 9, position: 209, next: undefined},
|
||||
{line: 13, column: 45, position: 75, next: undefined}))
|
||||
.toBeGreaterThan(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe('offsetSegment()', () => {
|
||||
it('should return an identical marker if offset is 0', () => {
|
||||
const startOfLinePositions =
|
||||
computeStartOfLinePositions('012345\n0123456789\r\n012*4567\n0123456');
|
||||
const marker = {line: 2, column: 3, position: 20, next: undefined};
|
||||
expect(offsetSegment(startOfLinePositions, marker, 0)).toBe(marker);
|
||||
});
|
||||
|
||||
it('should return a new marker offset by the given chars', () => {
|
||||
const startOfLinePositions =
|
||||
computeStartOfLinePositions('012345\n0123456789\r\n012*4567\n0123456');
|
||||
const marker = {line: 2, column: 3, position: 21, next: undefined};
|
||||
expect(offsetSegment(startOfLinePositions, marker, 1))
|
||||
.toEqual({line: 2, column: 4, position: 22, next: undefined});
|
||||
expect(offsetSegment(startOfLinePositions, marker, 2))
|
||||
.toEqual({line: 2, column: 5, position: 23, next: undefined});
|
||||
expect(offsetSegment(startOfLinePositions, marker, 4))
|
||||
.toEqual({line: 2, column: 7, position: 25, next: undefined});
|
||||
expect(offsetSegment(startOfLinePositions, marker, 6))
|
||||
.toEqual({line: 3, column: 0, position: 27, next: undefined});
|
||||
expect(offsetSegment(startOfLinePositions, marker, 8))
|
||||
.toEqual({line: 3, column: 2, position: 29, next: undefined});
|
||||
expect(offsetSegment(startOfLinePositions, marker, 20))
|
||||
.toEqual({line: 3, column: 14, position: 41, next: undefined});
|
||||
expect(offsetSegment(startOfLinePositions, marker, -1))
|
||||
.toEqual({line: 2, column: 2, position: 20, next: undefined});
|
||||
expect(offsetSegment(startOfLinePositions, marker, -2))
|
||||
.toEqual({line: 2, column: 1, position: 19, next: undefined});
|
||||
expect(offsetSegment(startOfLinePositions, marker, -3))
|
||||
.toEqual({line: 2, column: 0, position: 18, next: undefined});
|
||||
expect(offsetSegment(startOfLinePositions, marker, -4))
|
||||
.toEqual({line: 1, column: 10, position: 17, next: undefined});
|
||||
expect(offsetSegment(startOfLinePositions, marker, -6))
|
||||
.toEqual({line: 1, column: 8, position: 15, next: undefined});
|
||||
expect(offsetSegment(startOfLinePositions, marker, -16))
|
||||
.toEqual({line: 0, column: 5, position: 5, next: undefined});
|
||||
});
|
||||
});
|
||||
});
|
@ -1,296 +0,0 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google LLC All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
import {absoluteFrom, FileSystem, getFileSystem} from '@angular/compiler-cli/src/ngtsc/file_system';
|
||||
import {fromObject} from 'convert-source-map';
|
||||
|
||||
import {runInEachFileSystem} from '../../../src/ngtsc/file_system/testing';
|
||||
import {MockLogger} from '../../../src/ngtsc/logging/testing';
|
||||
import {RawSourceMap} from '../../src/sourcemaps/raw_source_map';
|
||||
import {SourceFileLoader as SourceFileLoader} from '../../src/sourcemaps/source_file_loader';
|
||||
|
||||
runInEachFileSystem(() => {
|
||||
describe('SourceFileLoader', () => {
|
||||
let fs: FileSystem;
|
||||
let logger: MockLogger;
|
||||
let _: typeof absoluteFrom;
|
||||
let registry: SourceFileLoader;
|
||||
beforeEach(() => {
|
||||
fs = getFileSystem();
|
||||
logger = new MockLogger();
|
||||
_ = absoluteFrom;
|
||||
registry = new SourceFileLoader(fs, logger);
|
||||
});
|
||||
|
||||
describe('loadSourceFile', () => {
|
||||
it('should load a file with no source map and inline contents', () => {
|
||||
const sourceFile = registry.loadSourceFile(_('/foo/src/index.js'), 'some inline content');
|
||||
if (sourceFile === null) {
|
||||
return fail('Expected source file to be defined');
|
||||
}
|
||||
expect(sourceFile.contents).toEqual('some inline content');
|
||||
expect(sourceFile.sourcePath).toEqual(_('/foo/src/index.js'));
|
||||
expect(sourceFile.rawMap).toEqual(null);
|
||||
expect(sourceFile.sources).toEqual([]);
|
||||
});
|
||||
|
||||
it('should load a file with no source map and read its contents from disk', () => {
|
||||
fs.ensureDir(_('/foo/src'));
|
||||
fs.writeFile(_('/foo/src/index.js'), 'some external content');
|
||||
const sourceFile = registry.loadSourceFile(_('/foo/src/index.js'));
|
||||
if (sourceFile === null) {
|
||||
return fail('Expected source file to be defined');
|
||||
}
|
||||
expect(sourceFile.contents).toEqual('some external content');
|
||||
expect(sourceFile.sourcePath).toEqual(_('/foo/src/index.js'));
|
||||
expect(sourceFile.rawMap).toEqual(null);
|
||||
expect(sourceFile.sources).toEqual([]);
|
||||
});
|
||||
|
||||
it('should load a file with an external source map', () => {
|
||||
fs.ensureDir(_('/foo/src'));
|
||||
const sourceMap = createRawSourceMap({file: 'index.js'});
|
||||
fs.writeFile(_('/foo/src/external.js.map'), JSON.stringify(sourceMap));
|
||||
const sourceFile = registry.loadSourceFile(
|
||||
_('/foo/src/index.js'), 'some inline content\n//# sourceMappingURL=external.js.map');
|
||||
if (sourceFile === null) {
|
||||
return fail('Expected source file to be defined');
|
||||
}
|
||||
expect(sourceFile.rawMap).toEqual(sourceMap);
|
||||
});
|
||||
|
||||
it('should handle a missing external source map', () => {
|
||||
fs.ensureDir(_('/foo/src'));
|
||||
const sourceFile = registry.loadSourceFile(
|
||||
_('/foo/src/index.js'), 'some inline content\n//# sourceMappingURL=external.js.map');
|
||||
if (sourceFile === null) {
|
||||
return fail('Expected source file to be defined');
|
||||
}
|
||||
expect(sourceFile.rawMap).toBe(null);
|
||||
});
|
||||
|
||||
it('should load a file with an inline encoded source map', () => {
|
||||
const sourceMap = createRawSourceMap({file: 'index.js'});
|
||||
const encodedSourceMap = Buffer.from(JSON.stringify(sourceMap)).toString('base64');
|
||||
const sourceFile = registry.loadSourceFile(
|
||||
_('/foo/src/index.js'),
|
||||
`some inline content\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,${
|
||||
encodedSourceMap}`);
|
||||
if (sourceFile === null) {
|
||||
return fail('Expected source file to be defined');
|
||||
}
|
||||
expect(sourceFile.rawMap).toEqual(sourceMap);
|
||||
});
|
||||
|
||||
it('should load a file with an implied source map', () => {
|
||||
const sourceMap = createRawSourceMap({file: 'index.js'});
|
||||
fs.ensureDir(_('/foo/src'));
|
||||
fs.writeFile(_('/foo/src/index.js.map'), JSON.stringify(sourceMap));
|
||||
const sourceFile = registry.loadSourceFile(_('/foo/src/index.js'), 'some inline content');
|
||||
if (sourceFile === null) {
|
||||
return fail('Expected source file to be defined');
|
||||
}
|
||||
expect(sourceFile.rawMap).toEqual(sourceMap);
|
||||
});
|
||||
|
||||
it('should handle missing implied source-map file', () => {
|
||||
fs.ensureDir(_('/foo/src'));
|
||||
const sourceFile = registry.loadSourceFile(_('/foo/src/index.js'), 'some inline content');
|
||||
if (sourceFile === null) {
|
||||
return fail('Expected source file to be defined');
|
||||
}
|
||||
expect(sourceFile.rawMap).toBe(null);
|
||||
});
|
||||
|
||||
it('should recurse into external original source files that are referenced from source maps',
|
||||
() => {
|
||||
// Setup a scenario where the generated files reference previous files:
|
||||
//
|
||||
// index.js
|
||||
// -> x.js
|
||||
// -> y.js
|
||||
// -> a.js
|
||||
// -> z.js (inline content)
|
||||
fs.ensureDir(_('/foo/src'));
|
||||
|
||||
const indexSourceMap = createRawSourceMap({
|
||||
file: 'index.js',
|
||||
sources: ['x.js', 'y.js', 'z.js'],
|
||||
'sourcesContent': [null, null, 'z content']
|
||||
});
|
||||
fs.writeFile(_('/foo/src/index.js.map'), JSON.stringify(indexSourceMap));
|
||||
|
||||
fs.writeFile(_('/foo/src/x.js'), 'x content');
|
||||
|
||||
const ySourceMap = createRawSourceMap({file: 'y.js', sources: ['a.js']});
|
||||
fs.writeFile(_('/foo/src/y.js'), 'y content');
|
||||
fs.writeFile(_('/foo/src/y.js.map'), JSON.stringify(ySourceMap));
|
||||
fs.writeFile(_('/foo/src/z.js'), 'z content');
|
||||
fs.writeFile(_('/foo/src/a.js'), 'a content');
|
||||
|
||||
const sourceFile = registry.loadSourceFile(_('/foo/src/index.js'), 'index content');
|
||||
if (sourceFile === null) {
|
||||
return fail('Expected source file to be defined');
|
||||
}
|
||||
|
||||
expect(sourceFile.contents).toEqual('index content');
|
||||
expect(sourceFile.sourcePath).toEqual(_('/foo/src/index.js'));
|
||||
expect(sourceFile.rawMap).toEqual(indexSourceMap);
|
||||
|
||||
expect(sourceFile.sources.length).toEqual(3);
|
||||
|
||||
expect(sourceFile.sources[0]!.contents).toEqual('x content');
|
||||
expect(sourceFile.sources[0]!.sourcePath).toEqual(_('/foo/src/x.js'));
|
||||
expect(sourceFile.sources[0]!.rawMap).toEqual(null);
|
||||
expect(sourceFile.sources[0]!.sources).toEqual([]);
|
||||
|
||||
|
||||
expect(sourceFile.sources[1]!.contents).toEqual('y content');
|
||||
expect(sourceFile.sources[1]!.sourcePath).toEqual(_('/foo/src/y.js'));
|
||||
expect(sourceFile.sources[1]!.rawMap).toEqual(ySourceMap);
|
||||
|
||||
expect(sourceFile.sources[1]!.sources.length).toEqual(1);
|
||||
expect(sourceFile.sources[1]!.sources[0]!.contents).toEqual('a content');
|
||||
expect(sourceFile.sources[1]!.sources[0]!.sourcePath).toEqual(_('/foo/src/a.js'));
|
||||
expect(sourceFile.sources[1]!.sources[0]!.rawMap).toEqual(null);
|
||||
expect(sourceFile.sources[1]!.sources[0]!.sources).toEqual([]);
|
||||
|
||||
expect(sourceFile.sources[2]!.contents).toEqual('z content');
|
||||
expect(sourceFile.sources[2]!.sourcePath).toEqual(_('/foo/src/z.js'));
|
||||
expect(sourceFile.sources[2]!.rawMap).toEqual(null);
|
||||
expect(sourceFile.sources[2]!.sources).toEqual([]);
|
||||
});
|
||||
|
||||
it('should handle a missing source file referenced from a source-map', () => {
|
||||
fs.ensureDir(_('/foo/src'));
|
||||
|
||||
const indexSourceMap =
|
||||
createRawSourceMap({file: 'index.js', sources: ['x.js'], 'sourcesContent': [null]});
|
||||
fs.writeFile(_('/foo/src/index.js.map'), JSON.stringify(indexSourceMap));
|
||||
|
||||
const sourceFile = registry.loadSourceFile(_('/foo/src/index.js'), 'index content');
|
||||
if (sourceFile === null) {
|
||||
return fail('Expected source file to be defined');
|
||||
}
|
||||
|
||||
expect(sourceFile.contents).toEqual('index content');
|
||||
expect(sourceFile.sourcePath).toEqual(_('/foo/src/index.js'));
|
||||
expect(sourceFile.rawMap).toEqual(indexSourceMap);
|
||||
expect(sourceFile.sources.length).toEqual(1);
|
||||
expect(sourceFile.sources[0]).toBe(null);
|
||||
});
|
||||
});
|
||||
|
||||
it('should log a warning if there is a cyclic dependency in source files loaded from disk',
|
||||
() => {
|
||||
fs.ensureDir(_('/foo/src'));
|
||||
|
||||
const aMap = createRawSourceMap({file: 'a.js', sources: ['b.js']});
|
||||
|
||||
const aPath = _('/foo/src/a.js');
|
||||
fs.writeFile(aPath, 'a content\n' + fromObject(aMap).toComment());
|
||||
|
||||
const bPath = _('/foo/src/b.js');
|
||||
fs.writeFile(
|
||||
bPath,
|
||||
'b content\n' +
|
||||
fromObject(createRawSourceMap({file: 'b.js', sources: ['c.js']})).toComment());
|
||||
|
||||
const cPath = _('/foo/src/c.js');
|
||||
fs.writeFile(
|
||||
cPath,
|
||||
'c content\n' +
|
||||
fromObject(createRawSourceMap({file: 'c.js', sources: ['a.js']})).toComment());
|
||||
|
||||
const sourceFile = registry.loadSourceFile(aPath)!;
|
||||
expect(sourceFile).not.toBe(null!);
|
||||
expect(sourceFile.contents).toEqual('a content\n');
|
||||
expect(sourceFile.sourcePath).toEqual(_('/foo/src/a.js'));
|
||||
expect(sourceFile.rawMap).toEqual(aMap);
|
||||
expect(sourceFile.sources.length).toEqual(1);
|
||||
|
||||
expect(logger.logs.warn[0][0])
|
||||
.toContain(
|
||||
`Circular source file mapping dependency: ` +
|
||||
`${aPath} -> ${bPath} -> ${cPath} -> ${aPath}`);
|
||||
});
|
||||
|
||||
it('should log a warning if there is a cyclic dependency in source maps loaded from disk',
|
||||
() => {
|
||||
fs.ensureDir(_('/foo/src'));
|
||||
|
||||
// Create a self-referencing source-map
|
||||
const aMap = createRawSourceMap({
|
||||
file: 'a.js',
|
||||
sources: ['a.js'],
|
||||
sourcesContent: ['inline a.js content\n//# sourceMappingURL=a.js.map']
|
||||
});
|
||||
const aMapPath = _('/foo/src/a.js.map');
|
||||
fs.writeFile(aMapPath, JSON.stringify(aMap));
|
||||
|
||||
const aPath = _('/foo/src/a.js');
|
||||
fs.writeFile(aPath, 'a.js content\n//# sourceMappingURL=a.js.map');
|
||||
|
||||
const sourceFile = registry.loadSourceFile(aPath)!;
|
||||
expect(sourceFile).not.toBe(null!);
|
||||
expect(sourceFile.contents).toEqual('a.js content\n');
|
||||
expect(sourceFile.sourcePath).toEqual(_('/foo/src/a.js'));
|
||||
expect(sourceFile.rawMap).toEqual(aMap);
|
||||
expect(sourceFile.sources.length).toEqual(1);
|
||||
|
||||
expect(logger.logs.warn[0][0])
|
||||
.toContain(
|
||||
`Circular source file mapping dependency: ` +
|
||||
`${aPath} -> ${aMapPath} -> ${aMapPath}`);
|
||||
|
||||
const innerSourceFile = sourceFile.sources[0]!;
|
||||
expect(innerSourceFile).not.toBe(null!);
|
||||
expect(innerSourceFile.contents).toEqual('inline a.js content\n');
|
||||
expect(innerSourceFile.sourcePath).toEqual(_('/foo/src/a.js'));
|
||||
expect(innerSourceFile.rawMap).toEqual(null);
|
||||
expect(innerSourceFile.sources.length).toEqual(0);
|
||||
});
|
||||
|
||||
it('should not fail if there is a cyclic dependency in filenames of inline sources', () => {
|
||||
fs.ensureDir(_('/foo/src'));
|
||||
|
||||
const aPath = _('/foo/src/a.js');
|
||||
fs.writeFile(
|
||||
aPath,
|
||||
'a content\n' +
|
||||
fromObject(createRawSourceMap({file: 'a.js', sources: ['b.js']})).toComment());
|
||||
|
||||
const bPath = _('/foo/src/b.js');
|
||||
fs.writeFile(bPath, 'b content');
|
||||
fs.writeFile(
|
||||
_('/foo/src/b.js.map'),
|
||||
JSON.stringify(createRawSourceMap({file: 'b.js', sources: ['c.js']})));
|
||||
|
||||
const cPath = _('/foo/src/c.js');
|
||||
fs.writeFile(cPath, 'c content');
|
||||
fs.writeFile(
|
||||
_('/foo/src/c.js.map'),
|
||||
JSON.stringify(createRawSourceMap(
|
||||
{file: 'c.js', sources: ['a.js'], sourcesContent: ['inline a.js content']})));
|
||||
|
||||
expect(() => registry.loadSourceFile(aPath)).not.toThrow();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
function createRawSourceMap(custom: Partial<RawSourceMap>): RawSourceMap {
|
||||
return {
|
||||
'version': 3,
|
||||
'sourceRoot': '',
|
||||
'sources': [],
|
||||
'sourcesContent': [],
|
||||
'names': [],
|
||||
'mappings': '',
|
||||
...custom
|
||||
};
|
||||
}
|
@ -1,537 +0,0 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google LLC All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
import {encode} from 'sourcemap-codec';
|
||||
|
||||
import {absoluteFrom} from '../../../src/ngtsc/file_system';
|
||||
import {runInEachFileSystem} from '../../../src/ngtsc/file_system/testing';
|
||||
import {RawSourceMap} from '../../src/sourcemaps/raw_source_map';
|
||||
import {SegmentMarker} from '../../src/sourcemaps/segment_marker';
|
||||
import {computeStartOfLinePositions, ensureOriginalSegmentLinks, extractOriginalSegments, findLastMappingIndexBefore, Mapping, parseMappings, SourceFile} from '../../src/sourcemaps/source_file';
|
||||
|
||||
runInEachFileSystem(() => {
|
||||
describe('SourceFile and utilities', () => {
|
||||
let _: typeof absoluteFrom;
|
||||
|
||||
beforeEach(() => {
|
||||
_ = absoluteFrom;
|
||||
});
|
||||
|
||||
describe('parseMappings()', () => {
|
||||
it('should be an empty array for source files with no source map', () => {
|
||||
const mappings = parseMappings(null, [], []);
|
||||
expect(mappings).toEqual([]);
|
||||
});
|
||||
|
||||
it('should be empty array for source files with no source map mappings', () => {
|
||||
const rawSourceMap: RawSourceMap = {mappings: '', names: [], sources: [], version: 3};
|
||||
const mappings = parseMappings(rawSourceMap, [], []);
|
||||
expect(mappings).toEqual([]);
|
||||
});
|
||||
|
||||
it('should parse the mappings from the raw source map', () => {
|
||||
const rawSourceMap: RawSourceMap = {
|
||||
mappings: encode([[[0, 0, 0, 0], [6, 0, 0, 3]]]),
|
||||
names: [],
|
||||
sources: ['a.js'],
|
||||
version: 3
|
||||
};
|
||||
const originalSource = new SourceFile(_('/foo/src/a.js'), 'abcdefg', null, false, []);
|
||||
const mappings = parseMappings(rawSourceMap, [originalSource], [0, 8]);
|
||||
expect(mappings).toEqual([
|
||||
{
|
||||
generatedSegment: {line: 0, column: 0, position: 0, next: undefined},
|
||||
originalSource,
|
||||
originalSegment: {line: 0, column: 0, position: 0, next: undefined},
|
||||
name: undefined
|
||||
},
|
||||
{
|
||||
generatedSegment: {line: 0, column: 6, position: 6, next: undefined},
|
||||
originalSource,
|
||||
originalSegment: {line: 0, column: 3, position: 3, next: undefined},
|
||||
name: undefined
|
||||
},
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('extractOriginalSegments()', () => {
|
||||
it('should return an empty Map for source files with no source map', () => {
|
||||
expect(extractOriginalSegments(parseMappings(null, [], []))).toEqual(new Map());
|
||||
});
|
||||
|
||||
it('should be empty Map for source files with no source map mappings', () => {
|
||||
const rawSourceMap: RawSourceMap = {mappings: '', names: [], sources: [], version: 3};
|
||||
expect(extractOriginalSegments(parseMappings(rawSourceMap, [], []))).toEqual(new Map());
|
||||
});
|
||||
|
||||
it('should parse the segments in ascending order of original position from the raw source map',
|
||||
() => {
|
||||
const originalSource = new SourceFile(_('/foo/src/a.js'), 'abcdefg', null, false, []);
|
||||
const rawSourceMap: RawSourceMap = {
|
||||
mappings: encode([[[0, 0, 0, 0], [2, 0, 0, 3], [4, 0, 0, 2]]]),
|
||||
names: [],
|
||||
sources: ['a.js'],
|
||||
version: 3
|
||||
};
|
||||
const originalSegments =
|
||||
extractOriginalSegments(parseMappings(rawSourceMap, [originalSource], [0, 8]));
|
||||
expect(originalSegments.get(originalSource)).toEqual([
|
||||
{line: 0, column: 0, position: 0, next: undefined},
|
||||
{line: 0, column: 2, position: 2, next: undefined},
|
||||
{line: 0, column: 3, position: 3, next: undefined},
|
||||
]);
|
||||
});
|
||||
|
||||
it('should create separate arrays for each original source file', () => {
|
||||
const sourceA = new SourceFile(_('/foo/src/a.js'), 'abcdefg', null, false, []);
|
||||
const sourceB = new SourceFile(_('/foo/src/b.js'), '1234567', null, false, []);
|
||||
const rawSourceMap: RawSourceMap = {
|
||||
mappings:
|
||||
encode([[[0, 0, 0, 0], [2, 1, 0, 3], [4, 0, 0, 2], [5, 1, 0, 5], [6, 1, 0, 2]]]),
|
||||
names: [],
|
||||
sources: ['a.js', 'b.js'],
|
||||
version: 3
|
||||
};
|
||||
const originalSegments =
|
||||
extractOriginalSegments(parseMappings(rawSourceMap, [sourceA, sourceB], [0, 8]));
|
||||
expect(originalSegments.get(sourceA)).toEqual([
|
||||
{line: 0, column: 0, position: 0, next: undefined},
|
||||
{line: 0, column: 2, position: 2, next: undefined},
|
||||
]);
|
||||
expect(originalSegments.get(sourceB)).toEqual([
|
||||
{line: 0, column: 2, position: 2, next: undefined},
|
||||
{line: 0, column: 3, position: 3, next: undefined},
|
||||
{line: 0, column: 5, position: 5, next: undefined},
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('findLastMappingIndexBefore', () => {
|
||||
it('should find the highest mapping index that has a segment marker below the given one if there is not an exact match',
|
||||
() => {
|
||||
const marker5: SegmentMarker = {line: 0, column: 50, position: 50, next: undefined};
|
||||
const marker4: SegmentMarker = {line: 0, column: 40, position: 40, next: marker5};
|
||||
const marker3: SegmentMarker = {line: 0, column: 30, position: 30, next: marker4};
|
||||
const marker2: SegmentMarker = {line: 0, column: 20, position: 20, next: marker3};
|
||||
const marker1: SegmentMarker = {line: 0, column: 10, position: 10, next: marker2};
|
||||
const mappings: Mapping[] = [marker1, marker2, marker3, marker4, marker5].map(
|
||||
marker => ({generatedSegment: marker} as Mapping));
|
||||
|
||||
const marker: SegmentMarker = {line: 0, column: 35, position: 35, next: undefined};
|
||||
const index = findLastMappingIndexBefore(mappings, marker, /* exclusive */ false, 0);
|
||||
expect(index).toEqual(2);
|
||||
});
|
||||
|
||||
it('should find the highest mapping index that has a segment marker (when there are duplicates) below the given one if there is not an exact match',
|
||||
() => {
|
||||
const marker5: SegmentMarker = {line: 0, column: 50, position: 50, next: undefined};
|
||||
const marker4: SegmentMarker = {line: 0, column: 30, position: 30, next: marker5};
|
||||
const marker3: SegmentMarker = {line: 0, column: 30, position: 30, next: marker4};
|
||||
const marker2: SegmentMarker = {line: 0, column: 20, position: 20, next: marker3};
|
||||
const marker1: SegmentMarker = {line: 0, column: 10, position: 10, next: marker2};
|
||||
const mappings: Mapping[] = [marker1, marker2, marker3, marker4, marker5].map(
|
||||
marker => ({generatedSegment: marker} as Mapping));
|
||||
|
||||
const marker: SegmentMarker = {line: 0, column: 35, position: 35, next: undefined};
|
||||
const index = findLastMappingIndexBefore(mappings, marker, /* exclusive */ false, 0);
|
||||
expect(index).toEqual(3);
|
||||
});
|
||||
|
||||
it('should find the last mapping if the segment marker is higher than all of them', () => {
|
||||
const marker5: SegmentMarker = {line: 0, column: 50, position: 50, next: undefined};
|
||||
const marker4: SegmentMarker = {line: 0, column: 40, position: 40, next: marker5};
|
||||
const marker3: SegmentMarker = {line: 0, column: 30, position: 30, next: marker4};
|
||||
const marker2: SegmentMarker = {line: 0, column: 20, position: 20, next: marker3};
|
||||
const marker1: SegmentMarker = {line: 0, column: 10, position: 10, next: marker2};
|
||||
const mappings: Mapping[] = [marker1, marker2, marker3, marker4, marker5].map(
|
||||
marker => ({generatedSegment: marker} as Mapping));
|
||||
|
||||
const marker: SegmentMarker = {line: 0, column: 60, position: 60, next: undefined};
|
||||
|
||||
const index = findLastMappingIndexBefore(mappings, marker, /* exclusive */ false, 0);
|
||||
expect(index).toEqual(4);
|
||||
});
|
||||
|
||||
it('should return -1 if the segment marker is lower than all of them', () => {
|
||||
const marker5: SegmentMarker = {line: 0, column: 50, position: 50, next: undefined};
|
||||
const marker4: SegmentMarker = {line: 0, column: 40, position: 40, next: marker5};
|
||||
const marker3: SegmentMarker = {line: 0, column: 30, position: 30, next: marker4};
|
||||
const marker2: SegmentMarker = {line: 0, column: 20, position: 20, next: marker3};
|
||||
const marker1: SegmentMarker = {line: 0, column: 10, position: 10, next: marker2};
|
||||
const mappings: Mapping[] = [marker1, marker2, marker3, marker4, marker5].map(
|
||||
marker => ({generatedSegment: marker} as Mapping));
|
||||
|
||||
const marker: SegmentMarker = {line: 0, column: 5, position: 5, next: undefined};
|
||||
|
||||
const index = findLastMappingIndexBefore(mappings, marker, /* exclusive */ false, 0);
|
||||
expect(index).toEqual(-1);
|
||||
});
|
||||
|
||||
describe('[exact match inclusive]', () => {
|
||||
it('should find the matching segment marker mapping index if there is only one of them',
|
||||
() => {
|
||||
const marker5: SegmentMarker = {line: 0, column: 50, position: 50, next: undefined};
|
||||
const marker4: SegmentMarker = {line: 0, column: 40, position: 40, next: marker5};
|
||||
const marker3: SegmentMarker = {line: 0, column: 30, position: 30, next: marker4};
|
||||
const marker2: SegmentMarker = {line: 0, column: 20, position: 20, next: marker3};
|
||||
const marker1: SegmentMarker = {line: 0, column: 10, position: 10, next: marker2};
|
||||
|
||||
const mappings: Mapping[] = [marker1, marker2, marker3, marker4, marker5].map(
|
||||
marker => ({generatedSegment: marker} as Mapping));
|
||||
const index = findLastMappingIndexBefore(mappings, marker3, /* exclusive */ false, 0);
|
||||
expect(index).toEqual(2);
|
||||
});
|
||||
|
||||
it('should find the highest matching segment marker mapping index if there is more than one of them',
|
||||
() => {
|
||||
const marker5: SegmentMarker = {line: 0, column: 50, position: 50, next: undefined};
|
||||
const marker4: SegmentMarker = {line: 0, column: 30, position: 30, next: marker5};
|
||||
const marker3: SegmentMarker = {line: 0, column: 30, position: 30, next: marker4};
|
||||
const marker2: SegmentMarker = {line: 0, column: 20, position: 20, next: marker3};
|
||||
const marker1: SegmentMarker = {line: 0, column: 10, position: 10, next: marker2};
|
||||
|
||||
const mappings: Mapping[] = [marker1, marker2, marker3, marker4, marker5].map(
|
||||
marker => ({generatedSegment: marker} as Mapping));
|
||||
const index = findLastMappingIndexBefore(mappings, marker3, /* exclusive */ false, 0);
|
||||
expect(index).toEqual(3);
|
||||
});
|
||||
});
|
||||
|
||||
describe('[exact match exclusive]', () => {
|
||||
it('should find the preceding mapping index if there is a matching segment marker', () => {
|
||||
const marker5: SegmentMarker = {line: 0, column: 50, position: 50, next: undefined};
|
||||
const marker4: SegmentMarker = {line: 0, column: 40, position: 40, next: marker5};
|
||||
const marker3: SegmentMarker = {line: 0, column: 30, position: 30, next: marker4};
|
||||
const marker2: SegmentMarker = {line: 0, column: 20, position: 20, next: marker3};
|
||||
const marker1: SegmentMarker = {line: 0, column: 10, position: 10, next: marker2};
|
||||
|
||||
const mappings: Mapping[] = [marker1, marker2, marker3, marker4, marker5].map(
|
||||
marker => ({generatedSegment: marker} as Mapping));
|
||||
const index = findLastMappingIndexBefore(mappings, marker3, /* exclusive */ true, 0);
|
||||
expect(index).toEqual(1);
|
||||
});
|
||||
|
||||
it('should find the highest preceding mapping index if there is more than one matching segment marker',
|
||||
() => {
|
||||
const marker5: SegmentMarker = {line: 0, column: 50, position: 50, next: undefined};
|
||||
const marker4: SegmentMarker = {line: 0, column: 30, position: 30, next: marker5};
|
||||
const marker3: SegmentMarker = {line: 0, column: 30, position: 30, next: marker4};
|
||||
const marker2: SegmentMarker = {line: 0, column: 20, position: 20, next: marker3};
|
||||
const marker1: SegmentMarker = {line: 0, column: 10, position: 10, next: marker2};
|
||||
|
||||
const mappings: Mapping[] = [marker1, marker2, marker3, marker4, marker5].map(
|
||||
marker => ({generatedSegment: marker} as Mapping));
|
||||
const index = findLastMappingIndexBefore(mappings, marker3, /* exclusive */ false, 0);
|
||||
expect(index).toEqual(3);
|
||||
});
|
||||
});
|
||||
|
||||
describe('[with lowerIndex hint', () => {
|
||||
it('should find the highest mapping index above the lowerIndex hint that has a segment marker below the given one if there is not an exact match',
|
||||
() => {
|
||||
const marker5: SegmentMarker = {line: 0, column: 50, position: 50, next: undefined};
|
||||
const marker4: SegmentMarker = {line: 0, column: 40, position: 40, next: marker5};
|
||||
const marker3: SegmentMarker = {line: 0, column: 30, position: 30, next: marker4};
|
||||
const marker2: SegmentMarker = {line: 0, column: 20, position: 20, next: marker3};
|
||||
const marker1: SegmentMarker = {line: 0, column: 10, position: 10, next: marker2};
|
||||
const mappings: Mapping[] = [marker1, marker2, marker3, marker4, marker5].map(
|
||||
marker => ({generatedSegment: marker} as Mapping));
|
||||
|
||||
const marker: SegmentMarker = {line: 0, column: 35, position: 35, next: undefined};
|
||||
const index = findLastMappingIndexBefore(mappings, marker, /* exclusive */ false, 1);
|
||||
expect(index).toEqual(2);
|
||||
});
|
||||
|
||||
it('should return the lowerIndex mapping index if there is a single exact match and we are not exclusive',
|
||||
() => {
|
||||
const marker5: SegmentMarker = {line: 0, column: 50, position: 50, next: undefined};
|
||||
const marker4: SegmentMarker = {line: 0, column: 40, position: 40, next: marker5};
|
||||
const marker3: SegmentMarker = {line: 0, column: 30, position: 30, next: marker4};
|
||||
const marker2: SegmentMarker = {line: 0, column: 20, position: 20, next: marker3};
|
||||
const marker1: SegmentMarker = {line: 0, column: 10, position: 10, next: marker2};
|
||||
const mappings: Mapping[] = [marker1, marker2, marker3, marker4, marker5].map(
|
||||
marker => ({generatedSegment: marker} as Mapping));
|
||||
|
||||
const marker: SegmentMarker = {line: 0, column: 30, position: 30, next: undefined};
|
||||
const index = findLastMappingIndexBefore(mappings, marker, /* exclusive */ false, 2);
|
||||
expect(index).toEqual(2);
|
||||
});
|
||||
|
||||
it('should return the lowerIndex mapping index if there are multiple exact matches and we are not exclusive',
|
||||
() => {
|
||||
const marker5: SegmentMarker = {line: 0, column: 50, position: 50, next: undefined};
|
||||
const marker4: SegmentMarker = {line: 0, column: 30, position: 30, next: marker5};
|
||||
const marker3: SegmentMarker = {line: 0, column: 30, position: 30, next: marker4};
|
||||
const marker2: SegmentMarker = {line: 0, column: 20, position: 20, next: marker3};
|
||||
const marker1: SegmentMarker = {line: 0, column: 10, position: 10, next: marker2};
|
||||
const mappings: Mapping[] = [marker1, marker2, marker3, marker4, marker5].map(
|
||||
marker => ({generatedSegment: marker} as Mapping));
|
||||
|
||||
const marker: SegmentMarker = {line: 0, column: 30, position: 30, next: undefined};
|
||||
const index = findLastMappingIndexBefore(mappings, marker, /* exclusive */ false, 3);
|
||||
expect(index).toEqual(3);
|
||||
});
|
||||
|
||||
it('should return -1 if the segment marker is lower than the lowerIndex hint', () => {
|
||||
const marker5: SegmentMarker = {line: 0, column: 50, position: 50, next: undefined};
|
||||
const marker4: SegmentMarker = {line: 0, column: 40, position: 40, next: marker5};
|
||||
const marker3: SegmentMarker = {line: 0, column: 30, position: 30, next: marker4};
|
||||
const marker2: SegmentMarker = {line: 0, column: 20, position: 20, next: marker3};
|
||||
const marker1: SegmentMarker = {line: 0, column: 10, position: 10, next: marker2};
|
||||
const mappings: Mapping[] = [marker1, marker2, marker3, marker4, marker5].map(
|
||||
marker => ({generatedSegment: marker} as Mapping));
|
||||
|
||||
const marker: SegmentMarker = {line: 0, column: 25, position: 25, next: undefined};
|
||||
|
||||
const index = findLastMappingIndexBefore(mappings, marker, /* exclusive */ false, 2);
|
||||
expect(index).toEqual(-1);
|
||||
});
|
||||
|
||||
it('should return -1 if the segment marker is equal to the lowerIndex hint and we are exclusive',
|
||||
() => {
|
||||
const marker5: SegmentMarker = {line: 0, column: 50, position: 50, next: undefined};
|
||||
const marker4: SegmentMarker = {line: 0, column: 40, position: 40, next: marker5};
|
||||
const marker3: SegmentMarker = {line: 0, column: 30, position: 30, next: marker4};
|
||||
const marker2: SegmentMarker = {line: 0, column: 20, position: 20, next: marker3};
|
||||
const marker1: SegmentMarker = {line: 0, column: 10, position: 10, next: marker2};
|
||||
const mappings: Mapping[] = [marker1, marker2, marker3, marker4, marker5].map(
|
||||
marker => ({generatedSegment: marker} as Mapping));
|
||||
|
||||
const marker: SegmentMarker = {line: 0, column: 30, position: 30, next: undefined};
|
||||
|
||||
const index = findLastMappingIndexBefore(mappings, marker, /* exclusive */ true, 2);
|
||||
expect(index).toEqual(-1);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('ensureOriginalSegmentLinks', () => {
|
||||
it('should add `next` properties to each segment that point to the next segment in the same source file',
|
||||
() => {
|
||||
const sourceA = new SourceFile(_('/foo/src/a.js'), 'abcdefg', null, false, []);
|
||||
const sourceB = new SourceFile(_('/foo/src/b.js'), '1234567', null, false, []);
|
||||
const rawSourceMap: RawSourceMap = {
|
||||
mappings:
|
||||
encode([[[0, 0, 0, 0], [2, 1, 0, 3], [4, 0, 0, 2], [5, 1, 0, 5], [6, 1, 0, 2]]]),
|
||||
names: [],
|
||||
sources: ['a.js', 'b.js'],
|
||||
version: 3
|
||||
};
|
||||
const mappings = parseMappings(rawSourceMap, [sourceA, sourceB], [0, 8]);
|
||||
ensureOriginalSegmentLinks(mappings);
|
||||
expect(mappings[0].originalSegment.next).toBe(mappings[2].originalSegment);
|
||||
expect(mappings[1].originalSegment.next).toBe(mappings[3].originalSegment);
|
||||
expect(mappings[2].originalSegment.next).toBeUndefined();
|
||||
expect(mappings[3].originalSegment.next).toBeUndefined();
|
||||
expect(mappings[4].originalSegment.next).toBe(mappings[1].originalSegment);
|
||||
});
|
||||
});
|
||||
|
||||
describe('SourceFile', () => {
|
||||
describe('flattenedMappings', () => {
|
||||
it('should be an empty array for source files with no source map', () => {
|
||||
const sourceFile =
|
||||
new SourceFile(_('/foo/src/index.js'), 'index contents', null, false, []);
|
||||
expect(sourceFile.flattenedMappings).toEqual([]);
|
||||
});
|
||||
|
||||
it('should be empty array for source files with no source map mappings', () => {
|
||||
const rawSourceMap: RawSourceMap = {mappings: '', names: [], sources: [], version: 3};
|
||||
const sourceFile =
|
||||
new SourceFile(_('/foo/src/index.js'), 'index contents', rawSourceMap, false, []);
|
||||
expect(sourceFile.flattenedMappings).toEqual([]);
|
||||
});
|
||||
|
||||
it('should be the same as non-flat mappings if there is only one level of source map',
|
||||
() => {
|
||||
const rawSourceMap: RawSourceMap = {
|
||||
mappings: encode([[[0, 0, 0, 0], [6, 0, 0, 3]]]),
|
||||
names: [],
|
||||
sources: ['a.js'],
|
||||
version: 3
|
||||
};
|
||||
const originalSource = new SourceFile(_('/foo/src/a.js'), 'abcdefg', null, false, []);
|
||||
const sourceFile = new SourceFile(
|
||||
_('/foo/src/index.js'), 'abc123defg', rawSourceMap, false, [originalSource]);
|
||||
expect(removeOriginalSegmentLinks(sourceFile.flattenedMappings))
|
||||
.toEqual(parseMappings(rawSourceMap, [originalSource], [0, 11]));
|
||||
});
|
||||
|
||||
it('should merge mappings from flattened original source files', () => {
|
||||
const cSource = new SourceFile(_('/foo/src/c.js'), 'bcd123', null, false, []);
|
||||
const dSource = new SourceFile(_('/foo/src/d.js'), 'aef', null, false, []);
|
||||
|
||||
const bSourceMap: RawSourceMap = {
|
||||
mappings: encode([[[0, 1, 0, 0], [1, 0, 0, 0], [4, 1, 0, 1]]]),
|
||||
names: [],
|
||||
sources: ['c.js', 'd.js'],
|
||||
version: 3
|
||||
};
|
||||
const bSource =
|
||||
new SourceFile(_('/foo/src/b.js'), 'abcdef', bSourceMap, false, [cSource, dSource]);
|
||||
|
||||
const aSourceMap: RawSourceMap = {
|
||||
mappings: encode([[[0, 0, 0, 0], [2, 0, 0, 3], [4, 0, 0, 2], [5, 0, 0, 5]]]),
|
||||
names: [],
|
||||
sources: ['b.js'],
|
||||
version: 3
|
||||
};
|
||||
const aSource =
|
||||
new SourceFile(_('/foo/src/a.js'), 'abdecf', aSourceMap, false, [bSource]);
|
||||
|
||||
expect(removeOriginalSegmentLinks(aSource.flattenedMappings)).toEqual([
|
||||
{
|
||||
generatedSegment: {line: 0, column: 0, position: 0, next: undefined},
|
||||
originalSource: dSource,
|
||||
originalSegment: {line: 0, column: 0, position: 0, next: undefined},
|
||||
name: undefined
|
||||
},
|
||||
{
|
||||
generatedSegment: {line: 0, column: 1, position: 1, next: undefined},
|
||||
originalSource: cSource,
|
||||
originalSegment: {line: 0, column: 0, position: 0, next: undefined},
|
||||
name: undefined
|
||||
},
|
||||
{
|
||||
generatedSegment: {line: 0, column: 2, position: 2, next: undefined},
|
||||
originalSource: cSource,
|
||||
originalSegment: {line: 0, column: 2, position: 2, next: undefined},
|
||||
name: undefined
|
||||
},
|
||||
{
|
||||
generatedSegment: {line: 0, column: 3, position: 3, next: undefined},
|
||||
originalSource: dSource,
|
||||
originalSegment: {line: 0, column: 1, position: 1, next: undefined},
|
||||
name: undefined
|
||||
},
|
||||
{
|
||||
generatedSegment: {line: 0, column: 4, position: 4, next: undefined},
|
||||
originalSource: cSource,
|
||||
originalSegment: {line: 0, column: 1, position: 1, next: undefined},
|
||||
name: undefined
|
||||
},
|
||||
{
|
||||
generatedSegment: {line: 0, column: 5, position: 5, next: undefined},
|
||||
originalSource: dSource,
|
||||
originalSegment: {line: 0, column: 2, position: 2, next: undefined},
|
||||
name: undefined
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
it('should ignore mappings to missing source files', () => {
|
||||
const bSourceMap: RawSourceMap = {
|
||||
mappings: encode([[[1, 0, 0, 0], [4, 0, 0, 3], [4, 0, 0, 6], [5, 0, 0, 7]]]),
|
||||
names: [],
|
||||
sources: ['c.js'],
|
||||
version: 3
|
||||
};
|
||||
const bSource = new SourceFile(_('/foo/src/b.js'), 'abcdef', bSourceMap, false, [null]);
|
||||
const aSourceMap: RawSourceMap = {
|
||||
mappings: encode([[[0, 0, 0, 0], [2, 0, 0, 3], [4, 0, 0, 2], [5, 0, 0, 5]]]),
|
||||
names: [],
|
||||
sources: ['b.js'],
|
||||
version: 3
|
||||
};
|
||||
const aSource =
|
||||
new SourceFile(_('/foo/src/a.js'), 'abdecf', aSourceMap, false, [bSource]);
|
||||
|
||||
// These flattened mappings are just the mappings from a to b.
|
||||
// (The mappings to c are dropped since there is no source file to map to.)
|
||||
expect(removeOriginalSegmentLinks(aSource.flattenedMappings))
|
||||
.toEqual(parseMappings(aSourceMap, [bSource], [0, 7]));
|
||||
});
|
||||
|
||||
/**
|
||||
* Clean out the links between original segments of each of the given `mappings`.
|
||||
*
|
||||
* @param mappings the mappings whose segments are to be cleaned.
|
||||
*/
|
||||
function removeOriginalSegmentLinks(mappings: Mapping[]) {
|
||||
for (const mapping of mappings) {
|
||||
mapping.originalSegment.next = undefined;
|
||||
}
|
||||
return mappings;
|
||||
}
|
||||
});
|
||||
|
||||
describe('renderFlattenedSourceMap()', () => {
|
||||
it('should convert the flattenedMappings into a raw source-map object', () => {
|
||||
const cSource = new SourceFile(_('/foo/src/c.js'), 'bcd123e', null, false, []);
|
||||
const bToCSourceMap: RawSourceMap = {
|
||||
mappings: encode([[[1, 0, 0, 0], [4, 0, 0, 3], [4, 0, 0, 6], [5, 0, 0, 7]]]),
|
||||
names: [],
|
||||
sources: ['c.js'],
|
||||
version: 3
|
||||
};
|
||||
const bSource =
|
||||
new SourceFile(_('/foo/src/b.js'), 'abcdef', bToCSourceMap, false, [cSource]);
|
||||
const aToBSourceMap: RawSourceMap = {
|
||||
mappings: encode([[[0, 0, 0, 0], [2, 0, 0, 3], [4, 0, 0, 2], [5, 0, 0, 5]]]),
|
||||
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(['c.js']);
|
||||
expect(aTocSourceMap.sourcesContent).toEqual(['bcd123e']);
|
||||
expect(aTocSourceMap.mappings).toEqual(encode([
|
||||
[[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);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('computeStartOfLinePositions()', () => {
|
||||
it('should compute the cumulative length of each line in the given string', () => {
|
||||
expect(computeStartOfLinePositions('')).toEqual([0]);
|
||||
expect(computeStartOfLinePositions('abc')).toEqual([0]);
|
||||
expect(computeStartOfLinePositions('\n')).toEqual([0, 1]);
|
||||
expect(computeStartOfLinePositions('\n\n')).toEqual([0, 1, 2]);
|
||||
expect(computeStartOfLinePositions('abc\n')).toEqual([0, 4]);
|
||||
expect(computeStartOfLinePositions('\nabc')).toEqual([0, 1]);
|
||||
expect(computeStartOfLinePositions('abc\ndefg')).toEqual([0, 4]);
|
||||
expect(computeStartOfLinePositions('abc\r\n')).toEqual([0, 4]);
|
||||
expect(computeStartOfLinePositions('abc\r\ndefg')).toEqual([0, 4]);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
Reference in New Issue
Block a user