@uni-ts/model
Version:
Utils for creating data models in TypeScript.
86 lines • 2.72 kB
JavaScript
/**
* Error thrown when data validation fails against a model's schema.
*
* Contains detailed information about all validation issues that occurred during validation.
* The error message is set to the first issue's message for convenience.
*
* @example
* ```typescript
* import { createModel, ModelValidationError } from '@uni-ts/model';
* import { z } from 'zod';
*
* const User = createModel(z.object({
* name: z.string().min(1),
* email: z.string().email(),
* }));
*
* try {
* User.from({ name: '', email: 'invalid-email' });
* } catch (ex) {
* if (ex instanceof ModelValidationError) {
* console.error('Issues:', ex.issues);
* }
* }
* ```
*/
export class ModelValidationError extends Error {
/**
* Used to distinguish this error from others with the same shape.
*/
type = 'ModelValidationError';
/**
* Array of all validation issues that caused the error.
* Each issue contains details about what validation rule failed and where.
*/
issues;
/**
* Creates a new ModelValidationError with the provided validation issues.
*
* @param issues - Array of validation issues from the schema validation
*/
constructor(issues) {
super(JSON.stringify(expandIssues(issues).map(({ message, dotPath }) => ({ message, path: dotPath })), null, 2));
this.name = ModelValidationError.name;
this.issues = issues;
}
}
export function prettifyError(error) {
const issues = expandIssues(error.issues);
const lines = [];
for (const { issue, dotPath } of issues) {
lines.push(`✖ ${issue.message}`);
if (dotPath)
lines.push(` → at ${dotPath}`);
}
return lines.join('\n');
}
function expandIssues(issues) {
return [...issues].map((issue) => {
const path = issue.path || [];
const message = issue.message;
const pathSegments = path.map(toPropertyKey);
const dotPath = toDotPath(pathSegments);
return { message, issue, path, pathSegments, dotPath };
});
}
function toDotPath(path) {
const segments = [];
for (const seg of path) {
if (typeof seg === 'number')
segments.push(`[${seg}]`);
else if (typeof seg === 'symbol')
segments.push(`[${JSON.stringify(String(seg))}]`);
else if (/[^\w$]/.test(seg))
segments.push(`[${JSON.stringify(seg)}]`);
else {
if (segments.length)
segments.push('.');
segments.push(seg);
}
}
return segments.join('');
}
function toPropertyKey(segment) {
return typeof segment === 'object' ? segment.key : segment;
}
//# sourceMappingURL=error.js.map