#!/usr/bin/env bun /** * Pre-publish gate — type-check every workspace package against the * monorepo's strict tsconfig. * * Required before any publish. The Bun test runner is intentionally * permissive (it transpiles, doesn't type-check), so without this gate * a package can pass `bun test` and still ship code that fails to * compile in a downstream consumer's strict TS project. * * Usage: * bun run scripts/typecheck-all.ts # check every package * bun run scripts/typecheck-all.ts core sdk # check only listed * * Exit code 0 if every package compiles, 1 otherwise. */ import { readdirSync, statSync, existsSync } from 'fs'; import { join } from 'path'; import { $ } from 'bun'; const ROOT = join(import.meta.dir, '..'); const PACKAGES_DIR = join(ROOT, 'packages'); const filter = new Set(process.argv.slice(2)); const packages = readdirSync(PACKAGES_DIR).filter((name) => { const p = join(PACKAGES_DIR, name); if (!statSync(p).isDirectory()) return false; if (!existsSync(join(p, 'tsconfig.json'))) return false; if (filter.size > 0 && !filter.has(name) && !filter.has(name.replace(/^shade-/, ''))) { return false; } return true; }); let failures = 0; const failed: { pkg: string; out: string }[] = []; for (const pkg of packages) { const dir = join(PACKAGES_DIR, pkg); const proc = Bun.spawnSync(['bunx', 'tsc', '--noEmit', '-p', 'tsconfig.json'], { cwd: dir, stdout: 'pipe', stderr: 'pipe', }); const stdout = proc.stdout.toString(); const stderr = proc.stderr.toString(); const out = (stdout + stderr) .split('\n') .filter((l) => !/^Resolving|^Resolved|^Saved/.test(l)) .join('\n') .trim(); if (proc.exitCode === 0 && out.length === 0) { console.log(` ✓ ${pkg}`); } else { failures++; failed.push({ pkg, out }); console.log(` ✗ ${pkg}`); } } console.log(); if (failures === 0) { console.log(`All ${packages.length} packages type-check cleanly.`); process.exit(0); } console.error(`${failures} of ${packages.length} packages failed:\n`); for (const f of failed) { console.error(`── ${f.pkg} ──`); console.error(f.out); console.error(); } process.exit(1);