import { SquashSpecSchema, type SquashSpec } from './types.js'; import { toPascalCase } from '../lib/migration-name.js'; export interface ValidationResult { valid: boolean; data?: SquashSpec; blockers: string[]; warnings: string[]; } export function validate(raw: unknown): ValidationResult { const parsed = SquashSpecSchema.safeParse(raw); if (!parsed.success) { return { valid: false, blockers: parsed.error.issues.map((i) => `[${i.path.join('.')}] ${i.message}`), warnings: [], }; } const data = parsed.data; const blockers: string[] = []; const warnings: string[] = []; if (!toPascalCase(data.description)) { blockers.push('[description] must contain at least one alphanumeric character'); } if (data.aggressive) { warnings.push('aggressive=true is deprecated and ignored — migrations present in the reference branch are always preserved. For a deliberate full re-baseline, use bruteForce.'); } if (data.bruteForce) { warnings.push( 'bruteForce=true: FULL re-baseline — EVERY migration (including those already on the reference/production branch) plus the snapshot will be deleted and replaced by one regenerated migration. The reference branch must be re-baselined in lock-step. Requires confirmBruteForce=true, blocked on main/master, and logged to .claude/Efcore-history.', ); } if (data.confirmBruteForce && !data.bruteForce) { warnings.push('confirmBruteForce=true is ignored without bruteForce=true.'); } return { valid: blockers.length === 0, data, blockers, warnings }; }