Skip to content

Commit fc9a5ec

Browse files
committed
successfully compiles but vscode still does not support ESM extensions (see microsoft/vscode#130367)
1 parent fb0e1b7 commit fc9a5ec

24 files changed

+1457
-1029
lines changed

.eslintrc.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,7 @@ module.exports = {
146146
"eol-last": "off",
147147
"eqeqeq": [
148148
"error",
149-
"always"
149+
"smart"
150150
],
151151
"guard-for-in": "error",
152152
"id-denylist": "error",

package-lock.json

+1,322-910
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

+7-4
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@
22
"name": "vs-verification-toolbox",
33
"version": "1.0.0",
44
"description": "Useful component to build VS Code extensions for verifiers.",
5-
"main": "out/index.js",
5+
"type": "module",
6+
"exports": "./out/index.js",
67
"activationEvents": [
78
"this property is required to run vs code tests"
89
],
@@ -25,15 +26,17 @@
2526
"npm",
2627
"node"
2728
],
28-
"author": "Julian Dunskus",
29+
"author": {
30+
"name": "Chair of Programming Methodology, ETH Zurich"
31+
},
2932
"license": "MPL-2.0",
3033
"bugs": {
3134
"url": "https://github.com/viperproject/vs-verification-toolbox/issues"
3235
},
3336
"homepage": "https://github.com/viperproject/vs-verification-toolbox#readme",
3437
"engines": {
3538
"vscode": "^1.43.0",
36-
"node": "*"
39+
"node": ">=18"
3740
},
3841
"devDependencies": {
3942
"@types/fs-extra": "^11.0.4",
@@ -61,6 +64,6 @@
6164
"@octokit/rest": "^20.0.2",
6265
"extract-zip": "^2.0.0",
6366
"fs-extra": "^11.2.0",
64-
"got": "^11.8.6"
67+
"got": "^14.4.4"
6568
}
6669
}

src/dependencies/Dependency.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import * as path from 'path';
22

3-
import { ConfirmResult, InstallResult, Success } from './';
4-
import { Location, ProgressListener } from '../util';
3+
import { ConfirmResult, InstallResult, Success } from './index.js';
4+
import { Location, ProgressListener } from '../util/index.js';
55

