forked from geolba/tethys.backend
170 lines
5.2 KiB
TypeScript
170 lines
5.2 KiB
TypeScript
|
// import { ValidationError } from '../errors/validation_error.js';
|
||
|
import { errors } from '@vinejs/vine';
|
||
|
import type { ErrorReporterContract, FieldContext } from '@vinejs/vine/types';
|
||
|
import string from '@poppinss/utils/string';
|
||
|
|
||
|
/**
|
||
|
* Shape of the Vanilla error node
|
||
|
*/
|
||
|
export type VanillaErrorNode = {
|
||
|
[field: string]: string[];
|
||
|
};
|
||
|
export interface MessagesBagContract {
|
||
|
get(pointer: string, rule: string, message: string, arrayExpressionPointer?: string, args?: any): string;
|
||
|
}
|
||
|
/**
|
||
|
* Message bag exposes the API to pull the most appropriate message for a
|
||
|
* given validation failure.
|
||
|
*/
|
||
|
export class MessagesBag implements MessagesBagContract {
|
||
|
messages;
|
||
|
wildCardCallback;
|
||
|
constructor(messages: string[]) {
|
||
|
this.messages = messages;
|
||
|
this.wildCardCallback = typeof this.messages['*'] === 'function' ? this.messages['*'] : undefined;
|
||
|
}
|
||
|
/**
|
||
|
* Transform message by replace placeholders with runtime values
|
||
|
*/
|
||
|
transform(message: any, rule: string, pointer: string, args: any) {
|
||
|
/**
|
||
|
* No interpolation required
|
||
|
*/
|
||
|
if (!message.includes('{{')) {
|
||
|
return message;
|
||
|
}
|
||
|
return string.interpolate(message, { rule, field: pointer, options: args || {} });
|
||
|
}
|
||
|
/**
|
||
|
* Returns the most appropriate message for the validation failure.
|
||
|
*/
|
||
|
get(pointer: string, rule: string, message: string, arrayExpressionPointer: string, args: any) {
|
||
|
let validationMessage = this.messages[`${pointer}.${rule}`];
|
||
|
/**
|
||
|
* Fetch message for the array expression pointer if it exists
|
||
|
*/
|
||
|
if (!validationMessage && arrayExpressionPointer) {
|
||
|
validationMessage = this.messages[`${arrayExpressionPointer}.${rule}`];
|
||
|
}
|
||
|
/**
|
||
|
* Fallback to the message for the rule
|
||
|
*/
|
||
|
if (!validationMessage) {
|
||
|
validationMessage = this.messages[rule];
|
||
|
}
|
||
|
/**
|
||
|
* Transform and return message. The wildcard callback is invoked when custom message
|
||
|
* is not defined
|
||
|
*/
|
||
|
return validationMessage
|
||
|
? this.transform(validationMessage, rule, pointer, args)
|
||
|
: this.wildCardCallback
|
||
|
? this.wildCardCallback(pointer, rule, arrayExpressionPointer, args)
|
||
|
: message;
|
||
|
}
|
||
|
}
|
||
|
/**
|
||
|
* Shape of the error message collected by the SimpleErrorReporter
|
||
|
*/
|
||
|
// type SimpleError = {
|
||
|
// message: string;
|
||
|
// field: string;
|
||
|
// rule: string;
|
||
|
// index?: number;
|
||
|
// meta?: Record<string, any>;
|
||
|
// };
|
||
|
/**
|
||
|
* Simple error reporter collects error messages as an array of object.
|
||
|
* Each object has following properties.
|
||
|
*
|
||
|
* - message: string
|
||
|
* - field: string
|
||
|
* - rule: string
|
||
|
* - index?: number (in case of an array member)
|
||
|
* - args?: Record<string, any>
|
||
|
*/
|
||
|
export class VanillaErrorReporter implements ErrorReporterContract {
|
||
|
private messages;
|
||
|
// private bail;
|
||
|
/**
|
||
|
* Boolean to know one or more errors have been reported
|
||
|
*/
|
||
|
hasErrors: boolean = false;
|
||
|
/**
|
||
|
* Collection of errors
|
||
|
*/
|
||
|
// errors: SimpleError[] = [];
|
||
|
errors = {};
|
||
|
/**
|
||
|
* Report an error.
|
||
|
*/
|
||
|
|
||
|
// constructor(messages: MessagesBagContract) {
|
||
|
// this.messages = messages;
|
||
|
// }
|
||
|
|
||
|
report(message: string, rule: string, field: FieldContext, meta?: Record<string, any> | undefined): void {
|
||
|
// const error: SimpleError = {
|
||
|
// message,
|
||
|
// rule,
|
||
|
// field: field.getFieldPath()
|
||
|
// };
|
||
|
// if (meta) {
|
||
|
// error.meta = meta;
|
||
|
// }
|
||
|
// if (field.isArrayMember) {
|
||
|
// error.index = field.name as number;
|
||
|
// }
|
||
|
// this.errors.push(error);
|
||
|
this.hasErrors = true;
|
||
|
const error = {
|
||
|
message,
|
||
|
rule,
|
||
|
field: field.getFieldPath(),
|
||
|
};
|
||
|
// field: 'titles.0.value'
|
||
|
// message: 'Main Title is required'
|
||
|
// rule: 'required' "required"
|
||
|
if (meta) {
|
||
|
error.meta = meta;
|
||
|
}
|
||
|
// if (field.isArrayMember) {
|
||
|
// error.index = field.name;
|
||
|
// }
|
||
|
this.hasErrors = true;
|
||
|
// this.errors.push(error);
|
||
|
if (this.errors[error.field]) {
|
||
|
this.errors[error.field]?.push(message);
|
||
|
} else {
|
||
|
this.errors[error.field] = [message];
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Collecting errors as per the JSONAPI spec
|
||
|
*/
|
||
|
// this.errors.push({
|
||
|
// code: rule,
|
||
|
// detail: message,
|
||
|
// source: {
|
||
|
// pointer: field.wildCardPath,
|
||
|
// },
|
||
|
// ...(meta ? { meta } : {}),
|
||
|
// });
|
||
|
|
||
|
// let pointer: string = field.wildCardPath as string; //'display_name'
|
||
|
// // if (field.isArrayMember) {
|
||
|
// // this.errors[pointer] = field.name;
|
||
|
// // }
|
||
|
// this.errors[pointer] = this.errors[pointer] || [];
|
||
|
// // this.errors[pointer].push(message);
|
||
|
// this.errors[pointer].push(this.messages.get(pointer, rule, message, arrayExpressionPointer, args));
|
||
|
}
|
||
|
/**
|
||
|
* Returns an instance of the validation error
|
||
|
*/
|
||
|
createError() {
|
||
|
return new errors.E_VALIDATION_ERROR(this.errors);
|
||
|
}
|
||
|
}
|
||
|
export {};
|