Skip to content

Commit 0988be2

Browse files
feat: better errors when the type keyword doesn't exist
1 parent facb431 commit 0988be2

File tree

4 files changed

+1018
-81
lines changed

4 files changed

+1018
-81
lines changed

src/ValidationError.js

Lines changed: 93 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,28 @@ function getArticle(type) {
223223
return 'a';
224224
}
225225

226+
function getSchemaNonTypes(schema) {
227+
if (!schema.type) {
228+
if (likeNumber(schema) || likeInteger(schema)) {
229+
return ' | should be any non-number';
230+
}
231+
232+
if (likeString(schema)) {
233+
return ' | should be any non-string';
234+
}
235+
236+
if (likeArray(schema)) {
237+
return ' | should be any non-array';
238+
}
239+
240+
if (likeObject(schema)) {
241+
return ' | should be any non-object';
242+
}
243+
}
244+
245+
return '';
246+
}
247+
226248
class ValidationError extends Error {
227249
constructor(errors, schema, configuration = {}) {
228250
super();
@@ -280,12 +302,18 @@ class ValidationError extends Error {
280302
return `non ${formatInnerSchema(schema.not)}`;
281303
}
282304

283-
// eslint-disable-next-line default-case
284-
switch (schema.instanceof) {
285-
case 'Function':
286-
return 'function';
287-
case 'RegExp':
288-
return 'RegExp';
305+
if (schema.instanceof) {
306+
if (Array.isArray(schema.instanceof)) {
307+
return schema.instanceof.map(formatInnerSchema).join(' | ');
308+
}
309+
310+
// eslint-disable-next-line default-case
311+
switch (schema.instanceof) {
312+
case 'Function':
313+
return 'function';
314+
case 'RegExp':
315+
return 'RegExp';
316+
}
289317
}
290318

291319
if (schema.enum) {
@@ -687,101 +715,129 @@ class ValidationError extends Error {
687715
case 'pattern':
688716
return `${dataPath} should match pattern ${JSON.stringify(
689717
error.params.pattern
718+
)}${getSchemaNonTypes(
719+
error.parentSchema
690720
)}.${this.getSchemaPartDescription(error.parentSchema)}`;
691721
case 'format':
692722
return `${dataPath} should match format ${JSON.stringify(
693723
error.params.format
724+
)}${getSchemaNonTypes(
725+
error.parentSchema
694726
)}.${this.getSchemaPartDescription(error.parentSchema)}`;
695727
case 'formatMinimum':
696728
case 'formatMaximum':
697729
return `${dataPath} should be ${
698730
error.params.comparison
699-
} ${JSON.stringify(error.params.limit)}.${this.getSchemaPartDescription(
731+
} ${JSON.stringify(error.params.limit)}${getSchemaNonTypes(
700732
error.parentSchema
701-
)}`;
733+
)}.${this.getSchemaPartDescription(error.parentSchema)}`;
702734
case 'minimum':
703735
case 'maximum':
704736
case 'exclusiveMinimum':
705737
case 'exclusiveMaximum':
706738
return `${dataPath} should be ${error.params.comparison} ${
707739
error.params.limit
708-
}.${this.getSchemaPartDescription(error.parentSchema)}`;
740+
}${getSchemaNonTypes(
741+
error.parentSchema
742+
)}.${this.getSchemaPartDescription(error.parentSchema)}`;
709743
case 'multipleOf':
710744
return `${dataPath} should be multiple of ${
711745
error.params.multipleOf
712-
}.${this.getSchemaPartDescription(error.parentSchema)}`;
746+
}${getSchemaNonTypes(
747+
error.parentSchema
748+
)}.${this.getSchemaPartDescription(error.parentSchema)}`;
713749
case 'patternRequired':
714750
return `${dataPath} should have property matching pattern ${JSON.stringify(
715751
error.params.missingPattern
752+
)}${getSchemaNonTypes(
753+
error.parentSchema
716754
)}.${this.getSchemaPartDescription(error.parentSchema)}`;
717755
case 'minLength': {
718756
if (error.params.limit === 1) {
719-
return `${dataPath} should be an non-empty string.${this.getSchemaPartDescription(
757+
return `${dataPath} should be an non-empty string${getSchemaNonTypes(
720758
error.parentSchema
721-
)}`;
759+
)}.${this.getSchemaPartDescription(error.parentSchema)}`;
722760
}
723761

724762
return `${dataPath} should not be shorter than ${
725763
error.params.limit
726-
} characters.${this.getSchemaPartDescription(error.parentSchema)}`;
764+
} characters${getSchemaNonTypes(
765+
error.parentSchema
766+
)}.${this.getSchemaPartDescription(error.parentSchema)}`;
727767
}
728768
case 'minItems': {
729769
if (error.params.limit === 1) {
730-
return `${dataPath} should be an non-empty array.${this.getSchemaPartDescription(
770+
return `${dataPath} should be an non-empty array${getSchemaNonTypes(
731771
error.parentSchema
732-
)}`;
772+
)}.${this.getSchemaPartDescription(error.parentSchema)}`;
733773
}
734774

735775
return `${dataPath} should not have fewer than ${
736776
error.params.limit
737-
} items.${this.getSchemaPartDescription(error.parentSchema)}`;
777+
} items${getSchemaNonTypes(
778+
error.parentSchema
779+
)}.${this.getSchemaPartDescription(error.parentSchema)}`;
738780
}
739781
case 'minProperties': {
740782
if (error.params.limit === 1) {
741-
return `${dataPath} should be an non-empty object.${this.getSchemaPartDescription(
783+
return `${dataPath} should be an non-empty object${getSchemaNonTypes(
742784
error.parentSchema
743-
)}`;
785+
)}.${this.getSchemaPartDescription(error.parentSchema)}`;
744786
}
745787

746788
return `${dataPath} should not have fewer than ${
747789
error.params.limit
748-
} properties.${this.getSchemaPartDescription(error.parentSchema)}`;
790+
} properties${getSchemaNonTypes(
791+
error.parentSchema
792+
)}.${this.getSchemaPartDescription(error.parentSchema)}`;
749793
}
750794
case 'maxLength':
751795
return `${dataPath} should not be longer than ${
752796
error.params.limit
753-
} characters.${this.getSchemaPartDescription(error.parentSchema)}`;
797+
} characters${getSchemaNonTypes(
798+
error.parentSchema
799+
)}.${this.getSchemaPartDescription(error.parentSchema)}`;
754800
case 'maxItems':
755801
return `${dataPath} should not have more than ${
756802
error.params.limit
757-
} items.${this.getSchemaPartDescription(error.parentSchema)}`;
803+
} items${getSchemaNonTypes(
804+
error.parentSchema
805+
)}.${this.getSchemaPartDescription(error.parentSchema)}`;
758806
case 'maxProperties':
759807
return `${dataPath} should not have more than ${
760808
error.params.limit
761-
} properties.${this.getSchemaPartDescription(error.parentSchema)}`;
809+
} properties${getSchemaNonTypes(
810+
error.parentSchema
811+
)}.${this.getSchemaPartDescription(error.parentSchema)}`;
762812
case 'uniqueItems':
763813
return `${dataPath} should not contain the item '${
764814
error.data[error.params.i]
765-
}' twice.${this.getSchemaPartDescription(error.parentSchema)}`;
815+
}' twice${getSchemaNonTypes(
816+
error.parentSchema
817+
)}.${this.getSchemaPartDescription(error.parentSchema)}`;
766818
case 'additionalItems':
767819
return `${dataPath} should not have more than ${
768820
error.params.limit
769-
} items. These items are valid:\n${this.getSchemaPartText(
821+
} items${getSchemaNonTypes(
822+
error.parentSchema
823+
)}. These items are valid:\n${this.getSchemaPartText(
770824
error.parentSchema
771825
)}`;
772826
case 'contains':
773827
return `${dataPath} should contains at least one ${this.getSchemaPartText(
774828
error.parentSchema,
775829
['contains']
776-
)} item.`;
830+
)} item${getSchemaNonTypes(error.parentSchema)}.`;
777831
case 'required': {
778832
const missingProperty = error.params.missingProperty.replace(/^\./, '');
779833
const hasProperty = Boolean(
780834
error.parentSchema.properties &&
781835
error.parentSchema.properties[missingProperty]
782836
);
783837

784-
return `${dataPath} misses the property '${missingProperty}'.${
838+
return `${dataPath} misses the property '${missingProperty}'${getSchemaNonTypes(
839+
error.parentSchema
840+
)}.${
785841
hasProperty
786842
? ` Should be:\n${this.getSchemaPartText(error.parentSchema, [
787843
'properties',
@@ -793,7 +849,9 @@ class ValidationError extends Error {
793849
case 'additionalProperties':
794850
return `${dataPath} has an unknown property '${
795851
error.params.additionalProperty
796-
}'. These properties are valid:\n${this.getSchemaPartText(
852+
}'${getSchemaNonTypes(
853+
error.parentSchema
854+
)}. These properties are valid:\n${this.getSchemaPartText(
797855
error.parentSchema
798856
)}`;
799857
case 'dependencies': {
@@ -804,12 +862,16 @@ class ValidationError extends Error {
804862

805863
return `${dataPath} should have properties ${dependencies} when property '${
806864
error.params.property
807-
}' is present.${this.getSchemaPartDescription(error.parentSchema)}`;
865+
}' is present${getSchemaNonTypes(
866+
error.parentSchema
867+
)}.${this.getSchemaPartDescription(error.parentSchema)}`;
808868
}
809869
case 'propertyNames': {
810-
const invalidProperty = error.params.propertyName;
811-
812-
return `${dataPath} property name '${invalidProperty}' is invalid. Property names should be match format ${JSON.stringify(
870+
return `${dataPath} property name '${
871+
error.params.propertyName
872+
}' is invalid${getSchemaNonTypes(
873+
error.parentSchema
874+
)}. Property names should be match format ${JSON.stringify(
813875
error.schema.format
814876
)}.${this.getSchemaPartDescription(error.parentSchema)}`;
815877
}

0 commit comments

Comments
 (0)