Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
125 changes: 125 additions & 0 deletions extensions/ql-vscode/scripts/source-map.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
/**
* 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>
Comment thread
koesie10 marked this conversation as resolved.
* 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"
*/

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[]>([
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So, this will only work for as long as the workflow runs are still available from actions. Ideally, we can publish the source map as part of the release process and download the release artifact instead.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Definitely! We'd probably need to create a ZIP file and upload it as a release asset. I think we can do this in a follow-up PR.

"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;
};