diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 3f16b85..feaed9e 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -12,6 +12,18 @@ updates: interval: weekly day: monday open-pull-requests-limit: 5 + ignore: + # `@types/vscode` tracks `engines.vscode`, not the latest release, and is + # pinned exactly (no caret) so the compiler enforces the floor instead of + # merely declaring it. `engines.vscode` is the OLDEST editor the extension + # supports; types newer than that let a call added in a later VS Code + # typecheck cleanly and then fail on the editor we promised to run on. + # `vsce package` refuses the mismatch outright: + # ERROR @types/vscode ^1.125.0 greater than engines.vscode ^1.85.0 + # Taking such a bump means dropping every VS Code in between — a support + # decision, not a dependency update. Raise `engines.vscode` deliberately + # and move the types with it, together. + - dependency-name: '@types/vscode' groups: typescript: patterns: diff --git a/apps/vscode/package.json b/apps/vscode/package.json index c9555aa..5d3426a 100644 --- a/apps/vscode/package.json +++ b/apps/vscode/package.json @@ -124,7 +124,7 @@ }, "devDependencies": { "@types/node": "^22.10.0", - "@types/vscode": "^1.85.0", + "@types/vscode": "1.85.0", "@vscode/vsce": "^3.9.2", "esbuild": "^0.21.5", "typescript": "^5.7.0", diff --git a/package.json b/package.json index e8c005a..ce47c8d 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,7 @@ "husky": "^9.1.0", "prettier": "^3.9.6", "typescript": "^5.7.0", - "typescript-eslint": "^8.61.1", + "typescript-eslint": "^8.67.0", "vitest": "^4.1.10" } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 9b75435..6cb11db 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -27,8 +27,8 @@ importers: specifier: ^5.7.0 version: 5.9.3 typescript-eslint: - specifier: ^8.61.1 - version: 8.65.0(eslint@10.8.0(jiti@1.21.7))(typescript@5.9.3) + specifier: ^8.67.0 + version: 8.67.0(eslint@10.8.0(jiti@1.21.7))(typescript@5.9.3) vitest: specifier: ^4.1.10 version: 4.1.10(@types/node@22.19.19)(vite@8.2.1(@types/node@22.19.19)(esbuild@0.21.5)(jiti@1.21.7)) @@ -176,8 +176,8 @@ importers: specifier: ^22.10.0 version: 22.19.19 '@types/vscode': - specifier: ^1.85.0 - version: 1.120.0 + specifier: 1.85.0 + version: 1.85.0 '@vscode/vsce': specifier: ^3.9.2 version: 3.9.2 @@ -792,66 +792,66 @@ packages: '@types/sarif@2.1.7': resolution: {integrity: sha512-kRz0VEkJqWLf1LLVN4pT1cg1Z9wAuvI6L97V3m2f5B76Tg8d413ddvLBPTEHAZJlnn4XSvu0FkZtViCQGVyrXQ==} - '@types/vscode@1.120.0': - resolution: {integrity: sha512-feaT4Rst+FkTch5zz/ZbNCxoIvo55YU80Be2kiL7OJcod4+CUYf2lUBPdIJzozNnSEMq1VRTGrWEcCGFB3fBmA==} + '@types/vscode@1.85.0': + resolution: {integrity: sha512-CF/RBon/GXwdfmnjZj0WTUMZN5H6YITOfBCP4iEZlOtVQXuzw6t7Le7+cR+7JzdMrnlm7Mfp49Oj2TuSXIWo3g==} - '@typescript-eslint/eslint-plugin@8.65.0': - resolution: {integrity: sha512-IEgob78X12rHpUmtcwFsXhZdVGJtwTVP8FiCLZkR6GlYVrl2PcuB+KhCE5BlVC/eQpQnu8WXRtkHZuPar+gCRA==} + '@typescript-eslint/eslint-plugin@8.67.0': + resolution: {integrity: sha512-Un7Heoyj65NREbKAyIrFxeM143NZpExWmy1Nep4DLeQOeLlTeumPjoNKnBrU5D5moWXbPJgRa5Uwcdu0faVNGQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - '@typescript-eslint/parser': ^8.65.0 + '@typescript-eslint/parser': ^8.67.0 eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/parser@8.65.0': - resolution: {integrity: sha512-CZ4nMxWwgu1HEEFNkeaCptra9QCtkmKdgf3sWh1rl1trIhmxLilgTV4cwcbQ4wemnT4sWQN8CaKOmdYx+g2gMA==} + '@typescript-eslint/parser@8.67.0': + resolution: {integrity: sha512-fUBfTuuEulWqX6V8+O3PtScV01tzYYRUDTAirHFKoRAt7nOzoGiPt0M/bB47wWNy0coOOcgEwAMUtBpykMxl6w==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/project-service@8.65.0': - resolution: {integrity: sha512-SxnPhbTsGahizDgbu7oqFH/xVtzIqMd/s+WtnSxNxJZJpLbdT5IPdzg8EZxO3+PoKahXmwJLeNQOpKJb3/bi7Q==} + '@typescript-eslint/project-service@8.67.0': + resolution: {integrity: sha512-cvE8c7ulYeXN9fYuszhCeCsbzyVEXuhrRCybnBre7TUmqb5nRmBfQAwCj0O3WJFDeyAZt4VYv51vMCC9LHSdYw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/scope-manager@8.65.0': - resolution: {integrity: sha512-Esbl8OSYiVxBokYgWPf7VVWg/BE798wXhimnn9ML9Pt5qoDf8bfQlgjlKXR/k98+AcNzlLKYrpCcrcuZ9DZLgg==} + '@typescript-eslint/scope-manager@8.67.0': + resolution: {integrity: sha512-EgvsleTwS4E+WzzSvem8fAUubLwatMNF1B5hHSLQxcvs7q2dtRhGyujHwLJSYlG41niJ7GP24Aha2+0mb1b2kg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/tsconfig-utils@8.65.0': - resolution: {integrity: sha512-j6GzGqCiRdA7Qhur2VVmKZAkBLfnHFQfx4TaJGL9RMveZqCo48jSHHO0DTgizEnGhtWnqmbtCUSrqSkdiY/0Hg==} + '@typescript-eslint/tsconfig-utils@8.67.0': + resolution: {integrity: sha512-vV+LUSv5njUWsknE71fqKTlXUva+R76SaeORd6Zojcunk/6DvKFXONU3BrAs2H49mbygUXt6gbYunzwqNwlhdg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/type-utils@8.65.0': - resolution: {integrity: sha512-YjaZ7PRI5qY7ax2L3PbvX0rRyGtipAReCWs0mhhDBHjH/vl0g0BonaGXrKdKpMbIIsMIwDgbk/xzkBTyAltS5g==} + '@typescript-eslint/type-utils@8.67.0': + resolution: {integrity: sha512-aVWDXbRmdXO9siTfX4ditQI1T9+zVcNazT48EJCD0v40/9RIFoUgZ05CmGEq9H2gixRpjUn/iplwvlcvutJW/Q==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/types@8.65.0': - resolution: {integrity: sha512-JSSwWNy+H0E/01jJEM+hrX6N0OFDzFzeIhHFSAS01tlVaevpG8cFyYRPhS5yjGOvBUx3sqQHVMjCL1CAZZMxBg==} + '@typescript-eslint/types@8.67.0': + resolution: {integrity: sha512-sBtgslww8nsMYUjhdPBiSyUqSzT8uR6g93A2QXnQC8+cGdjz0CyaOdqHDRJb1AtORbZCNUJBBeFA/tNR2uQmww==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/typescript-estree@8.65.0': - resolution: {integrity: sha512-JboAE2swaYt4tb1fHhHTABE2K+OLy09XfcTbhnk4Pw96f9dd2e9iYsJ28gBggHlo5z5x1rkyWvcPoTuNTd4oGg==} + '@typescript-eslint/typescript-estree@8.67.0': + resolution: {integrity: sha512-EKQBCE9yNlRJYm7jdTW5AhDacDUmSwQb0FAJAmK2EKYrNXIsa2vxcSZx6PvJ/dEdI6lS+Y9W+EXckLj0iPFGcw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/utils@8.65.0': - resolution: {integrity: sha512-gXiwIHsYreboxeJucHKPvgwl7dXt50mF8s1/c00cP/WoVTyWKFdtfhRWwZiXYFU5H2O8vVoSLNrexFZjYS/SGA==} + '@typescript-eslint/utils@8.67.0': + resolution: {integrity: sha512-U9D1FdwEWBwok3hxxSdhclMb0twvt9QnjIQ0VfQ1AiX2epnpSgv2ubVDsayOFyY8K6FX+AQ7E0FKWVG3iKsj1A==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/visitor-keys@8.65.0': - resolution: {integrity: sha512-8C71BQkGjiMmXtop7pHVJu1l2NNShFdkCyD6a2ezzs5vU/L3LRtb69EtcteFwz0mYMPzIgOw0n6OV4VBUWZd7A==} + '@typescript-eslint/visitor-keys@8.67.0': + resolution: {integrity: sha512-fkv8dHRDqfGtTHuJeebdrQ7cX6Ad4WAS00rgHh9UGvMycF1mjBfsxry1XsLIFhWZ6Judlh6UdzK+TYlbpCXgnA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} '@typespec/ts-http-runtime@0.3.8': @@ -2173,6 +2173,11 @@ packages: engines: {node: '>=10'} hasBin: true + semver@7.8.5: + resolution: {integrity: sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==} + engines: {node: '>=10'} + hasBin: true + send@1.2.1: resolution: {integrity: sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ==} engines: {node: '>= 18'} @@ -2365,8 +2370,8 @@ packages: typed-rest-client@1.8.11: resolution: {integrity: sha512-5UvfMpd1oelmUPRbbaVnq+rHP7ng2cE4qoQkQeAqxRL6PklkxsM0g32/HL0yfvruK6ojQ5x8EE+HF4YV6DtuCA==} - typescript-eslint@8.65.0: - resolution: {integrity: sha512-/ggrHAwyjENDusvyxbuqxAC2dTnZg/Z8F+fgQtYIz+L6n/9HfSlEZcFGV/NsMNa6CkGk0xUjUAFwC0vHOflvIA==} + typescript-eslint@8.67.0: + resolution: {integrity: sha512-S2udFs8tCKEKffuJ4TB1idGUZiXdCPGi3IPBGWXarbLQ5UPXORV8QEVzJ4gCRduURMb5EkpNCdjbk0eDIuI8Yg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 @@ -3079,16 +3084,16 @@ snapshots: '@types/sarif@2.1.7': {} - '@types/vscode@1.120.0': {} + '@types/vscode@1.85.0': {} - '@typescript-eslint/eslint-plugin@8.65.0(@typescript-eslint/parser@8.65.0(eslint@10.8.0(jiti@1.21.7))(typescript@5.9.3))(eslint@10.8.0(jiti@1.21.7))(typescript@5.9.3)': + '@typescript-eslint/eslint-plugin@8.67.0(@typescript-eslint/parser@8.67.0(eslint@10.8.0(jiti@1.21.7))(typescript@5.9.3))(eslint@10.8.0(jiti@1.21.7))(typescript@5.9.3)': dependencies: '@eslint-community/regexpp': 4.12.2 - '@typescript-eslint/parser': 8.65.0(eslint@10.8.0(jiti@1.21.7))(typescript@5.9.3) - '@typescript-eslint/scope-manager': 8.65.0 - '@typescript-eslint/type-utils': 8.65.0(eslint@10.8.0(jiti@1.21.7))(typescript@5.9.3) - '@typescript-eslint/utils': 8.65.0(eslint@10.8.0(jiti@1.21.7))(typescript@5.9.3) - '@typescript-eslint/visitor-keys': 8.65.0 + '@typescript-eslint/parser': 8.67.0(eslint@10.8.0(jiti@1.21.7))(typescript@5.9.3) + '@typescript-eslint/scope-manager': 8.67.0 + '@typescript-eslint/type-utils': 8.67.0(eslint@10.8.0(jiti@1.21.7))(typescript@5.9.3) + '@typescript-eslint/utils': 8.67.0(eslint@10.8.0(jiti@1.21.7))(typescript@5.9.3) + '@typescript-eslint/visitor-keys': 8.67.0 eslint: 10.8.0(jiti@1.21.7) ignore: 7.0.6 natural-compare: 1.4.0 @@ -3097,41 +3102,41 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@8.65.0(eslint@10.8.0(jiti@1.21.7))(typescript@5.9.3)': + '@typescript-eslint/parser@8.67.0(eslint@10.8.0(jiti@1.21.7))(typescript@5.9.3)': dependencies: - '@typescript-eslint/scope-manager': 8.65.0 - '@typescript-eslint/types': 8.65.0 - '@typescript-eslint/typescript-estree': 8.65.0(typescript@5.9.3) - '@typescript-eslint/visitor-keys': 8.65.0 + '@typescript-eslint/scope-manager': 8.67.0 + '@typescript-eslint/types': 8.67.0 + '@typescript-eslint/typescript-estree': 8.67.0(typescript@5.9.3) + '@typescript-eslint/visitor-keys': 8.67.0 debug: 4.4.3 eslint: 10.8.0(jiti@1.21.7) typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/project-service@8.65.0(typescript@5.9.3)': + '@typescript-eslint/project-service@8.67.0(typescript@5.9.3)': dependencies: - '@typescript-eslint/tsconfig-utils': 8.65.0(typescript@5.9.3) - '@typescript-eslint/types': 8.65.0 + '@typescript-eslint/tsconfig-utils': 8.67.0(typescript@5.9.3) + '@typescript-eslint/types': 8.67.0 debug: 4.4.3 typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/scope-manager@8.65.0': + '@typescript-eslint/scope-manager@8.67.0': dependencies: - '@typescript-eslint/types': 8.65.0 - '@typescript-eslint/visitor-keys': 8.65.0 + '@typescript-eslint/types': 8.67.0 + '@typescript-eslint/visitor-keys': 8.67.0 - '@typescript-eslint/tsconfig-utils@8.65.0(typescript@5.9.3)': + '@typescript-eslint/tsconfig-utils@8.67.0(typescript@5.9.3)': dependencies: typescript: 5.9.3 - '@typescript-eslint/type-utils@8.65.0(eslint@10.8.0(jiti@1.21.7))(typescript@5.9.3)': + '@typescript-eslint/type-utils@8.67.0(eslint@10.8.0(jiti@1.21.7))(typescript@5.9.3)': dependencies: - '@typescript-eslint/types': 8.65.0 - '@typescript-eslint/typescript-estree': 8.65.0(typescript@5.9.3) - '@typescript-eslint/utils': 8.65.0(eslint@10.8.0(jiti@1.21.7))(typescript@5.9.3) + '@typescript-eslint/types': 8.67.0 + '@typescript-eslint/typescript-estree': 8.67.0(typescript@5.9.3) + '@typescript-eslint/utils': 8.67.0(eslint@10.8.0(jiti@1.21.7))(typescript@5.9.3) debug: 4.4.3 eslint: 10.8.0(jiti@1.21.7) ts-api-utils: 2.5.0(typescript@5.9.3) @@ -3139,37 +3144,37 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/types@8.65.0': {} + '@typescript-eslint/types@8.67.0': {} - '@typescript-eslint/typescript-estree@8.65.0(typescript@5.9.3)': + '@typescript-eslint/typescript-estree@8.67.0(typescript@5.9.3)': dependencies: - '@typescript-eslint/project-service': 8.65.0(typescript@5.9.3) - '@typescript-eslint/tsconfig-utils': 8.65.0(typescript@5.9.3) - '@typescript-eslint/types': 8.65.0 - '@typescript-eslint/visitor-keys': 8.65.0 + '@typescript-eslint/project-service': 8.67.0(typescript@5.9.3) + '@typescript-eslint/tsconfig-utils': 8.67.0(typescript@5.9.3) + '@typescript-eslint/types': 8.67.0 + '@typescript-eslint/visitor-keys': 8.67.0 debug: 4.4.3 minimatch: 10.2.6 - semver: 7.8.1 + semver: 7.8.5 tinyglobby: 0.2.17 ts-api-utils: 2.5.0(typescript@5.9.3) typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/utils@8.65.0(eslint@10.8.0(jiti@1.21.7))(typescript@5.9.3)': + '@typescript-eslint/utils@8.67.0(eslint@10.8.0(jiti@1.21.7))(typescript@5.9.3)': dependencies: '@eslint-community/eslint-utils': 4.10.1(eslint@10.8.0(jiti@1.21.7)) - '@typescript-eslint/scope-manager': 8.65.0 - '@typescript-eslint/types': 8.65.0 - '@typescript-eslint/typescript-estree': 8.65.0(typescript@5.9.3) + '@typescript-eslint/scope-manager': 8.67.0 + '@typescript-eslint/types': 8.67.0 + '@typescript-eslint/typescript-estree': 8.67.0(typescript@5.9.3) eslint: 10.8.0(jiti@1.21.7) typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/visitor-keys@8.65.0': + '@typescript-eslint/visitor-keys@8.67.0': dependencies: - '@typescript-eslint/types': 8.65.0 + '@typescript-eslint/types': 8.67.0 eslint-visitor-keys: 5.0.1 '@typespec/ts-http-runtime@0.3.8': @@ -4538,6 +4543,8 @@ snapshots: semver@7.8.1: {} + semver@7.8.5: {} + send@1.2.1: dependencies: debug: 4.4.3 @@ -4770,12 +4777,12 @@ snapshots: tunnel: 0.0.6 underscore: 1.13.8 - typescript-eslint@8.65.0(eslint@10.8.0(jiti@1.21.7))(typescript@5.9.3): + typescript-eslint@8.67.0(eslint@10.8.0(jiti@1.21.7))(typescript@5.9.3): dependencies: - '@typescript-eslint/eslint-plugin': 8.65.0(@typescript-eslint/parser@8.65.0(eslint@10.8.0(jiti@1.21.7))(typescript@5.9.3))(eslint@10.8.0(jiti@1.21.7))(typescript@5.9.3) - '@typescript-eslint/parser': 8.65.0(eslint@10.8.0(jiti@1.21.7))(typescript@5.9.3) - '@typescript-eslint/typescript-estree': 8.65.0(typescript@5.9.3) - '@typescript-eslint/utils': 8.65.0(eslint@10.8.0(jiti@1.21.7))(typescript@5.9.3) + '@typescript-eslint/eslint-plugin': 8.67.0(@typescript-eslint/parser@8.67.0(eslint@10.8.0(jiti@1.21.7))(typescript@5.9.3))(eslint@10.8.0(jiti@1.21.7))(typescript@5.9.3) + '@typescript-eslint/parser': 8.67.0(eslint@10.8.0(jiti@1.21.7))(typescript@5.9.3) + '@typescript-eslint/typescript-estree': 8.67.0(typescript@5.9.3) + '@typescript-eslint/utils': 8.67.0(eslint@10.8.0(jiti@1.21.7))(typescript@5.9.3) eslint: 10.8.0(jiti@1.21.7) typescript: 5.9.3 transitivePeerDependencies: diff --git a/scripts/vscode-types-engine.test.ts b/scripts/vscode-types-engine.test.ts new file mode 100644 index 0000000..eb3435b --- /dev/null +++ b/scripts/vscode-types-engine.test.ts @@ -0,0 +1,62 @@ +// `@types/vscode` may never be newer than `engines.vscode`. +// +// `engines.vscode` states the OLDEST VS Code the extension supports. The types +// have to match that floor, not the newest release: compiling against 1.125's +// API surface while claiming to run on 1.85 lets an editor-version-gated call +// typecheck cleanly and then throw `undefined is not a function` on the older +// editor nobody tested. +// +// `vsce package` already enforces this and refuses to build: +// +// ERROR @types/vscode ^1.125.0 greater than engines.vscode ^1.85.0 +// +// but only inside `pnpm release:check`, several minutes into CI and after a +// full workspace build. A dependency bot proposing the newer types (#262) is +// the ordinary way this happens, so catch it in the unit suite where the +// message arrives in seconds — and where it names the reason rather than the +// symptom. +// +// Fixing it is not "take the bump": raising `engines.vscode` drops every VS +// Code between the two versions, which is a support decision to make on +// purpose. Move both together when you make it. + +import { readFileSync } from 'node:fs'; +import { resolve } from 'node:path'; +import { describe, expect, it } from 'vitest'; + +const root = resolve(import.meta.dirname, '..'); +const pkg = JSON.parse(readFileSync(resolve(root, 'apps/vscode/package.json'), 'utf8')) as { + engines: { vscode: string }; + devDependencies: Record; +}; + +/** `^1.85.0` → `[1, 85, 0]`. Ranges here are always a caret over an exact version. */ +function floor(range: string): number[] { + const match = /(\d+)\.(\d+)\.(\d+)/.exec(range); + if (!match) throw new Error(`cannot read a version out of ${JSON.stringify(range)}`); + return [Number(match[1]), Number(match[2]), Number(match[3])]; +} + +function compare(a: number[], b: number[]): number { + for (let i = 0; i < 3; i++) { + const diff = (a[i] ?? 0) - (b[i] ?? 0); + if (diff !== 0) return diff; + } + return 0; +} + +describe('the VS Code extension', () => { + it('does not compile against a newer API than it claims to run on', () => { + const engine = pkg.engines.vscode; + const types = pkg.devDependencies['@types/vscode']; + expect(types, 'apps/vscode must declare @types/vscode').toBeTypeOf('string'); + + expect( + compare(floor(types!), floor(engine)), + `@types/vscode ${types} is newer than engines.vscode ${engine}. ` + + `The types must match the oldest supported editor, so either pin them back ` + + `or raise engines.vscode deliberately — raising it drops support for every ` + + `VS Code in between.`, + ).toBeLessThanOrEqual(0); + }); +});