From 3ee3ef41df1c63b45872217389c337719b2239e5 Mon Sep 17 00:00:00 2001 From: zhom <2717306+zhom@users.noreply.github.com> Date: Tue, 20 Oct 2026 21:29:41 +0400 Subject: [PATCH] build: switch to tsrs --- .github/dependabot.yml | 5 +-- .github/workflows/lint-js.yml | 2 +- donut-sync/package.json | 3 +- flake.nix | 38 ++++++++++++++++++++ package.json | 3 +- pnpm-lock.yaml | 68 +++++++++++++++++++++++++++++++++++ scripts/sync-test-harness.mjs | 2 +- sdk/node/package.json | 6 ++-- src/lib/i18n-parity.test.mjs | 2 +- 9 files changed, 119 insertions(+), 10 deletions(-) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 47f077aa..c7f9d168 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -12,9 +12,10 @@ updates: allow: - dependency-type: "all" ignore: - # donut-sync stays on TypeScript 6: Nest CLI and ts-jest need the + # donut-sync stays on TypeScript 6: ts-jest and `nest start` need the # compiler API, which TypeScript 7.0 does not ship (it returns in 7.1). - # The root is on 7 already, so this only holds donut-sync back. + # Type checks and the donut-sync build use tsrs; this only holds the + # TypeScript 6 package that those tools load. - dependency-name: "typescript" update-types: ["version-update:semver-major"] groups: diff --git a/.github/workflows/lint-js.yml b/.github/workflows/lint-js.yml index a4e4adbc..5cb4a17d 100644 --- a/.github/workflows/lint-js.yml +++ b/.github/workflows/lint-js.yml @@ -22,7 +22,7 @@ concurrency: jobs: build: - # biome and tsc do not depend on the host. Linux starts faster than macOS + # biome and tsrs do not depend on the host. Linux starts faster than macOS # and leaves the five-runner macOS pool to the Rust and release builds. runs-on: ubuntu-latest timeout-minutes: 15 diff --git a/donut-sync/package.json b/donut-sync/package.json index 574b4b38..2c30f673 100644 --- a/donut-sync/package.json +++ b/donut-sync/package.json @@ -6,7 +6,7 @@ "private": true, "license": "UNLICENSED", "scripts": { - "build": "nest build", + "build": "rm -rf dist && tsrs -p tsconfig.build.json --incremental false", "start": "nest start", "start:dev": "nest start --watch", "start:debug": "nest start --debug --watch", @@ -44,6 +44,7 @@ "ts-loader": "^9.6.2", "ts-node": "^10.9.2", "tsconfig-paths": "^4.2.0", + "tsrs": "0.18.0-ts7.1.0-dev.20260929", "typescript": "^6.0.3" }, "jest": { diff --git a/flake.nix b/flake.nix index 6f3362ef..88ffe969 100644 --- a/flake.nix +++ b/flake.nix @@ -192,12 +192,50 @@ ''; }; + # tsrs, the type checker in package.json, installs a glibc build on + # Linux, which NixOS runs only through nix-ld. Its static musl build + # runs anywhere, so the shell and the apps point the npm launcher at + # it (TSRS_BINARY). When package.json moves to a tsrs version with no + # hash here, the launcher falls back to the binary in node_modules. + tsrsVersion = (builtins.fromJSON (builtins.readFile ./package.json)).devDependencies.tsrs; + tsrsHashes = { + "0.18.0-ts7.1.0-dev.20260929" = { + x86_64-linux = "sha512-LHk+AOAtXuTlhJhOJ2+elriEIX17ycXljojeNxrrzckOipTG1LksoVWuCSas2nu00EnWAzrdKpt9oqPylUKZfQ=="; + aarch64-linux = "sha512-Lw7VVU/YQ9JcarODICEiwzMLdFqZprqh5RGTgbS5Uc6I95P635/g5xA1pOC8RVs4efBvAR30J54iDG3l5JEYiw=="; + }; + }; + tsrsHash = (tsrsHashes.${tsrsVersion} or { }).${system} or null; + tsrsMusl = + if tsrsHash != null then + let + npmArch = if system == "x86_64-linux" then "x64" else "arm64"; + in + pkgs.stdenvNoCC.mkDerivation { + pname = "tsrs"; + version = tsrsVersion; + src = pkgs.fetchurl { + url = "https://registry.npmjs.org/@tsrs/linux-${npmArch}-musl/-/linux-${npmArch}-musl-${tsrsVersion}.tgz"; + hash = tsrsHash; + }; + dontFixup = true; + # The binary reads the lib.*.d.ts files next to it. + installPhase = '' + runHook preInstall + mkdir -p "$out/lib/tsrs" + cp -r . "$out/lib/tsrs/" + runHook postInstall + ''; + } + else + null; + linuxLibraryEnv = lib.optionalString isLinux '' export NIX_LD="${nixLd}" export NIX_LD_LIBRARY_PATH="${runtimeLibPath}:''${NIX_LD_LIBRARY_PATH:-}" export LD_LIBRARY_PATH="${runtimeLibPath}:''${LD_LIBRARY_PATH:-}" export LIBRARY_PATH="${runtimeLibPath}:''${LIBRARY_PATH:-}" export XDG_DATA_DIRS="${pkgs.gsettings-desktop-schemas}/share:${pkgs.gtk3}/share:''${XDG_DATA_DIRS:-}" + ${lib.optionalString (tsrsMusl != null) ''export TSRS_BINARY="${tsrsMusl}/lib/tsrs/tsrs"''} ''; pkgConfigModules = (lib.optionals isLinux [ "gdk-3.0" "webkit2gtk-4.1" "javascriptcoregtk-4.1" "libsoup-3.0" "ayatana-appindicator3-0.1" ]) diff --git a/package.json b/package.json index e959f75a..9a4e366b 100644 --- a/package.json +++ b/package.json @@ -48,7 +48,7 @@ "e2e:sync": "node e2e/run.mjs --suite=sync", "e2e:browser": "node e2e/run.mjs --suite=browser", "lint": "pnpm lint:js && pnpm lint:rust && pnpm lint:spell", - "lint:js": "biome check src/ e2e/ scripts/generate-licenses.mjs scripts/generate-licenses.test.mjs src-tauri/download-xray.mjs src-tauri/download-xray.test.mjs src-tauri/copy-proxy-binary.mjs && tsc --noEmit && cd donut-sync && biome check src/ && tsc --noEmit", + "lint:js": "biome check src/ e2e/ scripts/generate-licenses.mjs scripts/generate-licenses.test.mjs src-tauri/download-xray.mjs src-tauri/download-xray.test.mjs src-tauri/copy-proxy-binary.mjs && tsrs --noEmit && cd donut-sync && biome check src/ && tsrs --noEmit", "lint:rust": "cd src-tauri && cargo clippy --all-targets --all-features -- -D warnings -D clippy::all && cargo fmt --all", "lint:spell": "typos .", "tauri": "node scripts/run-with-env.mjs tauri", @@ -132,6 +132,7 @@ "spdx-expression-parse": "5.0.0", "tailwindcss": "^4.3.3", "ts-unused-exports": "^11.0.1", + "tsrs": "0.18.0-ts7.1.0-dev.20260929", "tw-animate-css": "^1.4.0", "typescript": "~7.0.2" }, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 9bb500ab..95a38b0d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -361,6 +361,9 @@ importers: ts-unused-exports: specifier: ^11.0.1 version: 11.0.1(typescript@7.0.2) + tsrs: + specifier: 0.18.0-ts7.1.0-dev.20260929 + version: 0.18.0-ts7.1.0-dev.20260929 tw-animate-css: specifier: ^1.4.0 version: 1.4.0 @@ -443,6 +446,9 @@ importers: tsconfig-paths: specifier: ^4.2.0 version: 4.2.0 + tsrs: + specifier: 0.18.0-ts7.1.0-dev.20260929 + version: 0.18.0-ts7.1.0-dev.20260929 typescript: specifier: ^6.0.3 version: 6.0.3 @@ -2485,6 +2491,40 @@ packages: '@tsconfig/node16@1.0.4': resolution: {integrity: sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==} + '@tsrs/darwin-arm64@0.18.0-ts7.1.0-dev.20260929': + resolution: {integrity: sha512-sAirMpaGA9uRQm2W+t4zC7PjnijNuFa4PCSIfLKKo0JyAUCRfnMeev0UGBQ9F3g+9Nz187tvikUs5Irh5+eajA==} + engines: {node: '>=16.20.0'} + cpu: [arm64] + os: [darwin] + + '@tsrs/linux-arm64-gnu@0.18.0-ts7.1.0-dev.20260929': + resolution: {integrity: sha512-zm9/z9yylig68JiZF4Aq0Cm26n09KEU8YoQRlG7tdDWTBNAIViYw8knxnWYsjMWVZ2XiU4mYq1xdrOKuOgABHg==} + engines: {node: '>=16.20.0'} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@tsrs/linux-arm64-musl@0.18.0-ts7.1.0-dev.20260929': + resolution: {integrity: sha512-Lw7VVU/YQ9JcarODICEiwzMLdFqZprqh5RGTgbS5Uc6I95P635/g5xA1pOC8RVs4efBvAR30J54iDG3l5JEYiw==} + engines: {node: '>=16.20.0'} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@tsrs/linux-x64-gnu@0.18.0-ts7.1.0-dev.20260929': + resolution: {integrity: sha512-EdBwBgNICGu1r1h23ixdcKwsMo6E9ll7ZsY3mNERNYqE1Pwdtcat99d5E7zB1J+oy/Xk6YqiizaB6nolIjpDTw==} + engines: {node: '>=16.20.0'} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@tsrs/linux-x64-musl@0.18.0-ts7.1.0-dev.20260929': + resolution: {integrity: sha512-LHk+AOAtXuTlhJhOJ2+elriEIX17ycXljojeNxrrzckOipTG1LksoVWuCSas2nu00EnWAzrdKpt9oqPylUKZfQ==} + engines: {node: '>=16.20.0'} + cpu: [x64] + os: [linux] + libc: [musl] + '@tybys/wasm-util@0.10.4': resolution: {integrity: sha512-W3c4gRigFS0T/Ma4qIYF3GDAc5AQdHb1yL5znJT1Zv1YaD9Kitx656wBjvr19qbiosmZT8lWDM5BEMynUqX65A==} @@ -4898,6 +4938,11 @@ packages: tslib@2.8.1: resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + tsrs@0.18.0-ts7.1.0-dev.20260929: + resolution: {integrity: sha512-9T0b4Uam/yMFIK16GUx0fUrJqYZnJ/gvSmV9JB8NTyDePvwCI45WFWxyEV/UMV3KfdNRJG/PBsm3fSIB9WmWsA==} + engines: {node: '>=16.20.0'} + hasBin: true + tw-animate-css@1.4.0: resolution: {integrity: sha512-7bziOlRqH0hJx80h/3mbicLW7o8qLsH5+RaLR2t+OHM3D0JlWGODQKQ4cxbK7WlvmUxpcj6Kgu6EKqjrGFe3QQ==} @@ -7236,6 +7281,21 @@ snapshots: '@tsconfig/node16@1.0.4': {} + '@tsrs/darwin-arm64@0.18.0-ts7.1.0-dev.20260929': + optional: true + + '@tsrs/linux-arm64-gnu@0.18.0-ts7.1.0-dev.20260929': + optional: true + + '@tsrs/linux-arm64-musl@0.18.0-ts7.1.0-dev.20260929': + optional: true + + '@tsrs/linux-x64-gnu@0.18.0-ts7.1.0-dev.20260929': + optional: true + + '@tsrs/linux-x64-musl@0.18.0-ts7.1.0-dev.20260929': + optional: true + '@tybys/wasm-util@0.10.4': dependencies: tslib: 2.8.1 @@ -9695,6 +9755,14 @@ snapshots: tslib@2.8.1: {} + tsrs@0.18.0-ts7.1.0-dev.20260929: + optionalDependencies: + '@tsrs/darwin-arm64': 0.18.0-ts7.1.0-dev.20260929 + '@tsrs/linux-arm64-gnu': 0.18.0-ts7.1.0-dev.20260929 + '@tsrs/linux-arm64-musl': 0.18.0-ts7.1.0-dev.20260929 + '@tsrs/linux-x64-gnu': 0.18.0-ts7.1.0-dev.20260929 + '@tsrs/linux-x64-musl': 0.18.0-ts7.1.0-dev.20260929 + tw-animate-css@1.4.0: {} type-detect@4.0.8: {} diff --git a/scripts/sync-test-harness.mjs b/scripts/sync-test-harness.mjs index 0006ee6f..ed3c87d8 100755 --- a/scripts/sync-test-harness.mjs +++ b/scripts/sync-test-harness.mjs @@ -152,7 +152,7 @@ async function startS3(bin) { async function buildDonutSync() { log("Building donut-sync..."); - // `nest build` runs incremental tsc, which silently skips emit when + // An incremental build silently skips emit when // tsconfig.build.tsbuildinfo says nothing changed — even if dist/ was // wiped. Drop the cache so we always produce a fresh dist. const syncDir = path.join(ROOT_DIR, "donut-sync"); diff --git a/sdk/node/package.json b/sdk/node/package.json index 267f92dd..6c74a38d 100644 --- a/sdk/node/package.json +++ b/sdk/node/package.json @@ -19,8 +19,8 @@ }, "scripts": { "test": "node --test test/*.test.mts", - "build": "tsc", - "typecheck": "tsc --noEmit", + "build": "tsrs", + "typecheck": "tsrs --noEmit", "prepublishOnly": "npm run build" }, "keywords": [ @@ -36,6 +36,6 @@ "directory": "sdk/node" }, "devDependencies": { - "typescript": "^7.0.2" + "tsrs": "^0.18.0-ts7.1.0-dev.20260929" } } diff --git a/src/lib/i18n-parity.test.mjs b/src/lib/i18n-parity.test.mjs index 001e553c..b3331d67 100644 --- a/src/lib/i18n-parity.test.mjs +++ b/src/lib/i18n-parity.test.mjs @@ -6,7 +6,7 @@ import { fileURLToPath } from "node:url"; /** * The project rule is that a new user-facing string lands in EVERY locale file - * in the same change. Nothing enforced it: `pnpm lint` runs biome, tsc, clippy + * in the same change. Nothing enforced it: `pnpm lint` runs biome, tsrs, clippy * and typos, and `pnpm test` runs ten suites, none of which reads more than one * locale. A review found four `backendErrors.wayfern*` keys, all of them * emitted by Rust and rendered by the frontend, missing from all nine