aboutsummaryrefslogtreecommitdiff
path: root/packages/bun-debug-adapter-protocol/debugger/sourcemap.ts
diff options
context:
space:
mode:
authorGravatar Ashcon Partovi <ashcon@partovi.net> 2023-08-24 13:10:53 -0700
committerGravatar Ashcon Partovi <ashcon@partovi.net> 2023-08-24 20:11:20 -0700
commit627de5b29d4ceba6615e53c996c0b03336f6404a (patch)
treeb33ec9d04420c887d478e45ade58f12ca56238ff /packages/bun-debug-adapter-protocol/debugger/sourcemap.ts
parent526f7d85416b7310a1fa7b9886f8bb645df3695c (diff)
downloadbun-627de5b29d4ceba6615e53c996c0b03336f6404a.tar.gz
bun-627de5b29d4ceba6615e53c996c0b03336f6404a.tar.zst
bun-627de5b29d4ceba6615e53c996c0b03336f6404a.zip
More source map fixes
Diffstat (limited to '')
-rw-r--r--packages/bun-debug-adapter-protocol/debugger/sourcemap.ts120
1 files changed, 87 insertions, 33 deletions
diff --git a/packages/bun-debug-adapter-protocol/debugger/sourcemap.ts b/packages/bun-debug-adapter-protocol/debugger/sourcemap.ts
index eeceb520f..adb6dc57d 100644
--- a/packages/bun-debug-adapter-protocol/debugger/sourcemap.ts
+++ b/packages/bun-debug-adapter-protocol/debugger/sourcemap.ts
@@ -1,13 +1,28 @@
+import type { LineRange, MappedPosition } from "source-map-js";
import { SourceMapConsumer } from "source-map-js";
-export type Location = {
- line: number;
- column: number;
+export type LocationRequest = {
+ line?: number;
+ column?: number;
+ url?: string;
};
+export type Location = {
+ line: number; // 0-based
+ column: number; // 0-based
+} & (
+ | {
+ verified: true;
+ }
+ | {
+ verified?: false;
+ message?: string;
+ }
+);
+
export interface SourceMap {
- generatedLocation(line?: number, column?: number, url?: string): Location;
- originalLocation(line?: number, column?: number): Location;
+ generatedLocation(request: LocationRequest): Location;
+ originalLocation(request: LocationRequest): Location;
}
class ActualSourceMap implements SourceMap {
@@ -21,11 +36,11 @@ class ActualSourceMap implements SourceMap {
#getSource(url?: string): string {
const sources = this.#sources;
- if (sources.length === 1) {
- return sources[0];
+ if (!sources.length) {
+ return "";
}
- if (!url) {
- return sources[0] ?? "";
+ if (sources.length === 1 || !url) {
+ return sources[0];
}
for (const source of sources) {
if (url.endsWith(source)) {
@@ -35,61 +50,87 @@ class ActualSourceMap implements SourceMap {
return "";
}
- generatedLocation(line?: number, column?: number, url?: string): Location {
+ generatedLocation(request: LocationRequest): Location {
+ const { line, column, url } = request;
+ let lineRange: LineRange;
try {
const source = this.#getSource(url);
- const { line: gline, column: gcolumn } = this.#sourceMap.generatedPositionFor({
+ lineRange = this.#sourceMap.generatedPositionFor({
line: lineTo1BasedLine(line),
column: columnToColumn(column),
source,
});
- console.log(`[sourcemap] -->`, { source, url, line, column }, { gline, gcolumn });
+ } catch (error) {
return {
- line: lineTo0BasedLine(gline),
- column: columnToColumn(gcolumn),
+ line: lineToLine(line),
+ column: columnToColumn(column),
+ verified: false,
+ message: unknownToError(error),
};
- } catch (error) {
- console.warn(error);
+ }
+ if (!locationIsValid(lineRange)) {
return {
line: lineToLine(line),
column: columnToColumn(column),
+ verified: false,
};
}
+ const { line: gline, column: gcolumn } = lineRange;
+ return {
+ line: lineToLine(gline),
+ column: columnToColumn(gcolumn),
+ verified: true,
+ };
}
- originalLocation(line?: number, column?: number): Location {
+ originalLocation(request: LocationRequest): Location {
+ const { line, column } = request;
+ let mappedPosition: MappedPosition;
try {
- const { line: oline, column: ocolumn } = this.#sourceMap.originalPositionFor({
+ mappedPosition = this.#sourceMap.originalPositionFor({
line: lineTo1BasedLine(line),
column: columnToColumn(column),
});
- console.log(`[sourcemap] <--`, { line, column }, { oline, ocolumn });
+ } catch (error) {
return {
- line: lineTo0BasedLine(oline),
- column: columnToColumn(ocolumn),
+ line: lineToLine(line),
+ column: columnToColumn(column),
+ verified: false,
+ message: unknownToError(error),
};
- } catch (error) {
- console.warn(error);
+ }
+ if (!locationIsValid(mappedPosition)) {
return {
line: lineToLine(line),
column: columnToColumn(column),
+ verified: false,
};
}
+ const { line: oline, column: ocolumn } = mappedPosition;
+ return {
+ line: lineTo0BasedLine(oline),
+ column: columnToColumn(ocolumn),
+ verified: true,
+ };
}
}
class NoopSourceMap implements SourceMap {
- generatedLocation(line?: number, column?: number, url?: string): Location {
+ generatedLocation(request: LocationRequest): Location {
+ const { line, column } = request;
return {
line: lineToLine(line),
column: columnToColumn(column),
+ verified: true,
};
}
- originalLocation(line?: number, column?: number): Location {
+ originalLocation(request: LocationRequest): Location {
+ const { line, column } = request;
return {
line: lineToLine(line),
column: columnToColumn(column),
+ verified: true,
};
}
}
@@ -104,10 +145,6 @@ export function SourceMap(url?: string): SourceMap {
const [_, base64] = url.split(",", 2);
const decoded = Buffer.from(base64, "base64url").toString("utf8");
const schema = JSON.parse(decoded);
- // HACK: Bun is sometimes sending invalid mappings
- try {
- schema.mappings = schema.mappings.replace(/[^a-z,;]/gi, "").slice(1);
- } catch {}
const sourceMap = new SourceMapConsumer(schema);
return new ActualSourceMap(sourceMap);
} catch (error) {
@@ -117,17 +154,34 @@ export function SourceMap(url?: string): SourceMap {
}
function lineTo1BasedLine(line?: number): number {
- return line ? line + 1 : 1;
+ return numberIsValid(line) ? line + 1 : 1;
}
function lineTo0BasedLine(line?: number): number {
- return line ? line - 1 : 0;
+ return numberIsValid(line) ? line - 1 : 0;
}
function lineToLine(line?: number): number {
- return line ?? 0;
+ return numberIsValid(line) ? line : 0;
}
function columnToColumn(column?: number): number {
- return column ?? 0;
+ return numberIsValid(column) ? column : 0;
+}
+
+function locationIsValid(location: Location): location is Location {
+ const { line, column } = location;
+ return numberIsValid(line) && numberIsValid(column);
+}
+
+function numberIsValid(number?: number): number is number {
+ return typeof number === "number" && isFinite(number) && number >= 0;
+}
+
+function unknownToError(error: unknown): string {
+ if (error instanceof Error) {
+ const { message } = error;
+ return message;
+ }
+ return String(error);
}