/** * cli:scaffold-tests — validate.ts * * validate() returns the Zod-PARSED spec (`data`): the semantic checks and * generate() both run on it, never on the raw JSON. `businessRules`, * `tenantMode`, `fields[].required` and `hasCreate` only exist after parse — * the raw business spec without `businessRules` died on `.length` with a * stack trace on stdout (2026-09-24, lot 13 / D4). */ import { ScaffoldTestsInputSchema, type ScaffoldTestsInput, type ValidationResult } from './types.js' import { existsSync } from 'node:fs' export function validateStructure(raw: unknown): ValidationResult { const result = ScaffoldTestsInputSchema.safeParse(raw) if (result.success) return { valid: true, errors: [], warnings: [], data: result.data } const errors = result.error.issues.map(i => `[${i.path.join('.')}] ${i.message}`) return { valid: false, errors, warnings: [] } } /** Semantic checks on the PARSED spec (defaults applied) — never on the raw JSON. */ export function validateBusinessRules(spec: ScaffoldTestsInput): ValidationResult { const errors: string[] = [] const warnings: string[] = [] if (!existsSync(spec.projectPath)) { errors.push(`Project path not found: ${spec.projectPath}`) } if (spec.layer === 'business' && spec.businessRules.length === 0) { warnings.push('No business rules provided — only validator tests will be generated') } return errors.length === 0 ? { valid: true, errors, warnings, data: spec } : { valid: false, errors, warnings } } export function validate(raw: unknown): ValidationResult { const structural = validateStructure(raw) if (!structural.valid || structural.data === undefined) return structural return validateBusinessRules(structural.data) }