Add script for retrieving original source location
This adds a script that can be used for retrieving the original source location when given a location in the released extension. It will download the source map from the Actions workflow run of the release and use the `source-map` library to extract the original location.
This commit is contained in:
124
extensions/ql-vscode/scripts/source-map.ts
Normal file
124
extensions/ql-vscode/scripts/source-map.ts
Normal file
@@ -0,0 +1,124 @@
|
||||
/**
|
||||
* This scripts helps finding the original source file and line number for a
|
||||
* given file and line number in the compiled extension. It currently only
|
||||
* works with released extensions.
|
||||
*
|
||||
* Usage: npx ts-node scripts/source-map.ts <version-number> <filename>:<line>:<column>
|
||||
*/
|
||||
|
||||
import { spawnSync } from "child_process";
|
||||
import { basename, resolve } from "path";
|
||||
import { pathExists, readJSON } from "fs-extra";
|
||||
import { SourceMapConsumer } from "source-map";
|
||||
|
||||
if (process.argv.length !== 4) {
|
||||
console.error(
|
||||
"Expected 2 arguments - the version number and the filename:line number",
|
||||
);
|
||||
}
|
||||
|
||||
const versionNumber = process.argv[2].startsWith("v")
|
||||
? process.argv[2]
|
||||
: `v${process.argv[2]}`;
|
||||
const filenameAndLine = process.argv[3];
|
||||
|
||||
async function extractSourceMap() {
|
||||
const sourceMapsDirectory = resolve(
|
||||
__dirname,
|
||||
"..",
|
||||
"artifacts",
|
||||
"source-maps",
|
||||
versionNumber,
|
||||
);
|
||||
|
||||
if (!(await pathExists(sourceMapsDirectory))) {
|
||||
console.log("Downloading source maps...");
|
||||
|
||||
const workflowRuns = runGhJSON<WorkflowRunListItem[]>([
|
||||
"run",
|
||||
"list",
|
||||
"--workflow",
|
||||
"release.yml",
|
||||
"--branch",
|
||||
versionNumber,
|
||||
"--json",
|
||||
"databaseId,number",
|
||||
]);
|
||||
|
||||
if (workflowRuns.length !== 1) {
|
||||
throw new Error(
|
||||
`Expected exactly one workflow run for ${versionNumber}, got ${workflowRuns.length}`,
|
||||
);
|
||||
}
|
||||
|
||||
const workflowRun = workflowRuns[0];
|
||||
|
||||
runGh([
|
||||
"run",
|
||||
"download",
|
||||
workflowRun.databaseId.toString(),
|
||||
"--name",
|
||||
"vscode-codeql-sourcemaps",
|
||||
"--dir",
|
||||
sourceMapsDirectory,
|
||||
]);
|
||||
}
|
||||
|
||||
const [filename, line, column] = filenameAndLine.split(":", 3);
|
||||
|
||||
const fileBasename = basename(filename);
|
||||
|
||||
const sourcemapName = `${fileBasename}.map`;
|
||||
const sourcemapPath = resolve(sourceMapsDirectory, sourcemapName);
|
||||
|
||||
if (!(await pathExists(sourcemapPath))) {
|
||||
throw new Error(`No source map found for ${fileBasename}`);
|
||||
}
|
||||
|
||||
const rawSourceMap = await readJSON(sourcemapPath);
|
||||
|
||||
const originalPosition = await SourceMapConsumer.with(
|
||||
rawSourceMap,
|
||||
null,
|
||||
async function (consumer) {
|
||||
return consumer.originalPositionFor({
|
||||
line: parseInt(line),
|
||||
column: parseInt(column),
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
if (!originalPosition.source) {
|
||||
throw new Error(`No source found for ${filenameAndLine}`);
|
||||
}
|
||||
|
||||
const originalFilename = resolve(filename, "..", originalPosition.source);
|
||||
|
||||
console.log(
|
||||
`${originalFilename}:${originalPosition.line}:${originalPosition.column}`,
|
||||
);
|
||||
}
|
||||
|
||||
extractSourceMap().catch((e: unknown) => {
|
||||
console.error(e);
|
||||
process.exit(2);
|
||||
});
|
||||
|
||||
function runGh(args: readonly string[]): string {
|
||||
const gh = spawnSync("gh", args);
|
||||
if (gh.status !== 0) {
|
||||
throw new Error(
|
||||
`Failed to get the source map for ${versionNumber}: ${gh.stderr}`,
|
||||
);
|
||||
}
|
||||
return gh.stdout.toString("utf-8");
|
||||
}
|
||||
|
||||
function runGhJSON<T>(args: readonly string[]): T {
|
||||
return JSON.parse(runGh(args));
|
||||
}
|
||||
|
||||
type WorkflowRunListItem = {
|
||||
databaseId: number;
|
||||
number: number;
|
||||
};
|
||||
Reference in New Issue
Block a user