From f9e459bcafd2a6f3b544beed27f198e3c60c62c2 Mon Sep 17 00:00:00 2001 From: Jake Bailey <5341706+jakebailey@users.noreply.github.com> Date: Wed, 26 Aug 2026 20:03:04 -0700 Subject: [PATCH 01/15] Upgrade adm-zip to 0.6.0 --- package-lock.json | 21 +++++---------------- package.json | 3 +-- 2 files changed, 6 insertions(+), 18 deletions(-) diff --git a/package-lock.json b/package-lock.json index 708f5a6411e26..206b7a4831ce0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,12 +12,11 @@ "packages/*" ], "devDependencies": { - "@types/adm-zip": "^0.5.8", "@types/node": "latest", "@types/tmp": "^0.2.6", "@types/which": "^3.0.4", "@unicode/unicode-15.1.0": "^1.6.17", - "adm-zip": "^0.5.17", + "adm-zip": "^0.6.0", "chokidar": "^5.0.0", "dprint": "^0.55.1", "execa": "^9.6.1", @@ -1493,16 +1492,6 @@ "@textlint/ast-node-types": "15.8.0" } }, - "node_modules/@types/adm-zip": { - "version": "0.5.8", - "resolved": "https://registry.npmjs.org/@types/adm-zip/-/adm-zip-0.5.8.tgz", - "integrity": "sha512-RVVH7QvZYbN+ihqZ4kX/dMiowf6o+Jk1fNwiSdx0NahBJLU787zkULhGhJM8mf/obmLGmgdMM0bXsQTmyfbR7Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/node": "*" - } - }, "node_modules/@types/node": { "version": "26.2.0", "resolved": "https://registry.npmjs.org/@types/node/-/node-26.2.0.tgz", @@ -2159,13 +2148,13 @@ ] }, "node_modules/adm-zip": { - "version": "0.5.18", - "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.5.18.tgz", - "integrity": "sha512-ufJnssQGbxzLNS1Ho9bCtX4rQKCCvoVuDLHoJyc3F9dOGDB4BkWs2Ci0kv53lqocAEQ/Cbi+I2XCsNYGqVYqng==", + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.6.0.tgz", + "integrity": "sha512-XleryMhbuksdKtofnWZ9Sk+4CUTbms4Mb/EU32SZwToAyZ5RgVos/ki8n+yr0LWHOGKuakbXTuuYNHLQjhddgg==", "dev": true, "license": "MIT", "engines": { - "node": ">=12.0" + "node": ">=14.0" } }, "node_modules/agent-base": { diff --git a/package.json b/package.json index cde72125317de..6527242043d7c 100644 --- a/package.json +++ b/package.json @@ -24,12 +24,11 @@ "setup-hooks": "node tools/scripts/link-hooks.mjs" }, "devDependencies": { - "@types/adm-zip": "^0.5.8", "@types/node": "latest", "@types/tmp": "^0.2.6", "@types/which": "^3.0.4", "@unicode/unicode-15.1.0": "^1.6.17", - "adm-zip": "^0.5.17", + "adm-zip": "^0.6.0", "chokidar": "^5.0.0", "dprint": "^0.55.1", "execa": "^9.6.1", From daeaa9f74fb2fcb300ecb64e1787d07b7f257809 Mon Sep 17 00:00:00 2001 From: Jake Bailey <5341706+jakebailey@users.noreply.github.com> Date: Wed, 26 Aug 2026 20:03:20 -0700 Subject: [PATCH 02/15] Replace tmp with Node file system APIs --- Herebyfile.mjs | 9 ++++----- package-lock.json | 9 --------- package.json | 2 -- 3 files changed, 4 insertions(+), 16 deletions(-) diff --git a/Herebyfile.mjs b/Herebyfile.mjs index 361b819ba9240..32b69c941d65e 100644 --- a/Herebyfile.mjs +++ b/Herebyfile.mjs @@ -15,7 +15,6 @@ import { parseArgs } from "node:util"; import pLimit from "p-limit"; import pc from "picocolors"; import * as tar from "tar"; -import tmp from "tmp"; import which from "which"; if (process.platform === "win32") { @@ -739,9 +738,9 @@ async function runTests() { let cleanupTracking; if (baselineTrackingEnabled) { - const tmpDir = tmp.dirSync({ prefix: "tsgo-baseline-tracking-", unsafeCleanup: true }); - trackingDir = tmpDir.name; - cleanupTracking = tmpDir.removeCallback; + const tempTrackingDir = fs.mkdtempSync(path.join(os.tmpdir(), "tsgo-baseline-tracking-")); + trackingDir = tempTrackingDir; + cleanupTracking = () => rimraf(tempTrackingDir); } try { @@ -778,7 +777,7 @@ async function runTests() { } finally { if (cleanupTracking) { - cleanupTracking(); + await cleanupTracking(); } } } diff --git a/package-lock.json b/package-lock.json index 206b7a4831ce0..a9fbf30a15db5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,7 +13,6 @@ ], "devDependencies": { "@types/node": "latest", - "@types/tmp": "^0.2.6", "@types/which": "^3.0.4", "@unicode/unicode-15.1.0": "^1.6.17", "adm-zip": "^0.6.0", @@ -25,7 +24,6 @@ "p-limit": "^7.3.0", "picocolors": "^1.1.1", "tar": "^7.5.19", - "tmp": "^0.2.7", "typescript": "^6.0.3", "which": "^6.0.1" }, @@ -1516,13 +1514,6 @@ "dev": true, "license": "MIT" }, - "node_modules/@types/tmp": { - "version": "0.2.6", - "resolved": "https://registry.npmjs.org/@types/tmp/-/tmp-0.2.6.tgz", - "integrity": "sha512-chhaNf2oKHlRkDGt+tiKE2Z5aJ6qalm7Z9rlLdBwmOiAAf09YQvvoLXjWK4HWPF1xU/fqvMgfNfpVoBscA/tKA==", - "dev": true, - "license": "MIT" - }, "node_modules/@types/vscode": { "version": "1.125.0", "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.125.0.tgz", diff --git a/package.json b/package.json index 6527242043d7c..0350d04d0cef7 100644 --- a/package.json +++ b/package.json @@ -25,7 +25,6 @@ }, "devDependencies": { "@types/node": "latest", - "@types/tmp": "^0.2.6", "@types/which": "^3.0.4", "@unicode/unicode-15.1.0": "^1.6.17", "adm-zip": "^0.6.0", @@ -37,7 +36,6 @@ "p-limit": "^7.3.0", "picocolors": "^1.1.1", "tar": "^7.5.19", - "tmp": "^0.2.7", "typescript": "^6.0.3", "which": "^6.0.1" }, From e97886ca9cdfb98009d76de604ba0906a7e77ccb Mon Sep 17 00:00:00 2001 From: Jake Bailey <5341706+jakebailey@users.noreply.github.com> Date: Wed, 26 Aug 2026 20:03:50 -0700 Subject: [PATCH 03/15] Use default Node type stripping --- package-lock.json | 2 +- package.json | 2 +- packages/typescript/package.json | 4 ++-- packages/typescript/scripts/generateSync.ts | 4 ++-- tools/scripts/tsc/generate-encoder.ts | 2 +- tools/scripts/tsc/generate-go-ast.ts | 2 +- tools/scripts/tsc/generate-ts-ast.ts | 2 +- tsc/internal/lsp/lsproto/_generate/fetchModel.mts | 4 ++-- tsc/internal/lsp/lsproto/_generate/generate.mts | 4 ++-- tsc/internal/stringutil/_scripts/generate-unicode-data.mts | 2 +- tsc/internal/stringutil/generate.go | 2 +- 11 files changed, 15 insertions(+), 15 deletions(-) diff --git a/package-lock.json b/package-lock.json index a9fbf30a15db5..96bbf3cd499b0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -28,7 +28,7 @@ "which": "^6.0.1" }, "engines": { - "node": ">=20.19" + "node": ">=22.18" } }, "node_modules/@azu/format-text": { diff --git a/package.json b/package.json index 0350d04d0cef7..c75a468180fc5 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,7 @@ "version": "0.0.0", "license": "Apache-2.0", "engines": { - "node": ">=20.19" + "node": ">=22.18" }, "workspaces": [ "packages/*" diff --git a/packages/typescript/package.json b/packages/typescript/package.json index 1cd3718a07ae6..8f9af6510f958 100644 --- a/packages/typescript/package.json +++ b/packages/typescript/package.json @@ -96,9 +96,9 @@ "#vscode-jsonrpc/node": "./vendor/vscode-jsonrpc/lib/node/main.js" }, "scripts": { - "node": "node --experimental-strip-types --no-warnings --conditions @typescript/source", + "node": "node --conditions @typescript/source", "generate": "npm run generate:ast && npm run generate:encoder && npm run generate:sync", - "generate:ast": "node --experimental-strip-types --no-warnings ../../tools/scripts/tsc/generate-ts-ast.ts", + "generate:ast": "node ../../tools/scripts/tsc/generate-ts-ast.ts", "generate:encoder": "npm run node -- ../../tools/scripts/tsc/generate-encoder.ts", "generate:sync": "npm run node -- scripts/generateSync.ts", "build": "tsc -b", diff --git a/packages/typescript/scripts/generateSync.ts b/packages/typescript/scripts/generateSync.ts index ec1cd8584ca02..751000df9b06f 100755 --- a/packages/typescript/scripts/generateSync.ts +++ b/packages/typescript/scripts/generateSync.ts @@ -1,4 +1,4 @@ -#!/usr/bin/env -S node --experimental-strip-types --no-warnings +#!/usr/bin/env node /** * Generates sync API from async API source files. @@ -18,7 +18,7 @@ * - Unwrap `Promise` → `T` in type references * * Usage: - * node --experimental-strip-types --no-warnings generateSync.ts + * node generateSync.ts */ import { execaSync } from "execa"; diff --git a/tools/scripts/tsc/generate-encoder.ts b/tools/scripts/tsc/generate-encoder.ts index fc1a67022a39d..b0951ab5a0da7 100644 --- a/tools/scripts/tsc/generate-encoder.ts +++ b/tools/scripts/tsc/generate-encoder.ts @@ -2,7 +2,7 @@ * Encoder/decoder code generator: reads tools/scripts/tsc/ast.json and produces binary * encoding/decoding code for Go and TypeScript. * - * Usage: node --experimental-strip-types tools/scripts/tsc/generate-encoder.ts + * Usage: node tools/scripts/tsc/generate-encoder.ts * * Generates: * - internal/api/encoder/encoder_generated.go diff --git a/tools/scripts/tsc/generate-go-ast.ts b/tools/scripts/tsc/generate-go-ast.ts index b64a685d90d67..b03089208c4ac 100644 --- a/tools/scripts/tsc/generate-go-ast.ts +++ b/tools/scripts/tsc/generate-go-ast.ts @@ -1,7 +1,7 @@ /** * Go AST code generator: reads tools/scripts/tsc/ast.json and produces internal/ast/ast_generated.go * - * Usage: node --experimental-strip-types tools/scripts/tsc/generate-go-ast.ts + * Usage: node tools/scripts/tsc/generate-go-ast.ts * * Generates: * - Struct definitions for each node kind diff --git a/tools/scripts/tsc/generate-ts-ast.ts b/tools/scripts/tsc/generate-ts-ast.ts index 753c7286ae094..fee099d29dab2 100644 --- a/tools/scripts/tsc/generate-ts-ast.ts +++ b/tools/scripts/tsc/generate-ts-ast.ts @@ -5,7 +5,7 @@ * - packages/typescript/src/ast/factory.generated.ts * - packages/typescript/src/ast/is.generated.ts * - * Usage: node --experimental-strip-types tools/scripts/tsc/generate-ts-ast.ts + * Usage: node tools/scripts/tsc/generate-ts-ast.ts */ import { execaSync } from "execa"; diff --git a/tsc/internal/lsp/lsproto/_generate/fetchModel.mts b/tsc/internal/lsp/lsproto/_generate/fetchModel.mts index 21957cfe5a607..ee3a9111d1441 100755 --- a/tsc/internal/lsp/lsproto/_generate/fetchModel.mts +++ b/tsc/internal/lsp/lsproto/_generate/fetchModel.mts @@ -1,6 +1,6 @@ -#!/usr/bin/env -S node --experimental-strip-types +#!/usr/bin/env node -// Usage: node --experimental-strip-types fetchModel.mts +// Usage: node fetchModel.mts import fs from "node:fs"; import path from "node:path"; diff --git a/tsc/internal/lsp/lsproto/_generate/generate.mts b/tsc/internal/lsp/lsproto/_generate/generate.mts index b8466ff18d705..9849d29f41d2b 100755 --- a/tsc/internal/lsp/lsproto/_generate/generate.mts +++ b/tsc/internal/lsp/lsproto/_generate/generate.mts @@ -1,6 +1,6 @@ -#!/usr/bin/env -S node --experimental-strip-types +#!/usr/bin/env node -// Usage: node --experimental-strip-types generate.mts +// Usage: node generate.mts import { $ } from "execa"; import fs from "node:fs"; diff --git a/tsc/internal/stringutil/_scripts/generate-unicode-data.mts b/tsc/internal/stringutil/_scripts/generate-unicode-data.mts index bd726d68026d5..0353b2141aae1 100644 --- a/tsc/internal/stringutil/_scripts/generate-unicode-data.mts +++ b/tsc/internal/stringutil/_scripts/generate-unicode-data.mts @@ -1,4 +1,4 @@ -#!/usr/bin/env -S node --experimental-strip-types --no-warnings +#!/usr/bin/env node import * as fs from "fs"; import * as path from "path"; diff --git a/tsc/internal/stringutil/generate.go b/tsc/internal/stringutil/generate.go index 3c5ad7ad481fe..196e2d59e3904 100644 --- a/tsc/internal/stringutil/generate.go +++ b/tsc/internal/stringutil/generate.go @@ -1,4 +1,4 @@ package stringutil -//go:generate node --experimental-strip-types --no-warnings ./_scripts/generate-unicode-data.mts +//go:generate node ./_scripts/generate-unicode-data.mts //go:generate npx dprint fmt js_case_generated.go identifier_parts_generated.go From 3415eada2833f7530246aeaac67647318570ad7e Mon Sep 17 00:00:00 2001 From: Jake Bailey <5341706+jakebailey@users.noreply.github.com> Date: Wed, 26 Aug 2026 20:04:21 -0700 Subject: [PATCH 04/15] Replace glob with Node file system APIs --- Herebyfile.mjs | 33 +++++++++++++++++++++++---------- package-lock.json | 1 - package.json | 1 - 3 files changed, 23 insertions(+), 12 deletions(-) diff --git a/Herebyfile.mjs b/Herebyfile.mjs index 32b69c941d65e..2eb3af7394195 100644 --- a/Herebyfile.mjs +++ b/Herebyfile.mjs @@ -3,7 +3,6 @@ import AdmZip from "adm-zip"; import chokidar from "chokidar"; import { $ as _$ } from "execa"; -import { glob } from "glob"; import { task } from "hereby"; import assert from "node:assert"; import crypto from "node:crypto"; @@ -141,6 +140,22 @@ function memoize(fn) { }; } +/** + * @param {string} pattern + * @param {string[]} [exclude] + */ +async function globFiles(pattern, exclude) { + const files = []; + const absolute = path.isAbsolute(pattern); + for await (const entry of fs.promises.glob(pattern, { exclude, withFileTypes: true })) { + if (entry.isFile()) { + const file = path.join(entry.parentPath, entry.name); + files.push(absolute ? file : path.relative(process.cwd(), file)); + } + } + return files; +} + const tools = new Map([ ["gotest.tools/gotestsum", "latest"], ]); @@ -700,7 +715,7 @@ async function checkUnusedBaselines(trackingDir) { return []; } - const allBaselines = await glob(`${refBaseline}/**`, { nodir: true }); + const allBaselines = await globFiles(`${refBaseline}/**`); const unusedBaselines = allBaselines .map(p => path.relative(refBaseline, p)) .filter(p => !usedBaselines.has(p)); @@ -889,15 +904,13 @@ const golangciLintPackage = memoize(() => { }); const customlintHash = memoize(() => { - const files = glob.sync([ + const files = fs.globSync([ "./tools/go.mod", "./tools/customlint/**/*", "./.custom-gcl.yml", ], { - ignore: "**/testdata/**", - nodir: true, - absolute: true, - }); + exclude: ["**/testdata/**"], + }).filter(file => fs.statSync(file).isFile()).map(file => path.resolve(file)); files.sort(); const hash = crypto.createHash("sha256"); @@ -1008,13 +1021,13 @@ function baselineAcceptTask(localBaseline, refBaseline) { } return async () => { - const toCopy = await glob(`${localBaseline}/**`, { nodir: true, ignore: `${localBaseline}/**/*.delete` }); + const toCopy = await globFiles(`${localBaseline}/**`, [`${localBaseline}/**/*.delete`]); for (const p of toCopy) { const out = localPathToRefPath(p); await fs.promises.mkdir(path.dirname(out), { recursive: true }); await fs.promises.copyFile(p, out); } - const toDelete = await glob(`${localBaseline}/**/*.delete`, { nodir: true }); + const toDelete = await globFiles(`${localBaseline}/**/*.delete`); for (const p of toDelete) { const out = localPathToRefPath(p).replace(/\.delete$/, ""); await rimraf(out); @@ -1934,7 +1947,7 @@ async function runBuildNativePreviewPackages() { await cpRecursive(path.join(inputDir, "dist"), path.join(mainPackageDir, "dist")); // Validate that .d.ts files contain no external imports (all imports must start with "." or "#"). - const dtsFiles = await glob(`${mainPackageDir}/dist/**/*.d.ts`); + const dtsFiles = await globFiles(`${mainPackageDir}/dist/**/*.d.ts`); const importErrors = []; for (const dtsFile of dtsFiles) { const content = await fs.promises.readFile(dtsFile, "utf-8"); diff --git a/package-lock.json b/package-lock.json index 96bbf3cd499b0..39653aff6c957 100644 --- a/package-lock.json +++ b/package-lock.json @@ -19,7 +19,6 @@ "chokidar": "^5.0.0", "dprint": "^0.55.1", "execa": "^9.6.1", - "glob": "^13.0.6", "hereby": "^1.15.1", "p-limit": "^7.3.0", "picocolors": "^1.1.1", diff --git a/package.json b/package.json index c75a468180fc5..a04239e99b872 100644 --- a/package.json +++ b/package.json @@ -31,7 +31,6 @@ "chokidar": "^5.0.0", "dprint": "^0.55.1", "execa": "^9.6.1", - "glob": "^13.0.6", "hereby": "^1.15.1", "p-limit": "^7.3.0", "picocolors": "^1.1.1", From 437664848b0aec42cae463b331b0b566eb1122d8 Mon Sep 17 00:00:00 2001 From: Jake Bailey <5341706+jakebailey@users.noreply.github.com> Date: Wed, 26 Aug 2026 20:04:48 -0700 Subject: [PATCH 05/15] Replace picocolors with Node styleText --- Herebyfile.mjs | 24 +++++++++++++----------- package-lock.json | 1 - package.json | 1 - 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/Herebyfile.mjs b/Herebyfile.mjs index 2eb3af7394195..6ef48403281bf 100644 --- a/Herebyfile.mjs +++ b/Herebyfile.mjs @@ -10,9 +10,11 @@ import fs from "node:fs"; import os from "node:os"; import path from "node:path"; import url from "node:url"; -import { parseArgs } from "node:util"; +import { + parseArgs, + styleText, +} from "node:util"; import pLimit from "p-limit"; -import pc from "picocolors"; import * as tar from "tar"; import which from "which"; @@ -770,12 +772,12 @@ async function runTests() { if (trackingDir) { const unusedBaselines = await checkUnusedBaselines(trackingDir); if (unusedBaselines.length > 0) { - console.error(pc.red(`\nFound ${unusedBaselines.length} unused baseline file(s):`)); + console.error(styleText("red", `\nFound ${unusedBaselines.length} unused baseline file(s):`)); for (const baseline of unusedBaselines.slice(0, 20)) { - console.error(pc.red(` ${baseline}`)); + console.error(styleText("red", ` ${baseline}`)); } if (unusedBaselines.length > 20) { - console.error(pc.red(` ... and ${unusedBaselines.length - 20} more`)); + console.error(styleText("red", ` ... and ${unusedBaselines.length - 20} more`)); } // Create .delete files for each unused baseline so baseline-accept can remove them @@ -784,7 +786,7 @@ async function runTests() { await fs.promises.mkdir(path.dirname(deleteFilePath), { recursive: true }); await fs.promises.writeFile(deleteFilePath, ""); } - console.error(pc.red(`\nRun 'hereby baseline-accept' to delete them.`)); + console.error(styleText("red", `\nRun 'hereby baseline-accept' to delete them.`)); throw new Error(`Found ${unusedBaselines.length} unused baseline file(s). Run 'hereby baseline-accept' to delete them.`); } @@ -1121,7 +1123,7 @@ async function watchDebounced(name, run, options) { running = false; } if (watching) { - console.log(pc.yellowBright(`[${name}] run complete, waiting for changes...`)); + console.log(styleText("yellowBright", `[${name}] run complete, waiting for changes...`)); await promise; } } @@ -1155,9 +1157,9 @@ async function watchDebounced(name, run, options) { */ function beginRun(path) { if (debouncer.empty) { - console.log(pc.yellowBright(`[${name}] changed due to '${path}', restarting...`)); + console.log(styleText("yellowBright", `[${name}] changed due to '${path}', restarting...`)); if (running) { - console.log(pc.yellowBright(`[${name}] aborting in-progress run...`)); + console.log(styleText("yellowBright", `[${name}] aborting in-progress run...`)); } abortController.abort(); abortController = new AbortController(); @@ -1177,7 +1179,7 @@ async function watchDebounced(name, run, options) { function endWatchMode() { if (watching) { watching = false; - console.log(pc.yellowBright(`[${name}] exiting watch mode...`)); + console.log(styleText("yellowBright", `[${name}] exiting watch mode...`)); abortController.abort(); watcher.close(); } @@ -1328,7 +1330,7 @@ async function sign(filelist, unchangedOutputOkay = false) { console.log("filelist:", data); if (!process.env.MBSIGN_APPFOLDER) { - console.log(pc.yellow("Faking signing because MBSIGN_APPFOLDER is not set.")); + console.log(styleText("yellow", "Faking signing because MBSIGN_APPFOLDER is not set.")); // Fake signing for testing. diff --git a/package-lock.json b/package-lock.json index 39653aff6c957..84443c1f15e0b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -21,7 +21,6 @@ "execa": "^9.6.1", "hereby": "^1.15.1", "p-limit": "^7.3.0", - "picocolors": "^1.1.1", "tar": "^7.5.19", "typescript": "^6.0.3", "which": "^6.0.1" diff --git a/package.json b/package.json index a04239e99b872..be9da51f785ac 100644 --- a/package.json +++ b/package.json @@ -33,7 +33,6 @@ "execa": "^9.6.1", "hereby": "^1.15.1", "p-limit": "^7.3.0", - "picocolors": "^1.1.1", "tar": "^7.5.19", "typescript": "^6.0.3", "which": "^6.0.1" From a6de9b7375cac508ef5d35a44ddcacc22b07b502 Mon Sep 17 00:00:00 2001 From: Jake Bailey <5341706+jakebailey@users.noreply.github.com> Date: Wed, 26 Aug 2026 20:22:01 -0700 Subject: [PATCH 06/15] Replace p-limit with local concurrency helper --- Herebyfile.mjs | 31 ++++++++++++++++++++++++++++--- package-lock.json | 30 ------------------------------ package.json | 1 - 3 files changed, 28 insertions(+), 34 deletions(-) diff --git a/Herebyfile.mjs b/Herebyfile.mjs index 6ef48403281bf..c7b009ae97aea 100644 --- a/Herebyfile.mjs +++ b/Herebyfile.mjs @@ -14,7 +14,6 @@ import { parseArgs, styleText, } from "node:util"; -import pLimit from "p-limit"; import * as tar from "tar"; import which from "which"; @@ -158,6 +157,33 @@ async function globFiles(pattern, exclude) { return files; } +/** + * @param {(() => Promise)[]} tasks + * @param {number} concurrency + */ +async function runWithConcurrencyLimit(tasks, concurrency) { + const queue = tasks.values(); + /** @type {unknown[]} */ + const errors = []; + const workers = Array.from({ length: Math.min(concurrency, tasks.length) }, async () => { + for (const task of queue) { + try { + await task(); + } + catch (error) { + errors.push(error); + } + } + }); + await Promise.all(workers); + if (errors.length === 1) { + throw errors[0]; + } + if (errors.length > 1) { + throw new AggregateError(errors, `${errors.length} concurrent tasks failed`); + } +} + const tools = new Map([ ["gotest.tools/gotestsum", "latest"], ]); @@ -2022,8 +2048,7 @@ async function runBuildNativePreviewPackages() { } } else { - const buildLimit = pLimit(os.availableParallelism()); - await Promise.all(platformBuilders.map(f => buildLimit(f))); + await runWithConcurrencyLimit(platformBuilders, os.availableParallelism()); } } diff --git a/package-lock.json b/package-lock.json index 84443c1f15e0b..880f419058180 100644 --- a/package-lock.json +++ b/package-lock.json @@ -20,7 +20,6 @@ "dprint": "^0.55.1", "execa": "^9.6.1", "hereby": "^1.15.1", - "p-limit": "^7.3.0", "tar": "^7.5.19", "typescript": "^6.0.3", "which": "^6.0.1" @@ -4350,22 +4349,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/p-limit": { - "version": "7.3.1", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-7.3.1.tgz", - "integrity": "sha512-0trZaiG7Y7kN/Egy9a8j47t9osC0Tch4PaIWd9yGF6bvmlk7muExRvGNYb8sXBwEKMoNKsbNN9P8EefuQekE4Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "yocto-queue": "^1.2.1" - }, - "engines": { - "node": ">=20" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/p-map": { "version": "7.0.6", "resolved": "https://registry.npmjs.org/p-map/-/p-map-7.0.6.tgz", @@ -5782,19 +5765,6 @@ "buffer-crc32": "~0.2.3" } }, - "node_modules/yocto-queue": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.2.2.tgz", - "integrity": "sha512-4LCcse/U2MHZ63HAJVE+v71o7yOdIe4cZ70Wpf8D/IyjDKYQLV5GD46B+hSTjJsvV5PztjvHoU580EftxjDZFQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12.20" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/yoctocolors": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/yoctocolors/-/yoctocolors-2.2.0.tgz", diff --git a/package.json b/package.json index be9da51f785ac..ac341cf0c3955 100644 --- a/package.json +++ b/package.json @@ -32,7 +32,6 @@ "dprint": "^0.55.1", "execa": "^9.6.1", "hereby": "^1.15.1", - "p-limit": "^7.3.0", "tar": "^7.5.19", "typescript": "^6.0.3", "which": "^6.0.1" From 4632a94aad96bb004e5feb001df444f12736f1a5 Mon Sep 17 00:00:00 2001 From: Jake Bailey <5341706+jakebailey@users.noreply.github.com> Date: Wed, 26 Aug 2026 20:41:49 -0700 Subject: [PATCH 07/15] Replace execa with tinyexec --- Herebyfile.mjs | 150 ++++++--- package-lock.json | 310 +----------------- package.json | 2 +- packages/typescript/scripts/generateSync.ts | 4 +- tools/scripts/tsc/generate-encoder.ts | 7 +- tools/scripts/tsc/generate-go-ast.ts | 7 +- tools/scripts/tsc/generate-ts-ast.ts | 7 +- .../lsp/lsproto/_generate/generate.mts | 7 +- 8 files changed, 137 insertions(+), 357 deletions(-) diff --git a/Herebyfile.mjs b/Herebyfile.mjs index c7b009ae97aea..10ed5fb6a9119 100644 --- a/Herebyfile.mjs +++ b/Herebyfile.mjs @@ -2,7 +2,6 @@ import AdmZip from "adm-zip"; import chokidar from "chokidar"; -import { $ as _$ } from "execa"; import { task } from "hereby"; import assert from "node:assert"; import crypto from "node:crypto"; @@ -15,6 +14,7 @@ import { styleText, } from "node:util"; import * as tar from "tar"; +import { x } from "tinyexec"; import which from "which"; if (process.platform === "win32") { @@ -26,8 +26,48 @@ const __dirname = path.dirname(__filename); const isCI = !!process.env.CI || !!process.env.TF_BUILD; -const $pipe = _$({ verbose: "short" }); -const $ = _$({ verbose: "short", stdio: "inherit" }); +/** + * @typedef {{ + * captureOutput?: boolean; + * cwd?: string; + * env?: NodeJS.ProcessEnv; + * signal?: AbortSignal; + * }} RunOptions + */ + +/** + * @param {string} arg + */ +function formatCommandArg(arg) { + return arg && /^[\w@%+=:,./-]+$/.test(arg) ? arg : JSON.stringify(arg); +} + +/** + * @param {string} command + * @param {readonly string[]} [args] + * @param {RunOptions} [options] + */ +function run(command, args = [], options = {}) { + console.log("$ " + [command, ...args].map(formatCommandArg).join(" ")); + return x(command, args, { + throwOnError: true, + ...(options.signal ? { signal: options.signal } : {}), + nodeOptions: { + cwd: options.cwd, + env: options.env ? { ...process.env, ...options.env } : undefined, + stdio: options.captureOutput ? "pipe" : "inherit", + }, + }); +} + +/** + * @param {string} command + * @param {readonly string[]} [args] + * @param {Omit} [options] + */ +function runOutput(command, args, options) { + return run(command, args, { ...options, captureOutput: true }); +} /** * @param {string} name @@ -243,7 +283,11 @@ function buildTsc(opts) { opts ||= {}; const out = opts.out ?? path.resolve("./built/local/tsc" + (process.platform === "win32" ? ".exe" : "")); const env = { ...goBuildEnv, ...opts.env }; - return $({ cancelSignal: opts.abortSignal, env, cwd: "./tsc" })`go build ${goBuildFlags} ${opts.extraFlags ?? []} ${goBuildTags("noembed")} -o ${out} ./cmd/tsc`; + return run("go", ["build", ...goBuildFlags, ...(opts.extraFlags ?? []), ...goBuildTags("noembed"), "-o", out, "./cmd/tsc"], { + signal: opts.abortSignal, + env, + cwd: "./tsc", + }); } export const tscBuild = task({ @@ -321,7 +365,7 @@ export const generate = task({ name: "generate", description: "Runs go generate on the project.", run: async () => { - await $({ cwd: "./tsc" })`go generate -v ./...`; + await run("go", ["generate", "-v", "./..."], { cwd: "./tsc" }); }, }); @@ -329,7 +373,7 @@ export const generateExtension = task({ name: "generate:extension", description: "Generates files in the extension", run: async () => { - await $`npm run -w native-preview generateLocBundle`; + await run("npm", ["run", "-w", "native-preview", "generateLocBundle"]); }, }); @@ -601,7 +645,7 @@ async function runGenerateEnums() { console.log(` ${def.name}: ${members.length} members → ${camelName}.enum.ts, ${camelName}.ts`); } - await $`dprint fmt ${generatedFiles}`; + await run("dprint", ["fmt", ...generatedFiles]); console.log("Done."); } @@ -614,15 +658,15 @@ export const generateEnums = task({ export const generateAST = task({ name: "generate:ast", description: "Generates AST and encoder files from ast.json.", - run: () => $`node --experimental-strip-types --no-warnings ./tools/scripts/tsc/generate.ts`, + run: () => run("node", ["./tools/scripts/tsc/generate.ts"]), }); export const generateAPI = task({ name: "generate:api", description: "Generates API files from internal/api/proto.go and internal/api/session.go.", run: async () => { - await $`go -C ./tools run ./gen-proto ../tsc/internal/api/proto.go ../packages/typescript/src/api/proto.generated.ts`; - await $`npx dprint fmt packages/typescript/src/api/proto.generated.ts`; + await run("go", ["-C", "./tools", "run", "./gen-proto", "../tsc/internal/api/proto.go", "../packages/typescript/src/api/proto.generated.ts"]); + await run("npx", ["dprint", "fmt", "packages/typescript/src/api/proto.generated.ts"]); }, }); @@ -751,8 +795,6 @@ async function checkUnusedBaselines(trackingDir) { return unusedBaselines; } -const $test = $({ env: goTestEnv, cwd: "./tsc" }); - /** * @param {string} taskName */ @@ -777,7 +819,7 @@ async function runTests() { // Create a tmp directory for baseline tracking if enabled /** @type {string | undefined} */ let trackingDir; - /** @type {(() => void) | undefined} */ + /** @type {(() => Promise) | undefined} */ let cleanupTracking; if (baselineTrackingEnabled) { @@ -791,8 +833,11 @@ async function runTests() { ...goTestEnv, ...(trackingDir ? { TSGO_BASELINE_TRACKING_DIR: trackingDir } : {}), }; - const $testWithTracking = $({ env: testEnv, cwd: "./tsc" }); - await $testWithTracking`${gotestsum("tests")} ./... ${isCI ? ["--timeout=45m"] : []}`; + const command = gotestsum("tests"); + await run(command[0], [...command.slice(1), "./...", ...(isCI ? ["--timeout=45m"] : [])], { + env: testEnv, + cwd: "./tsc", + }); // Check for unused baselines after tests complete if (trackingDir) { @@ -826,7 +871,7 @@ async function runTests() { } async function runTestExtension() { - await $`npm test -w native-preview`; + await run("npm", ["test", "-w", "native-preview"]); } export const testTsc = task({ @@ -846,7 +891,8 @@ export const test = task({ async function runTestBenchmarks() { // Run the benchmarks once to ensure they compile and run without errors. - await $test`${goTest("benchmarks")} -run=- -bench=. -benchtime=1x ./...`; + const command = goTest("benchmarks"); + await run(command[0], [...command.slice(1), "-run=-", "-bench=.", "-benchtime=1x", "./..."], { env: goTestEnv, cwd: "./tsc" }); } export const testBenchmarks = task({ @@ -856,12 +902,13 @@ export const testBenchmarks = task({ }); async function runTestTools() { - await $test({ cwd: path.join(__dirname, "tools") })`${gotestsum("tools")} ./...`; + const command = gotestsum("tools"); + await run(command[0], [...command.slice(1), "./..."], { env: goTestEnv, cwd: path.join(__dirname, "tools") }); } async function runTestAPI() { - // await $`npm run -w @typescript/typescript test:only`; // doesn't work on windows - some path escaping isn't done correctly, test runner runs no tests - await _$({ verbose: "short", stdio: "inherit", cwd: "./packages/typescript" })`node --experimental-strip-types --no-warnings --conditions @typescript/source --test ./test/**/*.test.ts`; + // Running the package script doesn't work on Windows; some path escaping isn't done correctly and the test runner runs no tests. + await run("node", ["--conditions", "@typescript/source", "--test", "./test/**/*.test.ts"], { cwd: "./packages/typescript" }); } export const testTools = task({ @@ -880,7 +927,7 @@ export const buildAPI = task({ name: "build:api", description: "Builds @typescript/typescript JS API.", run: async () => { - await $`npm run -w @typescript/typescript build`; + await run("npm", ["run", "-w", "@typescript/typescript", "build"]); }, }); @@ -889,7 +936,7 @@ export const buildAPITests = task({ description: "Builds the @typescript/typescript JS API tests.", dependencies: [generateEnums, generateAPI], run: async () => { - await $`npm run -w @typescript/typescript build:test`; + await run("npm", ["run", "-w", "@typescript/typescript", "build:test"]); }, }); @@ -961,8 +1008,8 @@ const buildCustomLinter = memoize(async () => { return; } - await $`go run ${golangciLintPackage()} custom`; - await $`${customLinterPath} cache clean`; + await run("go", ["run", golangciLintPackage(), "custom"]); + await run(customLinterPath, ["cache", "clean"]); fs.writeFileSync(customLinterHashPath, hash); }); @@ -985,9 +1032,9 @@ async function runLint() { } const resolvedCustomLinterPath = path.resolve(customLinterPath); - await $({ cwd: "./tsc" })`${resolvedCustomLinterPath} ${lintArgs} --config ../.golangci.yml`; + await run(resolvedCustomLinterPath, [...lintArgs, "--config", "../.golangci.yml"], { cwd: "./tsc" }); console.log("Linting tools"); - await $({ cwd: "./tools" })`${resolvedCustomLinterPath} ${lintArgs} --config ../.golangci.yml`; + await run(resolvedCustomLinterPath, [...lintArgs, "--config", "../.golangci.yml"], { cwd: "./tools" }); } export const installTools = task({ @@ -995,7 +1042,7 @@ export const installTools = task({ description: "Installs optional tools for developing within the repo.", run: async () => { await Promise.all([ - ...[...tools].map(([tool, version]) => $`go install ${tool}${version ? `@${version}` : ""}`), + ...[...tools].map(([tool, version]) => run("go", ["install", tool + (version ? `@${version}` : "")])), buildCustomLinter(), ]); }, @@ -1008,14 +1055,14 @@ export const format = task({ }); async function runFormat() { - await $`dprint fmt`; + await run("dprint", ["fmt"]); } export const checkFormat = task({ name: "check:format", description: "Checks that the repo is formatted.", run: async () => { - await $`dprint check`; + await run("dprint", ["check"]); }, }); @@ -1030,7 +1077,7 @@ export const checkScripts = task({ run: async () => { for (const tsconfig of scriptTsconfigs) { console.log(`Type-checking ${tsconfig}`); - await $`tsc -p ${tsconfig}`; + await run("tsc", ["-p", tsconfig]); } }, }); @@ -1085,7 +1132,7 @@ function getDiffTool() { export const diff = task({ name: "diff", description: "Diffs baselines using the diff tool specified by the 'DIFF' environment variable", - run: () => $`${getDiffTool()} ${refBaseline} ${localBaseline}`, + run: () => run(getDiffTool(), [refBaseline, localBaseline]), }); /** @@ -1467,7 +1514,7 @@ async function sign(filelist, unchangedOutputOkay = false) { try { const dll = path.join(process.env.MBSIGN_APPFOLDER, "DDSignFiles.dll"); const filelistFlag = `/filelist:${filelistPath}`; - await $`dotnet ${dll} -- ${filelistFlag}`; + await run("dotnet", [dll, "--", filelistFlag]); } finally { await fs.promises.unlink(filelistPath); @@ -1823,7 +1870,7 @@ function goDistTargetToPlatform(target) { } async function runCheckPlatforms() { - const { stdout } = await $pipe`go tool dist list -json`; + const { stdout } = await runOutput("go", ["tool", "dist", "list", "-json"]); /** @type {GoDistTarget[]} */ const goTargets = JSON.parse(stdout); const goTargetSet = new Set(goTargets.map(({ GOOS, GOARCH }) => `${GOOS}/${GOARCH}`)); @@ -1940,8 +1987,8 @@ async function runBuildNativePreviewPackages() { } stripSourceConditions(inputPackageJson); - const { stdout: gitHead } = await $pipe`git rev-parse HEAD`; - inputPackageJson.gitHead = gitHead; + const { stdout: gitHead } = await runOutput("git", ["rev-parse", "HEAD"]); + inputPackageJson.gitHead = gitHead.trim(); inputPackageJson.publishConfig = { access: "public", tag: getPublishTag(), @@ -1971,7 +2018,7 @@ async function runBuildNativePreviewPackages() { await fs.promises.copyFile("NOTICE.txt", path.join(mainPackageDir, "NOTICE.txt")); // Build JS API and copy dist into the package. - await $`npm run -w @typescript/typescript build`; + await run("npm", ["run", "-w", "@typescript/typescript", "build"]); await cpRecursive(path.join(inputDir, "dist"), path.join(mainPackageDir, "dist")); // Validate that .d.ts files contain no external imports (all imports must start with "." or "#"). @@ -2044,7 +2091,7 @@ async function runBuildNativePreviewPackages() { await build(); // Build machines have too little space. // Clear the Go build cache between platforms. - await $`go clean -cache`; + await run("go", ["clean", "-cache"]); } } else { @@ -2126,7 +2173,7 @@ async function runSignNativePreviewPackages() { // along with a notarization step. for (const p of filelistPaths) { // ESRP preserves entitlements from an existing ad-hoc signature. - await $pipe`go -C ./tools run ./cmd/machotool sign ${typescriptMacEntitlementsPath} ${p.path}`; + await runOutput("go", ["-C", "./tools", "run", "./cmd/machotool", "sign", typescriptMacEntitlementsPath, p.path]); const unsignedZipPath = path.join(tmp, `${p.tmpName}.unsigned.zip`); const signedZipPath = path.join(tmp, `${p.tmpName}.signed.zip`); @@ -2187,7 +2234,7 @@ async function runSignNativePreviewPackages() { for (const p of macZips) { await fs.promises.chmod(p.path, 0o755); - await $pipe`go -C ./tools run ./cmd/machotool verify ${typescriptMacEntitlementsPath} ${p.path}`; + await runOutput("go", ["-C", "./tools", "run", "./cmd/machotool", "verify", typescriptMacEntitlementsPath, p.path]); } } } @@ -2209,7 +2256,7 @@ async function runPackNativePreviewPackages() { const platforms = getPlatforms(); await Promise.all([mainNativePreviewPackage, ...platforms].map(async ({ npmDir, npmTarball }) => { - const { stdout } = await $pipe`npm pack --json ${npmDir}`; + const { stdout } = await runOutput("npm", ["pack", "--json", npmDir]); const filename = JSON.parse(stdout)[0].filename.replace("@", "").replace("/", "-"); await fs.promises.rename(filename, npmTarball); })); @@ -2330,7 +2377,10 @@ async function getPublishedPlatformPackageLibDirWorker(npmPackageName) { } console.log(`Fetching ${npmPackageName}@${version} with npm.`); - const { stdout } = await $pipe({ cwd: tarballDestination, env: releasePackageEnv })`npm pack --json ${npmPackageName}@${version}`; + const { stdout } = await runOutput("npm", ["pack", "--json", `${npmPackageName}@${version}`], { + cwd: tarballDestination, + env: releasePackageEnv, + }); const [packed] = JSON.parse(stdout); if (!packed.filename || typeof packed.filename !== "string") { throw new Error(`npm pack ${npmPackageName}@${version} did not return a filename.`); @@ -2361,7 +2411,7 @@ async function runPackVsixExtensions() { } // We don't use vscode:prepublish, as that would run the build for each package below. - await $({ cwd: extensionDir, env: releasePackageEnv })`npm run bundle:release`; + await run("npm", ["run", "bundle:release"], { cwd: extensionDir, env: releasePackageEnv }); let version = "0.0.0"; if (options.forRelease) { @@ -2400,10 +2450,16 @@ async function runPackVsixExtensions() { await fs.promises.copyFile("NOTICE.txt", path.join(thisExtensionDir, "NOTICE.txt")); - await $({ cwd: thisExtensionDir, env: releasePackageEnv })`vsce package ${version} --no-update-package-json --no-dependencies --out ${vsixPath} --target ${vscodeTarget}`; + await run("vsce", ["package", version, "--no-update-package-json", "--no-dependencies", "--out", vsixPath, "--target", vscodeTarget], { + cwd: thisExtensionDir, + env: releasePackageEnv, + }); if (options.forRelease) { - await $({ cwd: thisExtensionDir, env: releasePackageEnv })`vsce generate-manifest --packagePath ${vsixPath} --out ${vsixManifestPath}`; + await run("vsce", ["generate-manifest", "--packagePath", vsixPath, "--out", vsixManifestPath], { + cwd: thisExtensionDir, + env: releasePackageEnv, + }); await fs.promises.cp(vsixManifestPath, vsixSignaturePath); } })); @@ -2478,8 +2534,8 @@ export const tidy = task({ name: "tidy", description: "Tidies both Go modules and synchronizes the workspace.", run: async () => { - await $({ cwd: "./tsc" })`go mod tidy`; - await $({ cwd: "./tools" })`go mod tidy`; - await $`go work sync`; + await run("go", ["mod", "tidy"], { cwd: "./tsc" }); + await run("go", ["mod", "tidy"], { cwd: "./tools" }); + await run("go", ["work", "sync"]); }, }); diff --git a/package-lock.json b/package-lock.json index 880f419058180..2efbcb0f1dae5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -18,9 +18,9 @@ "adm-zip": "^0.6.0", "chokidar": "^5.0.0", "dprint": "^0.55.1", - "execa": "^9.6.1", "hereby": "^1.15.1", "tar": "^7.5.19", + "tinyexec": "^1.3.0", "typescript": "^6.0.3", "which": "^6.0.1" }, @@ -1207,13 +1207,6 @@ "node": ">= 8" } }, - "node_modules/@sec-ant/readable-stream": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/@sec-ant/readable-stream/-/readable-stream-0.4.1.tgz", - "integrity": "sha512-831qok9r2t8AlxLko40y2ebgSDhenenCatLVeW/uBtnHPyhHOvG0C7TvfgecV+wHzIm5KUICgzmVpWS+IMEAeg==", - "dev": true, - "license": "MIT" - }, "node_modules/@secretlint/config-creator": { "version": "10.2.2", "resolved": "https://registry.npmjs.org/@secretlint/config-creator/-/config-creator-10.2.2.tgz", @@ -1388,19 +1381,6 @@ "node": ">=20.0.0" } }, - "node_modules/@sindresorhus/merge-streams": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@sindresorhus/merge-streams/-/merge-streams-4.0.0.tgz", - "integrity": "sha512-tlqY9xq5ukxTUZBmoOp+m61cqwQD5pHJtFY3Mn8CA8ps6yghLH/Hw8UPdqg4OLmFW3IFlcXnQNmo/dh8HzXYIQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/@textlint/ast-node-types": { "version": "15.8.0", "resolved": "https://registry.npmjs.org/@textlint/ast-node-types/-/ast-node-types-15.8.0.tgz", @@ -2581,44 +2561,6 @@ "node": ">=18" } }, - "node_modules/cross-spawn": { - "version": "7.0.6", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", - "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", - "dev": true, - "license": "MIT", - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/cross-spawn/node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true, - "license": "ISC" - }, - "node_modules/cross-spawn/node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "license": "ISC", - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, "node_modules/css-select": { "version": "5.2.2", "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.2.2.tgz", @@ -3037,33 +2979,6 @@ "@esbuild/win32-x64": "0.28.2" } }, - "node_modules/execa": { - "version": "9.6.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-9.6.1.tgz", - "integrity": "sha512-9Be3ZoN4LmYR90tUoVu2te2BsbzHfhJyfEiAVfz7N5/zv+jduIfLrV2xdQXOHbaD6KgpGdO9PRPM1Y4Q9QkPkA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@sindresorhus/merge-streams": "^4.0.0", - "cross-spawn": "^7.0.6", - "figures": "^6.1.0", - "get-stream": "^9.0.0", - "human-signals": "^8.0.1", - "is-plain-obj": "^4.1.0", - "is-stream": "^4.0.1", - "npm-run-path": "^6.0.0", - "pretty-ms": "^9.2.0", - "signal-exit": "^4.1.0", - "strip-final-newline": "^4.0.0", - "yoctocolors": "^2.1.1" - }, - "engines": { - "node": "^18.19.0 || >=20.5.0" - }, - "funding": { - "url": "https://github.com/sindresorhus/execa?sponsor=1" - } - }, "node_modules/expand-template": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", @@ -3126,22 +3041,6 @@ "reusify": "^1.0.4" } }, - "node_modules/figures": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-6.1.0.tgz", - "integrity": "sha512-d+l3qxjSesT4V7v2fh+QnmFnUWv9lSpjarhShNTgBOfA0ttejbQUAlHLitbjkoRiDulW0OPoQPYIGhIC8ohejg==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-unicode-supported": "^2.0.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/fill-range": { "version": "7.1.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", @@ -3244,23 +3143,6 @@ "node": ">= 0.4" } }, - "node_modules/get-stream": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-9.0.1.tgz", - "integrity": "sha512-kVCxPF3vQM/N0B1PmoqVUqgHP+EeVjmZSQn+1oCRPxd2P21P2F19lIgbR3HBosbB1PUhOAoctJnfEn2GbN2eZA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@sec-ant/readable-stream": "^0.4.1", - "is-stream": "^4.0.1" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/github-from-package": { "version": "0.0.0", "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", @@ -3513,16 +3395,6 @@ "node": ">= 14" } }, - "node_modules/human-signals": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-8.0.1.tgz", - "integrity": "sha512-eKCa6bwnJhvxj14kZk5NCPc6Hb6BdsU9DZcOnmQKSnO1VKrfV0zCvtttPZUsBvjmNDn8rpcJfpwSYnHBjc95MQ==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=18.18.0" - } - }, "node_modules/iconv-lite": { "version": "0.6.3", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", @@ -3675,45 +3547,6 @@ "node": ">=0.12.0" } }, - "node_modules/is-plain-obj": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", - "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-stream": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-4.0.1.tgz", - "integrity": "sha512-Dnz92NInDqYckGEUJv689RbRiTSEHCQ7wOVeALbkOz999YpqT46yMRIGtSNl2iCL1waAZSx40+h59NV/EwzV/A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-unicode-supported": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-2.1.0.tgz", - "integrity": "sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/is-wsl": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-3.1.1.tgz", @@ -4263,36 +4096,6 @@ "dev": true, "license": "ISC" }, - "node_modules/npm-run-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-6.0.0.tgz", - "integrity": "sha512-9qny7Z9DsQU8Ou39ERsPU4OZQlSTP47ShQzuKZ6PRXpYLtIFgl/DEBYEXKlvcEa+9tHVcK8CF81Y2V72qaZhWA==", - "dev": true, - "license": "MIT", - "dependencies": { - "path-key": "^4.0.0", - "unicorn-magic": "^0.3.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/npm-run-path/node_modules/path-key": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", - "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/nth-check": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", @@ -4380,19 +4183,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/parse-ms": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/parse-ms/-/parse-ms-4.0.0.tgz", - "integrity": "sha512-TXfryirbmq34y8QBwgqCVLi+8oA3oWx2eAnSn62ITyEhEYaWRlVZ2DvMM9eZbMs/RfxPu/PK/aBLyGj4IrqMHw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/parse-semver": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/parse-semver/-/parse-semver-1.1.1.tgz", @@ -4466,16 +4256,6 @@ "url": "https://github.com/fb55/entities?sponsor=1" } }, - "node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, "node_modules/path-scurry": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.2.tgz", @@ -4572,22 +4352,6 @@ "node": ">=10" } }, - "node_modules/pretty-ms": { - "version": "9.3.0", - "resolved": "https://registry.npmjs.org/pretty-ms/-/pretty-ms-9.3.0.tgz", - "integrity": "sha512-gjVS5hOP+M3wMm5nmNOucbIrqudzs9v/57bWRHQWLYklXqoXKrVfYW2W9+glfGsqtPgpiz5WwyEEB+ksXIx3gQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "parse-ms": "^4.0.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/pump": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.4.tgz", @@ -4884,29 +4648,6 @@ "node": ">=10" } }, - "node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, - "license": "MIT", - "dependencies": { - "shebang-regex": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, "node_modules/side-channel": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.1.tgz", @@ -4983,19 +4724,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/signal-exit": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", - "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/simple-concat": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", @@ -5177,19 +4905,6 @@ "url": "https://github.com/chalk/strip-ansi?sponsor=1" } }, - "node_modules/strip-final-newline": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-4.0.0.tgz", - "integrity": "sha512-aulFJcD6YK8V1G7iRB5tigAP4TsHBZZrOV8pjV++zdUwmeV8uzbY7yn6h9MswN62adStNZFuCIx4haBnRuMDaw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/strip-json-comments": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", @@ -5397,6 +5112,16 @@ "node": ">=20.0.0" } }, + "node_modules/tinyexec": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.3.0.tgz", + "integrity": "sha512-QKAl9m8gWWGHV8jZcPeym6j+XULi6tOf1mT83WYJ4Lk2ytW/uwAWkrP0uFsdoYMdueVJ0qs26wZ+23xeB4ibNQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, "node_modules/tmp": { "version": "0.2.7", "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.7.tgz", @@ -5765,19 +5490,6 @@ "buffer-crc32": "~0.2.3" } }, - "node_modules/yoctocolors": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/yoctocolors/-/yoctocolors-2.2.0.tgz", - "integrity": "sha512-xYqdZFUK/VYazNl/oCDYN+3WloWQwMfZxBoiNt6qNyk+xfOdi598muWE42rNZFp1kNOiqW936q5RhUdnpqElSg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "packages/typescript": { "name": "@typescript/typescript", "version": "0.0.0", diff --git a/package.json b/package.json index ac341cf0c3955..dac3a45d732a3 100644 --- a/package.json +++ b/package.json @@ -30,9 +30,9 @@ "adm-zip": "^0.6.0", "chokidar": "^5.0.0", "dprint": "^0.55.1", - "execa": "^9.6.1", "hereby": "^1.15.1", "tar": "^7.5.19", + "tinyexec": "^1.3.0", "typescript": "^6.0.3", "which": "^6.0.1" }, diff --git a/packages/typescript/scripts/generateSync.ts b/packages/typescript/scripts/generateSync.ts index 751000df9b06f..fb990d546e796 100755 --- a/packages/typescript/scripts/generateSync.ts +++ b/packages/typescript/scripts/generateSync.ts @@ -21,7 +21,6 @@ * node generateSync.ts */ -import { execaSync } from "execa"; import { mkdirSync, readFileSync, @@ -32,6 +31,7 @@ import { join, relative, } from "node:path"; +import { xSync } from "tinyexec"; import ts from "typescript"; function generatedHeader(asyncSourceRelPath: string): string { @@ -269,7 +269,7 @@ function removeAsyncAwaitAndPromise(source: string, fileName: string): string { // ── Formatting ─────────────────────────────────────────────────── function formatFiles(paths: string[]): void { - execaSync("dprint", ["fmt", ...paths]); + xSync("dprint", ["fmt", ...paths], { throwOnError: true }); } // ── Main ───────────────────────────────────────────────────────── diff --git a/tools/scripts/tsc/generate-encoder.ts b/tools/scripts/tsc/generate-encoder.ts index b0951ab5a0da7..953b55fe9d546 100644 --- a/tools/scripts/tsc/generate-encoder.ts +++ b/tools/scripts/tsc/generate-encoder.ts @@ -10,10 +10,10 @@ * - packages/typescript/src/api/node/protocol.generated.ts */ -import { execaSync } from "execa"; import * as fs from "node:fs"; import * as path from "node:path"; import { fileURLToPath } from "node:url"; +import { xSync } from "tinyexec"; import type { KindType, MemberInfo, @@ -1989,7 +1989,10 @@ function writeAndFormat(filePath: string, content: string, formatter: string) { fs.writeFileSync(filePath, content); try { const [cmd, ...args] = formatter.split(" "); - execaSync(cmd, [...args, filePath], { stdio: "inherit", cwd: ROOT }); + xSync(cmd, [...args, filePath], { + throwOnError: true, + nodeOptions: { stdio: "inherit", cwd: ROOT }, + }); } catch { console.warn(`Warning: formatter failed for ${filePath}`); diff --git a/tools/scripts/tsc/generate-go-ast.ts b/tools/scripts/tsc/generate-go-ast.ts index b03089208c4ac..e85658397729c 100644 --- a/tools/scripts/tsc/generate-go-ast.ts +++ b/tools/scripts/tsc/generate-go-ast.ts @@ -14,10 +14,10 @@ * - Is*() type guard functions */ -import { execaSync } from "execa"; import * as fs from "node:fs"; import * as path from "node:path"; import { fileURLToPath } from "node:url"; +import { xSync } from "tinyexec"; import type { MemberInfo, NodeType, @@ -1084,7 +1084,10 @@ function generateKind(): string { function writeAndFormat(filePath: string, content: string) { fs.writeFileSync(filePath, content); - execaSync("dprint", ["fmt", filePath], { stdio: "inherit", cwd: ROOT }); + xSync("dprint", ["fmt", filePath], { + throwOnError: true, + nodeOptions: { stdio: "inherit", cwd: ROOT }, + }); console.log(`Wrote ${filePath}`); } diff --git a/tools/scripts/tsc/generate-ts-ast.ts b/tools/scripts/tsc/generate-ts-ast.ts index fee099d29dab2..054ac3576dd11 100644 --- a/tools/scripts/tsc/generate-ts-ast.ts +++ b/tools/scripts/tsc/generate-ts-ast.ts @@ -8,10 +8,10 @@ * Usage: node tools/scripts/tsc/generate-ts-ast.ts */ -import { execaSync } from "execa"; import * as fs from "node:fs"; import * as path from "node:path"; import { fileURLToPath } from "node:url"; +import { xSync } from "tinyexec"; import type { MemberInfo, NodeType, @@ -1717,7 +1717,10 @@ function generateVisitor(): string { function writeAndFormat(filePath: string, content: string) { fs.writeFileSync(filePath, content); - execaSync("dprint", ["fmt", filePath], { stdio: "inherit", cwd: ROOT }); + xSync("dprint", ["fmt", filePath], { + throwOnError: true, + nodeOptions: { stdio: "inherit", cwd: ROOT }, + }); console.log(`Generated ${filePath}`); } diff --git a/tsc/internal/lsp/lsproto/_generate/generate.mts b/tsc/internal/lsp/lsproto/_generate/generate.mts index 9849d29f41d2b..6f65a9af99c1e 100755 --- a/tsc/internal/lsp/lsproto/_generate/generate.mts +++ b/tsc/internal/lsp/lsproto/_generate/generate.mts @@ -2,10 +2,10 @@ // Usage: node generate.mts -import { $ } from "execa"; import fs from "node:fs"; import path from "node:path"; import url from "node:url"; +import { x } from "tinyexec"; import type { Enumeration, MetaModel, @@ -3608,7 +3608,10 @@ async function main() { const generatedCode = generateCode(); fs.writeFileSync(out, generatedCode); - await $({ cwd: repoRoot })`dprint fmt ${out}`; + await x("dprint", ["fmt", out], { + throwOnError: true, + nodeOptions: { cwd: repoRoot, stdio: "inherit" }, + }); console.log(`Successfully generated ${out}`); } From 16cd55bbb6f02c4841909a3d3c00f7f6e405d8d0 Mon Sep 17 00:00:00 2001 From: Jake Bailey <5341706+jakebailey@users.noreply.github.com> Date: Wed, 26 Aug 2026 21:01:12 -0700 Subject: [PATCH 08/15] Replace which with tinyexec probing --- Herebyfile.mjs | 28 +++++++++++++++++----------- package-lock.json | 37 +------------------------------------ package.json | 4 +--- 3 files changed, 19 insertions(+), 50 deletions(-) diff --git a/Herebyfile.mjs b/Herebyfile.mjs index 10ed5fb6a9119..295d9d72a003a 100644 --- a/Herebyfile.mjs +++ b/Herebyfile.mjs @@ -14,8 +14,10 @@ import { styleText, } from "node:util"; import * as tar from "tar"; -import { x } from "tinyexec"; -import which from "which"; +import { + x, + xSync, +} from "tinyexec"; if (process.platform === "win32") { process.chdir(fs.realpathSync.native(process.cwd())); @@ -228,12 +230,16 @@ const tools = new Map([ ["gotest.tools/gotestsum", "latest"], ]); -/** - * @param {string} tool - */ -function isInstalled(tool) { - return !!which.sync(tool, { nothrow: true }); -} +const hasGotestsum = memoize(() => { + try { + return xSync("gotestsum", ["--version"], { + nodeOptions: { stdio: "ignore" }, + }).exitCode === 0; + } + catch { + return false; + } +}); const builtLocal = "./built/local"; @@ -799,7 +805,7 @@ async function checkUnusedBaselines(trackingDir) { * @param {string} taskName */ function gotestsum(taskName) { - const args = isInstalled("gotestsum") ? ["gotestsum", ...goTestSumFlags, "--"] : ["go", "test"]; + const args = hasGotestsum() ? ["gotestsum", ...goTestSumFlags, "--"] : ["go", "test"]; return args.concat(goTestFlags(taskName)); } @@ -961,7 +967,7 @@ export const testAll = task({ }, }); -const customLinterPath = "./tools/custom-gcl"; +const customLinterPath = `./tools/custom-gcl${process.platform === "win32" ? ".exe" : ""}`; const customLinterHashPath = customLinterPath + ".hash"; const golangciLintPackage = memoize(() => { @@ -1001,7 +1007,7 @@ const customlintHash = memoize(() => { const buildCustomLinter = memoize(async () => { const hash = customlintHash(); if ( - isInstalled(customLinterPath) + fs.existsSync(customLinterPath) && fs.existsSync(customLinterHashPath) && fs.readFileSync(customLinterHashPath, "utf8") === hash ) { diff --git a/package-lock.json b/package-lock.json index 2efbcb0f1dae5..8aee16a041326 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,7 +13,6 @@ ], "devDependencies": { "@types/node": "latest", - "@types/which": "^3.0.4", "@unicode/unicode-15.1.0": "^1.6.17", "adm-zip": "^0.6.0", "chokidar": "^5.0.0", @@ -21,8 +20,7 @@ "hereby": "^1.15.1", "tar": "^7.5.19", "tinyexec": "^1.3.0", - "typescript": "^6.0.3", - "which": "^6.0.1" + "typescript": "^6.0.3" }, "engines": { "node": ">=22.18" @@ -1498,13 +1496,6 @@ "dev": true, "license": "MIT" }, - "node_modules/@types/which": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@types/which/-/which-3.0.4.tgz", - "integrity": "sha512-liyfuo/106JdlgSchJzXEQCVArk0CvevqPote8F8HgWgJ3dRCcTHgJIsLDuee0kxk/mhbInzIZk3QWSZJ8R+2w==", - "dev": true, - "license": "MIT" - }, "node_modules/@typescript/bundled-typescript": { "name": "typescript", "version": "7.0.2", @@ -3563,16 +3554,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/isexe": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-4.0.0.tgz", - "integrity": "sha512-FFUtZMpoZ8RqHS3XeXEmHWLA4thH+ZxCv2lOiPIn1Xc7CxrqhWzNSDzD+/chS/zbYezmiwWLdQC09JdQKmthOw==", - "dev": true, - "license": "BlueOak-1.0.0", - "engines": { - "node": ">=20" - } - }, "node_modules/istextorbinary": { "version": "9.5.0", "resolved": "https://registry.npmjs.org/istextorbinary/-/istextorbinary-9.5.0.tgz", @@ -5393,22 +5374,6 @@ "node": ">=18" } }, - "node_modules/which": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/which/-/which-6.0.1.tgz", - "integrity": "sha512-oGLe46MIrCRqX7ytPUf66EAYvdeMIZYn3WaocqqKZAxrBpkqHfL/qvTyJ/bTk5+AqHCjXmrv3CEWgy368zhRUg==", - "dev": true, - "license": "ISC", - "dependencies": { - "isexe": "^4.0.0" - }, - "bin": { - "node-which": "bin/which.js" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", diff --git a/package.json b/package.json index dac3a45d732a3..033500c646894 100644 --- a/package.json +++ b/package.json @@ -25,7 +25,6 @@ }, "devDependencies": { "@types/node": "latest", - "@types/which": "^3.0.4", "@unicode/unicode-15.1.0": "^1.6.17", "adm-zip": "^0.6.0", "chokidar": "^5.0.0", @@ -33,8 +32,7 @@ "hereby": "^1.15.1", "tar": "^7.5.19", "tinyexec": "^1.3.0", - "typescript": "^6.0.3", - "which": "^6.0.1" + "typescript": "^6.0.3" }, "overrides": { "@microsoft/applicationinsights-web-basic": "3.3.11", From 4cfe1f81062cc3a37c45d8b185692e29a9cb06dd Mon Sep 17 00:00:00 2001 From: Jake Bailey <5341706+jakebailey@users.noreply.github.com> Date: Wed, 26 Aug 2026 21:17:28 -0700 Subject: [PATCH 09/15] Remove stale script allowances --- package.json | 2 -- 1 file changed, 2 deletions(-) diff --git a/package.json b/package.json index 033500c646894..a7fa45d14049e 100644 --- a/package.json +++ b/package.json @@ -45,8 +45,6 @@ "npm": "11.17.0" }, "allowScripts": { - "dprint@0.55.1": true, - "esbuild@0.28.1": true, "@vscode/vsce-sign@2.0.9": true, "keytar@7.9.0": true, "dprint@0.55.2": true, From d88ebcd2fa6a40ff42d98062102eaabd49e322ad Mon Sep 17 00:00:00 2001 From: Jake Bailey <5341706+jakebailey@users.noreply.github.com> Date: Wed, 26 Aug 2026 21:43:32 -0700 Subject: [PATCH 10/15] Use Node 22 types for API package --- package-lock.json | 16 ++++++++-------- packages/typescript/package.json | 2 +- packages/typescript/src/api/node/encoder.ts | 1 + .../src/api/node/node.infrastructure.ts | 4 ++-- packages/typescript/src/api/node/wtf8.ts | 8 +++++--- 5 files changed, 17 insertions(+), 14 deletions(-) diff --git a/package-lock.json b/package-lock.json index 8aee16a041326..6048a91f0a50f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5463,7 +5463,7 @@ "tsc": "bin/tsc" }, "devDependencies": { - "@types/node": "^25.9.4", + "@types/node": "^22.18.0", "tinybench": "^6.0.2", "vscode-jsonrpc": "^9.0.0" }, @@ -5472,19 +5472,19 @@ } }, "packages/typescript/node_modules/@types/node": { - "version": "25.9.5", - "resolved": "https://registry.npmjs.org/@types/node/-/node-25.9.5.tgz", - "integrity": "sha512-OScDchr2fwuUmWdf4kZ9h7PcJiYDVInhJizG/biAq3cAvqwYktuy/TYGGdZNMtNTFUP7rnb0NU4TUdm82kt4Rg==", + "version": "22.20.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.20.1.tgz", + "integrity": "sha512-EANqOCF9QFyra+4pfxUcX9STKJpCLjMbObVzljIJomAWSnuSIEAvyzEU53GaajbXJEgdh0iEcPL+DGvpUd4k1Q==", "dev": true, "license": "MIT", "dependencies": { - "undici-types": ">=7.24.0 <7.24.7" + "undici-types": "~6.21.0" } }, "packages/typescript/node_modules/undici-types": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.24.6.tgz", - "integrity": "sha512-WRNW+sJgj5OBN4/0JpHFqtqzhpbnV0GuB+OozA9gCL7a993SmU+1JBZCzLNxYsbMfIeDL+lTsphD5jN5N+n0zg==", + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", "dev": true, "license": "MIT" }, diff --git a/packages/typescript/package.json b/packages/typescript/package.json index 8f9af6510f958..0b4898baf3b4c 100644 --- a/packages/typescript/package.json +++ b/packages/typescript/package.json @@ -107,7 +107,7 @@ "test": "npm run test:only" }, "devDependencies": { - "@types/node": "^25.9.4", + "@types/node": "^22.18.0", "tinybench": "^6.0.2", "vscode-jsonrpc": "^9.0.0" } diff --git a/packages/typescript/src/api/node/encoder.ts b/packages/typescript/src/api/node/encoder.ts index 0071f7970a579..5ed4bdbf71d86 100644 --- a/packages/typescript/src/api/node/encoder.ts +++ b/packages/typescript/src/api/node/encoder.ts @@ -1,3 +1,4 @@ +import { TextEncoder } from "node:util"; import type { FileReference, LiteralLikeNode, diff --git a/packages/typescript/src/api/node/node.infrastructure.ts b/packages/typescript/src/api/node/node.infrastructure.ts index 92b2922877e2a..5ba888afac659 100644 --- a/packages/typescript/src/api/node/node.infrastructure.ts +++ b/packages/typescript/src/api/node/node.infrastructure.ts @@ -39,9 +39,9 @@ export const NODE_EXTENDED_DATA_MASK = 0x00_ff_ff_ff; // source file, avoiding a direct dependency on RemoteSourceFile. // ═══════════════════════════════════════════════════════════════════════════ -// The global type is not available in earlier @types/node versions +// The global type is not available in earlier @types/node versions. export interface TextDecoder { - decode(input?: ArrayBufferView | ArrayBufferLike): string; + decode(input?: Uint8Array): string; } export interface SourceFileInfo { diff --git a/packages/typescript/src/api/node/wtf8.ts b/packages/typescript/src/api/node/wtf8.ts index 45bba64a91081..5a982498df32f 100644 --- a/packages/typescript/src/api/node/wtf8.ts +++ b/packages/typescript/src/api/node/wtf8.ts @@ -1,10 +1,12 @@ import { Buffer } from "node:buffer"; +import { TextDecoder } from "node:util"; const surrogateLeadByte = 0xED; const surrogateSecondByteMin = 0xA0; const surrogateSecondByteMax = 0xBF; const continuationByteMin = 0x80; const continuationByteMax = 0xBF; +type DecodeInput = ArrayBufferView | ArrayBufferLike | null; type DecodeOptions = Parameters[1]; function isWtf8Surrogate(bytes: Uint8Array, index: number): boolean { @@ -24,7 +26,7 @@ function hasSurrogateLeadByte(bytes: Uint8Array): boolean { return Buffer.from(bytes.buffer, bytes.byteOffset, bytes.byteLength).indexOf(surrogateLeadByte) >= 0; } -function toUint8Array(input: NodeJS.AllowSharedBufferSource): Uint8Array { +function toUint8Array(input: Exclude): Uint8Array { if (input instanceof Uint8Array) { return input; } @@ -35,8 +37,8 @@ function toUint8Array(input: NodeJS.AllowSharedBufferSource): Uint8Array { } export class Wtf8Decoder extends TextDecoder { - override decode(input?: NodeJS.AllowSharedBufferSource, options?: DecodeOptions): string { - if (input === undefined) { + override decode(input?: DecodeInput, options?: DecodeOptions): string { + if (input == null) { return super.decode(input, options); } From 98e51093bd9ed852a88852c99ce81ff8d0163477 Mon Sep 17 00:00:00 2001 From: Jake Bailey <5341706+jakebailey@users.noreply.github.com> Date: Wed, 26 Aug 2026 21:49:27 -0700 Subject: [PATCH 11/15] Update vscode-tas-client to 0.3.1 --- package-lock.json | 10 +++++----- packages/vscode-typescript/package.json | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/package-lock.json b/package-lock.json index 6048a91f0a50f..5136c1acf6078 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5335,12 +5335,12 @@ "license": "MIT" }, "node_modules/vscode-tas-client": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/vscode-tas-client/-/vscode-tas-client-0.2.1.tgz", - "integrity": "sha512-htmjTFhOkM213OKv42cyCboc6D4vhZTdGHLb+GiNvFeK66eBdTbec2P41rgIg9YxnBgcDOlkvTElRorm3VitXw==", + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/vscode-tas-client/-/vscode-tas-client-0.3.1.tgz", + "integrity": "sha512-UD9rTFHEpFfUQgbIVsugNYk17E5zn6JW/VGwAIDmcBWT0XvYEgb6xP9m1FamdjTEvBo4o039S/1uaropj1H9FQ==", "license": "MIT", "dependencies": { - "tas-client": "^0.4.0" + "tas-client": "^0.4.3" }, "engines": { "vscode": "^1.85.0" @@ -5494,7 +5494,7 @@ "dependencies": { "@vscode/extension-telemetry": "^1.5.2", "vscode-languageclient": "^10.0.1", - "vscode-tas-client": "^0.2.1" + "vscode-tas-client": "^0.3.1" }, "devDependencies": { "@types/vscode": "~1.125.0", diff --git a/packages/vscode-typescript/package.json b/packages/vscode-typescript/package.json index b1a6d81ecdb5c..b85446bba7a61 100644 --- a/packages/vscode-typescript/package.json +++ b/packages/vscode-typescript/package.json @@ -380,7 +380,7 @@ "dependencies": { "@vscode/extension-telemetry": "^1.5.2", "vscode-languageclient": "^10.0.1", - "vscode-tas-client": "^0.2.1" + "vscode-tas-client": "^0.3.1" }, "devDependencies": { "@types/vscode": "~1.125.0", From b8ddffa969ce6a9fba361b7b38b84ec33b8d903f Mon Sep 17 00:00:00 2001 From: Jake Bailey <5341706+jakebailey@users.noreply.github.com> Date: Thu, 27 Aug 2026 10:26:39 -0700 Subject: [PATCH 12/15] Use Node 22 types at repository root --- package-lock.json | 33 ++++++++------------------------- package.json | 2 +- 2 files changed, 9 insertions(+), 26 deletions(-) diff --git a/package-lock.json b/package-lock.json index 5136c1acf6078..adb31ed740824 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,7 +12,7 @@ "packages/*" ], "devDependencies": { - "@types/node": "latest", + "@types/node": "^22.18.0", "@unicode/unicode-15.1.0": "^1.6.17", "adm-zip": "^0.6.0", "chokidar": "^5.0.0", @@ -1466,13 +1466,13 @@ } }, "node_modules/@types/node": { - "version": "26.2.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-26.2.0.tgz", - "integrity": "sha512-5IviulTZeRNp2vAJ514cc/HUlY5nZ9fCbq9DMyC52BrhFZACo3nI0R7qBxhQmo/d27NFe96ur/b7Wwxklda+kg==", + "version": "22.20.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.20.1.tgz", + "integrity": "sha512-EANqOCF9QFyra+4pfxUcX9STKJpCLjMbObVzljIJomAWSnuSIEAvyzEU53GaajbXJEgdh0iEcPL+DGvpUd4k1Q==", "dev": true, "license": "MIT", "dependencies": { - "undici-types": "~8.3.0" + "undici-types": "~6.21.0" } }, "node_modules/@types/normalize-package-data": { @@ -5220,9 +5220,9 @@ } }, "node_modules/undici-types": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-8.3.0.tgz", - "integrity": "sha512-j375ScV60dom+YkPFIfTLcOiPxkN/buHz5GobjLhixFuANaNs3C9l4GmrWqejgXWJ7BbJcFYpTEUkS1Ge8bpZQ==", + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", "dev": true, "license": "MIT" }, @@ -5471,23 +5471,6 @@ "node": ">=16.20.0" } }, - "packages/typescript/node_modules/@types/node": { - "version": "22.20.1", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.20.1.tgz", - "integrity": "sha512-EANqOCF9QFyra+4pfxUcX9STKJpCLjMbObVzljIJomAWSnuSIEAvyzEU53GaajbXJEgdh0iEcPL+DGvpUd4k1Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "undici-types": "~6.21.0" - } - }, - "packages/typescript/node_modules/undici-types": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", - "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", - "dev": true, - "license": "MIT" - }, "packages/vscode-typescript": { "name": "native-preview", "version": "0.0.0", diff --git a/package.json b/package.json index a7fa45d14049e..2e6fbb4158e34 100644 --- a/package.json +++ b/package.json @@ -24,7 +24,7 @@ "setup-hooks": "node tools/scripts/link-hooks.mjs" }, "devDependencies": { - "@types/node": "latest", + "@types/node": "^22.18.0", "@unicode/unicode-15.1.0": "^1.6.17", "adm-zip": "^0.6.0", "chokidar": "^5.0.0", From f4d5b5ac1f134c625bc7a862fcc29525780596ec Mon Sep 17 00:00:00 2001 From: Jake Bailey <5341706+jakebailey@users.noreply.github.com> Date: Thu, 27 Aug 2026 10:28:54 -0700 Subject: [PATCH 13/15] Type-check the Herebyfile in CI --- .github/workflows/ci.yml | 1 + Herebyfile.mjs | 26 ++++++++++++++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1c7ffb11454f7..25c3f4cc9f017 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -310,6 +310,7 @@ jobs: - uses: ./.github/actions/setup-go - run: npm ci - run: go -C ./tools run ./cmd/checkmodpaths "$PWD" + - run: npx hereby check:herebyfile - run: npx hereby check:scripts - run: npx hereby typescript:check-platforms diff --git a/Herebyfile.mjs b/Herebyfile.mjs index 295d9d72a003a..0f312902df2e8 100644 --- a/Herebyfile.mjs +++ b/Herebyfile.mjs @@ -1072,6 +1072,32 @@ export const checkFormat = task({ }, }); +export const checkHerebyfile = task({ + name: "check:herebyfile", + description: "Type-checks Herebyfile.mjs.", + run: () => + run("node", [ + "./node_modules/typescript/bin/tsc", + "--noEmit", + "--allowJs", + "--checkJs", + "--target", + "es2022", + "--lib", + "es2024,esnext.array,esnext.collection,esnext.iterator", + "--module", + "nodenext", + "--moduleResolution", + "nodenext", + "--types", + "node", + "--strict", + "--esModuleInterop", + "--skipLibCheck", + "Herebyfile.mjs", + ]), +}); + const scriptTsconfigs = [ "./tools/scripts/tsc/tsconfig.json", "./tsc/internal/lsp/lsproto/_generate/tsconfig.json", From d73ef7db2d18999bf38baa97d7e389b00894e9c3 Mon Sep 17 00:00:00 2001 From: Jake Bailey <5341706+jakebailey@users.noreply.github.com> Date: Thu, 27 Aug 2026 10:47:56 -0700 Subject: [PATCH 14/15] Fix Node dependency update CI failures --- .github/workflows/ci.yml | 6 +++--- package.json | 2 +- packages/typescript/src/api/node/wtf8.ts | 11 +++++++++-- 3 files changed, 13 insertions(+), 6 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 25c3f4cc9f017..a85dc4dd39dbc 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -263,15 +263,15 @@ jobs: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 with: - node-version: '>=22.16.0' + node-version: '>=22.18.0' - uses: ./.github/actions/setup-go - run: npm ci - run: npx hereby generate - run: npx hereby generate:enums - run: npx hereby generate:ast - run: npx hereby generate:vendor - - run: node --experimental-strip-types ./tsc/internal/lsp/lsproto/_generate/fetchModel.mts - - run: node --experimental-strip-types ./tsc/internal/lsp/lsproto/_generate/generate.mts + - run: node ./tsc/internal/lsp/lsproto/_generate/fetchModel.mts + - run: node ./tsc/internal/lsp/lsproto/_generate/generate.mts - run: npx hereby generate:extension - run: npx hereby check:scripts - run: git add . diff --git a/package.json b/package.json index 2e6fbb4158e34..144bf658a3476 100644 --- a/package.json +++ b/package.json @@ -45,7 +45,7 @@ "npm": "11.17.0" }, "allowScripts": { - "@vscode/vsce-sign@2.0.9": true, + "@vscode/vsce-sign@2.1.0": true, "keytar@7.9.0": true, "dprint@0.55.2": true, "esbuild@0.28.2": true diff --git a/packages/typescript/src/api/node/wtf8.ts b/packages/typescript/src/api/node/wtf8.ts index 5a982498df32f..49b6e0b17b326 100644 --- a/packages/typescript/src/api/node/wtf8.ts +++ b/packages/typescript/src/api/node/wtf8.ts @@ -1,5 +1,4 @@ import { Buffer } from "node:buffer"; -import { TextDecoder } from "node:util"; const surrogateLeadByte = 0xED; const surrogateSecondByteMin = 0xA0; @@ -7,7 +6,15 @@ const surrogateSecondByteMax = 0xBF; const continuationByteMin = 0x80; const continuationByteMax = 0xBF; type DecodeInput = ArrayBufferView | ArrayBufferLike | null; -type DecodeOptions = Parameters[1]; +interface TextDecoder { + decode(input?: DecodeInput, options?: DecodeOptions): string; +} +interface DecodeOptions { + stream?: boolean; +} +declare const TextDecoder: { + new (): TextDecoder; +}; function isWtf8Surrogate(bytes: Uint8Array, index: number): boolean { return index + 2 < bytes.length From 97a71921e868174ff69e683d70affa05c5458fff Mon Sep 17 00:00:00 2001 From: Jake Bailey <5341706+jakebailey@users.noreply.github.com> Date: Thu, 27 Aug 2026 15:38:14 -0700 Subject: [PATCH 15/15] Use the global TextDecoder type --- packages/typescript/src/api/node/wtf8.ts | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/packages/typescript/src/api/node/wtf8.ts b/packages/typescript/src/api/node/wtf8.ts index 49b6e0b17b326..6ec4165b39848 100644 --- a/packages/typescript/src/api/node/wtf8.ts +++ b/packages/typescript/src/api/node/wtf8.ts @@ -5,16 +5,8 @@ const surrogateSecondByteMin = 0xA0; const surrogateSecondByteMax = 0xBF; const continuationByteMin = 0x80; const continuationByteMax = 0xBF; -type DecodeInput = ArrayBufferView | ArrayBufferLike | null; -interface TextDecoder { - decode(input?: DecodeInput, options?: DecodeOptions): string; -} -interface DecodeOptions { - stream?: boolean; -} -declare const TextDecoder: { - new (): TextDecoder; -}; +type DecodeInput = ArrayBufferView | ArrayBufferLike; +type DecodeOptions = Parameters[1]; function isWtf8Surrogate(bytes: Uint8Array, index: number): boolean { return index + 2 < bytes.length @@ -45,7 +37,7 @@ function toUint8Array(input: Exclude): Uint8Array export class Wtf8Decoder extends TextDecoder { override decode(input?: DecodeInput, options?: DecodeOptions): string { - if (input == null) { + if (input === undefined) { return super.decode(input, options); }