/** Validate CLI definitions. */ import * as fs from 'node:fs'; import * as path from 'node:path'; import yaml from 'js-yaml'; export function validateClisWithTarget(dirs: string[], target?: string): any { const results: any[] = []; let errors = 0; let warnings = 0; let files = 0; for (const dir of dirs) { if (!fs.existsSync(dir)) continue; for (const site of fs.readdirSync(dir)) { if (target && site !== target && !target.startsWith(site + '/')) continue; const siteDir = path.join(dir, site); if (!fs.statSync(siteDir).isDirectory()) continue; for (const file of fs.readdirSync(siteDir)) { if (!file.endsWith('.yaml') && !file.endsWith('.yml')) continue; if (target && target.includes('/') && !target.endsWith(file.replace(/\.(yaml|yml)$/, ''))) continue; files++; const filePath = path.join(siteDir, file); const r = validateYamlFile(filePath); results.push(r); errors += r.errors.length; warnings += r.warnings.length; } } } return { ok: errors === 0, results, errors, warnings, files }; } function validateYamlFile(filePath: string): any { const errors: string[] = []; const warnings: string[] = []; try { const raw = fs.readFileSync(filePath, 'utf-8'); const def = yaml.load(raw) as any; if (!def || typeof def !== 'object') { errors.push('Not a valid YAML object'); return { path: filePath, errors, warnings }; } if (!def.site) errors.push('Missing "site"'); if (!def.name) errors.push('Missing "name"'); if (def.pipeline && !Array.isArray(def.pipeline)) errors.push('"pipeline" must be an array'); if (def.columns && !Array.isArray(def.columns)) errors.push('"columns" must be an array'); if (def.args && typeof def.args !== 'object') errors.push('"args" must be an object'); } catch (e: any) { errors.push(`YAML parse error: ${e.message}`); } return { path: filePath, errors, warnings }; } export function renderValidationReport(report: any): string { const lines = [`opencli validate: ${report.ok ? 'PASS' : 'FAIL'}`, `Checked ${report.results.length} CLI(s) in ${report.files} file(s)`, `Errors: ${report.errors} Warnings: ${report.warnings}`]; for (const r of report.results) { if (r.errors.length > 0 || r.warnings.length > 0) { lines.push(`\n${r.path}:`); for (const e of r.errors) lines.push(` ❌ ${e}`); for (const w of r.warnings) lines.push(` ⚠️ ${w}`); } } return lines.join('\n'); }