Skip to content

Commit b000fbf

Browse files
committed
Fix error for nested object properties with multiiple types
1 parent 38641e2 commit b000fbf

File tree

4 files changed

+59
-12
lines changed

4 files changed

+59
-12
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "json-schema-yup-transformer",
33
"author": "Ritchie Anesco <[email protected]>",
4-
"version": "1.6.3",
4+
"version": "1.6.4",
55
"description": "Transforms a draft 7 specification JSON Schema to a Yup Schema",
66
"license": "MIT",
77
"main": "dist/index.js",

src/yup/builder/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ export const buildProperties = (
7474
}
7575
return { ...all, ...buildCondition(schema) };
7676
}, [])
77-
: [];
77+
: [];
7878
const newSchema = createValidationSchema([key, value], jsonSchema);
7979
schema = {
8080
...schema,

src/yup/schemas/object/object.schema.ts

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -25,16 +25,24 @@ const createObjectSchema = (
2525
const defaultMessage = getErrorMessage(description, DataTypes.OBJECT)
2626
|| capitalize(`${label} is not of type object`);
2727

28-
let shape = value.properties
29-
&& buildProperties(value.properties, jsonSchema);
30-
31-
(value.required ?? []).forEach(requiredField => {
32-
if (shape !== undefined) {
33-
shape[requiredField] = createRequiredSchema(shape[requiredField], value, [requiredField, value])
34-
}
35-
});
36-
37-
let Schema = Yup.object(shape).typeError(defaultMessage);
28+
// Seperate compositional schemas from standard schemas.
29+
// Standard schemas return Object schemas, compositional schemas return mixed or lazy schemas.
30+
// Lazy schemas can not be concatenated which will throw an error when traversing a nested object.
31+
const schm = JSON.stringify(jsonSchema.properties)
32+
const isComposition = schm.indexOf("anyOf") > -1 || schm.indexOf("oneOf") > -1
33+
34+
let Schema: Yup.ObjectSchema
35+
if (isComposition) {
36+
let shape = value.properties && buildProperties(value.properties, jsonSchema);
37+
(value.required ?? []).forEach(requiredField => {
38+
if (shape !== undefined) {
39+
shape[requiredField] = createRequiredSchema(shape[requiredField], value, [requiredField, value])
40+
}
41+
});
42+
Schema = Yup.object(shape).typeError(defaultMessage);
43+
} else {
44+
Schema = Yup.object().typeError(defaultMessage);
45+
}
3846

3947
/** Set required if ID is in required schema */
4048
Schema = createRequiredSchema(Schema, jsonSchema, [key, value]);

test/yup/string.test.ts

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -408,4 +408,43 @@ describe("convertToYup() string", () => {
408408
}
409409
expect(errorMessage).toBe(`${fieldTitle} is required`);
410410
});
411+
412+
413+
it("should validate multiple types in a nested object", () => {
414+
const schema: JSONSchema7Extended = {
415+
type: "object",
416+
$schema: "http://json-schema.org/draft-07/schema#",
417+
$id: "test",
418+
title: "Test",
419+
properties: {
420+
address: {
421+
type: "object",
422+
properties: {
423+
name: {
424+
type: ["string", "null"]
425+
}
426+
}
427+
}
428+
}
429+
};
430+
const yupschema = convertToYup(schema) as Yup.ObjectSchema;
431+
432+
expect(() => {
433+
yupschema.isValidSync({
434+
address: {
435+
name: ""
436+
}
437+
});
438+
}).toBeTruthy();
439+
440+
expect(() => {
441+
yupschema.isValidSync({
442+
address: {
443+
name: null
444+
}
445+
});
446+
}).toBeTruthy();
447+
448+
});
449+
411450
});

0 commit comments

Comments
 (0)