()
| 448 | } |
| 449 | |
| 450 | async function main() { |
| 451 | const files = await resolveFiles(process.argv.slice(2)) |
| 452 | if (files === null) process.exit(0) |
| 453 | |
| 454 | if (files.length === 0) { |
| 455 | console.log('✓ No new migrations to check.') |
| 456 | process.exit(0) |
| 457 | } |
| 458 | |
| 459 | let errors = 0 |
| 460 | let warnings = 0 |
| 461 | for (const rel of files) { |
| 462 | const content = await readFile(path.join(ROOT, rel), 'utf8') |
| 463 | const findings = lintSql(content) |
| 464 | if (findings.length === 0) continue |
| 465 | |
| 466 | console.error(`\n${rel}`) |
| 467 | for (const f of findings.sort((a, b) => a.line - b.line)) { |
| 468 | const icon = f.tier === 'error' ? '✗' : '⚠' |
| 469 | if (f.tier === 'error') errors++ |
| 470 | else warnings++ |
| 471 | console.error(` ${icon} ${rel}:${f.line} [${f.rule}]`) |
| 472 | console.error(` ${f.statement.replace(/\s+/g, ' ').slice(0, 120)}`) |
| 473 | console.error(` → ${f.message}`) |
| 474 | } |
| 475 | } |
| 476 | |
| 477 | if (errors === 0) { |
| 478 | console.log( |
| 479 | warnings > 0 |
| 480 | ? `\n✓ No blocking migration issues (${warnings} warning(s) to review).` |
| 481 | : '\n✓ Migrations are backward-compatible.' |
| 482 | ) |
| 483 | process.exit(0) |
| 484 | } |
| 485 | console.error( |
| 486 | `\nFound ${errors} blocking migration issue(s). Rewrite hard errors into expand/contract, or annotate contract ops once safe. See the /db-migrate skill.` |
| 487 | ) |
| 488 | process.exit(1) |
| 489 | } |
| 490 | |
| 491 | if (import.meta.main) main() |
no test coverage detected