Skip to content

Commit

Permalink
Implement scopes generator
Browse files Browse the repository at this point in the history
  • Loading branch information
jridgewell committed Jun 25, 2024
1 parent 75eff9d commit ccd8f87
Show file tree
Hide file tree
Showing 4 changed files with 167 additions and 16 deletions.
13 changes: 9 additions & 4 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@
},
"dependencies": {
"@jridgewell/set-array": "^1.2.1",
"@jridgewell/sourcemap-codec": "^1.4.10",
"@jridgewell/sourcemap-codec": "1.4.16-beta.0",
"@jridgewell/trace-mapping": "^0.3.24"
}
}
148 changes: 139 additions & 9 deletions src/gen-mapping.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { SetArray, put, remove } from '@jridgewell/set-array';
import { encode } from '@jridgewell/sourcemap-codec';
import { encode, encodeGeneratedRanges, encodeOriginalScopes } from '@jridgewell/sourcemap-codec';
import { TraceMap, decodedMappings } from '@jridgewell/trace-mapping';

import {
Expand All @@ -11,8 +11,17 @@ import {
} from './sourcemap-segment';

import type { SourceMapInput } from '@jridgewell/trace-mapping';
import type { OriginalScope, GeneratedRange } from '@jridgewell/sourcemap-codec';
import type { SourceMapSegment } from './sourcemap-segment';
import type { DecodedSourceMap, EncodedSourceMap, Pos, Mapping } from './types';
import type {
DecodedSourceMap,
EncodedSourceMap,
Pos,
Mapping,
BindingExpressionRange,
OriginalPos,
OriginalScopeInfo,
} from './types';

export type { DecodedSourceMap, EncodedSourceMap, Mapping };

Expand All @@ -31,6 +40,8 @@ export class GenMapping {
private declare _sources: SetArray<string>;
private declare _sourcesContent: (string | null)[];
private declare _mappings: SourceMapSegment[][];
private declare _originalScopes: OriginalScope[][];
private declare _generatedRanges: GeneratedRange[];
private declare _ignoreList: SetArray<number>;
declare file: string | null | undefined;
declare sourceRoot: string | null | undefined;
Expand All @@ -40,6 +51,8 @@ export class GenMapping {
this._sources = new SetArray();
this._sourcesContent = [];
this._mappings = [];
this._originalScopes = [];
this._generatedRanges = [];
this.file = file;
this.sourceRoot = sourceRoot;
this._ignoreList = new SetArray();
Expand All @@ -51,6 +64,8 @@ interface PublicMap {
_sources: GenMapping['_sources'];
_sourcesContent: GenMapping['_sourcesContent'];
_mappings: GenMapping['_mappings'];
_originalScopes: GenMapping['_originalScopes'];
_generatedRanges: GenMapping['_generatedRanges'];
_ignoreList: GenMapping['_ignoreList'];
}

Expand Down Expand Up @@ -207,15 +222,26 @@ export const maybeAddMapping: typeof addMapping = (map, mapping) => {
* Adds/removes the content of the source file to the source map.
*/
export function setSourceContent(map: GenMapping, source: string, content: string | null): void {
const { _sources: sources, _sourcesContent: sourcesContent } = cast(map);
const {
_sources: sources,
_sourcesContent: sourcesContent,
_originalScopes: originalScopes,
} = cast(map);
const index = put(sources, source);
sourcesContent[index] = content;
if (index === originalScopes.length) originalScopes[index] = [];
}

export function setIgnore(map: GenMapping, source: string, ignore = true) {
const { _sources: sources, _sourcesContent: sourcesContent, _ignoreList: ignoreList } = cast(map);
const {
_sources: sources,
_sourcesContent: sourcesContent,
_ignoreList: ignoreList,
_originalScopes: originalScopes,
} = cast(map);
const index = put(sources, source);
if (index === sourcesContent.length) sourcesContent[index] = null;
if (index === originalScopes.length) originalScopes[index] = [];
if (ignore) put(ignoreList, index);
else remove(ignoreList, index);
}
Expand All @@ -231,6 +257,8 @@ export function toDecodedMap(map: GenMapping): DecodedSourceMap {
_sourcesContent: sourcesContent,
_names: names,
_ignoreList: ignoreList,
_originalScopes: originalScopes,
_generatedRanges: generatedRanges,
} = cast(map);
removeEmptyFinalLines(mappings);

Expand All @@ -242,6 +270,8 @@ export function toDecodedMap(map: GenMapping): DecodedSourceMap {
sources: sources.array,
sourcesContent,
mappings,
originalScopes,
generatedRanges,
ignoreList: ignoreList.array,
};
}
Expand All @@ -254,6 +284,8 @@ export function toEncodedMap(map: GenMapping): EncodedSourceMap {
const decoded = toDecodedMap(map);
return {
...decoded,
originalScopes: decoded.originalScopes.map((os) => encodeOriginalScopes(os)),
generatedRanges: encodeGeneratedRanges(decoded.generatedRanges as GeneratedRange[]),
mappings: encode(decoded.mappings as SourceMapSegment[][]),
};
}
Expand All @@ -269,6 +301,7 @@ export function fromMap(input: SourceMapInput): GenMapping {
putAll(cast(gen)._sources, map.sources as string[]);
cast(gen)._sourcesContent = map.sourcesContent || map.sources.map(() => null);
cast(gen)._mappings = decodedMappings(map) as GenMapping['_mappings'];
// TODO: implement originalScopes/generatedRanges
if (map.ignoreList) putAll(cast(gen)._ignoreList, map.ignoreList);

return gen;
Expand Down Expand Up @@ -323,8 +356,9 @@ function addSegmentInternal<S extends string | null | undefined>(
_sources: sources,
_sourcesContent: sourcesContent,
_names: names,
_originalScopes: originalScopes,
} = cast(map);
const line = getLine(mappings, genLine);
const line = getIndex(mappings, genLine);
const index = getColumnIndex(line, genColumn);

if (!source) {
Expand All @@ -340,6 +374,7 @@ function addSegmentInternal<S extends string | null | undefined>(
const sourcesIndex = put(sources, source);
const namesIndex = name ? put(names, name) : NO_NAME;
if (sourcesIndex === sourcesContent.length) sourcesContent[sourcesIndex] = content ?? null;
if (sourcesIndex === originalScopes.length) originalScopes[sourcesIndex] = [];

if (skipable && skipSource(line, index, sourcesIndex, sourceLine, sourceColumn, namesIndex)) {
return;
Expand All @@ -358,11 +393,11 @@ function assert<T>(_val: unknown): asserts _val is T {
// noop.
}

function getLine(mappings: SourceMapSegment[][], index: number): SourceMapSegment[] {
for (let i = mappings.length; i <= index; i++) {
mappings[i] = [];
function getIndex<T>(arr: T[][], index: number): T[] {
for (let i = arr.length; i <= index; i++) {
arr[i] = [];
}
return mappings[index];
return arr[index];
}

function getColumnIndex(line: SourceMapSegment[], genColumn: number): number {
Expand Down Expand Up @@ -470,3 +505,98 @@ function addMappingInternal<S extends string | null | undefined>(
content,
);
}

export function addOriginalScope(
map: GenMapping,
data: {
start: Pos;
end: Pos;
source: string;
kind: string;
name?: string;
variables?: string[];
},
): OriginalScopeInfo {
const { start, end, source, kind, name, variables } = data;
const {
_sources: sources,
_sourcesContent: sourcesContent,
_originalScopes: originalScopes,
_names: names,
} = cast(map);
const index = put(sources, source);
if (index === sourcesContent.length) sourcesContent[index] = null;
if (index === originalScopes.length) originalScopes[index] = [];

const kindIndex = put(names, kind);
const scope: OriginalScope = name
? [start.line - 1, start.column, end.line - 1, end.column, kindIndex, put(names, name)]
: [start.line - 1, start.column, end.line - 1, end.column, kindIndex];
if (variables) {
scope.vars = variables.map((v) => put(names, v));
}
const len = originalScopes[index].push(scope);
return [index, len - 1, variables];
}

// Generated Ranges
export function addGeneratedRange(
map: GenMapping,
data: {
start: Pos;
isScope: boolean;
originalScope?: OriginalScopeInfo;
callsite?: OriginalPos;
},
): GeneratedRange {
const { start, isScope, originalScope, callsite } = data;
const {
_originalScopes: originalScopes,
_sources: sources,
_sourcesContent: sourcesContent,
} = cast(map);

const range: GeneratedRange = [
start.line - 1,
start.column,
0,
0,
originalScope ? originalScope[0] : -1,
originalScope ? originalScope[1] : -1,
];
if (originalScope) (range as any).vars = originalScopes[originalScope[0]][originalScope[1]].vars;
if (isScope) range.isScope = true;
if (callsite) {
const index = put(sources, callsite.source);
if (index === sourcesContent.length) sourcesContent[index] = null;
if (index === originalScopes.length) originalScopes[index] = [];
range.callsite = [index, callsite.line - 1, callsite.column];
}

return range;
}

export function setEndPosition(range: GeneratedRange, pos: Pos) {
range[2] = pos.line - 1;
range[3] = pos.column;
}

export function addBinding(
map: GenMapping,
range: GeneratedRange,
variable: string,
expression: string | BindingExpressionRange,
) {
const { _names: names } = cast(map);
const vars: string[] = (range as any).vars;
const bindings = (range.bindings ||= []);

const index = vars.indexOf(variable);
const binding = getIndex(bindings, index);

if (typeof expression === 'string') binding[0] = [put(names, expression)];
else {
const { start } = expression;
binding.push([put(names, expression.expression), start.line - 1, start.column]);
}
}
20 changes: 18 additions & 2 deletions src/types.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import type { GeneratedRange, OriginalScope } from '@jridgewell/sourcemap-codec';
import type { SourceMapSegment } from './sourcemap-segment';

export interface SourceMapV3 {
Expand All @@ -12,17 +13,32 @@ export interface SourceMapV3 {

export interface EncodedSourceMap extends SourceMapV3 {
mappings: string;
originalScopes: string[];
generatedRanges: string;
}

export interface DecodedSourceMap extends SourceMapV3 {
mappings: readonly SourceMapSegment[][];
originalScopes: readonly OriginalScope[][];
generatedRanges: readonly GeneratedRange[];
}

export interface Pos {
line: number;
column: number;
line: number; // 1-based
column: number; // 0-based
}

export interface OriginalPos extends Pos {
source: string;
}

export interface BindingExpressionRange {
start: Pos;
expression: string;
}

export type OriginalScopeInfo = [number, number, string[] | undefined];

export type Mapping =
| {
generated: Pos;
Expand Down

0 comments on commit ccd8f87

Please sign in to comment.