Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
BelfordZ committed Mar 11, 2024
1 parent dfa6b2a commit da29de5
Show file tree
Hide file tree
Showing 3 changed files with 147 additions and 26 deletions.
36 changes: 20 additions & 16 deletions src/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,22 +6,26 @@ describe("traverse", () => {
mockMutation: any,
schema: JSONSchema,
isCycle = expect.any(Boolean),
nth?: number
nth?: number,
parent = expect.anything(),
) => {
if (parent === false) {
parent = undefined;
}
if (nth) {
expect(mockMutation).toHaveBeenNthCalledWith(
nth,
schema,
isCycle,
expect.any(String),
expect.anything(),
parent
);
} else {
expect(mockMutation).toHaveBeenCalledWith(
schema,
isCycle,
expect.any(String),
expect.anything(),
parent
);
}
};
Expand Down Expand Up @@ -126,7 +130,7 @@ describe("traverse", () => {

traverse(testSchema, mockMutation);

testCalls(mockMutation, testSchema)
testCalls(mockMutation, testSchema, false, undefined, false)
expect(mockMutation).toHaveBeenCalledTimes(1);
});

Expand Down Expand Up @@ -288,7 +292,7 @@ describe("traverse", () => {
traverse(testSchema, mockMutation);

testCalls(mockMutation, testSchema.additionalItems);
testCalls(mockMutation, testSchema);
testCalls(mockMutation, testSchema, false, undefined, false);

expect(mockMutation).toHaveBeenCalledTimes(2);
});
Expand All @@ -302,7 +306,7 @@ describe("traverse", () => {
traverse(testSchema, mockMutation);

testCalls(mockMutation, testSchema.additionalItems);
testCalls(mockMutation, testSchema);
testCalls(mockMutation, testSchema, false, undefined, false);

expect(mockMutation).toHaveBeenCalledTimes(2);
});
Expand All @@ -318,7 +322,7 @@ describe("traverse", () => {

testCalls(mockMutation, testSchema.additionalItems);
testCalls(mockMutation, testSchema.items[0]);
testCalls(mockMutation, testSchema);
testCalls(mockMutation, testSchema, false, undefined, false);

expect(mockMutation).toHaveBeenCalledTimes(3);
});
Expand All @@ -334,7 +338,7 @@ describe("traverse", () => {

testCalls(mockMutation, testSchema.additionalItems);
testCalls(mockMutation, testSchema.items);
testCalls(mockMutation, testSchema);
testCalls(mockMutation, testSchema, false, undefined, false);

expect(mockMutation).toHaveBeenCalledTimes(3);
});
Expand All @@ -357,7 +361,7 @@ describe("traverse", () => {
testCalls(mockMutation, testSchema.items[0]);
testCalls(mockMutation, testSchema.additionalItems.properties.c);
testCalls(mockMutation, testSchema.additionalItems.properties.d);
testCalls(mockMutation, testSchema);
testCalls(mockMutation, testSchema, false, undefined, false);

expect(mockMutation).toHaveBeenCalledTimes(5);
});
Expand All @@ -380,7 +384,7 @@ describe("traverse", () => {
testCalls(mockMutation, testSchema.items);
testCalls(mockMutation, testSchema.additionalItems.properties.c);
testCalls(mockMutation, testSchema.additionalItems.properties.d);
testCalls(mockMutation, testSchema);
testCalls(mockMutation, testSchema, false, undefined, false);

expect(mockMutation).toHaveBeenCalledTimes(5);
});
Expand Down Expand Up @@ -439,7 +443,7 @@ describe("traverse", () => {
{
title: "3",
type: "array",
items: { title: "4" },
items: { title: "replaced with root" },
},
],
},
Expand Down Expand Up @@ -479,7 +483,7 @@ describe("traverse", () => {
expect(mockMutation).toHaveBeenCalledTimes(4);
});

it("handles chained cycles where the cycle starts in the middle of a different branch of the tree", () => {
it.only("handles chained cycles where the cycle starts in the middle of a different branch of the tree", () => {
const schema = {
title: "1",
type: "object",
Expand All @@ -493,17 +497,17 @@ describe("traverse", () => {
items: {
title: "4",
properties: {
baz: { title: "5" },
baz: { title: "replaced with root" },
},
},
},
],
},
bar: {
title: "6",
title: "5",
type: "object",
allOf: [
{ title: "7", type: "object", properties: { baz: { title: "8" } } },
{ title: "6", type: "object", properties: { baz: { title: "replaced with #3" } } },
],
},
},
Expand Down Expand Up @@ -539,7 +543,7 @@ describe("traverse", () => {
title: "6",
type: "object",
allOf: [
{ title: "7", type: "object", properties: { baz: { title: "5" } } },
{ title: "7", type: "object", properties: { baz: { title: "replaced with #5" } } },
],
},
},
Expand Down
26 changes: 22 additions & 4 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,13 @@ import { JSONSchema, JSONSchemaObject, PatternProperties } from "@json-schema-to
* @param schema The schema or subschema node being traversed
* @param isCycle false if the schema passed is not the root of a detected cycle. Useful for special handling of cycled schemas.
* @param path json-path string in dot-notation as per [draft-goessner-dispatch-jsonpath-00](https://www.ietf.org/archive/id/draft-goessner-dispatch-jsonpath-00.html#name-overview-of-jsonpath-expres)
* @param parent if the schema is the root, this will be the same as `schema`. Otherwise, it will be a reference to JSONSchema that is the parent.
* @param parent if the schema is a cycle, parent will be the same as `schema`. Otherwise, it will be a reference to JSONSchema that is the parent. If the schema has no parent (ie is the root), it will be undefined.
*/
export type MutationFunction = (
schema: JSONSchema,
isCycle: boolean,
path: string,
parent: JSONSchema,
parent: JSONSchema | undefined,
) => JSONSchema;

/**
Expand Down Expand Up @@ -107,11 +107,12 @@ export default function traverse(
if (opts.skipFirstMutation === true && depth === 0) {
return schema;
} else {
console.log('mutableSchema:', schema, 'last: ', recursiveStack[recursiveStack.length - 1]);
return mutation(
schema,
false,
jsonPathStringify(pathStack),
last(recursiveStack) || schema
recursiveStack[recursiveStack.length - 1]
);
}
}
Expand Down Expand Up @@ -269,11 +270,28 @@ export default function traverse(
return mutableSchema;
} else {
const isCycle = cycleSet.indexOf(schema) !== -1
let parent: JSONSchema | undefined = recursiveStack[recursiveStack.length - 2];
console.log(
'mutableSchema:', mutableSchema,
'recursive stack: ', recursiveStack,
'parent: ', parent,
'isCycle: ', isCycle,
'depth:, ', depth
);
if (depth === 0) {
// console.log('depth 0 is root: root doesnt have a parent');
parent = undefined;
}
if (isCycle) {
// console.log('isCycle:', isCycle, 'mutableSchema: ', mutableSchema);
parent = recursiveStack[recursiveStack.length - 1];
}
// recursiveStack.pop();
return mutation(
mutableSchema,
isCycle,
jsonPathStringify(pathStack),
last(recursiveStack, true) || schema
parent
);
}
}
111 changes: 105 additions & 6 deletions src/parent.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import traverse from "./";
import { JSONSchema } from "@json-schema-tools/meta-schema";

describe("traverse parent", () => {
const test = (s: JSONSchema, parents: JSONSchema[]) => {
const test = (s: JSONSchema, parents: (JSONSchema | undefined)[], isCycle = false) => {
const mutator = jest.fn((s) => s);

traverse(s, mutator);
Expand All @@ -15,13 +15,22 @@ describe("traverse parent", () => {
expect.any(String),
parent,
);

if (!isCycle) {
expect(mutator).not.toHaveBeenCalledWith(
s,
expect.any(Boolean),
expect.any(String),
s
);
}
});
};

describe("schema is a boolean", () => {
it("allows root schema as boolean", () => {
it("allows root schema as boolean, but its parent is undefined", () => {
const testSchema: JSONSchema = true;
test(testSchema, [testSchema]);
test(testSchema, [undefined]);
});
});

Expand Down Expand Up @@ -92,6 +101,29 @@ describe("traverse parent", () => {

test(testSchema, [testSchema, testSchema.additionalItems]);
});

it("parent for additionalItems is correct", () => {
const testSchema: any = {
type: "array",
additionalItems: {
properties: {
c: {},
d: {},
},
},
};

const mutator = jest.fn((s) => s);

traverse(testSchema, mutator);

expect(mutator).toHaveBeenCalledWith(
expect.anything(),
false,
expect.any(String),
testSchema.additionalItems
);
});
});

describe("schema.items", () => {
Expand All @@ -115,21 +147,76 @@ describe("traverse parent", () => {

test(testSchema, [testSchema]);
});

it("doesnt call mutator with parent being itself when there is no cycle", () => {
const testSchema: any = {
type: "array",
items: {
properties: {
c: {},
d: {},
},
},
};

const mutator = jest.fn((...args) => {
console.log(args);
return args[0];
});

traverse(testSchema, mutator);

expect(mutator).toHaveBeenCalledWith(
testSchema.items.properties.c,
false,
expect.any(String),
testSchema.items
);

// additionalItems is not the root should not be the its own parent
expect(mutator).not.toHaveBeenCalledWith(
testSchema.items,
false,
expect.any(String),
testSchema.items
);
});
});

describe("schema.oneOf", () => {
it("works with deeply nested oneOfs", () => {
it.only("works with deeply nested oneOfs", () => {
const testSchema: any = {
title: '1',
oneOf: [
{
oneOf: [{ type: "number" }, { type: "string" }]
title: '2',
oneOf: [
{
title: '3',
type: "number"
},
{
title: '4',
type: "string"
}
]
},
{
title: '5',
type: "object",
properties: {
foo: {
title: '6',
oneOf: [
{ type: "array", items: true }, { type: "boolean" }
{
title: '7',
type: "array",
items: true
},
{
title: '8',
type: "boolean"
}
]
}
}
Expand All @@ -144,5 +231,17 @@ describe("traverse parent", () => {
testSchema.oneOf[1].properties.foo,
]);
});

it("works with cycle to the root", () => {
const testSchema: any = {
oneOf: [
{},
]
};

testSchema.oneOf[0] = testSchema;

test(testSchema, [testSchema], true);
});
});
});

0 comments on commit da29de5

Please sign in to comment.