diff --git a/config/scripts/typecheck-diagnostic-baseline.mjs b/config/scripts/typecheck-diagnostic-baseline.mjs index ae7cc1bcdd3..e7198b816c7 100644 --- a/config/scripts/typecheck-diagnostic-baseline.mjs +++ b/config/scripts/typecheck-diagnostic-baseline.mjs @@ -1,9 +1,10 @@ import { spawnSync } from 'node:child_process' +import { realpathSync } from 'node:fs' import { readFile, writeFile } from 'node:fs/promises' import { relative, resolve } from 'node:path' import { fileURLToPath } from 'node:url' -const repoRoot = fileURLToPath(new URL('../..', import.meta.url)) +const repoRoot = realpathSync(fileURLToPath(new URL('../..', import.meta.url))) function parseArgs(argv) { const options = { write: false } @@ -95,10 +96,12 @@ function collectDiagnostics(projectPath, tscPath) { if (result.signal) { throw new Error(`TypeScript exited with signal ${result.signal}`) } - const output = `${result.stdout ?? ''}${result.stderr ?? ''}` - const diagnostics = parseDiagnostics(output) + const stdout = result.stdout ?? '' + const diagnostics = parseDiagnostics(stdout) if (result.status !== 0 && diagnostics.length === 0) { - throw new Error(`TypeScript exited ${result.status} without parseable diagnostics:\n${output}`) + throw new Error( + `TypeScript exited ${result.status} without parseable diagnostics:\nstdout:\n${stdout}\nstderr:\n${result.stderr ?? ''}` + ) } return diagnostics } diff --git a/config/scripts/typecheck-diagnostic-baseline.test.mjs b/config/scripts/typecheck-diagnostic-baseline.test.mjs index fc4dc426ce0..c39bbaf5580 100644 --- a/config/scripts/typecheck-diagnostic-baseline.test.mjs +++ b/config/scripts/typecheck-diagnostic-baseline.test.mjs @@ -1,4 +1,4 @@ -import { mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs' +import { mkdtempSync, readFileSync, rmSync, symlinkSync, writeFileSync } from 'node:fs' import { tmpdir } from 'node:os' import { join } from 'node:path' import { spawnSync } from 'node:child_process' @@ -32,11 +32,25 @@ function createFixture(source) { } } -function runBaseline(paths, extraArgs = []) { +function runBaseline(paths, extraArgs = [], spawnOptions = {}) { return spawnSync( process.execPath, - [script, '--project', paths.project, '--baseline', paths.baseline, '--tsc', tsc, ...extraArgs], - { cwd: repoRoot, encoding: 'utf8' } + [ + ...(spawnOptions.nodeArgs ?? []), + spawnOptions.script ?? script, + '--project', + paths.project, + '--baseline', + paths.baseline, + '--tsc', + paths.tsc ?? tsc, + ...extraArgs + ], + { + cwd: repoRoot, + encoding: 'utf8', + env: { ...process.env, ...spawnOptions.env } + } ) } @@ -91,6 +105,46 @@ describe('typecheck diagnostic baseline', () => { expect(runBaseline(paths).status).toBe(0) }) + it('matches recorded diagnostics through a symlinked checkout path', () => { + fixtureDir = mkdtempSync(join(tmpdir(), 'orca-typecheck-symlink-')) + const linkedCheckout = join(fixtureDir, 'checkout') + symlinkSync(repoRoot, linkedCheckout, process.platform === 'win32' ? 'junction' : 'dir') + + const result = runBaseline( + { + project: 'config/tsconfig.e2e.json', + baseline: 'config/typecheck-e2e-diagnostics.json' + }, + [], + { + nodeArgs: ['--preserve-symlinks-main'], + script: join(linkedCheckout, 'config/scripts/typecheck-diagnostic-baseline.mjs') + } + ) + + expect(result.status).toBe(0) + expect(result.stdout).toContain('240 known diagnostics, no drift') + }) + + it('ignores stderr warnings while parsing compiler diagnostics', () => { + const paths = createFixture("const value: number = 'bad'\n") + paths.tsc = join(fixtureDir, 'fake-tsc.mjs') + writeFileSync( + paths.tsc, + [ + "if (process.env.INJECT_TSC_WARNING) process.stderr.write('pnpm warning: unsupported engine\\n')", + "process.stdout.write(\"source.ts(1,7): error TS2322: Type 'string' is not assignable to type 'number'.\\n\")", + 'process.exitCode = 1' + ].join('\n') + ) + expect(runBaseline(paths, ['--write']).status).toBe(0) + + const result = runBaseline(paths, [], { env: { INJECT_TSC_WARNING: '1' } }) + + expect(result.status).toBe(0) + expect(result.stdout).toContain('1 known diagnostics, no drift') + }) + it('refuses to regenerate a baseline that grows from the PR base', () => { const paths = createFixture("const first: number = 'bad'\n") expect(runBaseline(paths, ['--write']).status).toBe(0)