46 lines
1.4 KiB
TypeScript
46 lines
1.4 KiB
TypeScript
import { ValueErrorType, type ValueError } from '@sinclair/typebox/value';
|
|
|
|
export interface ConfigIssue {
|
|
path: string;
|
|
message: string;
|
|
}
|
|
|
|
export class ConfigError extends Error {
|
|
readonly issues: readonly ConfigIssue[];
|
|
|
|
constructor(issues: readonly ConfigIssue[] = []) {
|
|
super('Invalid configuration');
|
|
this.name = 'ConfigError';
|
|
this.issues = issues;
|
|
}
|
|
}
|
|
|
|
export function toConfigIssue(error: ValueError): ConfigIssue {
|
|
const segments = error.path.split('/').slice(1);
|
|
let message = error.message;
|
|
if (error.type === ValueErrorType.ObjectAdditionalProperties) {
|
|
segments.pop();
|
|
const allowedFields = Object.keys(error.schema.properties ?? {});
|
|
message =
|
|
allowedFields.length > 0
|
|
? `Unexpected property. Allowed fields: ${allowedFields.join(', ')}`
|
|
: 'Unexpected property';
|
|
}
|
|
if (segments[0] === 'domains') {
|
|
if (segments.length > 1) segments[1] = '*';
|
|
if (segments[2] === 'links' && segments.length > 3) segments[3] = '*';
|
|
}
|
|
return { path: `/${segments.join('/')}`, message };
|
|
}
|
|
|
|
export function formatConfigError(error: ConfigError, headline = error.message): string {
|
|
return [headline, ...error.issues.map((issue) => ` ${issue.path}: ${issue.message}`)].join('\n');
|
|
}
|
|
|
|
export function formatConfigWarnings(warnings: readonly ConfigIssue[]): string {
|
|
return [
|
|
'Configuration warnings',
|
|
...warnings.map((issue) => ` ${issue.path}: ${issue.message}`)
|
|
].join('\n');
|
|
}
|