Skip to content

Commit 648e674

Browse files
authored
Merge pull request #2037 from github/koesie10/source-map-script
Add script for retrieving original source location
2 parents 943229f + 6d1c66b commit 648e674

File tree

1 file changed

+125
-0
lines changed

1 file changed

+125
-0
lines changed
Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
/**
2+
* This scripts helps finding the original source file and line number for a
3+
* given file and line number in the compiled extension. It currently only
4+
* works with released extensions.
5+
*
6+
* Usage: npx ts-node scripts/source-map.ts <version-number> <filename>:<line>:<column>
7+
* For example: npx ts-node scripts/source-map.ts v1.7.8 "/Users/user/.vscode/extensions/github.vscode-codeql-1.7.8/out/extension.js:131164:13"
8+
*/
9+
10+
import { spawnSync } from "child_process";
11+
import { basename, resolve } from "path";
12+
import { pathExists, readJSON } from "fs-extra";
13+
import { SourceMapConsumer } from "source-map";
14+
15+
if (process.argv.length !== 4) {
16+
console.error(
17+
"Expected 2 arguments - the version number and the filename:line number",
18+
);
19+
}
20+
21+
const versionNumber = process.argv[2].startsWith("v")
22+
? process.argv[2]
23+
: `v${process.argv[2]}`;
24+
const filenameAndLine = process.argv[3];
25+
26+
async function extractSourceMap() {
27+
const sourceMapsDirectory = resolve(
28+
__dirname,
29+
"..",
30+
"artifacts",
31+
"source-maps",
32+
versionNumber,
33+
);
34+
35+
if (!(await pathExists(sourceMapsDirectory))) {
36+
console.log("Downloading source maps...");
37+
38+
const workflowRuns = runGhJSON<WorkflowRunListItem[]>([
39+
"run",
40+
"list",
41+
"--workflow",
42+
"release.yml",
43+
"--branch",
44+
versionNumber,
45+
"--json",
46+
"databaseId,number",
47+
]);
48+
49+
if (workflowRuns.length !== 1) {
50+
throw new Error(
51+
`Expected exactly one workflow run for ${versionNumber}, got ${workflowRuns.length}`,
52+
);
53+
}
54+
55+
const workflowRun = workflowRuns[0];
56+
57+
runGh([
58+
"run",
59+
"download",
60+
workflowRun.databaseId.toString(),
61+
"--name",
62+
"vscode-codeql-sourcemaps",
63+
"--dir",
64+
sourceMapsDirectory,
65+
]);
66+
}
67+
68+
const [filename, line, column] = filenameAndLine.split(":", 3);
69+
70+
const fileBasename = basename(filename);
71+
72+
const sourcemapName = `${fileBasename}.map`;
73+
const sourcemapPath = resolve(sourceMapsDirectory, sourcemapName);
74+
75+
if (!(await pathExists(sourcemapPath))) {
76+
throw new Error(`No source map found for ${fileBasename}`);
77+
}
78+
79+
const rawSourceMap = await readJSON(sourcemapPath);
80+
81+
const originalPosition = await SourceMapConsumer.with(
82+
rawSourceMap,
83+
null,
84+
async function (consumer) {
85+
return consumer.originalPositionFor({
86+
line: parseInt(line),
87+
column: parseInt(column),
88+
});
89+
},
90+
);
91+
92+
if (!originalPosition.source) {
93+
throw new Error(`No source found for ${filenameAndLine}`);
94+
}
95+
96+
const originalFilename = resolve(filename, "..", originalPosition.source);
97+
98+
console.log(
99+
`${originalFilename}:${originalPosition.line}:${originalPosition.column}`,
100+
);
101+
}
102+
103+
extractSourceMap().catch((e: unknown) => {
104+
console.error(e);
105+
process.exit(2);
106+
});
107+
108+
function runGh(args: readonly string[]): string {
109+
const gh = spawnSync("gh", args);
110+
if (gh.status !== 0) {
111+
throw new Error(
112+
`Failed to get the source map for ${versionNumber}: ${gh.stderr}`,
113+
);
114+
}
115+
return gh.stdout.toString("utf-8");
116+
}
117+
118+
function runGhJSON<T>(args: readonly string[]): T {
119+
return JSON.parse(runGh(args));
120+
}
121+
122+
type WorkflowRunListItem = {
123+
databaseId: number;
124+
number: number;
125+
};

0 commit comments

Comments
 (0)