Apply module bundling
[platform/framework/web/wrtjs.git] / node_modules / schema-utils / dist / ValidationError.js
1 "use strict";
2
3 Object.defineProperty(exports, "__esModule", {
4   value: true
5 });
6 exports.default = void 0;
7
8 const {
9   stringHints,
10   numberHints
11 } = require("./util/hints");
12 /** @typedef {import("json-schema").JSONSchema6} JSONSchema6 */
13
14 /** @typedef {import("json-schema").JSONSchema7} JSONSchema7 */
15
16 /** @typedef {import("./validate").Schema} Schema */
17
18 /** @typedef {import("./validate").ValidationErrorConfiguration} ValidationErrorConfiguration */
19
20 /** @typedef {import("./validate").PostFormatter} PostFormatter */
21
22 /** @typedef {import("./validate").SchemaUtilErrorObject} SchemaUtilErrorObject */
23
24 /** @enum {number} */
25
26
27 const SPECIFICITY = {
28   type: 1,
29   not: 1,
30   oneOf: 1,
31   anyOf: 1,
32   if: 1,
33   enum: 1,
34   const: 1,
35   instanceof: 1,
36   required: 2,
37   pattern: 2,
38   patternRequired: 2,
39   format: 2,
40   formatMinimum: 2,
41   formatMaximum: 2,
42   minimum: 2,
43   exclusiveMinimum: 2,
44   maximum: 2,
45   exclusiveMaximum: 2,
46   multipleOf: 2,
47   uniqueItems: 2,
48   contains: 2,
49   minLength: 2,
50   maxLength: 2,
51   minItems: 2,
52   maxItems: 2,
53   minProperties: 2,
54   maxProperties: 2,
55   dependencies: 2,
56   propertyNames: 2,
57   additionalItems: 2,
58   additionalProperties: 2,
59   absolutePath: 2
60 };
61 /**
62  *
63  * @param {Array<SchemaUtilErrorObject>} array
64  * @param {(item: SchemaUtilErrorObject) => number} fn
65  * @returns {Array<SchemaUtilErrorObject>}
66  */
67
68 function filterMax(array, fn) {
69   const evaluatedMax = array.reduce((max, item) => Math.max(max, fn(item)), 0);
70   return array.filter(item => fn(item) === evaluatedMax);
71 }
72 /**
73  *
74  * @param {Array<SchemaUtilErrorObject>} children
75  * @returns {Array<SchemaUtilErrorObject>}
76  */
77
78
79 function filterChildren(children) {
80   let newChildren = children;
81   newChildren = filterMax(newChildren,
82   /**
83    *
84    * @param {SchemaUtilErrorObject} error
85    * @returns {number}
86    */
87   error => error.dataPath ? error.dataPath.length : 0);
88   newChildren = filterMax(newChildren,
89   /**
90    * @param {SchemaUtilErrorObject} error
91    * @returns {number}
92    */
93   error => SPECIFICITY[
94   /** @type {keyof typeof SPECIFICITY} */
95   error.keyword] || 2);
96   return newChildren;
97 }
98 /**
99  * Find all children errors
100  * @param {Array<SchemaUtilErrorObject>} children
101  * @param {Array<string>} schemaPaths
102  * @return {number} returns index of first child
103  */
104
105
106 function findAllChildren(children, schemaPaths) {
107   let i = children.length - 1;
108
109   const predicate =
110   /**
111    * @param {string} schemaPath
112    * @returns {boolean}
113    */
114   schemaPath => children[i].schemaPath.indexOf(schemaPath) !== 0;
115
116   while (i > -1 && !schemaPaths.every(predicate)) {
117     if (children[i].keyword === "anyOf" || children[i].keyword === "oneOf") {
118       const refs = extractRefs(children[i]);
119       const childrenStart = findAllChildren(children.slice(0, i), refs.concat(children[i].schemaPath));
120       i = childrenStart - 1;
121     } else {
122       i -= 1;
123     }
124   }
125
126   return i + 1;
127 }
128 /**
129  * Extracts all refs from schema
130  * @param {SchemaUtilErrorObject} error
131  * @return {Array<string>}
132  */
133
134
135 function extractRefs(error) {
136   const {
137     schema
138   } = error;
139
140   if (!Array.isArray(schema)) {
141     return [];
142   }
143
144   return schema.map(({
145     $ref
146   }) => $ref).filter(s => s);
147 }
148 /**
149  * Groups children by their first level parent (assuming that error is root)
150  * @param {Array<SchemaUtilErrorObject>} children
151  * @return {Array<SchemaUtilErrorObject>}
152  */
153
154
155 function groupChildrenByFirstChild(children) {
156   const result = [];
157   let i = children.length - 1;
158
159   while (i > 0) {
160     const child = children[i];
161
162     if (child.keyword === "anyOf" || child.keyword === "oneOf") {
163       const refs = extractRefs(child);
164       const childrenStart = findAllChildren(children.slice(0, i), refs.concat(child.schemaPath));
165
166       if (childrenStart !== i) {
167         result.push(Object.assign({}, child, {
168           children: children.slice(childrenStart, i)
169         }));
170         i = childrenStart;
171       } else {
172         result.push(child);
173       }
174     } else {
175       result.push(child);
176     }
177
178     i -= 1;
179   }
180
181   if (i === 0) {
182     result.push(children[i]);
183   }
184
185   return result.reverse();
186 }
187 /**
188  * @param {string} str
189  * @param {string} prefix
190  * @returns {string}
191  */
192
193
194 function indent(str, prefix) {
195   return str.replace(/\n(?!$)/g, `\n${prefix}`);
196 }
197 /**
198  * @param {Schema} schema
199  * @returns {schema is (Schema & {not: Schema})}
200  */
201
202
203 function hasNotInSchema(schema) {
204   return !!schema.not;
205 }
206 /**
207  * @param {Schema} schema
208  * @return {Schema}
209  */
210
211
212 function findFirstTypedSchema(schema) {
213   if (hasNotInSchema(schema)) {
214     return findFirstTypedSchema(schema.not);
215   }
216
217   return schema;
218 }
219 /**
220  * @param {Schema} schema
221  * @return {boolean}
222  */
223
224
225 function canApplyNot(schema) {
226   const typedSchema = findFirstTypedSchema(schema);
227   return likeNumber(typedSchema) || likeInteger(typedSchema) || likeString(typedSchema) || likeNull(typedSchema) || likeBoolean(typedSchema);
228 }
229 /**
230  * @param {any} maybeObj
231  * @returns {boolean}
232  */
233
234
235 function isObject(maybeObj) {
236   return typeof maybeObj === "object" && maybeObj !== null;
237 }
238 /**
239  * @param {Schema} schema
240  * @returns {boolean}
241  */
242
243
244 function likeNumber(schema) {
245   return schema.type === "number" || typeof schema.minimum !== "undefined" || typeof schema.exclusiveMinimum !== "undefined" || typeof schema.maximum !== "undefined" || typeof schema.exclusiveMaximum !== "undefined" || typeof schema.multipleOf !== "undefined";
246 }
247 /**
248  * @param {Schema} schema
249  * @returns {boolean}
250  */
251
252
253 function likeInteger(schema) {
254   return schema.type === "integer" || typeof schema.minimum !== "undefined" || typeof schema.exclusiveMinimum !== "undefined" || typeof schema.maximum !== "undefined" || typeof schema.exclusiveMaximum !== "undefined" || typeof schema.multipleOf !== "undefined";
255 }
256 /**
257  * @param {Schema} schema
258  * @returns {boolean}
259  */
260
261
262 function likeString(schema) {
263   return schema.type === "string" || typeof schema.minLength !== "undefined" || typeof schema.maxLength !== "undefined" || typeof schema.pattern !== "undefined" || typeof schema.format !== "undefined" || typeof schema.formatMinimum !== "undefined" || typeof schema.formatMaximum !== "undefined";
264 }
265 /**
266  * @param {Schema} schema
267  * @returns {boolean}
268  */
269
270
271 function likeBoolean(schema) {
272   return schema.type === "boolean";
273 }
274 /**
275  * @param {Schema} schema
276  * @returns {boolean}
277  */
278
279
280 function likeArray(schema) {
281   return schema.type === "array" || typeof schema.minItems === "number" || typeof schema.maxItems === "number" || typeof schema.uniqueItems !== "undefined" || typeof schema.items !== "undefined" || typeof schema.additionalItems !== "undefined" || typeof schema.contains !== "undefined";
282 }
283 /**
284  * @param {Schema & {patternRequired?: Array<string>}} schema
285  * @returns {boolean}
286  */
287
288
289 function likeObject(schema) {
290   return schema.type === "object" || typeof schema.minProperties !== "undefined" || typeof schema.maxProperties !== "undefined" || typeof schema.required !== "undefined" || typeof schema.properties !== "undefined" || typeof schema.patternProperties !== "undefined" || typeof schema.additionalProperties !== "undefined" || typeof schema.dependencies !== "undefined" || typeof schema.propertyNames !== "undefined" || typeof schema.patternRequired !== "undefined";
291 }
292 /**
293  * @param {Schema} schema
294  * @returns {boolean}
295  */
296
297
298 function likeNull(schema) {
299   return schema.type === "null";
300 }
301 /**
302  * @param {string} type
303  * @returns {string}
304  */
305
306
307 function getArticle(type) {
308   if (/^[aeiou]/i.test(type)) {
309     return "an";
310   }
311
312   return "a";
313 }
314 /**
315  * @param {Schema=} schema
316  * @returns {string}
317  */
318
319
320 function getSchemaNonTypes(schema) {
321   if (!schema) {
322     return "";
323   }
324
325   if (!schema.type) {
326     if (likeNumber(schema) || likeInteger(schema)) {
327       return " | should be any non-number";
328     }
329
330     if (likeString(schema)) {
331       return " | should be any non-string";
332     }
333
334     if (likeArray(schema)) {
335       return " | should be any non-array";
336     }
337
338     if (likeObject(schema)) {
339       return " | should be any non-object";
340     }
341   }
342
343   return "";
344 }
345 /**
346  * @param {Array<string>} hints
347  * @returns {string}
348  */
349
350
351 function formatHints(hints) {
352   return hints.length > 0 ? `(${hints.join(", ")})` : "";
353 }
354 /**
355  * @param {Schema} schema
356  * @param {boolean} logic
357  * @returns {string[]}
358  */
359
360
361 function getHints(schema, logic) {
362   if (likeNumber(schema) || likeInteger(schema)) {
363     return numberHints(schema, logic);
364   } else if (likeString(schema)) {
365     return stringHints(schema, logic);
366   }
367
368   return [];
369 }
370
371 class ValidationError extends Error {
372   /**
373    * @param {Array<SchemaUtilErrorObject>} errors
374    * @param {Schema} schema
375    * @param {ValidationErrorConfiguration} configuration
376    */
377   constructor(errors, schema, configuration = {}) {
378     super();
379     /** @type {string} */
380
381     this.name = "ValidationError";
382     /** @type {Array<SchemaUtilErrorObject>} */
383
384     this.errors = errors;
385     /** @type {Schema} */
386
387     this.schema = schema;
388     let headerNameFromSchema;
389     let baseDataPathFromSchema;
390
391     if (schema.title && (!configuration.name || !configuration.baseDataPath)) {
392       const splittedTitleFromSchema = schema.title.match(/^(.+) (.+)$/);
393
394       if (splittedTitleFromSchema) {
395         if (!configuration.name) {
396           [, headerNameFromSchema] = splittedTitleFromSchema;
397         }
398
399         if (!configuration.baseDataPath) {
400           [,, baseDataPathFromSchema] = splittedTitleFromSchema;
401         }
402       }
403     }
404     /** @type {string} */
405
406
407     this.headerName = configuration.name || headerNameFromSchema || "Object";
408     /** @type {string} */
409
410     this.baseDataPath = configuration.baseDataPath || baseDataPathFromSchema || "configuration";
411     /** @type {PostFormatter | null} */
412
413     this.postFormatter = configuration.postFormatter || null;
414     const header = `Invalid ${this.baseDataPath} object. ${this.headerName} has been initialized using ${getArticle(this.baseDataPath)} ${this.baseDataPath} object that does not match the API schema.\n`;
415     /** @type {string} */
416
417     this.message = `${header}${this.formatValidationErrors(errors)}`;
418     Error.captureStackTrace(this, this.constructor);
419   }
420   /**
421    * @param {string} path
422    * @returns {Schema}
423    */
424
425
426   getSchemaPart(path) {
427     const newPath = path.split("/");
428     let schemaPart = this.schema;
429
430     for (let i = 1; i < newPath.length; i++) {
431       const inner = schemaPart[
432       /** @type {keyof Schema} */
433       newPath[i]];
434
435       if (!inner) {
436         break;
437       }
438
439       schemaPart = inner;
440     }
441
442     return schemaPart;
443   }
444   /**
445    * @param {Schema} schema
446    * @param {boolean} logic
447    * @param {Array<Object>} prevSchemas
448    * @returns {string}
449    */
450
451
452   formatSchema(schema, logic = true, prevSchemas = []) {
453     let newLogic = logic;
454
455     const formatInnerSchema =
456     /**
457      *
458      * @param {Object} innerSchema
459      * @param {boolean=} addSelf
460      * @returns {string}
461      */
462     (innerSchema, addSelf) => {
463       if (!addSelf) {
464         return this.formatSchema(innerSchema, newLogic, prevSchemas);
465       }
466
467       if (prevSchemas.includes(innerSchema)) {
468         return "(recursive)";
469       }
470
471       return this.formatSchema(innerSchema, newLogic, prevSchemas.concat(schema));
472     };
473
474     if (hasNotInSchema(schema) && !likeObject(schema)) {
475       if (canApplyNot(schema.not)) {
476         newLogic = !logic;
477         return formatInnerSchema(schema.not);
478       }
479
480       const needApplyLogicHere = !schema.not.not;
481       const prefix = logic ? "" : "non ";
482       newLogic = !logic;
483       return needApplyLogicHere ? prefix + formatInnerSchema(schema.not) : formatInnerSchema(schema.not);
484     }
485
486     if (
487     /** @type {Schema & {instanceof: string | Array<string>}} */
488     schema.instanceof) {
489       const {
490         instanceof: value
491       } =
492       /** @type {Schema & {instanceof: string | Array<string>}} */
493       schema;
494       const values = !Array.isArray(value) ? [value] : value;
495       return values.map(
496       /**
497        * @param {string} item
498        * @returns {string}
499        */
500       item => item === "Function" ? "function" : item).join(" | ");
501     }
502
503     if (schema.enum) {
504       return (
505         /** @type {Array<any>} */
506         schema.enum.map(item => JSON.stringify(item)).join(" | ")
507       );
508     }
509
510     if (typeof schema.const !== "undefined") {
511       return JSON.stringify(schema.const);
512     }
513
514     if (schema.oneOf) {
515       return (
516         /** @type {Array<Schema>} */
517         schema.oneOf.map(item => formatInnerSchema(item, true)).join(" | ")
518       );
519     }
520
521     if (schema.anyOf) {
522       return (
523         /** @type {Array<Schema>} */
524         schema.anyOf.map(item => formatInnerSchema(item, true)).join(" | ")
525       );
526     }
527
528     if (schema.allOf) {
529       return (
530         /** @type {Array<Schema>} */
531         schema.allOf.map(item => formatInnerSchema(item, true)).join(" & ")
532       );
533     }
534
535     if (
536     /** @type {JSONSchema7} */
537     schema.if) {
538       const {
539         if: ifValue,
540         then: thenValue,
541         else: elseValue
542       } =
543       /** @type {JSONSchema7} */
544       schema;
545       return `${ifValue ? `if ${formatInnerSchema(ifValue)}` : ""}${thenValue ? ` then ${formatInnerSchema(thenValue)}` : ""}${elseValue ? ` else ${formatInnerSchema(elseValue)}` : ""}`;
546     }
547
548     if (schema.$ref) {
549       return formatInnerSchema(this.getSchemaPart(schema.$ref), true);
550     }
551
552     if (likeNumber(schema) || likeInteger(schema)) {
553       const [type, ...hints] = getHints(schema, logic);
554       const str = `${type}${hints.length > 0 ? ` ${formatHints(hints)}` : ""}`;
555       return logic ? str : hints.length > 0 ? `non-${type} | ${str}` : `non-${type}`;
556     }
557
558     if (likeString(schema)) {
559       const [type, ...hints] = getHints(schema, logic);
560       const str = `${type}${hints.length > 0 ? ` ${formatHints(hints)}` : ""}`;
561       return logic ? str : str === "string" ? "non-string" : `non-string | ${str}`;
562     }
563
564     if (likeBoolean(schema)) {
565       return `${logic ? "" : "non-"}boolean`;
566     }
567
568     if (likeArray(schema)) {
569       // not logic already applied in formatValidationError
570       newLogic = true;
571       const hints = [];
572
573       if (typeof schema.minItems === "number") {
574         hints.push(`should not have fewer than ${schema.minItems} item${schema.minItems > 1 ? "s" : ""}`);
575       }
576
577       if (typeof schema.maxItems === "number") {
578         hints.push(`should not have more than ${schema.maxItems} item${schema.maxItems > 1 ? "s" : ""}`);
579       }
580
581       if (schema.uniqueItems) {
582         hints.push("should not have duplicate items");
583       }
584
585       const hasAdditionalItems = typeof schema.additionalItems === "undefined" || Boolean(schema.additionalItems);
586       let items = "";
587
588       if (schema.items) {
589         if (Array.isArray(schema.items) && schema.items.length > 0) {
590           items = `${
591           /** @type {Array<Schema>} */
592           schema.items.map(item => formatInnerSchema(item)).join(", ")}`;
593
594           if (hasAdditionalItems) {
595             if (schema.additionalItems && isObject(schema.additionalItems) && Object.keys(schema.additionalItems).length > 0) {
596               hints.push(`additional items should be ${formatInnerSchema(schema.additionalItems)}`);
597             }
598           }
599         } else if (schema.items && Object.keys(schema.items).length > 0) {
600           // "additionalItems" is ignored
601           items = `${formatInnerSchema(schema.items)}`;
602         } else {
603           // Fallback for empty `items` value
604           items = "any";
605         }
606       } else {
607         // "additionalItems" is ignored
608         items = "any";
609       }
610
611       if (schema.contains && Object.keys(schema.contains).length > 0) {
612         hints.push(`should contains at least one ${this.formatSchema(schema.contains)} item`);
613       }
614
615       return `[${items}${hasAdditionalItems ? ", ..." : ""}]${hints.length > 0 ? ` (${hints.join(", ")})` : ""}`;
616     }
617
618     if (likeObject(schema)) {
619       // not logic already applied in formatValidationError
620       newLogic = true;
621       const hints = [];
622
623       if (typeof schema.minProperties === "number") {
624         hints.push(`should not have fewer than ${schema.minProperties} ${schema.minProperties > 1 ? "properties" : "property"}`);
625       }
626
627       if (typeof schema.maxProperties === "number") {
628         hints.push(`should not have more than ${schema.maxProperties} ${schema.minProperties && schema.minProperties > 1 ? "properties" : "property"}`);
629       }
630
631       if (schema.patternProperties && Object.keys(schema.patternProperties).length > 0) {
632         const patternProperties = Object.keys(schema.patternProperties);
633         hints.push(`additional property names should match pattern${patternProperties.length > 1 ? "s" : ""} ${patternProperties.map(pattern => JSON.stringify(pattern)).join(" | ")}`);
634       }
635
636       const properties = schema.properties ? Object.keys(schema.properties) : [];
637       const required = schema.required ? schema.required : [];
638       const allProperties = [...new Set(
639       /** @type {Array<string>} */
640       [].concat(required).concat(properties))];
641       const objectStructure = allProperties.map(property => {
642         const isRequired = required.includes(property); // Some properties need quotes, maybe we should add check
643         // Maybe we should output type of property (`foo: string`), but it is looks very unreadable
644
645         return `${property}${isRequired ? "" : "?"}`;
646       }).concat(typeof schema.additionalProperties === "undefined" || Boolean(schema.additionalProperties) ? schema.additionalProperties && isObject(schema.additionalProperties) ? [`<key>: ${formatInnerSchema(schema.additionalProperties)}`] : ["…"] : []).join(", ");
647       const {
648         dependencies,
649         propertyNames,
650         patternRequired
651       } =
652       /** @type {Schema & {patternRequired?: Array<string>;}} */
653       schema;
654
655       if (dependencies) {
656         Object.keys(dependencies).forEach(dependencyName => {
657           const dependency = dependencies[dependencyName];
658
659           if (Array.isArray(dependency)) {
660             hints.push(`should have ${dependency.length > 1 ? "properties" : "property"} ${dependency.map(dep => `'${dep}'`).join(", ")} when property '${dependencyName}' is present`);
661           } else {
662             hints.push(`should be valid according to the schema ${formatInnerSchema(dependency)} when property '${dependencyName}' is present`);
663           }
664         });
665       }
666
667       if (propertyNames && Object.keys(propertyNames).length > 0) {
668         hints.push(`each property name should match format ${JSON.stringify(schema.propertyNames.format)}`);
669       }
670
671       if (patternRequired && patternRequired.length > 0) {
672         hints.push(`should have property matching pattern ${patternRequired.map(
673         /**
674          * @param {string} item
675          * @returns {string}
676          */
677         item => JSON.stringify(item))}`);
678       }
679
680       return `object {${objectStructure ? ` ${objectStructure} ` : ""}}${hints.length > 0 ? ` (${hints.join(", ")})` : ""}`;
681     }
682
683     if (likeNull(schema)) {
684       return `${logic ? "" : "non-"}null`;
685     }
686
687     if (Array.isArray(schema.type)) {
688       // not logic already applied in formatValidationError
689       return `${schema.type.join(" | ")}`;
690     } // Fallback for unknown keywords
691     // not logic already applied in formatValidationError
692
693     /* istanbul ignore next */
694
695
696     return JSON.stringify(schema, null, 2);
697   }
698   /**
699    * @param {Schema=} schemaPart
700    * @param {(boolean | Array<string>)=} additionalPath
701    * @param {boolean=} needDot
702    * @param {boolean=} logic
703    * @returns {string}
704    */
705
706
707   getSchemaPartText(schemaPart, additionalPath, needDot = false, logic = true) {
708     if (!schemaPart) {
709       return "";
710     }
711
712     if (Array.isArray(additionalPath)) {
713       for (let i = 0; i < additionalPath.length; i++) {
714         /** @type {Schema | undefined} */
715         const inner = schemaPart[
716         /** @type {keyof Schema} */
717         additionalPath[i]];
718
719         if (inner) {
720           // eslint-disable-next-line no-param-reassign
721           schemaPart = inner;
722         } else {
723           break;
724         }
725       }
726     }
727
728     while (schemaPart.$ref) {
729       // eslint-disable-next-line no-param-reassign
730       schemaPart = this.getSchemaPart(schemaPart.$ref);
731     }
732
733     let schemaText = `${this.formatSchema(schemaPart, logic)}${needDot ? "." : ""}`;
734
735     if (schemaPart.description) {
736       schemaText += `\n-> ${schemaPart.description}`;
737     }
738
739     if (schemaPart.link) {
740       schemaText += `\n-> Read more at ${schemaPart.link}`;
741     }
742
743     return schemaText;
744   }
745   /**
746    * @param {Schema=} schemaPart
747    * @returns {string}
748    */
749
750
751   getSchemaPartDescription(schemaPart) {
752     if (!schemaPart) {
753       return "";
754     }
755
756     while (schemaPart.$ref) {
757       // eslint-disable-next-line no-param-reassign
758       schemaPart = this.getSchemaPart(schemaPart.$ref);
759     }
760
761     let schemaText = "";
762
763     if (schemaPart.description) {
764       schemaText += `\n-> ${schemaPart.description}`;
765     }
766
767     if (schemaPart.link) {
768       schemaText += `\n-> Read more at ${schemaPart.link}`;
769     }
770
771     return schemaText;
772   }
773   /**
774    * @param {SchemaUtilErrorObject} error
775    * @returns {string}
776    */
777
778
779   formatValidationError(error) {
780     const {
781       keyword,
782       dataPath: errorDataPath
783     } = error;
784     const dataPath = `${this.baseDataPath}${errorDataPath}`;
785
786     switch (keyword) {
787       case "type":
788         {
789           const {
790             parentSchema,
791             params
792           } = error; // eslint-disable-next-line default-case
793
794           switch (
795           /** @type {import("ajv").TypeParams} */
796           params.type) {
797             case "number":
798               return `${dataPath} should be a ${this.getSchemaPartText(parentSchema, false, true)}`;
799
800             case "integer":
801               return `${dataPath} should be an ${this.getSchemaPartText(parentSchema, false, true)}`;
802
803             case "string":
804               return `${dataPath} should be a ${this.getSchemaPartText(parentSchema, false, true)}`;
805
806             case "boolean":
807               return `${dataPath} should be a ${this.getSchemaPartText(parentSchema, false, true)}`;
808
809             case "array":
810               return `${dataPath} should be an array:\n${this.getSchemaPartText(parentSchema)}`;
811
812             case "object":
813               return `${dataPath} should be an object:\n${this.getSchemaPartText(parentSchema)}`;
814
815             case "null":
816               return `${dataPath} should be a ${this.getSchemaPartText(parentSchema, false, true)}`;
817
818             default:
819               return `${dataPath} should be:\n${this.getSchemaPartText(parentSchema)}`;
820           }
821         }
822
823       case "instanceof":
824         {
825           const {
826             parentSchema
827           } = error;
828           return `${dataPath} should be an instance of ${this.getSchemaPartText(parentSchema, false, true)}`;
829         }
830
831       case "pattern":
832         {
833           const {
834             params,
835             parentSchema
836           } = error;
837           const {
838             pattern
839           } =
840           /** @type {import("ajv").PatternParams} */
841           params;
842           return `${dataPath} should match pattern ${JSON.stringify(pattern)}${getSchemaNonTypes(parentSchema)}.${this.getSchemaPartDescription(parentSchema)}`;
843         }
844
845       case "format":
846         {
847           const {
848             params,
849             parentSchema
850           } = error;
851           const {
852             format
853           } =
854           /** @type {import("ajv").FormatParams} */
855           params;
856           return `${dataPath} should match format ${JSON.stringify(format)}${getSchemaNonTypes(parentSchema)}.${this.getSchemaPartDescription(parentSchema)}`;
857         }
858
859       case "formatMinimum":
860       case "formatMaximum":
861         {
862           const {
863             params,
864             parentSchema
865           } = error;
866           const {
867             comparison,
868             limit
869           } =
870           /** @type {import("ajv").ComparisonParams} */
871           params;
872           return `${dataPath} should be ${comparison} ${JSON.stringify(limit)}${getSchemaNonTypes(parentSchema)}.${this.getSchemaPartDescription(parentSchema)}`;
873         }
874
875       case "minimum":
876       case "maximum":
877       case "exclusiveMinimum":
878       case "exclusiveMaximum":
879         {
880           const {
881             parentSchema,
882             params
883           } = error;
884           const {
885             comparison,
886             limit
887           } =
888           /** @type {import("ajv").ComparisonParams} */
889           params;
890           const [, ...hints] = getHints(
891           /** @type {Schema} */
892           parentSchema, true);
893
894           if (hints.length === 0) {
895             hints.push(`should be ${comparison} ${limit}`);
896           }
897
898           return `${dataPath} ${hints.join(" ")}${getSchemaNonTypes(parentSchema)}.${this.getSchemaPartDescription(parentSchema)}`;
899         }
900
901       case "multipleOf":
902         {
903           const {
904             params,
905             parentSchema
906           } = error;
907           const {
908             multipleOf
909           } =
910           /** @type {import("ajv").MultipleOfParams} */
911           params;
912           return `${dataPath} should be multiple of ${multipleOf}${getSchemaNonTypes(parentSchema)}.${this.getSchemaPartDescription(parentSchema)}`;
913         }
914
915       case "patternRequired":
916         {
917           const {
918             params,
919             parentSchema
920           } = error;
921           const {
922             missingPattern
923           } =
924           /** @type {import("ajv").PatternRequiredParams} */
925           params;
926           return `${dataPath} should have property matching pattern ${JSON.stringify(missingPattern)}${getSchemaNonTypes(parentSchema)}.${this.getSchemaPartDescription(parentSchema)}`;
927         }
928
929       case "minLength":
930         {
931           const {
932             params,
933             parentSchema
934           } = error;
935           const {
936             limit
937           } =
938           /** @type {import("ajv").LimitParams} */
939           params;
940
941           if (limit === 1) {
942             return `${dataPath} should be a non-empty string${getSchemaNonTypes(parentSchema)}.${this.getSchemaPartDescription(parentSchema)}`;
943           }
944
945           const length = limit - 1;
946           return `${dataPath} should be longer than ${length} character${length > 1 ? "s" : ""}${getSchemaNonTypes(parentSchema)}.${this.getSchemaPartDescription(parentSchema)}`;
947         }
948
949       case "minItems":
950         {
951           const {
952             params,
953             parentSchema
954           } = error;
955           const {
956             limit
957           } =
958           /** @type {import("ajv").LimitParams} */
959           params;
960
961           if (limit === 1) {
962             return `${dataPath} should be a non-empty array${getSchemaNonTypes(parentSchema)}.${this.getSchemaPartDescription(parentSchema)}`;
963           }
964
965           return `${dataPath} should not have fewer than ${limit} items${getSchemaNonTypes(parentSchema)}.${this.getSchemaPartDescription(parentSchema)}`;
966         }
967
968       case "minProperties":
969         {
970           const {
971             params,
972             parentSchema
973           } = error;
974           const {
975             limit
976           } =
977           /** @type {import("ajv").LimitParams} */
978           params;
979
980           if (limit === 1) {
981             return `${dataPath} should be a non-empty object${getSchemaNonTypes(parentSchema)}.${this.getSchemaPartDescription(parentSchema)}`;
982           }
983
984           return `${dataPath} should not have fewer than ${limit} properties${getSchemaNonTypes(parentSchema)}.${this.getSchemaPartDescription(parentSchema)}`;
985         }
986
987       case "maxLength":
988         {
989           const {
990             params,
991             parentSchema
992           } = error;
993           const {
994             limit
995           } =
996           /** @type {import("ajv").LimitParams} */
997           params;
998           const max = limit + 1;
999           return `${dataPath} should be shorter than ${max} character${max > 1 ? "s" : ""}${getSchemaNonTypes(parentSchema)}.${this.getSchemaPartDescription(parentSchema)}`;
1000         }
1001
1002       case "maxItems":
1003         {
1004           const {
1005             params,
1006             parentSchema
1007           } = error;
1008           const {
1009             limit
1010           } =
1011           /** @type {import("ajv").LimitParams} */
1012           params;
1013           return `${dataPath} should not have more than ${limit} items${getSchemaNonTypes(parentSchema)}.${this.getSchemaPartDescription(parentSchema)}`;
1014         }
1015
1016       case "maxProperties":
1017         {
1018           const {
1019             params,
1020             parentSchema
1021           } = error;
1022           const {
1023             limit
1024           } =
1025           /** @type {import("ajv").LimitParams} */
1026           params;
1027           return `${dataPath} should not have more than ${limit} properties${getSchemaNonTypes(parentSchema)}.${this.getSchemaPartDescription(parentSchema)}`;
1028         }
1029
1030       case "uniqueItems":
1031         {
1032           const {
1033             params,
1034             parentSchema
1035           } = error;
1036           const {
1037             i
1038           } =
1039           /** @type {import("ajv").UniqueItemsParams} */
1040           params;
1041           return `${dataPath} should not contain the item '${error.data[i]}' twice${getSchemaNonTypes(parentSchema)}.${this.getSchemaPartDescription(parentSchema)}`;
1042         }
1043
1044       case "additionalItems":
1045         {
1046           const {
1047             params,
1048             parentSchema
1049           } = error;
1050           const {
1051             limit
1052           } =
1053           /** @type {import("ajv").LimitParams} */
1054           params;
1055           return `${dataPath} should not have more than ${limit} items${getSchemaNonTypes(parentSchema)}. These items are valid:\n${this.getSchemaPartText(parentSchema)}`;
1056         }
1057
1058       case "contains":
1059         {
1060           const {
1061             parentSchema
1062           } = error;
1063           return `${dataPath} should contains at least one ${this.getSchemaPartText(parentSchema, ["contains"])} item${getSchemaNonTypes(parentSchema)}.`;
1064         }
1065
1066       case "required":
1067         {
1068           const {
1069             parentSchema,
1070             params
1071           } = error;
1072           const missingProperty =
1073           /** @type {import("ajv").DependenciesParams} */
1074           params.missingProperty.replace(/^\./, "");
1075           const hasProperty = parentSchema && Boolean(
1076           /** @type {Schema} */
1077           parentSchema.properties &&
1078           /** @type {Schema} */
1079           parentSchema.properties[missingProperty]);
1080           return `${dataPath} misses the property '${missingProperty}'${getSchemaNonTypes(parentSchema)}.${hasProperty ? ` Should be:\n${this.getSchemaPartText(parentSchema, ["properties", missingProperty])}` : this.getSchemaPartDescription(parentSchema)}`;
1081         }
1082
1083       case "additionalProperties":
1084         {
1085           const {
1086             params,
1087             parentSchema
1088           } = error;
1089           const {
1090             additionalProperty
1091           } =
1092           /** @type {import("ajv").AdditionalPropertiesParams} */
1093           params;
1094           return `${dataPath} has an unknown property '${additionalProperty}'${getSchemaNonTypes(parentSchema)}. These properties are valid:\n${this.getSchemaPartText(parentSchema)}`;
1095         }
1096
1097       case "dependencies":
1098         {
1099           const {
1100             params,
1101             parentSchema
1102           } = error;
1103           const {
1104             property,
1105             deps
1106           } =
1107           /** @type {import("ajv").DependenciesParams} */
1108           params;
1109           const dependencies = deps.split(",").map(
1110           /**
1111            * @param {string} dep
1112            * @returns {string}
1113            */
1114           dep => `'${dep.trim()}'`).join(", ");
1115           return `${dataPath} should have properties ${dependencies} when property '${property}' is present${getSchemaNonTypes(parentSchema)}.${this.getSchemaPartDescription(parentSchema)}`;
1116         }
1117
1118       case "propertyNames":
1119         {
1120           const {
1121             params,
1122             parentSchema,
1123             schema
1124           } = error;
1125           const {
1126             propertyName
1127           } =
1128           /** @type {import("ajv").PropertyNamesParams} */
1129           params;
1130           return `${dataPath} property name '${propertyName}' is invalid${getSchemaNonTypes(parentSchema)}. Property names should be match format ${JSON.stringify(schema.format)}.${this.getSchemaPartDescription(parentSchema)}`;
1131         }
1132
1133       case "enum":
1134         {
1135           const {
1136             parentSchema
1137           } = error;
1138
1139           if (parentSchema &&
1140           /** @type {Schema} */
1141           parentSchema.enum &&
1142           /** @type {Schema} */
1143           parentSchema.enum.length === 1) {
1144             return `${dataPath} should be ${this.getSchemaPartText(parentSchema, false, true)}`;
1145           }
1146
1147           return `${dataPath} should be one of these:\n${this.getSchemaPartText(parentSchema)}`;
1148         }
1149
1150       case "const":
1151         {
1152           const {
1153             parentSchema
1154           } = error;
1155           return `${dataPath} should be equal to constant ${this.getSchemaPartText(parentSchema, false, true)}`;
1156         }
1157
1158       case "not":
1159         {
1160           const postfix = likeObject(
1161           /** @type {Schema} */
1162           error.parentSchema) ? `\n${this.getSchemaPartText(error.parentSchema)}` : "";
1163           const schemaOutput = this.getSchemaPartText(error.schema, false, false, false);
1164
1165           if (canApplyNot(error.schema)) {
1166             return `${dataPath} should be any ${schemaOutput}${postfix}.`;
1167           }
1168
1169           const {
1170             schema,
1171             parentSchema
1172           } = error;
1173           return `${dataPath} should not be ${this.getSchemaPartText(schema, false, true)}${parentSchema && likeObject(parentSchema) ? `\n${this.getSchemaPartText(parentSchema)}` : ""}`;
1174         }
1175
1176       case "oneOf":
1177       case "anyOf":
1178         {
1179           const {
1180             parentSchema,
1181             children
1182           } = error;
1183
1184           if (children && children.length > 0) {
1185             if (error.schema.length === 1) {
1186               const lastChild = children[children.length - 1];
1187               const remainingChildren = children.slice(0, children.length - 1);
1188               return this.formatValidationError(Object.assign({}, lastChild, {
1189                 children: remainingChildren,
1190                 parentSchema: Object.assign({}, parentSchema, lastChild.parentSchema)
1191               }));
1192             }
1193
1194             let filteredChildren = filterChildren(children);
1195
1196             if (filteredChildren.length === 1) {
1197               return this.formatValidationError(filteredChildren[0]);
1198             }
1199
1200             filteredChildren = groupChildrenByFirstChild(filteredChildren);
1201             return `${dataPath} should be one of these:\n${this.getSchemaPartText(parentSchema)}\nDetails:\n${filteredChildren.map(
1202             /**
1203              * @param {SchemaUtilErrorObject} nestedError
1204              * @returns {string}
1205              */
1206             nestedError => ` * ${indent(this.formatValidationError(nestedError), "   ")}`).join("\n")}`;
1207           }
1208
1209           return `${dataPath} should be one of these:\n${this.getSchemaPartText(parentSchema)}`;
1210         }
1211
1212       case "if":
1213         {
1214           const {
1215             params,
1216             parentSchema
1217           } = error;
1218           const {
1219             failingKeyword
1220           } =
1221           /** @type {import("ajv").IfParams} */
1222           params;
1223           return `${dataPath} should match "${failingKeyword}" schema:\n${this.getSchemaPartText(parentSchema, [failingKeyword])}`;
1224         }
1225
1226       case "absolutePath":
1227         {
1228           const {
1229             message,
1230             parentSchema
1231           } = error;
1232           return `${dataPath}: ${message}${this.getSchemaPartDescription(parentSchema)}`;
1233         }
1234
1235       /* istanbul ignore next */
1236
1237       default:
1238         {
1239           const {
1240             message,
1241             parentSchema
1242           } = error;
1243           const ErrorInJSON = JSON.stringify(error, null, 2); // For `custom`, `false schema`, `$ref` keywords
1244           // Fallback for unknown keywords
1245
1246           return `${dataPath} ${message} (${ErrorInJSON}).\n${this.getSchemaPartText(parentSchema, false)}`;
1247         }
1248     }
1249   }
1250   /**
1251    * @param {Array<SchemaUtilErrorObject>} errors
1252    * @returns {string}
1253    */
1254
1255
1256   formatValidationErrors(errors) {
1257     return errors.map(error => {
1258       let formattedError = this.formatValidationError(error);
1259
1260       if (this.postFormatter) {
1261         formattedError = this.postFormatter(formattedError, error);
1262       }
1263
1264       return ` - ${indent(formattedError, "   ")}`;
1265     }).join("\n");
1266   }
1267
1268 }
1269
1270 var _default = ValidationError;
1271 exports.default = _default;