Skip to content

Commit

Permalink
fix: issue#58 merge missing parent properties in oneOf-object resolution
Browse files Browse the repository at this point in the history
  • Loading branch information
sagold committed Jun 4, 2024
1 parent 773ace8 commit e282d8b
Show file tree
Hide file tree
Showing 2 changed files with 167 additions and 3 deletions.
20 changes: 17 additions & 3 deletions lib/step.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,13 @@ import createSchemaOf from "./createSchemaOf";
import { JsonSchema, JsonError, isJsonError } from "./types";
import { SchemaNode } from "./schemaNode";
import { reduceSchema } from "./reduceSchema";
import { mergeSchema } from "./mergeSchema";

type StepFunction = (node: SchemaNode, key: string, data: any) => SchemaNode | JsonError | undefined;
type StepFunction = (
node: SchemaNode,
key: string,
data: any
) => SchemaNode | JsonError | undefined;

const stepType: Record<string, StepFunction> = {
array: (node, key, data) => {
Expand Down Expand Up @@ -101,7 +106,12 @@ const stepType: Record<string, StepFunction> = {
if (nextPropertyNode && Array.isArray(nextPropertyNode.schema.oneOf)) {
// @special case: this is a mix of a schema and optional definitions
// we resolve the schema here and add the original schema to `oneOfSchema`
return draft.resolveOneOf(node.next(nextPropertyNode.schema, key), data[key]);
const nextNode = node.next(nextPropertyNode.schema, key);
const result = draft.resolveOneOf(nextNode, data[key]);
if (isJsonError(result)) {
return result;
}
return nextNode.merge(result.schema, "oneOf");
}
if (nextPropertyNode) {
return nextPropertyNode;
Expand Down Expand Up @@ -155,7 +165,11 @@ const stepType: Record<string, StepFunction> = {
* @param [pointer] - pointer to schema and data (parent of key)
* @return Schema or Error if failed resolving key
*/
export default function step(node: SchemaNode, key: string | number, data?: any): SchemaNode | JsonError {
export default function step(
node: SchemaNode,
key: string | number,
data?: any
): SchemaNode | JsonError {
const { draft, schema, pointer } = node;
const typeOfData = getTypeOf(data);
let schemaType = schema.type ?? typeOfData;
Expand Down
150 changes: 150 additions & 0 deletions test/unit/issues/issue58.oneOfType.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
import { strict as assert } from "assert";
import { Draft07 as Draft } from "../../../lib/draft07";

describe("issue#58 - oneOf should invalid type error", () => {
let draft: Draft;
beforeEach(() => (draft = new Draft()));

it("should return one-of-error for invalid type", () => {
draft.setSchema({
oneOf: [{ type: "null" }, { type: "number" }]
});
const errors = draft.validate("string");
assert(errors.length > 0);
});

it("should validate correct type defined in one-of statement", () => {
draft.setSchema({
oneOf: [{ type: "null" }, { type: "number" }]
});
const errors = draft.validate(123);
assert(errors.length === 0);
});

it("should return type-error for non-integer value", () => {
draft.setSchema({
properties: {
foo: {
properties: {
number: {
type: "integer"
}
}
}
}
});
const errors = draft.validate({ foo: { number: "not an integer" } });
assert(errors.length > 0);
});

it("should return type-error for non-integer value in combination with oneOf", () => {
draft.setSchema({
properties: {
foo: {
properties: {
number: {
type: "integer"
}
},
oneOf: [
{
type: "null"
},
{
type: "object"
}
]
}
}
});
const errors = draft.validate({ foo: { number: "not an integer" } });
assert(errors.length > 0);
});

it("should return type-error", () => {
const schema = {
$schema: "http:https://json-schema.org/draft-04/schema#",
properties: {
foo: {
additionalProperties: false,
properties: {
number: {
type: "integer"
}
},
oneOf: [
{
type: "null"
},
{
type: "object"
}
]
}
},
additionalProperties: false,
oneOf: [
{
type: "null"
},
{
type: "object"
}
]
};
const inputData: {
foo: { number: string };
} = {
foo: {
number: "not an integer"
}
};

draft.setSchema(schema);
const errors = draft.validate(inputData);
assert.equal(errors.length, 1);
assert.equal(errors[0].code, "type-error");
});

it("should validate without type-error", () => {
const schema = {
$schema: "http:https://json-schema.org/draft-04/schema#",
properties: {
foo: {
additionalProperties: false,
properties: {
number: {
type: "integer"
}
},
oneOf: [
{
type: "null"
},
{
type: "object"
}
]
}
},
additionalProperties: false,
oneOf: [
{
type: "null"
},
{
type: "object"
}
]
};
const inputData = {
foo: {
number: 123
}
};

draft.setSchema(schema);
const errors = draft.validate(inputData);
assert.equal(errors.length, 0);
});
});

0 comments on commit e282d8b

Please sign in to comment.