66
/**
77
* Manages the installation for a dependency, maintaining separate installations for each source (in a folder using their name).

src/dependencies/FileDownloader.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
import * as fs from 'fs-extra';
2-
import * as path from 'path';
2+
import * as path from 'node:path';
33
import got, { Headers, Options, Progress } from 'got';
44
import * as stream from 'stream';
55
import { promisify } from 'util';
66

7-
import { Canceled, ConfirmResult, DependencyInstaller, InstallResult, Success } from './';
8-
import { Location, ProgressListener } from '../util';
7+
import { Canceled, ConfirmResult, DependencyInstaller, InstallResult, Success } from './index.js';
8+
import { Location, ProgressListener } from '../util/index.js';
99

1010

1111
const pipeline = promisify(stream.pipeline);

src/dependencies/GitHubReleaseAsset.ts

+5-5
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,10 @@ export class GitHubReleaseAsset {
2828
// get the first release which corresponds to the latest pre- or non-pre-release.
2929
// note that draft releases do not show up for unauthenticated users
3030
// see https://octokit.github.io/rest.js/v18#repos-list-releases
31-
let listReleasesParams: RestEndpointMethodTypes["repos"]["listReleases"]["parameters"] = {
32-
owner: owner,
33-
repo: repo,
34-
}
31+
const listReleasesParams: RestEndpointMethodTypes["repos"]["listReleases"]["parameters"] = {
32+
owner,
33+
repo,
34+
};
3535
if (token == null) {
3636
listReleasesParams.per_page = 1;
3737
listReleasesParams.page = 1;
@@ -88,7 +88,7 @@ export class GitHubReleaseAsset {
8888
* @param token personal access token, OAuth token, installation access token, or JSON Web Token for GitHub App authentication
8989
*/
9090
private static buildOctokit(token?: string): Octokit {
91-
if (token) {
91+
if (token != null) {
9292
return new Octokit({
9393
auth: token,
9494
});

src/dependencies/GitHubZipExtractor.ts

+5-7
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,10 @@
1-
import * as path from 'path';
2-
3-
import { ConfirmResult, DependencyInstaller, FileDownloader, InstallerSequence, InstallResult, Success, ZipExtractor } from './';
4-
import { Location, ProgressListener } from '../util';
1+
import { ConfirmResult, DependencyInstaller, FileDownloader, InstallerSequence, InstallResult, Success, ZipExtractor } from './index.js';
2+
import { Location, ProgressListener } from '../util/index.js';
53

64
/**
75
* Extension of RemoteZipExtractor with the following features:
86
* - no remote URL needed at construction time: a (potentially expensive) computation of the remote URL is only
9-
* performed when a download will actually take place.
7+
* performed when a download will actually take place.
108
* - the correct header for downloading a GitHub release asset is set
119
* - if a GitHub token is provided it is used to perform the download as an authenticated user
1210
*/
@@ -32,8 +30,8 @@ export class GitHubZipExtractor implements DependencyInstaller {
3230
const downloadHeaders: Record<string, string | string[] | undefined> = {
3331
"Accept": "application/octet-stream"
3432
};
35-
if (this.token) {
36-
downloadHeaders["Authorization"] = `token ${this.token}`;
33+
if (this.token != null) {
34+
downloadHeaders.Authorization = `token ${this.token}`;
3735
}
3836

3937
// lazily initialize sequence:

src/dependencies/InstallResult.ts

+3-2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
/* eslint-disable no-underscore-dangle */
12
export interface InstallResult<T> {
23
isSuccess(): boolean;
34
}
@@ -7,8 +8,8 @@ export class Success<T> implements InstallResult<T> {
78
private readonly _value: T;
89

910
/**
10-
* @param t non-null
11-
*/
11+
* @param t non-null
12+
*/
1213
constructor(t: T) {
1314
if (t == null) {
1415
throw new Error(`Invalid argument: Success(v) can only be constructed with a non-null value`);

src/dependencies/InstallerSequence.ts

+7-7
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
import { ConfirmResult, DependencyInstaller, InstallResult, Success } from './';
2-
import { Location, ProgressListener } from '../util';
1+
import { ConfirmResult, DependencyInstaller, InstallResult, Success } from './index.js';
2+
import { Location, ProgressListener } from '../util/index.js';
33

44
export class InstallerSequence {
55
constructor(readonly installers: DependencyInstaller[]) {
@@ -16,17 +16,17 @@ export class InstallerSequence {
1616

1717
public async install(location: Location, shouldUpdate: boolean, progressListener: ProgressListener, confirm:() => Promise<ConfirmResult>): Promise<InstallResult<Location>> {
1818
let index = 0;
19-
let firstConfirmPromise: Promise<ConfirmResult> | undefined = undefined;
19+
let firstConfirmPromise: Promise<ConfirmResult> | undefined;
2020
let result: InstallResult<Location> = new Success(location);
2121
const total = this.installers.length;
2222
for (const installer of this.installers) {
23-
function intermediateListener(fraction: number, message: string) {
23+
const intermediateListener = (fraction: number, message: string) => {
2424
progressListener(
2525
(index + fraction) / total,
2626
`${message} (step ${index + 1} of ${total})`
2727
);
28-
}
29-
function intermediateConfirm(): Promise<ConfirmResult> {
28+
};
29+
const intermediateConfirm = () => {
3030
// only ask once
3131
if (firstConfirmPromise == null) {
3232
firstConfirmPromise = confirm();
@@ -35,7 +35,7 @@ export class InstallerSequence {
3535
// return same promise:
3636
return firstConfirmPromise;
3737
}
38-
}
38+
};
3939

4040
if (result instanceof Success) {
4141
// continue with next installer

src/dependencies/LocalReference.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import * as fs from 'fs-extra';
22

3-
import { ConfirmResult, DependencyInstaller, InstallResult, Success } from './';
4-
import { Location, ProgressListener } from '../util';
3+
import { ConfirmResult, DependencyInstaller, InstallResult, Success } from './index.js';
4+
import { Location, ProgressListener } from '../util/index.js';
55

66
export class LocalReference implements DependencyInstaller {
77
constructor(

src/dependencies/RemoteZipExtractor.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
import * as path from 'path';
1+
import * as path from 'node:path';
22

3-
import { ConfirmResult, DependencyInstaller, FileDownloader, InstallerSequence, InstallResult, Success, ZipExtractor } from './';
4-
import { Location, ProgressListener } from '../util';
3+
import { ConfirmResult, DependencyInstaller, FileDownloader, InstallerSequence, InstallResult, Success, ZipExtractor } from './index.js';
4+
import { Location, ProgressListener } from '../util/index.js';
55

66
export class RemoteZipExtractor implements DependencyInstaller {
77
private readonly sequence: InstallerSequence;

src/dependencies/ZipExtractor.ts

+4-4
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
import * as extractZip from 'extract-zip';
1+
import * as extract from 'extract-zip';
22
import * as fs from 'fs-extra';
33

4-
import { Canceled, ConfirmResult, DependencyInstaller, InstallResult, Success } from './';
5-
import { Location, ProgressListener } from '../util';
4+
import { Canceled, ConfirmResult, DependencyInstaller, InstallResult, Success } from './index.js';
5+
import { Location, ProgressListener } from '../util/index.js';
66

77
/** Extracts the zip at the location provided to `install` to a folder named `targetName`. */
88
export class ZipExtractor implements DependencyInstaller {
@@ -29,7 +29,7 @@ export class ZipExtractor implements DependencyInstaller {
2929

3030
let extractedBytes = 0;
3131
let prevEntrySize = 0;
32-
await extractZip(location.basePath, {
32+
await extract.default(location.basePath, {
3333
dir: target.basePath,
3434
onEntry: (entry, zip) => {
3535
extractedBytes += prevEntrySize;

src/dependencies/index.ts

+9-9
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
export * from './Dependency';
2-
export * from './FileDownloader';
3-
export * from './GitHubReleaseAsset';
4-
export * from './GitHubZipExtractor';
5-
export * from './ZipExtractor';
6-
export * from './InstallerSequence';
7-
export * from './InstallResult';
8-
export * from './LocalReference';
9-
export * from './RemoteZipExtractor';
1+
export * from './Dependency.js';
2+
export * from './FileDownloader.js';
3+
export * from './GitHubReleaseAsset.js';
4+
export * from './GitHubZipExtractor.js';
5+
export * from './ZipExtractor.js';
6+
export * from './InstallerSequence.js';
7+
export * from './InstallResult.js';
8+
export * from './LocalReference.js';
9+
export * from './RemoteZipExtractor.js';

src/index.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// exports all modules of this package
22

3-
export * from './dependencies';
4-
export * from './util';
5-
export * from './vscode-util';
3+
export * from './dependencies/index.js';
4+
export * from './util/index.js';
5+
export * from './vscode-util/index.js';

src/test/dependencies.test.ts

+25-26
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,18 @@
1-
import * as path from 'path';
2-
import * as fs from 'fs';
3-
import * as assert from 'assert';
1+
/* eslint-disable import/no-extraneous-dependencies */
2+
import * as path from 'node:path';
3+
import { fileURLToPath } from 'node:url';
4+
import * as fs from 'node:fs';
5+
import * as assert from 'node:assert';
46
import * as md5File from 'md5-file';
57

6-
import { Canceled, ConfirmResult, Dependency, FileDownloader, GitHubReleaseAsset, GitHubZipExtractor, InstallerSequence, LocalReference, Success, ZipExtractor } from '..';
7-
import { withProgressInWindow } from '../vscode-util';
8+
import { Canceled, ConfirmResult, Dependency, FileDownloader, GitHubReleaseAsset, GitHubZipExtractor, InstallerSequence, LocalReference, Success, ZipExtractor } from '../index.js';
9+
import { withProgressInWindow } from '../vscode-util/index.js';
810

911
suite("dependencies", () => {
1012

11-
const PROJECT_ROOT = path.join(__dirname, "../../");
13+
const FILE_NAME = fileURLToPath(import.meta.url); // get the resolved path to the file
14+
const DIRNAME = path.dirname(FILE_NAME); // get the name of the directory
15+
const PROJECT_ROOT = path.join(DIRNAME, "../../");
1216
const TMP_PATH: string = path.join(PROJECT_ROOT, "src", "test", "tmp");
1317
const HTTP_DOWNLOAD_URL: string = "http://viper.ethz.ch/examples/";
1418
const HTTP_DOWNLOAD_TIMEOUT_MS: number = 10 * 1000; // 10s
@@ -20,7 +24,7 @@ suite("dependencies", () => {
2024
const ASSET_OWNER: string = "viperproject";
2125
const ASSET_REPO: string = "vs-verification-toolbox-release-testing";
2226

23-
suiteSetup(function() {
27+
suiteSetup(() => {
2428
// create a tmp directory for downloading files to it
2529
if (!fs.existsSync(TMP_PATH)) {
2630
fs.mkdirSync(TMP_PATH);
@@ -138,10 +142,9 @@ suite("dependencies", () => {
138142
// latest non-pre-release is v1
139143
const md5HashOfExtractedFile = "3cf1da395ac560a38415620e43b0f759"; // md5 of small.bin
140144

141-
function getUrl(): Promise<string> {
142-
return GitHubReleaseAsset.getLatestAssetUrl(
145+
const getUrl = () =>
146+
GitHubReleaseAsset.getLatestAssetUrl(
143147
ASSET_OWNER, ASSET_REPO, assetName, false, getToken());
144-
}
145148

146149
const myDependency = new Dependency<"remote">(
147150
TMP_PATH,
@@ -154,24 +157,22 @@ suite("dependencies", () => {
154157
listener => myDependency.install("remote", true, listener));
155158
// check md5 of this file
156159
if (unzippedDestination instanceof Success) {
157-
const actual: string = await md5File(unzippedDestination.value.child(unzippedFilename).basePath);
160+
const actual: string = await md5File.default(unzippedDestination.value.child(unzippedFilename).basePath);
158161
assert.strictEqual(actual, md5HashOfExtractedFile, `md5 hash does not match for file named '${unzippedFilename}`);
159162
} else {
160-
assert.fail(`expected installation success but got ${unzippedDestination}`)
163+
assert.fail(`expected installation success but got ${unzippedDestination}`);
161164
}
162165
});
163166

164-
function getToken(): string | undefined {
165-
return process.env["GITHUB_TOKEN"];
166-
}
167+
const getToken: () => string | undefined = () => process.env.GITHUB_TOKEN;
167168

168-
async function downloadAndCheckGitHubAsset(url: string, assetName: string, md5Hash: string): Promise<void> {
169+
const downloadAndCheckGitHubAsset: (url: string, assetName: string, md5Hash: string) => Promise<void> = async (url, assetName, md5Hash) => {
169170
const headers: Record<string, string | string[] | undefined> = {
170171
"Accept": "application/octet-stream"
171172
};
172173
const token = getToken();
173-
if (token) {
174-
headers["Authorization"] = `token ${token}`;
174+
if (token != null) {
175+
headers.Authorization = `token ${token}`;
175176
}
176177
const myDependency = new Dependency<"remote">(
177178
TMP_PATH,
@@ -182,33 +183,31 @@ suite("dependencies", () => {
182183
]
183184
);
184185
let confirmCallbackCalls: number = 0;
185-
async function confirm(): Promise<ConfirmResult> {
186+
const confirm: () => Promise<ConfirmResult> = async () => {
186187
confirmCallbackCalls++;
187188
return ConfirmResult.Continue;
188-
}
189+
};
189190
const { result: downloadDestination } = await withProgressInWindow(
190191
`Downloading GitHub asset ${assetName}`,
191192
listener => myDependency.install("remote", true, listener, confirm));
192193
assert.strictEqual(confirmCallbackCalls, 1, `callback to confirm download should only be called once`);
193194
if (downloadDestination instanceof Success) {
194195
// check md5 of this file
195-
const actual: string = await md5File(downloadDestination.value.basePath);
196+
const actual: string = await md5File.default(downloadDestination.value.basePath);
196197
assert.strictEqual(actual, md5Hash, `md5 hash does not match for asset named '${assetName} (downloaded from ${url})`);
197198
} else {
198199
assert.fail(`expected success but got ${downloadDestination}`);
199200
}
200201

201202
// test that installation is aborted if confirmation is canceled:
202-
async function cancelConfirmation(): Promise<ConfirmResult> {
203-
return ConfirmResult.Cancel;
204-
}
203+
const cancelConfirmation: () => Promise<ConfirmResult> = async () => ConfirmResult.Cancel;
205204
const canceledResult = await myDependency.install("remote", true, undefined, cancelConfirmation);
206205
if (!(canceledResult instanceof Canceled)) {
207206
assert.fail(`expected cancellation of installation due to cancel confirmation but got ${canceledResult}`);
208207
}
209-
}
208+
};
210209

211-
suiteTeardown(function() {
210+
suiteTeardown(() => {
212211
// delete tmp directory containing downloaded files:
213212
if (fs.existsSync(TMP_PATH)) {
214213
fs.rmdirSync(TMP_PATH, { recursive: true });

src/test/index.ts

+9-5
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,21 @@
1+
/* eslint-disable import/no-extraneous-dependencies */
12
import { glob } from 'glob';
2-
import * as path from 'path';
3+
import * as path from 'node:path';
4+
import { fileURLToPath } from 'node:url';
35
import * as Mocha from 'mocha';
46

57
// kept as-is (except for the mocha config) from `yo code` extension template
6-
export async function run(): Promise<void> {
8+
export const run: () => Promise<void> = async () => {
79
// Create the mocha test
8-
const mocha = new Mocha({
10+
const mocha = new Mocha.default({
911
ui: 'tdd',
1012
timeout: 2000, // ms
1113
color: true,
1214
});
1315

14-
const testsRoot = path.resolve(__dirname, '..');
16+
const filename = fileURLToPath(import.meta.url); // get the resolved path to the file
17+
const dirname = path.dirname(filename); // get the name of the directory
18+
const testsRoot = path.resolve(dirname, '..');
1519

1620
const files = await glob('**/**.test.js', { cwd: testsRoot });
1721

@@ -32,4 +36,4 @@ export async function run(): Promise<void> {
3236
e(err);
3337
}
3438
});
35-
}
39+
};

0 commit comments

Comments
 (0)