Skip to content
Open
Changes from 7 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
76 changes: 64 additions & 12 deletions lib/process-schema.js
Original file line number Diff line number Diff line change
@@ -1,36 +1,88 @@
const NESTED_WITH_NAME = ["definitions", "properties"];
/**
* @typedef {Object} JSONSchema
* @property {string} [$id]
* @property {string} [$schema]
* @property {string} [$ref]
* @property {string} [title]
* @property {string} [description]
* @property {string | string[]} [type]
* @property {boolean} [nullable]
* @property {JSONSchema | boolean} [items]
* @property {Record<string, JSONSchema | boolean>} [properties]
* @property {JSONSchema | boolean} [additionalProperties]
* @property {JSONSchema[]} [oneOf]
* @property {JSONSchema[]} [anyOf]
* @property {JSONSchema[]} [allOf]
* @property {Record<string, JSONSchema | boolean>} [definitions]
* @property {unknown} [enum]
* @property {unknown} [const]
* @property {unknown} [default]
* @property {Record<string, unknown>} [examples]
* @property {Record<string, unknown>} [other] - Any additional schema fields.
Comment thread
Manas-Dikshit marked this conversation as resolved.
Outdated
*/

const NESTED_DIRECT = ["items", "additionalProperties", "not"];
/**
* @typedef {Object} ProcessContext
* @property {JSONSchema} [rootSchema] - The root schema being processed.
* @property {string[]} [path] - Path segments from the root to the current node.
* @property {Record<string, unknown>} [meta] - Arbitrary metadata shared across recursion.
*/

/**
* @typedef {Object} SchemaVisitor
* @property {(schema: JSONSchema | boolean, context?: ProcessContext) => JSONSchema | boolean | void} [schema]
* @property {(obj: JSONSchema | boolean, context?: ProcessContext) => JSONSchema | boolean | void} [object]
* @property {(arr: (JSONSchema | boolean)[], context?: ProcessContext) => void} [array]
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just interesting why we have boolean here?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch. JSON Schema allows boolean schemas, but instead of manually adding boolean I can switch to JSONSchema7Definition from json-schema types which already includes it.
can i ?
@alexander-akait

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We support more than JSONSchema7, it should be support old formats too

Copy link
Copy Markdown
Author

@Manas-Dikshit Manas-Dikshit Mar 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what kind of changes the below code needs
Screenshot 2026-03-13 013743

*/
Comment thread
Manas-Dikshit marked this conversation as resolved.

// Constants defining nested schema traversal structure
const NESTED_WITH_NAME = ["definitions", "properties"];
const NESTED_DIRECT = ["items", "additionalProperties", "not"];
const NESTED_ARRAY = ["oneOf", "anyOf", "allOf"];

/**
* Recursively processes a JSON Schema using the visitor pattern.
*
* @param {SchemaVisitor} visitor - Visitor functions to apply.
* @param {JSONSchema | boolean} json - JSON Schema to process.
* @param {ProcessContext} [context] - Optional shared context passed through recursion.
* @returns {JSONSchema | boolean} - The processed JSON Schema.
*/
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;