123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271 |
- 'use strict';
- const Annotate = require('./annotate');
- const Common = require('./common');
- const Template = require('./template');
- const internals = {};
- exports.Report = class {
- constructor(code, value, local, flags, messages, state, prefs) {
- this.code = code;
- this.flags = flags;
- this.messages = messages;
- this.path = state.path;
- this.prefs = prefs;
- this.state = state;
- this.value = value;
- this.message = null;
- this.template = null;
- this.local = local || {};
- this.local.label = exports.label(this.flags, this.state, this.prefs, this.messages);
- if (this.value !== undefined &&
- !this.local.hasOwnProperty('value')) {
- this.local.value = this.value;
- }
- if (this.path.length) {
- const key = this.path[this.path.length - 1];
- if (typeof key !== 'object') {
- this.local.key = key;
- }
- }
- }
- _setTemplate(template) {
- this.template = template;
- if (!this.flags.label &&
- this.path.length === 0) {
- const localized = this._template(this.template, 'root');
- if (localized) {
- this.local.label = localized;
- }
- }
- }
- toString() {
- if (this.message) {
- return this.message;
- }
- const code = this.code;
- if (!this.prefs.errors.render) {
- return this.code;
- }
- const template = this._template(this.template) ||
- this._template(this.prefs.messages) ||
- this._template(this.messages);
- if (template === undefined) {
- return `Error code "${code}" is not defined, your custom type is missing the correct messages definition`;
- }
- // Render and cache result
- this.message = template.render(this.value, this.state, this.prefs, this.local, { errors: this.prefs.errors, messages: [this.prefs.messages, this.messages] });
- if (!this.prefs.errors.label) {
- this.message = this.message.replace(/^"" /, '').trim();
- }
- return this.message;
- }
- _template(messages, code) {
- return exports.template(this.value, messages, code || this.code, this.state, this.prefs);
- }
- };
- exports.path = function (path) {
- let label = '';
- for (const segment of path) {
- if (typeof segment === 'object') { // Exclude array single path segment
- continue;
- }
- if (typeof segment === 'string') {
- if (label) {
- label += '.';
- }
- label += segment;
- }
- else {
- label += `[${segment}]`;
- }
- }
- return label;
- };
- exports.template = function (value, messages, code, state, prefs) {
- if (!messages) {
- return;
- }
- if (Template.isTemplate(messages)) {
- return code !== 'root' ? messages : null;
- }
- let lang = prefs.errors.language;
- if (Common.isResolvable(lang)) {
- lang = lang.resolve(value, state, prefs);
- }
- if (lang &&
- messages[lang]) {
- if (messages[lang][code] !== undefined) {
- return messages[lang][code];
- }
- if (messages[lang]['*'] !== undefined) {
- return messages[lang]['*'];
- }
- }
- if (!messages[code]) {
- return messages['*'];
- }
- return messages[code];
- };
- exports.label = function (flags, state, prefs, messages) {
- if (flags.label) {
- return flags.label;
- }
- if (!prefs.errors.label) {
- return '';
- }
- let path = state.path;
- if (prefs.errors.label === 'key' &&
- state.path.length > 1) {
- path = state.path.slice(-1);
- }
- const normalized = exports.path(path);
- if (normalized) {
- return normalized;
- }
- return exports.template(null, prefs.messages, 'root', state, prefs) ||
- messages && exports.template(null, messages, 'root', state, prefs) ||
- 'value';
- };
- exports.process = function (errors, original, prefs) {
- if (!errors) {
- return null;
- }
- const { override, message, details } = exports.details(errors);
- if (override) {
- return override;
- }
- if (prefs.errors.stack) {
- return new exports.ValidationError(message, details, original);
- }
- const limit = Error.stackTraceLimit;
- Error.stackTraceLimit = 0;
- const validationError = new exports.ValidationError(message, details, original);
- Error.stackTraceLimit = limit;
- return validationError;
- };
- exports.details = function (errors, options = {}) {
- let messages = [];
- const details = [];
- for (const item of errors) {
- // Override
- if (item instanceof Error) {
- if (options.override !== false) {
- return { override: item };
- }
- const message = item.toString();
- messages.push(message);
- details.push({
- message,
- type: 'override',
- context: { error: item }
- });
- continue;
- }
- // Report
- const message = item.toString();
- messages.push(message);
- details.push({
- message,
- path: item.path.filter((v) => typeof v !== 'object'),
- type: item.code,
- context: item.local
- });
- }
- if (messages.length > 1) {
- messages = [...new Set(messages)];
- }
- return { message: messages.join('. '), details };
- };
- exports.ValidationError = class extends Error {
- constructor(message, details, original) {
- super(message);
- this._original = original;
- this.details = details;
- }
- static isError(err) {
- return err instanceof exports.ValidationError;
- }
- };
- exports.ValidationError.prototype.isJoi = true;
- exports.ValidationError.prototype.name = 'ValidationError';
- exports.ValidationError.prototype.annotate = Annotate.error;
|