import { errorCodeToClassName, type ParsedCommandDoc } from "./parse-command-doc"; export function moduleNameToPrefix(moduleName: string): string { return moduleName.toUpperCase().replace(/-/g, "_"); } interface CollectedError { description: string; sources: { commandName: string; description: string }[]; } export function generateErrors(moduleName: string, docs: ParsedCommandDoc[]): string { const collected = new Map(); for (const doc of docs) { for (const error of doc.errors) { const existing = collected.get(error.code); if (!existing) { collected.set(error.code, { description: error.description, sources: [{ commandName: doc.commandName, description: error.description }], }); continue; } existing.sources.push({ commandName: doc.commandName, description: error.description }); } } const conflicts = [...collected.entries()].filter( ([, entry]) => new Set(entry.sources.map((s) => s.description)).size > 1, ); if (conflicts.length > 0) { const details = conflicts .map(([code, entry]) => { const sourceLines = entry.sources .map((s) => ` - ${s.commandName}: ${JSON.stringify(s.description)}`) .join("\n"); return ` - ${code}\n${sourceLines}`; }) .join("\n"); throw new Error( `Error code conflicts in module "${moduleName}": the same code is declared with different descriptions. ` + `Unify the descriptions or split into distinct codes.\n${details}`, ); } if (collected.size === 0) return ""; const prefix = moduleNameToPrefix(moduleName); const lines: string[] = []; for (const [code, entry] of collected) { const className = errorCodeToClassName(code); const prefixedCode = `${prefix}_${code}`; lines.push(`export const ${className} = createDomainError(`); lines.push(` "${className}", "${prefixedCode}",`); const escapedDesc = entry.description.replace(/`/g, "'"); lines.push(` (identifier: string) => \`${escapedDesc}: \${identifier}\`,`); lines.push(`);`); lines.push(``); } return `// @generated — do not edit import { createDomainError } from "@tailor-platform/erp-kit/core"; ${lines.join("\n")}`; }