From 4cc7db906994e475c0bea4ab63553ea2ee029968 Mon Sep 17 00:00:00 2001 From: Aditya kumar singh <143548997+Adityakk9031@users.noreply.github.com> Date: Mon, 2 Mar 2026 23:10:54 +0530 Subject: [PATCH] Bugfix and refactoring of the JSON Schema scope detection logic in the JsonEditor component. --- lib/getScopesOfParsedJsonSchema.ts | 124 ++++++++++++++++++++--------- 1 file changed, 86 insertions(+), 38 deletions(-) diff --git a/lib/getScopesOfParsedJsonSchema.ts b/lib/getScopesOfParsedJsonSchema.ts index 185272df8..e4e6993b2 100644 --- a/lib/getScopesOfParsedJsonSchema.ts +++ b/lib/getScopesOfParsedJsonSchema.ts @@ -13,47 +13,95 @@ export default function getScopesOfParsedJsonSchema( ): JsonSchemaPathWithScope[] { if (typeof parsedJsonSchema !== 'object' || parsedJsonSchema === null) return []; - const typeDefinitionScope = { - jsonPath, - scope: JsonSchemaScope.TypeDefinition, - }; - if (parsedJsonSchema.type === 'object') { - const scopesOfProperties = Object.keys( - parsedJsonSchema?.properties || {}, - ).reduce((acc, property) => { - return [ - ...acc, - ...getScopesOfParsedJsonSchema( - parsedJsonSchema.properties?.[property], - `${jsonPath}['properties']['${property}']`, - ), + + let scopes: JsonSchemaPathWithScope[] = [ + { + jsonPath, + scope: JsonSchemaScope.TypeDefinition, + }, + ]; + + // 1. Objects where each value is a subschema + const mapKeywords = [ + 'properties', + 'patternProperties', + 'definitions', + '$defs', + 'dependentSchemas', + ]; + mapKeywords.forEach((keyword) => { + const map = parsedJsonSchema[keyword]; + if (map && typeof map === 'object' && !Array.isArray(map)) { + Object.keys(map).forEach((key) => { + scopes = [ + ...scopes, + ...getScopesOfParsedJsonSchema( + map[key], + `${jsonPath}['${keyword}']['${key}']`, + ), + ]; + }); + } + }); + + // 2. Arrays where each item is a subschema + const arrayKeywords = ['allOf', 'anyOf', 'oneOf', 'prefixItems']; + arrayKeywords.forEach((keyword) => { + const list = parsedJsonSchema[keyword]; + if (Array.isArray(list)) { + list.forEach((subschema: any, index: number) => { + scopes = [ + ...scopes, + ...getScopesOfParsedJsonSchema( + subschema, + `${jsonPath}['${keyword}'][${index}]`, + ), + ]; + }); + } + }); + + // 3. Single subschemas + const singleKeywords = [ + 'items', + 'not', + 'if', + 'then', + 'else', + 'additionalProperties', + 'propertyNames', + 'unevaluatedProperties', + 'additionalItems', + 'unevaluatedItems', + ]; + singleKeywords.forEach((keyword) => { + const subschema = parsedJsonSchema[keyword]; + // In JSON Schema, a subschema can be an object or a boolean (true/false) + if (typeof subschema === 'object' && subschema !== null) { + scopes = [ + ...scopes, + ...getScopesOfParsedJsonSchema(subschema, `${jsonPath}['${keyword}']`), ]; - }, []); - const scopesOfPatternProperties = Object.keys( - parsedJsonSchema?.patternProperties || {}, - ).reduce((acc, property) => { - return [ - ...acc, + } else if (typeof subschema === 'boolean') { + scopes.push({ + jsonPath: `${jsonPath}['${keyword}']`, + scope: JsonSchemaScope.TypeDefinition, + }); + } + }); + + // Special case: "items" as an array (pre-Draft 2020-12 style) + if (Array.isArray(parsedJsonSchema.items)) { + parsedJsonSchema.items.forEach((subschema: any, index: number) => { + scopes = [ + ...scopes, ...getScopesOfParsedJsonSchema( - parsedJsonSchema.patternProperties?.[property], - `${jsonPath}['patternProperties']['${property}']`, + subschema, + `${jsonPath}['items'][${index}]`, ), ]; - }, []); - return [ - typeDefinitionScope, - ...scopesOfProperties, - ...scopesOfPatternProperties, - ]; + }); } - if (parsedJsonSchema.type === 'array') { - return [ - typeDefinitionScope, - ...getScopesOfParsedJsonSchema( - parsedJsonSchema.items, - `${jsonPath}['items']`, - ), - ]; - } - return [typeDefinitionScope]; + + return scopes; }