2024-05-16 11:47:06 +00:00
|
|
|
// 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 {
|
2024-05-21 12:41:10 +00:00
|
|
|
messages: Message;
|
2024-05-16 11:47:06 +00:00
|
|
|
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
|
|
|
|
*/
|
2024-05-21 12:41:10 +00:00
|
|
|
type SimpleError = {
|
|
|
|
message: string;
|
|
|
|
field: string;
|
|
|
|
rule: string;
|
|
|
|
index?: number;
|
|
|
|
meta?: Record<string, any>;
|
|
|
|
};
|
|
|
|
export interface Message {
|
|
|
|
[key: string]: any;
|
|
|
|
}
|
2024-05-16 11:47:06 +00:00
|
|
|
/**
|
|
|
|
* 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 {
|
2024-05-21 12:41:10 +00:00
|
|
|
// private messages;
|
2024-05-16 11:47:06 +00:00
|
|
|
// private bail;
|
|
|
|
/**
|
|
|
|
* Boolean to know one or more errors have been reported
|
|
|
|
*/
|
|
|
|
hasErrors: boolean = false;
|
|
|
|
/**
|
|
|
|
* Collection of errors
|
|
|
|
*/
|
|
|
|
// errors: SimpleError[] = [];
|
2024-05-21 12:41:10 +00:00
|
|
|
errors: Message = {};
|
2024-05-16 11:47:06 +00:00
|
|
|
/**
|
|
|
|
* 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;
|
2024-05-21 12:41:10 +00:00
|
|
|
// if (this.errors[field.getFieldPath()]) {
|
|
|
|
// this.errors[field.getFieldPath()]?.push(message);
|
|
|
|
// } else {
|
|
|
|
// this.errors[field.getFieldPath()] = [message];
|
|
|
|
// }
|
|
|
|
const error: SimpleError = {
|
2024-05-16 11:47:06 +00:00
|
|
|
message,
|
|
|
|
rule,
|
2024-10-31 10:02:36 +00:00
|
|
|
field: field.wildCardPath ?field.wildCardPath.split('.')[0] : field.getFieldPath(),
|
2024-05-16 11:47:06 +00:00
|
|
|
};
|
|
|
|
// field: 'titles.0.value'
|
|
|
|
// message: 'Main Title is required'
|
|
|
|
// rule: 'required' "required"
|
2024-10-31 10:02:36 +00:00
|
|
|
|
2024-05-16 11:47:06 +00:00
|
|
|
if (meta) {
|
|
|
|
error.meta = meta;
|
|
|
|
}
|
|
|
|
// if (field.isArrayMember) {
|
|
|
|
// error.index = field.name;
|
|
|
|
// }
|
|
|
|
this.hasErrors = true;
|
2024-10-31 10:02:36 +00:00
|
|
|
|
2024-05-16 11:47:06 +00:00
|
|
|
// this.errors.push(error);
|
2024-10-31 10:02:36 +00:00
|
|
|
// if (this.errors[error.field]) {
|
|
|
|
// this.errors[error.field]?.push(message);
|
|
|
|
// }
|
|
|
|
if (field.isArrayMember) {
|
|
|
|
// Check if the field has wildCardPath and if the error field already exists
|
|
|
|
if (this.errors[error.field] && field.wildCardPath) {
|
|
|
|
// Do nothing, as we don't want to push further messages
|
|
|
|
} else {
|
|
|
|
// If the error field already exists, push the message
|
|
|
|
if (this.errors[error.field]) {
|
|
|
|
this.errors[error.field].push(message);
|
|
|
|
} else {
|
|
|
|
this.errors[error.field] = [message];
|
|
|
|
}
|
|
|
|
}
|
2024-05-16 11:47:06 +00:00
|
|
|
} else {
|
2024-10-31 10:02:36 +00:00
|
|
|
// normal field
|
2024-05-16 11:47:06 +00:00
|
|
|
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 {};
|