export interface ConfigValidationIssue { code: string; message: string; path: string; targetName?: string; } export function formatConfigIssues(issues: ConfigValidationIssue[]): string { return issues.map(formatConfigIssue).join("\n"); } export function issue(code: string, path: string, message: string, targetName?: string): ConfigValidationIssue { return targetName === undefined ? { code, message, path } : { code, message, path, targetName }; } export function joinPath(base: string, key: string): string { if (base === "") return key; if (key.startsWith("[")) return `${base}${key}`; return `${base}.${key}`; } export function renderPath(path: string): string { return path === "" ? "配置文件" : path; } export function throwConfigIssues(issues: ConfigValidationIssue[]): never { throw new Error(formatConfigIssues(issues)); } function formatConfigIssue(issue: ConfigValidationIssue): string { if (issue.targetName) { const path = issue.path.replace(/^targets\[\d+\]\.?/, ""); const renderedPath = path === "" ? "配置" : path; return `target "${issue.targetName}" 的 ${renderedPath} ${issue.message}`; } return `${renderPath(issue.path)} ${issue.message}`; }