Skip to content
Open
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 42 additions & 10 deletions lib/process-schema.js
Original file line number Diff line number Diff line change
@@ -1,36 +1,68 @@
/**
* Keys that contain nested objects with named children (e.g., definitions, properties).
* @type {string[]}
*/
const NESTED_WITH_NAME = ["definitions", "properties"];

/**
* Keys that contain directly nested schema objects (e.g., items, additionalProperties, not).
* @type {string[]}
*/
const NESTED_DIRECT = ["items", "additionalProperties", "not"];

/**
* Keys that contain arrays of schema objects (e.g., oneOf, anyOf, allOf).
* @type {string[]}
*/
Comment thread
Manas-Dikshit marked this conversation as resolved.
const NESTED_ARRAY = ["oneOf", "anyOf", "allOf"];

/**
* Recursively processes a JSON Schema using the visitor pattern.
*
* @param {{
* schema?: (schema: Record<string, any>, context?: Record<string, any>) => Record<string, any> | void,
* object?: (obj: Record<string, any>, context?: Record<string, any>) => Record<string, any> | void,
* array?: (collection: any[], context?: Record<string, any>) => void
* }} visitor - Visitor object with optional handlers for schema, object, and array nodes.
* @param {Record<string, any>} json - The JSON Schema node to process.
* @param {Record<string, any>} [context] - Optional shared context passed through recursive calls.
* @returns {Record<string, any>} - The processed schema node.
Comment thread
Manas-Dikshit marked this conversation as resolved.
Outdated
*/
const processSchema = (visitor, json, context) => {
Comment thread
Manas-Dikshit marked this conversation as resolved.
if (!json || typeof json !== "object") return json; // safety check

json = { ...json };
if (visitor.schema) json = visitor.schema(json, context);
if (typeof visitor?.schema === "function") {
json = visitor.schema(json, context) || json;
}

for (const name of NESTED_WITH_NAME) {
if (name in json && json[name] && typeof json[name] === "object") {
if (visitor.object) json[name] = visitor.object(json[name], context);
for (const key in json[name]) {
if (json[name] && typeof json[name] === "object" && !Array.isArray(json[name])) {
Comment thread
Manas-Dikshit marked this conversation as resolved.
Outdated
if (typeof visitor?.object === "function") {
json[name] = visitor.object(json[name], context) || json[name];
}
for (const key of Object.keys(json[name])) {
json[name][key] = processSchema(visitor, json[name][key], context);
}
}
}

for (const name of NESTED_DIRECT) {
if (name in json && json[name] && typeof json[name] === "object") {
if (json[name] && typeof json[name] === "object" && !Array.isArray(json[name])) {
json[name] = processSchema(visitor, json[name], context);
}
}

for (const name of NESTED_ARRAY) {
if (name in json && Array.isArray(json[name])) {
json[name] = json[name].slice();
for (let i = 0; i < json[name].length; i++) {
json[name][i] = processSchema(visitor, json[name][i], context);
if (Array.isArray(json[name])) {
json[name] = json[name].map((item) => processSchema(visitor, item, context));
if (typeof visitor?.array === "function") {
visitor.array(json[name], context);
}
if (visitor.array) visitor.array(json[name], context);
}
}

return json;
};

module.exports = processSchema;