Skip to content

Commit

Permalink
Update types to import trace-mapping's definitions
Browse files Browse the repository at this point in the history
  • Loading branch information
jridgewell committed Apr 23, 2022
1 parent cd8b447 commit 13c44eb
Show file tree
Hide file tree
Showing 6 changed files with 121 additions and 142 deletions.
3 changes: 2 additions & 1 deletion src/remapping.ts
Expand Up @@ -5,7 +5,8 @@ import SourceMap from './source-map';
import type { SourceMapInput, SourceMapLoader, Options } from './types';
export type {
SourceMapSegment,
RawSourceMap,
EncodedSourceMap,
EncodedSourceMap as RawSourceMap,
DecodedSourceMap,
SourceMapInput,
SourceMapLoader,
Expand Down
204 changes: 100 additions & 104 deletions src/source-map-tree.ts
Expand Up @@ -15,7 +15,106 @@ type MappingSource = SourceMapSegmentObject | typeof INVALID_MAPPING | typeof SO
* traceMappings is only called on the root level SourceMapTree, and begins the process of
* resolving each mapping in terms of the original source files.
*/
export let traceMappings: (tree: SourceMapTree) => TraceMap;
export function traceMappings(tree: SourceMapTree): TraceMap {
const mappings: SourceMapSegment[][] = [];
const names = new FastStringArray();
const sources = new FastStringArray();
const sourcesContent: (string | null)[] = [];
const { sources: rootSources, map } = tree;
const rootNames = map.names;
const rootMappings = decodedMappings(map);

let lastLineWithSegment = -1;
for (let i = 0; i < rootMappings.length; i++) {
const segments = rootMappings[i];
const tracedSegments: SourceMapSegment[] = [];

let lastSourcesIndex = -1;
let lastSourceLine = -1;
let lastSourceColumn = -1;

for (let j = 0; j < segments.length; j++) {
const segment = segments[j];

let traced: MappingSource = SOURCELESS_MAPPING;
// 1-length segments only move the current generated column, there's no source information
// to gather from it.
if (segment.length !== 1) {
const source = rootSources[segment[1]];
traced = source.originalPositionFor(
segment[2],
segment[3],
segment.length === 5 ? rootNames[segment[4]] : ''
);

// If the trace is invalid, then the trace ran into a sourcemap that doesn't contain a
// respective segment into an original source.
if (traced === INVALID_MAPPING) continue;
}

const genCol = segment[0];
if (traced === SOURCELESS_MAPPING) {
if (lastSourcesIndex === -1) {
// This is a consecutive source-less segment, which doesn't carry any new information.
continue;
}
lastSourcesIndex = lastSourceLine = lastSourceColumn = -1;
tracedSegments.push([genCol]);
continue;
}

// So we traced a segment down into its original source file. Now push a
// new segment pointing to this location.
const { column, line, name, content, source } = traced;

// Store the source location, and ensure we keep sourcesContent up to
// date with the sources array.
const sourcesIndex = put(sources, source);
sourcesContent[sourcesIndex] = content;

if (
lastSourcesIndex === sourcesIndex &&
lastSourceLine === line &&
lastSourceColumn === column
) {
// This is a duplicate mapping pointing at the exact same starting point in the source
// file. It doesn't carry any new information, and only bloats the sourcemap.
continue;
}
lastLineWithSegment = i;
lastSourcesIndex = sourcesIndex;
lastSourceLine = line;
lastSourceColumn = column;

// This looks like unnecessary duplication, but it noticeably increases performance. If we
// were to push the nameIndex onto length-4 array, v8 would internally allocate 22 slots!
// That's 68 wasted bytes! Array literals have the same capacity as their length, saving
// memory.
tracedSegments.push(
name
? [genCol, sourcesIndex, line, column, put(names, name)]
: [genCol, sourcesIndex, line, column]
);
}

mappings.push(tracedSegments);
}

if (mappings.length > lastLineWithSegment + 1) {
mappings.length = lastLineWithSegment + 1;
}

return presortedDecodedMap(
Object.assign({}, tree.map, {
mappings,
// TODO: Make all sources relative to the sourceRoot.
sourceRoot: undefined,
names: names.array,
sources: sources.array,
sourcesContent,
})
);
}

/**
* SourceMapTree represents a single sourcemap, with the ability to trace
Expand All @@ -30,109 +129,6 @@ export class SourceMapTree {
this.sources = sources;
}

static {
traceMappings = (tree) => {
const mappings: SourceMapSegment[][] = [];
const names = new FastStringArray();
const sources = new FastStringArray();
const sourcesContent: (string | null)[] = [];
const { sources: rootSources, map } = tree;
const rootNames = map.names;
const rootMappings = decodedMappings(map);

let lastLineWithSegment = -1;
for (let i = 0; i < rootMappings.length; i++) {
const segments = rootMappings[i];
const tracedSegments: SourceMapSegment[] = [];

let lastSourcesIndex = -1;
let lastSourceLine = -1;
let lastSourceColumn = -1;

for (let j = 0; j < segments.length; j++) {
const segment = segments[j];

let traced: MappingSource = SOURCELESS_MAPPING;
// 1-length segments only move the current generated column, there's no source information
// to gather from it.
if (segment.length !== 1) {
const source = rootSources[segment[1]];
traced = source.originalPositionFor(
segment[2],
segment[3],
segment.length === 5 ? rootNames[segment[4]] : ''
);

// If the trace is invalid, then the trace ran into a sourcemap that doesn't contain a
// respective segment into an original source.
if (traced === INVALID_MAPPING) continue;
}

const genCol = segment[0];
if (traced === SOURCELESS_MAPPING) {
if (lastSourcesIndex === -1) {
// This is a consecutive source-less segment, which doesn't carry any new information.
continue;
}
lastSourcesIndex = lastSourceLine = lastSourceColumn = -1;
tracedSegments.push([genCol]);
continue;
}

// So we traced a segment down into its original source file. Now push a
// new segment pointing to this location.
const { column, line, name, content, source } = traced;

// Store the source location, and ensure we keep sourcesContent up to
// date with the sources array.
const sourcesIndex = put(sources, source);
sourcesContent[sourcesIndex] = content;

if (
lastSourcesIndex === sourcesIndex &&
lastSourceLine === line &&
lastSourceColumn === column
) {
// This is a duplicate mapping pointing at the exact same starting point in the source
// file. It doesn't carry any new information, and only bloats the sourcemap.
continue;
}
lastLineWithSegment = i;
lastSourcesIndex = sourcesIndex;
lastSourceLine = line;
lastSourceColumn = column;

// This looks like unnecessary duplication, but it noticeably increases performance. If we
// were to push the nameIndex onto length-4 array, v8 would internally allocate 22 slots!
// That's 68 wasted bytes! Array literals have the same capacity as their length, saving
// memory.
tracedSegments.push(
name
? [genCol, sourcesIndex, line, column, put(names, name)]
: [genCol, sourcesIndex, line, column]
);
}

mappings.push(tracedSegments);
}

if (mappings.length > lastLineWithSegment + 1) {
mappings.length = lastLineWithSegment + 1;
}

return presortedDecodedMap(
Object.assign({}, tree.map, {
mappings,
// TODO: Make all sources relative to the sourceRoot.
sourceRoot: undefined,
names: names.array,
sources: sources.array,
sourcesContent,
})
);
};
}

/**
* originalPositionFor is only called on children SourceMapTrees. It recurses down
* into its own child SourceMapTrees, until we find the original source map.
Expand Down
8 changes: 5 additions & 3 deletions src/source-map.ts
@@ -1,15 +1,15 @@
import { encodedMappings, decodedMappings } from '@jridgewell/trace-mapping';

import type { TraceMap } from '@jridgewell/trace-mapping';
import type { DecodedSourceMap, RawSourceMap, Options } from './types';
import type { DecodedSourceMap, EncodedSourceMap, Options } from './types';

/**
* A SourceMap v3 compatible sourcemap, which only includes fields that were
* provided to it.
*/
export default class SourceMap {
declare file?: string | null;
declare mappings: RawSourceMap['mappings'] | DecodedSourceMap['mappings'];
declare mappings: EncodedSourceMap['mappings'] | DecodedSourceMap['mappings'];
declare sourceRoot?: string;
declare names: string[];
declare sources: (string | null)[];
Expand All @@ -19,7 +19,9 @@ export default class SourceMap {
constructor(map: TraceMap, options: Options) {
this.version = 3; // SourceMap spec says this should be first.
this.file = map.file;
this.mappings = options.decodedMappings ? decodedMappings(map) : encodedMappings(map);
this.mappings = options.decodedMappings
? (decodedMappings(map) as DecodedSourceMap['mappings'])
: encodedMappings(map);
this.names = map.names;

this.sourceRoot = map.sourceRoot;
Expand Down
36 changes: 8 additions & 28 deletions src/types.ts
@@ -1,30 +1,12 @@
interface SourceMapV3 {
file?: string | null;
names: string[];
sourceRoot?: string;
sources: (string | null)[];
sourcesContent?: (string | null)[];
version: 3;
}

type Column = number;
type SourcesIndex = number;
type SourceLine = number;
type SourceColumn = number;
type NamesIndex = number;

export type SourceMapSegment =
| [Column]
| [Column, SourcesIndex, SourceLine, SourceColumn]
| [Column, SourcesIndex, SourceLine, SourceColumn, NamesIndex];
import type { SourceMapInput } from '@jridgewell/trace-mapping';

export interface RawSourceMap extends SourceMapV3 {
mappings: string;
}
export type {
SourceMapSegment,
DecodedSourceMap,
EncodedSourceMap,
} from '@jridgewell/trace-mapping';

export interface DecodedSourceMap extends SourceMapV3 {
mappings: SourceMapSegment[][];
}
export type { SourceMapInput };

export interface SourceMapSegmentObject {
column: number;
Expand All @@ -34,8 +16,6 @@ export interface SourceMapSegmentObject {
content: string | null;
}

export type SourceMapInput = string | RawSourceMap | DecodedSourceMap;

export type LoaderContext = {
readonly importer: string;
readonly depth: number;
Expand All @@ -46,7 +26,7 @@ export type LoaderContext = {
export type SourceMapLoader = (
file: string,
ctx: LoaderContext
) => SourceMapInput | null | undefined;
) => SourceMapInput | null | undefined | void;

export type Options = {
excludeContent?: boolean;
Expand Down
4 changes: 2 additions & 2 deletions test/unit/build-source-map-tree.ts
@@ -1,8 +1,8 @@
import buildSourceMapTree from '../../src/build-source-map-tree';
import type { DecodedSourceMap, RawSourceMap } from '../../src/types';
import type { DecodedSourceMap, EncodedSourceMap } from '../../src/types';

describe('buildSourceMapTree', () => {
const rawMap: RawSourceMap = {
const rawMap: EncodedSourceMap = {
mappings: 'AAAA',
names: [],
sources: ['helloworld.js'],
Expand Down
8 changes: 4 additions & 4 deletions test/unit/remapping.ts
@@ -1,8 +1,8 @@
import remapping from '../../src/remapping';
import type { RawSourceMap } from '../../src/types';
import type { EncodedSourceMap } from '../../src/types';

describe('remapping', () => {
const rawMap: RawSourceMap = {
const rawMap: EncodedSourceMap = {
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.
Expand All @@ -12,7 +12,7 @@ describe('remapping', () => {
sourcesContent: ['1+1'],
version: 3,
};
const transpiledMap: RawSourceMap = {
const transpiledMap: EncodedSourceMap = {
// 1st column of 2nd line of output file translates into the 1st source
// file, line 3, column 2
mappings: ';CAEE',
Expand All @@ -21,7 +21,7 @@ describe('remapping', () => {
sourcesContent: ['\n\n 1 + 1;'],
version: 3,
};
const translatedMap: RawSourceMap = {
const translatedMap: EncodedSourceMap = {
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
Expand Down

0 comments on commit 13c44eb

Please sign in to comment.