Skip to content

Commit a1b7714

Browse files
cklinCopilot
andcommitted
Read VS Code Electron version from metadata
VS Code no longer consistently declares Electron in its root package.json. Prefer that declaration for older releases and fall back to the Electron target in .npmrc for newer releases. Validate the resolved version and cover both metadata layouts. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: c8ecd08e-7635-4742-b943-e0fc528b7949
1 parent 670390b commit a1b7714

3 files changed

Lines changed: 154 additions & 12 deletions

File tree

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,20 @@
1-
export async function fetchJson<T>(url: string): Promise<T> {
1+
async function fetchResponse(url: string): Promise<Response> {
22
const response = await fetch(url);
33
if (!response.ok) {
44
throw new Error(
55
`Could not fetch ${url}: ${response.status} ${response.statusText}`,
66
);
77
}
88

9+
return response;
10+
}
11+
12+
export async function fetchJson<T>(url: string): Promise<T> {
13+
const response = await fetchResponse(url);
914
return (await response.json()) as T;
1015
}
16+
17+
export async function fetchText(url: string): Promise<string> {
18+
const response = await fetchResponse(url);
19+
return await response.text();
20+
}

‎extensions/ql-vscode/scripts/util/vscode-versions.ts‎

Lines changed: 39 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
import { minVersion } from "semver";
2-
import { fetchJson } from "./fetch";
1+
import { minVersion, valid } from "semver";
2+
import { fetchJson, fetchText } from "./fetch";
33

44
type VsCodePackageJson = {
5-
devDependencies: {
6-
electron: string;
5+
devDependencies?: {
6+
electron?: string;
77
};
88
};
99

@@ -15,6 +15,40 @@ async function getVsCodePackageJson(
1515
);
1616
}
1717

18+
async function getVsCodeNpmrc(version: string): Promise<string> {
19+
return await fetchText(
20+
`https://raw.githubusercontent.com/microsoft/vscode/${version}/.npmrc`,
21+
);
22+
}
23+
24+
export function parseElectronVersion(npmrc: string): string {
25+
const electronVersion = /^target="([^"]+)"$/m.exec(npmrc)?.[1];
26+
if (!electronVersion || !valid(electronVersion)) {
27+
throw new Error(
28+
"Could not find a valid Electron version in VS Code .npmrc",
29+
);
30+
}
31+
32+
return electronVersion;
33+
}
34+
35+
async function getVsCodeElectronVersion(version: string): Promise<string> {
36+
const packageJson = await getVsCodePackageJson(version);
37+
const packageElectronVersion = packageJson.devDependencies?.electron;
38+
if (packageElectronVersion) {
39+
const electronVersion = minVersion(packageElectronVersion)?.version;
40+
if (!electronVersion) {
41+
throw new Error(
42+
"Could not find a valid Electron version in VS Code package.json",
43+
);
44+
}
45+
46+
return electronVersion;
47+
}
48+
49+
return parseElectronVersion(await getVsCodeNpmrc(version));
50+
}
51+
1852
interface ElectronVersion {
1953
version: string;
2054
date: string;
@@ -44,13 +78,7 @@ type VersionInformation = {
4478
export async function getVersionInformation(
4579
vscodeVersion: string,
4680
): Promise<VersionInformation> {
47-
const vsCodePackageJson = await getVsCodePackageJson(vscodeVersion);
48-
const electronVersion = minVersion(
49-
vsCodePackageJson.devDependencies.electron,
50-
)?.version;
51-
if (!electronVersion) {
52-
throw new Error("Could not find Electron version");
53-
}
81+
const electronVersion = await getVsCodeElectronVersion(vscodeVersion);
5482

5583
const electronReleases = await getElectronReleases();
5684

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
import {
2+
getVersionInformation,
3+
parseElectronVersion,
4+
} from "../../../../scripts/util/vscode-versions";
5+
6+
const electronReleases = [
7+
{
8+
version: "29.4.0",
9+
node: "20.9.0",
10+
chrome: "122.0.6261.156",
11+
},
12+
{
13+
version: "42.10.0",
14+
node: "24.18.1",
15+
chrome: "148.0.7778.280",
16+
},
17+
];
18+
19+
function mockFetch(
20+
responses: Record<string, unknown>,
21+
): jest.SpiedFunction<typeof fetch> {
22+
return jest.spyOn(globalThis, "fetch").mockImplementation(async (input) => {
23+
const url = input.toString();
24+
const response = responses[url];
25+
if (response === undefined) {
26+
throw new Error(`Unexpected URL: ${url}`);
27+
}
28+
29+
return {
30+
ok: true,
31+
json: async () => response,
32+
text: async () => response,
33+
} as Response;
34+
});
35+
}
36+
37+
afterEach(() => {
38+
jest.restoreAllMocks();
39+
});
40+
41+
describe("parseElectronVersion", () => {
42+
it("parses the Electron target from a VS Code .npmrc", () => {
43+
expect(
44+
parseElectronVersion(
45+
['target="42.10.0"', 'runtime="electron"', "disturl=example"].join(
46+
"\n",
47+
),
48+
),
49+
).toBe("42.10.0");
50+
});
51+
52+
it.each([
53+
["a missing target", 'runtime="electron"'],
54+
["an invalid target", 'target="not-a-version"'],
55+
["an unquoted target", "target=42.10.0"],
56+
])("rejects %s", (_description, npmrc) => {
57+
expect(() => parseElectronVersion(npmrc)).toThrow(
58+
"Could not find a valid Electron version in VS Code .npmrc",
59+
);
60+
});
61+
});
62+
63+
describe("getVersionInformation", () => {
64+
it("reads Electron from package.json for older VS Code releases", async () => {
65+
const fetchMock = mockFetch({
66+
"https://raw.githubusercontent.com/microsoft/vscode/1.90.0/package.json":
67+
{
68+
devDependencies: {
69+
electron: "29.4.0",
70+
},
71+
},
72+
"https://releases.electronjs.org/releases.json": electronReleases,
73+
});
74+
75+
await expect(getVersionInformation("1.90.0")).resolves.toEqual({
76+
vscodeVersion: "1.90.0",
77+
electronVersion: "29.4.0",
78+
nodeVersion: "20.9.0",
79+
chromiumVersion: "122.0.6261.156",
80+
});
81+
expect(fetchMock).not.toHaveBeenCalledWith(
82+
"https://raw.githubusercontent.com/microsoft/vscode/1.90.0/.npmrc",
83+
);
84+
});
85+
86+
it("falls back to .npmrc for newer VS Code releases", async () => {
87+
mockFetch({
88+
"https://raw.githubusercontent.com/microsoft/vscode/1.137.0/package.json":
89+
{
90+
devDependencies: {},
91+
},
92+
"https://raw.githubusercontent.com/microsoft/vscode/1.137.0/.npmrc":
93+
'target="42.10.0"\nruntime="electron"\n',
94+
"https://releases.electronjs.org/releases.json": electronReleases,
95+
});
96+
97+
await expect(getVersionInformation("1.137.0")).resolves.toEqual({
98+
vscodeVersion: "1.137.0",
99+
electronVersion: "42.10.0",
100+
nodeVersion: "24.18.1",
101+
chromiumVersion: "148.0.7778.280",
102+
});
103+
});
104+
});

0 commit comments

Comments
 (0)