1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
|
import { SourceMapConsumer } from "source-map-js";
export type Position = {
line: number;
column: number;
};
export interface SourceMap {
generatedPosition(line?: number, column?: number, url?: string): Position;
originalPosition(line?: number, column?: number): Position;
}
class ActualSourceMap implements SourceMap {
#sourceMap: SourceMapConsumer;
#sources: string[];
constructor(sourceMap: SourceMapConsumer) {
this.#sourceMap = sourceMap;
// @ts-ignore
this.#sources = sourceMap._absoluteSources;
}
#getSource(url?: string): string {
const sources = this.#sources;
if (sources.length === 1) {
return sources[0];
}
if (!url) {
return sources[0] ?? "";
}
for (const source of sources) {
if (url.endsWith(source)) {
return source;
}
}
return "";
}
generatedPosition(line?: number, column?: number, url?: string): Position {
try {
const source = this.#getSource(url);
const { line: gline, column: gcolumn } = this.#sourceMap.generatedPositionFor({
line: line ?? 0,
column: column ?? 0,
source,
});
console.log(`[sourcemap] -->`, { source, url, line, column }, { gline, gcolumn });
return {
line: gline || 0,
column: gcolumn || 0,
};
} catch (error) {
console.error(error);
return {
line: line || 0,
column: column || 0,
};
}
}
originalPosition(line?: number, column?: number): Position {
try {
const { line: oline, column: ocolumn } = this.#sourceMap.originalPositionFor({
line: line ?? 0,
column: column ?? 0,
});
console.log(`[sourcemap] <--`, { line, column }, { oline, ocolumn });
return {
line: oline || 0,
column: ocolumn || 0,
};
} catch (error) {
console.error(error);
return {
line: line || 0,
column: column || 0,
};
}
}
}
class NoopSourceMap implements SourceMap {
generatedPosition(line?: number, column?: number, url?: string): Position {
return {
line: line ?? 0,
column: column ?? 0,
};
}
originalPosition(line?: number, column?: number): Position {
return {
line: line ?? 0,
column: column ?? 0,
};
}
}
const defaultSourceMap = new NoopSourceMap();
export function SourceMap(url?: string): SourceMap {
if (!url || !url.startsWith("data:")) {
return defaultSourceMap;
}
try {
const [_, base64] = url.split(",", 2);
const decoded = Buffer.from(base64, "base64").toString("utf8");
const sourceMap = new SourceMapConsumer(JSON.parse(decoded));
return new ActualSourceMap(sourceMap);
} catch (error) {
console.warn("Failed to parse source map URL", url);
}
return defaultSourceMap;
}
|