mirror of
https://github.com/bookorbit/bookorbit.git
synced 2026-11-03 00:11:37 -06:00
121 lines
3.9 KiB
JavaScript
121 lines
3.9 KiB
JavaScript
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs'
|
|
import { dirname, resolve } from 'node:path'
|
|
import { spawnSync } from 'node:child_process'
|
|
|
|
const mode = process.argv[2] ?? 'check'
|
|
const rootDir = process.cwd()
|
|
const baselinePath = resolve(rootDir, 'client/typecheck-baseline.txt')
|
|
|
|
function runClientTypecheck() {
|
|
const result = spawnSync('pnpm', ['--filter', 'client', 'exec', 'vue-tsc', '--build', '--pretty', 'false'], {
|
|
cwd: rootDir,
|
|
encoding: 'utf8',
|
|
})
|
|
|
|
if (result.error) {
|
|
throw result.error
|
|
}
|
|
|
|
const combinedOutput = `${result.stdout ?? ''}\n${result.stderr ?? ''}`
|
|
const diagnostics = parseDiagnostics(combinedOutput)
|
|
return { result, combinedOutput, diagnostics }
|
|
}
|
|
|
|
function parseDiagnostics(output) {
|
|
const regex = /^(.*\.(?:ts|tsx|vue)\(\d+,\d+\): error TS\d+: .*)$/gm
|
|
const rows = []
|
|
|
|
for (const match of output.matchAll(regex)) {
|
|
const raw = String(match[1] ?? '').trim()
|
|
rows.push(normalizeDiagnostic(raw))
|
|
}
|
|
|
|
return [...new Set(rows)].sort((a, b) => a.localeCompare(b))
|
|
}
|
|
|
|
function normalizeDiagnostic(row) {
|
|
const rootPrefix = `${rootDir.replaceAll('\\', '/')}/`
|
|
let normalized = row.replaceAll('\\', '/')
|
|
normalized = normalized.split(`${rootPrefix}client/`).join('')
|
|
normalized = normalized.split(rootPrefix).join('')
|
|
if (normalized.startsWith('client/')) normalized = normalized.slice('client/'.length)
|
|
return normalized
|
|
}
|
|
|
|
function readBaseline() {
|
|
if (!existsSync(baselinePath)) return []
|
|
return readFileSync(baselinePath, 'utf8')
|
|
.split('\n')
|
|
.map((line) => line.trim())
|
|
.filter((line) => line.length > 0 && !line.startsWith('#'))
|
|
}
|
|
|
|
function writeBaseline(diagnostics) {
|
|
mkdirSync(dirname(baselinePath), { recursive: true })
|
|
const header = [
|
|
'# Client typecheck baseline',
|
|
'# Auto-generated by: pnpm run typecheck:client:baseline:update',
|
|
'# One diagnostic per line. Do not edit manually unless necessary.',
|
|
'',
|
|
]
|
|
writeFileSync(baselinePath, `${header.join('\n')}${diagnostics.join('\n')}\n`, 'utf8')
|
|
}
|
|
|
|
if (mode === 'update') {
|
|
const { result, combinedOutput, diagnostics } = runClientTypecheck()
|
|
if (result.status !== 0 && diagnostics.length === 0) {
|
|
console.error('Client typecheck failed without parsable diagnostics output.')
|
|
console.error(combinedOutput)
|
|
process.exit(1)
|
|
}
|
|
writeBaseline(diagnostics)
|
|
console.log(`Updated ${baselinePath} with ${diagnostics.length} diagnostics.`)
|
|
process.exit(0)
|
|
}
|
|
|
|
if (mode !== 'check') {
|
|
console.error(`Unknown mode "${mode}". Use "check" or "update".`)
|
|
process.exit(2)
|
|
}
|
|
|
|
const { result, combinedOutput, diagnostics } = runClientTypecheck()
|
|
|
|
if (result.status === 0) {
|
|
console.log('Client typecheck is clean.')
|
|
process.exit(0)
|
|
}
|
|
|
|
if (diagnostics.length === 0) {
|
|
console.error('Client typecheck failed without parsable diagnostics output.')
|
|
console.error(combinedOutput)
|
|
process.exit(1)
|
|
}
|
|
|
|
const baseline = readBaseline()
|
|
if (baseline.length === 0) {
|
|
console.error(`No baseline found at ${baselinePath}.`)
|
|
console.error('Run: pnpm run typecheck:client:baseline:update')
|
|
process.exit(1)
|
|
}
|
|
|
|
const baselineSet = new Set(baseline)
|
|
const newDiagnostics = diagnostics.filter((line) => !baselineSet.has(line))
|
|
|
|
if (newDiagnostics.length > 0) {
|
|
console.error(`Found ${newDiagnostics.length} new client type errors not present in baseline:`)
|
|
for (const line of newDiagnostics) {
|
|
console.error(`- ${line}`)
|
|
}
|
|
console.error('If these are intentional and accepted, refresh baseline:')
|
|
console.error('pnpm run typecheck:client:baseline:update')
|
|
process.exit(1)
|
|
}
|
|
|
|
const resolvedCount = baseline.filter((line) => !diagnostics.includes(line)).length
|
|
console.log(`No new client type errors. Baseline size: ${baseline.length}. Current: ${diagnostics.length}. Resolved: ${resolvedCount}.`)
|
|
if (resolvedCount > 0) {
|
|
console.log('You can refresh baseline to capture improvements:')
|
|
console.log('pnpm run typecheck:client:baseline:update')
|
|
}
|
|
process.exit(0)
|