diff --git a/.lintstagedrc.json b/.lintstagedrc.json index 34d14f96..06a3befd 100644 --- a/.lintstagedrc.json +++ b/.lintstagedrc.json @@ -1,4 +1,4 @@ { - "*.{ts,tsx}": ["eslint --fix", "prettier --write"], + "*.{ts,tsx}": ["eslint --fix", "prettier --write", "node scripts/tsc-staged.mjs"], "*.{json,md,css}": ["prettier --write"] } diff --git a/scripts/tsc-staged.mjs b/scripts/tsc-staged.mjs new file mode 100644 index 00000000..65964193 --- /dev/null +++ b/scripts/tsc-staged.mjs @@ -0,0 +1,55 @@ +#!/usr/bin/env node +/** + * Pre-commit type check for staged TS files. + * + * Writes a temp tsconfig that extends the project root and pins + * `files` to whatever lint-staged passed in. `tsc -p` then compiles + * the whole dep graph from those entrypoints — catches errors in + * the staged code AND in anything it imports — while still skipping + * the 22s full-project pass. + * + * Replaces `tsc-files` (npm), which silently fails under pnpm because + * its tsc-resolution path (typescript/../.bin/tsc) doesn't exist in + * pnpm's virtual store layout. + */ + +import { spawnSync } from 'node:child_process'; +import { mkdtempSync, rmSync, writeFileSync } from 'node:fs'; +import { tmpdir } from 'node:os'; +import { join, relative, resolve } from 'node:path'; + +const cwd = process.cwd(); +const args = process.argv.slice(2); +const files = args.filter((a) => /\.(ts|tsx)$/.test(a)); + +if (files.length === 0) { + process.exit(0); +} + +const tmpDir = mkdtempSync(join(tmpdir(), 'tsc-staged-')); +const tmpConfig = join(tmpDir, 'tsconfig.json'); + +const relFiles = files.map((f) => relative(tmpDir, resolve(cwd, f))); + +writeFileSync( + tmpConfig, + JSON.stringify( + { + extends: relative(tmpDir, join(cwd, 'tsconfig.json')), + compilerOptions: { noEmit: true, skipLibCheck: true }, + files: relFiles, + include: [], + }, + null, + 2, + ), +); + +const tsc = spawnSync('pnpm', ['exec', 'tsc', '-p', tmpConfig, '--pretty'], { + cwd, + stdio: 'inherit', +}); + +rmSync(tmpDir, { recursive: true, force: true }); + +process.exit(tsc.status ?? 1);