From 354c6d6b4e7ef2ed87fad60b2632a65cfc968740 Mon Sep 17 00:00:00 2001 From: skovhus Date: Sun, 20 Sep 2026 23:43:33 +0200 Subject: [PATCH 1/2] Enable type-aware Oxlint rules and compiler diagnostics --- .oxlintrc.json | 13 ++++ docs/development-guide.md | 10 ++- package.json | 3 +- pnpm-lock.yaml | 69 ++++++++++++++++++- .../__tests__/background-lifecycle.test.ts | 2 +- server/src/__tests__/server.test.ts | 4 +- server/src/analyser.ts | 10 ++- server/src/server.ts | 22 +++--- .../shellcheck/__tests__/lifecycle.test.ts | 16 ++--- server/src/shellcheck/index.ts | 12 ++-- server/src/shfmt/index.ts | 4 +- server/src/util/logger.ts | 2 +- tsconfig.json | 3 +- vscode-client/src/server.ts | 5 +- 14 files changed, 137 insertions(+), 38 deletions(-) diff --git a/.oxlintrc.json b/.oxlintrc.json index b64ca1d19..550a18b90 100644 --- a/.oxlintrc.json +++ b/.oxlintrc.json @@ -1,5 +1,9 @@ { "$schema": "./node_modules/oxlint/configuration_schema.json", + "options": { + "typeAware": true, + "typeCheck": true + }, "categories": { "correctness": "error" }, @@ -45,5 +49,14 @@ "typescript/no-unnecessary-type-constraint": "error", "typescript/no-unsafe-function-type": "error" }, + "overrides": [ + { + "files": ["**/*.test.ts"], + "rules": { + // Vitest assertions inspect mock methods without calling them. + "typescript/unbound-method": "off" + } + } + ], "ignorePatterns": ["**/out/**", "**/node_modules/**", "coverage/**", ".context/**"] } diff --git a/docs/development-guide.md b/docs/development-guide.md index 75495340d..549cdfdb4 100644 --- a/docs/development-guide.md +++ b/docs/development-guide.md @@ -51,8 +51,9 @@ Development uses [Oxlint][oxlint], [Prettier][prettier], and integration tests u pnpm verify # fixes lint/formatting, compiles, type-checks, and runs tests pnpm verify:bail # checks lint/formatting, compiles, and runs tests with coverage - pnpm lint # fixes lint and formatting - pnpm lint:bail # checks lint and formatting without rewriting files + pnpm lint # fixes lint and formatting, and checks types + pnpm lint:bail # checks lint, formatting, and types without rewriting files + pnpm typecheck # checks lint and types through Oxlint without emitting files pnpm test pnpm test:coverage pnpm test:watch @@ -64,6 +65,10 @@ pnpm test server/src/__tests__/input-declarations.test.ts pnpm test server/src/__tests__/server.test.ts -t 'rename' ``` +The lint commands and `pnpm typecheck` run [type-aware rules and TypeScript +compiler diagnostics through Oxlint][oxlint-types]. `pnpm compile` and `pnpm watch` +still use `tsc` to emit JavaScript and declarations. + Tests and test helpers are type-checked using `tsconfig.test.json`. Vitest runs files sequentially so subprocess and filesystem integration tests stay isolated. Coverage reports are written to `coverage/` in HTML and LCOV formats. @@ -146,5 +151,6 @@ To analyze the performance of the extension or server using the Chrome inspector [vitest]: https://vitest.dev/ [prettier]: https://prettier.io/ [oxlint]: https://oxc.rs/docs/guide/usage/linter/ +[oxlint-types]: https://oxc.rs/docs/guide/usage/linter/type-aware.html [pnpm]: https://pnpm.io/installation [node]: https://nodejs.org/en/download/ diff --git a/package.json b/package.json index 689a7a8ca..69102047d 100644 --- a/package.json +++ b/package.json @@ -18,13 +18,14 @@ "postinstall": "pnpm --dir=vscode-client install", "format": "prettier --write \"**/*.{js,ts,tsx,mts}\"", "format:check": "prettier --check \"**/*.{js,ts,tsx,mts}\"", - "typecheck": "tsc --noEmit -p tsconfig.test.json" + "typecheck": "oxlint --deny-warnings" }, "devDependencies": { "@types/node": "22.20.4", "@vitest/coverage-v8": "5.0.1", "cross-spawn": "7.0.6", "oxlint": "1.83.0", + "oxlint-tsgolint": "7.0.2002", "prettier": "2.8.8", "typescript": "6.0.3", "vitest": "5.0.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 1dedc516f..921877fae 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -180,7 +180,10 @@ importers: version: 7.0.6 oxlint: specifier: 1.83.0 - version: 1.83.0 + version: 1.83.0(oxlint-tsgolint@7.0.2002) + oxlint-tsgolint: + specifier: 7.0.2002 + version: 7.0.2002 prettier: specifier: 2.8.8 version: 2.8.8 @@ -288,6 +291,36 @@ packages: '@oxc-project/types@0.150.0': resolution: {integrity: sha512-rDS5/31E9HfPl/CIzGrn0DOlvBbXFseQ5URJ9sYMfstbKLD/c6Gm9vmRzRGDdAXyOIL4zmO37lc9RIwYqVruZw==} + '@oxlint-tsgolint/darwin-arm64@7.0.2002': + resolution: {integrity: sha512-E3yYb/tI+5M3SqGgKwrwUD0nmjA2FMGD1xFbma46qi8Y7+nPTlGY6bZk/hqxijc9Vda/tdtUxQ2d5zGIEX9qlg==} + cpu: [arm64] + os: [darwin] + + '@oxlint-tsgolint/darwin-x64@7.0.2002': + resolution: {integrity: sha512-qEaMySdvzs8faaJwMO4dFtPFCa+degFCz+HbkFQ0REcIJqJ16KmC0smt30FAI9TeEHCoAtz6sU/6acJvi4uaxg==} + cpu: [x64] + os: [darwin] + + '@oxlint-tsgolint/linux-arm64@7.0.2002': + resolution: {integrity: sha512-bqPObCNIR6tDQSc0Xn9Nu7EfWRXFB+qFzADRl/q6YA8zT9YUg3pGUbmicV2hV91uLpiot74so9ocGjx35SaX6w==} + cpu: [arm64] + os: [linux] + + '@oxlint-tsgolint/linux-x64@7.0.2002': + resolution: {integrity: sha512-E5CcRALAYdiQMbdYjEqlLOiYuEdt21RtXiyxIoD8bfypdfkpWppacijKOR4i0DtLXFRVwCGQggZBWk5bOIpU1A==} + cpu: [x64] + os: [linux] + + '@oxlint-tsgolint/win32-arm64@7.0.2002': + resolution: {integrity: sha512-L+ul0ZFDiz/ZmTwCQ1J/qS7S6s45ktiaFqb+ZIzx+1sSdtdRxm8/H0+p4VDQYrCKBFzKNb6VjUlm48bNEe3BUg==} + cpu: [arm64] + os: [win32] + + '@oxlint-tsgolint/win32-x64@7.0.2002': + resolution: {integrity: sha512-zkZeJfo4UmYiCzj77u85eCDpdxOiQiSAsV6j9Pvj5e7Vu5+MvwLtK1xmVutE77tJmUJ3eBOSXHR6WgY4AwHHGQ==} + cpu: [x64] + os: [win32] + '@oxlint/binding-android-arm-eabi@1.83.0': resolution: {integrity: sha512-0yGY24EwsLk5YDe6F+VkmZyRHSwJDALa3nIrPpq7FXmp2lV2d0TzvBCGeZk+wgiULRGr5blhyr4QMp5KCXJUqA==} engines: {node: ^20.19.0 || >=22.12.0} @@ -762,6 +795,10 @@ packages: resolution: {integrity: sha512-XrsrhT5sybtKI6wakr2SPOlGZWWYbUXZ7a0jT8/QOeAPau+1X/bSegNe5YR75oJmEZQbKningirmGOEJCIk61Q==} engines: {node: '>=12.20.0'} + oxlint-tsgolint@7.0.2002: + resolution: {integrity: sha512-rQAj2RAQM57nCwTd3PhtnAkREGW2StqI47tzudNlJF8WwGommM7rVpeP4O1O8/ZiuDZ9f2GnTESzLHGTluwkvQ==} + hasBin: true + oxlint@1.83.0: resolution: {integrity: sha512-cyDzSzaw3uzP0TeCeq3lLRPPoaUxkbB4ZOXj+kn+5r+BX9V+4bNVGk9lxer+WrgcpebH4JxLlJ3KQjveVztOLQ==} engines: {node: ^20.19.0 || >=22.12.0} @@ -1033,6 +1070,24 @@ snapshots: '@oxc-project/types@0.150.0': {} + '@oxlint-tsgolint/darwin-arm64@7.0.2002': + optional: true + + '@oxlint-tsgolint/darwin-x64@7.0.2002': + optional: true + + '@oxlint-tsgolint/linux-arm64@7.0.2002': + optional: true + + '@oxlint-tsgolint/linux-x64@7.0.2002': + optional: true + + '@oxlint-tsgolint/win32-arm64@7.0.2002': + optional: true + + '@oxlint-tsgolint/win32-x64@7.0.2002': + optional: true + '@oxlint/binding-android-arm-eabi@1.83.0': optional: true @@ -1345,7 +1400,16 @@ snapshots: obug@2.2.1: {} - oxlint@1.83.0: + oxlint-tsgolint@7.0.2002: + optionalDependencies: + '@oxlint-tsgolint/darwin-arm64': 7.0.2002 + '@oxlint-tsgolint/darwin-x64': 7.0.2002 + '@oxlint-tsgolint/linux-arm64': 7.0.2002 + '@oxlint-tsgolint/linux-x64': 7.0.2002 + '@oxlint-tsgolint/win32-arm64': 7.0.2002 + '@oxlint-tsgolint/win32-x64': 7.0.2002 + + oxlint@1.83.0(oxlint-tsgolint@7.0.2002): optionalDependencies: '@oxlint/binding-android-arm-eabi': 1.83.0 '@oxlint/binding-android-arm64': 1.83.0 @@ -1366,6 +1430,7 @@ snapshots: '@oxlint/binding-win32-arm64-msvc': 1.83.0 '@oxlint/binding-win32-ia32-msvc': 1.83.0 '@oxlint/binding-win32-x64-msvc': 1.83.0 + oxlint-tsgolint: 7.0.2002 path-key@3.1.1: {} diff --git a/server/src/__tests__/background-lifecycle.test.ts b/server/src/__tests__/background-lifecycle.test.ts index 8061d42a6..0217f005a 100644 --- a/server/src/__tests__/background-lifecycle.test.ts +++ b/server/src/__tests__/background-lifecycle.test.ts @@ -32,7 +32,7 @@ it.each(['shutdown', 'configuration change'])( if (event === 'shutdown') { await connection.onShutdown.mock.calls[0][0]({} as any) } else { - connection.onDidChangeConfiguration.mock.calls[0][0]({ + await connection.onDidChangeConfiguration.mock.calls[0][0]({ settings: { bashIde: { backgroundAnalysisMaxFiles: 0 } }, }) } diff --git a/server/src/__tests__/server.test.ts b/server/src/__tests__/server.test.ts index 37b243b44..15f2a401d 100644 --- a/server/src/__tests__/server.test.ts +++ b/server/src/__tests__/server.test.ts @@ -308,7 +308,9 @@ describe('server', () => { const onDidChangeConfiguration = connection.onDidChangeConfiguration.mock.calls[0][0] - onDidChangeConfiguration({ settings: { bashIde: { explainshellEndpoint: 42 } } }) + await onDidChangeConfiguration({ + settings: { bashIde: { explainshellEndpoint: 42 } }, + }) expect(connection.workspace.getConfiguration).toHaveBeenCalled() expect(Logger.prototype.log).toHaveBeenCalledWith(expect.any(Number), [ diff --git a/server/src/analyser.ts b/server/src/analyser.ts index d5d69a824..6f5e775b0 100644 --- a/server/src/analyser.ts +++ b/server/src/analyser.ts @@ -232,7 +232,9 @@ export default class Analyzer { } catch (error) { if (!signal.aborted) logger.warn( - `BackgroundAnalysis: failed resolving glob "${globPattern}". The experience across files will be degraded. Error: ${error}`, + `BackgroundAnalysis: failed resolving glob "${globPattern}". The experience across files will be degraded. Error: ${String( + error, + )}`, ) return { filesParsed } } @@ -293,7 +295,9 @@ export default class Analyzer { filesParsed++ } catch (error) { if (stopped()) break - logger.warn(`BackgroundAnalysis: Failed analyzing ${uri}. Error: ${error}`) + logger.warn( + `BackgroundAnalysis: Failed analyzing ${uri}. Error: ${String(error)}`, + ) } } // Rereading background files can remove source relationships. Recompute @@ -1067,7 +1071,7 @@ export default class Analyzer { uri, }) } catch (err) { - logger.warn(`Error while analyzing file ${uri}: ${err}`) + logger.warn(`Error while analyzing file ${uri}: ${String(err)}`) return false } } diff --git a/server/src/server.ts b/server/src/server.ts index e980c72c9..0698e88f3 100644 --- a/server/src/server.ts +++ b/server/src/server.ts @@ -161,7 +161,7 @@ export default class BashServer { // when the text document first opened or when its content has changed. currentDocument = document if (initialized) { - this.analyzeAndLintDocument(document) + void this.analyzeAndLintDocument(document) } }) @@ -170,7 +170,7 @@ export default class BashServer { if (currentDocument?.uri === event.document.uri) { currentDocument = null } - connection.sendDiagnostics({ uri: event.document.uri, diagnostics: [] }) + void connection.sendDiagnostics({ uri: event.document.uri, diagnostics: [] }) delete this.uriToCodeActions[event.document.uri] }) @@ -230,7 +230,7 @@ export default class BashServer { if (hasConfigurationCapability) { // Register event for all configuration changes. if (canDynamicallyRegisterConfigurationChangeNotification) { - connection.client.register(LSP.DidChangeConfigurationNotification.type, { + void connection.client.register(LSP.DidChangeConfigurationNotification.type, { section: CONFIGURATION_SECTION, }) } @@ -247,7 +247,7 @@ export default class BashServer { if (currentDocument) { // If we already have a document, analyze it now that we're initialized // and the linter is ready. - this.analyzeAndLintDocument(currentDocument) + void this.analyzeAndLintDocument(currentDocument) } // NOTE: we do not block the server initialization on this background analysis. @@ -259,9 +259,9 @@ export default class BashServer { const configChanged = this.updateConfiguration(settings[CONFIGURATION_SECTION]) if (configChanged && initialized) { logger.debug('Configuration changed') - this.startBackgroundAnalysis() + void this.startBackgroundAnalysis() for (const document of this.documents.all()) { - this.analyzeAndLintDocument(document) + void this.analyzeAndLintDocument(document) } } }) @@ -335,7 +335,7 @@ export default class BashServer { return true } } catch (err) { - logger.warn(`updateConfiguration: failed with ${err}`) + logger.warn(`updateConfiguration: failed with ${String(err)}`) } } @@ -373,11 +373,11 @@ export default class BashServer { result, }) } catch (err) { - logger.error(`Error while linting: ${err}`) + logger.error(`Error while linting: ${String(err)}`) } } - this.connection.sendDiagnostics({ uri, version, diagnostics }) + await this.connection.sendDiagnostics({ uri, version, diagnostics }) } private logRequest({ @@ -724,7 +724,7 @@ export default class BashServer { } } catch (error) { const errorMessage = error instanceof Error ? error.message : error - logger.warn(`getExplainshellDocumentation exception: ${errorMessage}`) + logger.warn(`getExplainshellDocumentation exception: ${String(errorMessage)}`) } } @@ -886,7 +886,7 @@ export default class BashServer { return await this.formatter.format(document, params.options, this.config.shfmt) } catch (err) { - logger.error(`Error while formatting: ${err}`) + logger.error(`Error while formatting: ${String(err)}`) } } diff --git a/server/src/shellcheck/__tests__/lifecycle.test.ts b/server/src/shellcheck/__tests__/lifecycle.test.ts index 6cbb8c6cb..418e609f1 100644 --- a/server/src/shellcheck/__tests__/lifecycle.test.ts +++ b/server/src/shellcheck/__tests__/lifecycle.test.ts @@ -25,7 +25,7 @@ async function initializeServer() { workspaceFolders: null, }) server.register(connection) - connection.onDidChangeConfiguration.mock.calls[0][0]({ + await connection.onDidChangeConfiguration.mock.calls[0][0]({ settings: { bashIde: { shellcheckPath: 'controlled-shellcheck' } }, }) await connection.onInitialized.mock.calls[0][0]({}) @@ -186,18 +186,18 @@ describe('lint process lifecycle', () => { it('cancels on close without republishing diagnostics or relinting a closed document', async () => { const { connection, server } = await initializeServer() const analyze = vi.spyOn(server, 'analyzeAndLintDocument') - connection.onDidOpenTextDocument.mock.calls[0][0]({ + await connection.onDidOpenTextDocument.mock.calls[0][0]({ textDocument: { uri, languageId: 'shellscript', version: 1, text: 'echo stale' }, }) vi.advanceTimersByTime(500) - connection.onDidCloseTextDocument.mock.calls[0][0]({ textDocument: { uri } }) + await connection.onDidCloseTextDocument.mock.calls[0][0]({ textDocument: { uri } }) await analyze.mock.results[0].value await exits[0] expect(children[0].signalCode).toBe('SIGTERM') expect(connection.sendDiagnostics.mock.calls).toEqual([[{ uri, diagnostics: [] }]]) - connection.onDidChangeConfiguration.mock.calls[0][0]({ + await connection.onDidChangeConfiguration.mock.calls[0][0]({ settings: { bashIde: { shellcheckPath: 'another-shellcheck' } }, }) vi.advanceTimersByTime(500) @@ -208,12 +208,12 @@ describe('lint process lifecycle', () => { it('cancels the old checker when configuration disables linting', async () => { const { connection, server } = await initializeServer() const analyze = vi.spyOn(server, 'analyzeAndLintDocument') - connection.onDidOpenTextDocument.mock.calls[0][0]({ + await connection.onDidOpenTextDocument.mock.calls[0][0]({ textDocument: { uri, languageId: 'shellscript', version: 1, text: 'echo stale' }, }) vi.advanceTimersByTime(500) - connection.onDidChangeConfiguration.mock.calls[0][0]({ + await connection.onDidChangeConfiguration.mock.calls[0][0]({ settings: { bashIde: { shellcheckPath: '' } }, }) await Promise.all(analyze.mock.results.map(({ value }) => value)) @@ -240,12 +240,12 @@ describe('lint process lifecycle', () => { }, ] for (const textDocument of openDocuments) { - connection.onDidOpenTextDocument.mock.calls[0][0]({ textDocument }) + await connection.onDidOpenTextDocument.mock.calls[0][0]({ textDocument }) } vi.advanceTimersByTime(500) expect(children).toHaveLength(2) - connection.onDidChangeConfiguration.mock.calls[0][0]({ + await connection.onDidChangeConfiguration.mock.calls[0][0]({ settings: { bashIde: { shellcheckPath } }, }) await Promise.all(exits) diff --git a/server/src/shellcheck/index.ts b/server/src/shellcheck/index.ts index cbd70b0bd..a6bf29a94 100644 --- a/server/src/shellcheck/index.ts +++ b/server/src/shellcheck/index.ts @@ -243,7 +243,7 @@ export class Linter { let out = '' let err = '' - const proc = new Promise((resolve, reject) => { + const proc = new Promise((resolve, reject) => { const useProcessGroup = process.platform !== 'win32' // The abort listener below owns termination. Passing signal here as well // would race Node's direct-child kill against process-group cleanup. @@ -261,7 +261,9 @@ export class Linter { process.kill(-proc.pid, killSignal) } catch (error) { if ((error as NodeJS.ErrnoException).code !== 'ESRCH') { - logger.warn(`ShellCheck: failed to terminate process group: ${error}`) + logger.warn( + `ShellCheck: failed to terminate process group: ${String(error)}`, + ) proc.kill(killSignal) } } @@ -333,7 +335,7 @@ export class Linter { return { comments: [] } } throw new Error( - `ShellCheck: failed with code ${exit}: ${e}\nout:\n${out}\nerr:\n${err}`, + `ShellCheck: failed with code ${exit}: ${String(e)}\nout:\n${out}\nerr:\n${err}`, ) } @@ -342,7 +344,9 @@ export class Linter { raw = JSON.parse(out) } catch (e) { throw new Error( - `ShellCheck: json parse failed with error ${e}\nout:\n${out}\nerr:\n${err}`, + `ShellCheck: json parse failed with error ${String( + e, + )}\nout:\n${out}\nerr:\n${err}`, ) } diff --git a/server/src/shfmt/index.ts b/server/src/shfmt/index.ts index 5f2cede2d..7e4f0de7c 100644 --- a/server/src/shfmt/index.ts +++ b/server/src/shfmt/index.ts @@ -149,7 +149,7 @@ export class Formatter { let out = '' let err = '' - const proc = new Promise((resolve, reject) => { + const proc = new Promise((resolve, reject) => { const proc = spawn(this.executablePath, [...args, '-'], { cwd: this.cwd }) proc.on('error', reject) proc.on('close', resolve) @@ -176,7 +176,7 @@ export class Formatter { this._canFormat = false return '' } - throw new Error(`Shfmt: child process error: ${e}`) + throw new Error(`Shfmt: child process error: ${String(e)}`) } if (exit != 0) { diff --git a/server/src/util/logger.ts b/server/src/util/logger.ts index 949e0f0e6..c6da686cb 100644 --- a/server/src/util/logger.ts +++ b/server/src/util/logger.ts @@ -78,7 +78,7 @@ export class Logger { const time = new Date().toISOString().substring(11, 23) const message = `${time} ${level} ${prefix}${formattedMessage}` - _connection.sendNotification(LSP.LogMessageNotification.type, { + void _connection.sendNotification(LSP.LogMessageNotification.type, { type: severity, message, }) diff --git a/tsconfig.json b/tsconfig.json index 0ac7b43fc..5a1bbf193 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -29,6 +29,7 @@ ], "references": [ { "path": "./vscode-client" }, - { "path": "./server" } + { "path": "./server" }, + { "path": "./tsconfig.test.json" } ] } diff --git a/vscode-client/src/server.ts b/vscode-client/src/server.ts index e0be210a4..d84f88ee3 100644 --- a/vscode-client/src/server.ts +++ b/vscode-client/src/server.ts @@ -1,4 +1,5 @@ import BashLanguageServer from 'bash-language-server' +import { inspect } from 'node:util' import { createConnection, InitializeParams, @@ -21,7 +22,9 @@ connection.listen() // Don't die on unhandled Promise rejections process.on('unhandledRejection', (reason, p) => { const stack = reason instanceof Error ? reason.stack : reason - connection.console.error(`Unhandled Rejection at promise: ${p}, reason: ${stack}`) + connection.console.error( + `Unhandled Rejection at promise: ${inspect(p)}, reason: ${String(stack)}`, + ) }) process.on('SIGPIPE', () => { From 7691946d2bf9cb4d3fcdaead63c493e526105b4c Mon Sep 17 00:00:00 2001 From: skovhus Date: Sun, 20 Sep 2026 23:48:55 +0200 Subject: [PATCH 2/2] Remove redundant standalone typecheck command --- docs/development-guide.md | 8 ++++---- package.json | 7 +++---- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/docs/development-guide.md b/docs/development-guide.md index 549cdfdb4..d6db38a07 100644 --- a/docs/development-guide.md +++ b/docs/development-guide.md @@ -53,7 +53,6 @@ Development uses [Oxlint][oxlint], [Prettier][prettier], and integration tests u pnpm verify:bail # checks lint/formatting, compiles, and runs tests with coverage pnpm lint # fixes lint and formatting, and checks types pnpm lint:bail # checks lint, formatting, and types without rewriting files - pnpm typecheck # checks lint and types through Oxlint without emitting files pnpm test pnpm test:coverage pnpm test:watch @@ -65,9 +64,10 @@ pnpm test server/src/__tests__/input-declarations.test.ts pnpm test server/src/__tests__/server.test.ts -t 'rename' ``` -The lint commands and `pnpm typecheck` run [type-aware rules and TypeScript -compiler diagnostics through Oxlint][oxlint-types]. `pnpm compile` and `pnpm watch` -still use `tsc` to emit JavaScript and declarations. +The lint commands run [type-aware rules and TypeScript compiler diagnostics +through Oxlint][oxlint-types]. Test commands run Vitest without repeating lint or +type checks. `pnpm compile` and `pnpm watch` still use `tsc` to emit JavaScript and +declarations. Tests and test helpers are type-checked using `tsconfig.test.json`. Vitest runs files sequentially so subprocess and filesystem integration tests stay isolated. diff --git a/package.json b/package.json index 69102047d..fb06c8ea4 100644 --- a/package.json +++ b/package.json @@ -8,17 +8,16 @@ "watch": "tsc -b -w", "lint": "oxlint --fix --deny-warnings && pnpm format", "lint:bail": "oxlint --deny-warnings && pnpm format:check", - "test": "pnpm typecheck && vitest run", + "test": "vitest run", "test:coverage": "pnpm run test --coverage", - "test:watch": "pnpm typecheck && vitest --watch", + "test:watch": "vitest --watch", "verify": "pnpm lint && pnpm compile && pnpm run test", "verify:bail": "pnpm lint:bail && pnpm compile && pnpm test:coverage", "reinstall-server": "npm uninstall -g bash-language-server && pnpm compile && npm i -g ./server", "link-server": "pnpm compile && node scripts/link-server.mjs", "postinstall": "pnpm --dir=vscode-client install", "format": "prettier --write \"**/*.{js,ts,tsx,mts}\"", - "format:check": "prettier --check \"**/*.{js,ts,tsx,mts}\"", - "typecheck": "oxlint --deny-warnings" + "format:check": "prettier --check \"**/*.{js,ts,tsx,mts}\"" }, "devDependencies": { "@types/node": "22.20.4",