From 3708238e94f95e4043a82094ff7051f909157e9e Mon Sep 17 00:00:00 2001 From: SB-virendrasolanke Date: Mon, 4 Aug 2025 15:41:36 +0530 Subject: [PATCH 1/4] fix : Schema Combiner issue for Previewer --- .../HttpOperation/LazySchemaTreePreviewer.tsx | 245 ++++++++++++++---- packages/elements-dev-portal/src/version.ts | 2 +- 2 files changed, 199 insertions(+), 48 deletions(-) diff --git a/packages/elements-core/src/components/Docs/HttpOperation/LazySchemaTreePreviewer.tsx b/packages/elements-core/src/components/Docs/HttpOperation/LazySchemaTreePreviewer.tsx index 454d30916..f8d81f5ce 100644 --- a/packages/elements-core/src/components/Docs/HttpOperation/LazySchemaTreePreviewer.tsx +++ b/packages/elements-core/src/components/Docs/HttpOperation/LazySchemaTreePreviewer.tsx @@ -1,5 +1,5 @@ import { Box, Flex, VStack } from '@stoplight/mosaic'; -import React, { useEffect, useMemo, useState } from 'react'; +import React, { useEffect, useState } from 'react'; interface LazySchemaTreePreviewerProps { schema: any; @@ -83,6 +83,7 @@ const trimSlashes = (str: string) => { }; function isPropertiesAllHidden(path: string, hideData: Array<{ path: string; required?: boolean }>) { + if (!hideData.length) return false; const current = trimSlashes(path); const parts = current.split('/'); for (let i = parts.length; i >= 2; i--) { @@ -100,34 +101,46 @@ function isPropertiesAllHidden(path: string, hideData: Array<{ path: string; req } function isRequiredOverride(path: string, hideData: Array<{ path: string; required?: boolean }>) { + if (!hideData.length) return undefined; const entry = hideData.find(h => trimSlashes(h.path) === trimSlashes(path)); return entry && typeof entry.required === 'boolean' ? entry.required : undefined; } -// New utility for array/items-based hiding function isPathHidden(path: string, hideData: Array<{ path: string; required?: boolean }>) { const normalizedPath = trimSlashes(path); - // Direct match (root-level or property-level) const direct = hideData.find(h => trimSlashes(h.path) === normalizedPath); if (direct && direct.required === undefined) return true; - // Check for ancestor "properties" disables (properties/carr/properties, etc) if (isPropertiesAllHidden(path, hideData)) return true; - // Check for array/items disables: e.g. properties/aircraftGroup/items/aircraft/items/aircraftGroup - // Go up the path looking for a hideData.path which is a prefix of this path and ends with '/items/[field]' for (const h of hideData) { const hPath = trimSlashes(h.path); if (h.required !== undefined) continue; - // Must be prefix + const oneOfPattern = hPath.match(/^(.*\/)?oneOf\/\d+\/(.*)$/); + const anyOfPattern = hPath.match(/^(.*\/)?anyOf\/\d+\/(.*)$/); + const allOfPattern = hPath.match(/^(.*\/)?allOf\/\d+\/(.*)$/); + const pattern = oneOfPattern || anyOfPattern || allOfPattern; + if (pattern) { + const prefix = pattern[1] || ''; + const suffix = pattern[2] || ''; + const schemaType = oneOfPattern ? 'oneOf' : anyOfPattern ? 'anyOf' : 'allOf'; + const flexiblePattern = `${prefix}${schemaType}/\\d+/${suffix}`; + const regex = new RegExp(`^${flexiblePattern.replace(/\//g, '\\/')}$`); + if (regex.test(normalizedPath)) { + return true; + } + const flexiblePrefixPattern = `${prefix}${schemaType}/\\d+/${suffix}`; + const prefixRegex = new RegExp(`^${flexiblePrefixPattern.replace(/\//g, '\\/')}`); + if (prefixRegex.test(normalizedPath) && normalizedPath.startsWith(prefix + schemaType)) { + return true; + } + } if ( normalizedPath.length > hPath.length && normalizedPath.startsWith(hPath) && - // hPath is items/field (array hiding) (hPath.endsWith('/items') || (hPath.match(/\/items\/[^\/]+$/) && normalizedPath.startsWith(hPath + '/'))) ) { - // Hide all descendants under this path return true; } } @@ -165,22 +178,14 @@ const LazySchemaTreePreviewer: React.FC = ({ useEffect(() => { setSelectedSchemaIndex(0); - }, [schema?.anyOf, schema?.oneOf]); - const thisNodeRequiredOverride = isRequiredOverride(path, hideData); + }, [schema?.anyOf, schema?.oneOf, schema?.allOf, schema?.items?.anyOf, schema?.items?.oneOf, schema?.items?.allOf]); + const thisNodeRequiredOverride = isRequiredOverride(path, hideData); const shouldHideAllChildren = (isRoot && hideData.some(h => trimSlashes(h.path) === 'properties' && h.required === undefined)) || (!isRoot && isPropertiesAllHidden(path, hideData)); - const shouldHideNode = useMemo(() => { - if (isRoot) return false; - if (isPathHidden(path, hideData) && thisNodeRequiredOverride === undefined) return true; - return false; - }, [path, hideData, isRoot, thisNodeRequiredOverride]); - - if (!schema || shouldHideNode) { - return null; - } + const shouldHideNode = !isRoot && isPathHidden(path, hideData) && thisNodeRequiredOverride === undefined; const displayTitle = level === 1 && (title === undefined || path === '') ? '' : title ?? schema?.title ?? 'Node'; @@ -191,6 +196,10 @@ const LazySchemaTreePreviewer: React.FC = ({ } }; + if (!schema || shouldHideNode) { + return null; + } + const renderChildren = () => { if (shouldHideAllChildren) return null; if (!expanded && !isRoot) return null; @@ -198,27 +207,51 @@ const LazySchemaTreePreviewer: React.FC = ({ const children: JSX.Element[] = []; if (schema?.type === 'object' && (schema?.properties || schema?.allOf || schema?.anyOf || schema?.oneOf)) { - let props = schema?.properties; + let props = schema?.properties || {}; + let requiredFields = schema?.required || []; if (schema?.allOf) { schema?.allOf.forEach((item: any) => { - props = { ...props, ...item.properties }; + if (item.properties) { + props = { ...props, ...item.properties }; + } + if (item.required) { + requiredFields = [...requiredFields, ...item.required]; + } }); } + if (schema?.anyOf && schema?.anyOf.length > 0) { const selectedSchema = schema?.anyOf[selectedSchemaIndex] || schema?.anyOf[0]; - props = { ...props, ...selectedSchema.properties }; + if (selectedSchema.properties) { + props = { ...props, ...selectedSchema.properties }; + } + if (selectedSchema.required) { + requiredFields = [...requiredFields, ...selectedSchema.required]; + } } + if (schema?.oneOf && schema?.oneOf.length > 0) { const selectedSchema = schema?.oneOf[selectedSchemaIndex] || schema?.oneOf[0]; - props = { ...props, ...selectedSchema.properties }; + if (selectedSchema.properties) { + props = { ...props, ...selectedSchema.properties }; + } + if (selectedSchema.required) { + requiredFields = [...requiredFields, ...selectedSchema.required]; + } } for (const [key, child] of Object.entries(props || {})) { - const childPath = `${path}/properties/${key}`; + let childPath = `${path}/properties/${key}`; + if (schema?.oneOf && schema?.oneOf.length > 0) { + childPath = `${path}/oneOf/${selectedSchemaIndex}/properties/${key}`; + } else if (schema?.anyOf && schema?.anyOf.length > 0) { + childPath = `${path}/anyOf/${selectedSchemaIndex}/properties/${key}`; + } else if (schema?.allOf && schema?.allOf.length > 0) { + childPath = `${path}/allOf/${selectedSchemaIndex}/properties/${key}`; + } const childRequiredOverride = isRequiredOverride(childPath, hideData); const shouldHideChild = isPathHidden(childPath, hideData) && childRequiredOverride === undefined; - const resolved = dereference(child, root); if (!shouldHideChild) { children.push( @@ -230,7 +263,7 @@ const LazySchemaTreePreviewer: React.FC = ({ level={level + 1} path={childPath} hideData={hideData} - parentRequired={schema?.required} + parentRequired={requiredFields} propertyKey={key} _subType={resolved?.items?.type} /> @@ -247,35 +280,83 @@ const LazySchemaTreePreviewer: React.FC = ({ const resolvedItems = dereference(schema?.items, root); const itemsPath = `${path}/items`; - if (resolvedItems && resolvedItems.type === 'object' && resolvedItems.properties) { - for (const [key, child] of Object.entries(resolvedItems.properties)) { - const childPath = `${itemsPath}/properties/${key}`; + if ( + resolvedItems && + (resolvedItems.type === 'object' || resolvedItems.anyOf || resolvedItems.oneOf || resolvedItems.allOf) + ) { + if (resolvedItems.anyOf || resolvedItems.oneOf || resolvedItems.allOf) { + const childPath = `${path}/items`; const childRequiredOverride = isRequiredOverride(childPath, hideData); const shouldHideChild = isPathHidden(childPath, hideData) && childRequiredOverride === undefined; + let schemaToPass = resolvedItems; + if ( + schema?.type === 'array' && + schema?.items && + (schema?.items?.anyOf || schema?.items?.oneOf || schema?.items?.allOf) + ) { + if (schema.items.anyOf && selectedSchemaIndex < schema.items.anyOf.length) { + schemaToPass = schema.items.anyOf[selectedSchemaIndex]; + } else if (schema.items.oneOf && selectedSchemaIndex < schema.items.oneOf.length) { + schemaToPass = schema.items.oneOf[selectedSchemaIndex]; + } else if (schema.items.allOf && selectedSchemaIndex < schema.items.allOf.length) { + schemaToPass = schema.items.allOf[selectedSchemaIndex]; + } + } + if (!shouldHideChild) { children.push( -
  • +
  • , ); } + } else if (resolvedItems.properties) { + for (const [key, child] of Object.entries(resolvedItems.properties)) { + let childPath = `${itemsPath}/properties/${key}`; + if (schema?.items?.oneOf && schema?.items?.oneOf.length > 0) { + childPath = `${path}/items/oneOf/${selectedSchemaIndex}/properties/${key}`; + } else if (schema?.items?.anyOf && schema?.items?.anyOf.length > 0) { + childPath = `${path}/items/anyOf/${selectedSchemaIndex}/properties/${key}`; + } else if (schema?.items?.allOf && schema?.items?.allOf.length > 0) { + childPath = `${path}/items/allOf/${selectedSchemaIndex}/properties/${key}`; + } + const childRequiredOverride = isRequiredOverride(childPath, hideData); + const shouldHideChild = isPathHidden(childPath, hideData) && childRequiredOverride === undefined; + + if (!shouldHideChild) { + children.push( +
  • + +
  • , + ); + } + } } } else if (resolvedItems && resolvedItems.type === 'array' && resolvedItems.items.length > 0) { const childPath = `${path}/items`; const childRequiredOverride = isRequiredOverride(childPath, hideData); const shouldHideChild = isPathHidden(childPath, hideData) && childRequiredOverride === undefined; - if (!shouldHideChild) { children.push(
  • @@ -299,6 +380,18 @@ const LazySchemaTreePreviewer: React.FC = ({ }; const combinedSchemaSelector = () => { + let schemaOptions = []; + if (schema?.anyOf) schemaOptions = schema.anyOf; + else if (schema?.oneOf) schemaOptions = schema.oneOf; + else if (schema?.allOf) schemaOptions = schema.allOf; + else if (schema?.type === 'array' && schema?.items) { + if (schema.items.anyOf) schemaOptions = schema.items.anyOf; + else if (schema.items.oneOf) schemaOptions = schema.items.oneOf; + else if (schema.items.allOf) schemaOptions = schema.items.allOf; + } + + if (!schemaOptions || schemaOptions.length === 0) return null; + return ( <> = ({ fontSize="sm" onClick={(e: React.MouseEvent) => e.stopPropagation()} > - {(schema?.anyOf || schema?.oneOf)?.map((schemaOption: any, index: number) => ( + {schemaOptions.map((schemaOption: any, index: number) => ( = ({ display="flex" alignItems="center" style={{ - borderBottom: - index < (schema?.anyOf || schema?.oneOf).length - 1 ? '1px solid rgba(0, 0, 0, 0.1)' : 'none', + borderBottom: index < schemaOptions.length - 1 ? '1px solid rgba(0, 0, 0, 0.1)' : 'none', gap: '8px', }} onMouseEnter={(e: React.MouseEvent) => { @@ -446,13 +538,27 @@ const LazySchemaTreePreviewer: React.FC = ({ {' ' + displayTitle} ) : null} - {!isRoot ? ( + {!isRoot || + (isRoot && + (schema?.anyOf || + schema?.oneOf || + schema?.allOf || + (schema?.type === 'array' && + schema?.items && + (schema?.items?.anyOf || schema?.items?.oneOf || schema?.items?.allOf)))) ? ( { - if (schema?.anyOf || schema?.oneOf) { + if ( + schema?.anyOf || + schema?.oneOf || + schema?.allOf || + (schema?.type === 'array' && + schema?.items && + (schema?.items?.anyOf || schema?.items?.oneOf || schema?.items?.allOf)) + ) { setIsHoveringSelector(true); } }} @@ -462,15 +568,41 @@ const LazySchemaTreePreviewer: React.FC = ({ } }} onClick={(e: React.MouseEvent) => { - if (schema?.anyOf || schema?.oneOf) { + if ( + schema?.anyOf || + schema?.oneOf || + schema?.allOf || + (schema?.type === 'array' && + schema?.items && + (schema?.items?.anyOf || schema?.items?.oneOf || schema?.items?.allOf)) + ) { e.stopPropagation(); setShowSchemaDropdown(prev => !prev); } }} style={{ - cursor: schema?.anyOf || schema?.oneOf ? 'pointer' : 'default', + cursor: + schema?.anyOf || + schema?.oneOf || + schema?.allOf || + (schema?.type === 'array' && + schema?.items && + (schema?.items?.anyOf || schema?.items?.oneOf || schema?.items?.allOf)) + ? 'pointer' + : 'default', }} > + {isRoot && + (schema?.anyOf || + schema?.oneOf || + schema?.allOf || + (schema?.type === 'array' && + schema?.items && + (schema?.items?.anyOf || schema?.items?.oneOf || schema?.items?.allOf))) && ( + + {title || schema?.title || 'Schema'} + + )} {(() => { let typeDisplay = @@ -480,13 +612,25 @@ const LazySchemaTreePreviewer: React.FC = ({ return `any of ${typeDisplay}`; } else if (schema?.oneOf && schema?.oneOf.length > 0) { return `one of ${typeDisplay}`; + } else if (schema?.allOf && schema?.allOf.length > 0) { + return `all of ${typeDisplay}`; } return typeDisplay; })()} {schema?.items && schema?.items?.title !== undefined ? ` [${schema?.items?.title}] ` : null} + {schema?.type === 'array' && + schema?.items && + (schema?.items?.anyOf || schema?.items?.oneOf || schema?.items?.allOf) + ? ` [${schema?.items?.anyOf ? 'any of' : schema?.items?.oneOf ? 'one of' : 'all of'} object]` + : null} - {(schema?.anyOf || schema?.oneOf) && ( + {(schema?.anyOf || + schema?.oneOf || + schema?.allOf || + (schema?.type === 'array' && + schema?.items && + (schema?.items?.anyOf || schema?.items?.oneOf || schema?.items?.allOf))) && ( = ({ )} {schema?.format !== undefined ? `<${schema?.format}>` : null} - {(schema?.anyOf || schema?.oneOf) && showSchemaDropdown && combinedSchemaSelector()} + {(schema?.anyOf || + schema?.oneOf || + schema?.allOf || + (schema?.type === 'array' && + schema?.items && + (schema?.items?.anyOf || schema?.items?.oneOf || schema?.items?.allOf))) && + showSchemaDropdown && + combinedSchemaSelector()} ) : null} diff --git a/packages/elements-dev-portal/src/version.ts b/packages/elements-dev-portal/src/version.ts index ecd86f5e7..7d3dd749c 100644 --- a/packages/elements-dev-portal/src/version.ts +++ b/packages/elements-dev-portal/src/version.ts @@ -1,2 +1,2 @@ // auto-updated during build -export const appVersion = '3.0.4'; +export const appVersion = '3.0.6'; From 76e225e95c790e533dae24b240fd9daed6fdde92 Mon Sep 17 00:00:00 2001 From: SB-virendrasolanke Date: Mon, 4 Aug 2025 15:57:15 +0530 Subject: [PATCH 2/4] removed label for all of --- .../Docs/HttpOperation/LazySchemaTreePreviewer.tsx | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/packages/elements-core/src/components/Docs/HttpOperation/LazySchemaTreePreviewer.tsx b/packages/elements-core/src/components/Docs/HttpOperation/LazySchemaTreePreviewer.tsx index f8d81f5ce..cd03bc6a7 100644 --- a/packages/elements-core/src/components/Docs/HttpOperation/LazySchemaTreePreviewer.tsx +++ b/packages/elements-core/src/components/Docs/HttpOperation/LazySchemaTreePreviewer.tsx @@ -383,7 +383,6 @@ const LazySchemaTreePreviewer: React.FC = ({ let schemaOptions = []; if (schema?.anyOf) schemaOptions = schema.anyOf; else if (schema?.oneOf) schemaOptions = schema.oneOf; - else if (schema?.allOf) schemaOptions = schema.allOf; else if (schema?.type === 'array' && schema?.items) { if (schema.items.anyOf) schemaOptions = schema.items.anyOf; else if (schema.items.oneOf) schemaOptions = schema.items.oneOf; @@ -542,7 +541,6 @@ const LazySchemaTreePreviewer: React.FC = ({ (isRoot && (schema?.anyOf || schema?.oneOf || - schema?.allOf || (schema?.type === 'array' && schema?.items && (schema?.items?.anyOf || schema?.items?.oneOf || schema?.items?.allOf)))) ? ( @@ -554,7 +552,6 @@ const LazySchemaTreePreviewer: React.FC = ({ if ( schema?.anyOf || schema?.oneOf || - schema?.allOf || (schema?.type === 'array' && schema?.items && (schema?.items?.anyOf || schema?.items?.oneOf || schema?.items?.allOf)) @@ -571,7 +568,6 @@ const LazySchemaTreePreviewer: React.FC = ({ if ( schema?.anyOf || schema?.oneOf || - schema?.allOf || (schema?.type === 'array' && schema?.items && (schema?.items?.anyOf || schema?.items?.oneOf || schema?.items?.allOf)) @@ -584,7 +580,6 @@ const LazySchemaTreePreviewer: React.FC = ({ cursor: schema?.anyOf || schema?.oneOf || - schema?.allOf || (schema?.type === 'array' && schema?.items && (schema?.items?.anyOf || schema?.items?.oneOf || schema?.items?.allOf)) @@ -595,7 +590,6 @@ const LazySchemaTreePreviewer: React.FC = ({ {isRoot && (schema?.anyOf || schema?.oneOf || - schema?.allOf || (schema?.type === 'array' && schema?.items && (schema?.items?.anyOf || schema?.items?.oneOf || schema?.items?.allOf))) && ( @@ -612,8 +606,6 @@ const LazySchemaTreePreviewer: React.FC = ({ return `any of ${typeDisplay}`; } else if (schema?.oneOf && schema?.oneOf.length > 0) { return `one of ${typeDisplay}`; - } else if (schema?.allOf && schema?.allOf.length > 0) { - return `all of ${typeDisplay}`; } return typeDisplay; @@ -627,7 +619,6 @@ const LazySchemaTreePreviewer: React.FC = ({ {(schema?.anyOf || schema?.oneOf || - schema?.allOf || (schema?.type === 'array' && schema?.items && (schema?.items?.anyOf || schema?.items?.oneOf || schema?.items?.allOf))) && ( @@ -653,7 +644,6 @@ const LazySchemaTreePreviewer: React.FC = ({ {schema?.format !== undefined ? `<${schema?.format}>` : null} {(schema?.anyOf || schema?.oneOf || - schema?.allOf || (schema?.type === 'array' && schema?.items && (schema?.items?.anyOf || schema?.items?.oneOf || schema?.items?.allOf))) && From b35ef892e7202e40b639c9de7884650471da0db7 Mon Sep 17 00:00:00 2001 From: SB-virendrasolanke Date: Mon, 4 Aug 2025 16:20:22 +0530 Subject: [PATCH 3/4] fix : removed props --- .../Docs/HttpOperation/LazySchemaTreePreviewer.tsx | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/packages/elements-core/src/components/Docs/HttpOperation/LazySchemaTreePreviewer.tsx b/packages/elements-core/src/components/Docs/HttpOperation/LazySchemaTreePreviewer.tsx index cd03bc6a7..355787315 100644 --- a/packages/elements-core/src/components/Docs/HttpOperation/LazySchemaTreePreviewer.tsx +++ b/packages/elements-core/src/components/Docs/HttpOperation/LazySchemaTreePreviewer.tsx @@ -178,7 +178,14 @@ const LazySchemaTreePreviewer: React.FC = ({ useEffect(() => { setSelectedSchemaIndex(0); - }, [schema?.anyOf, schema?.oneOf, schema?.allOf, schema?.items?.anyOf, schema?.items?.oneOf, schema?.items?.allOf]); + }, [ + schema?.anyOf?.length, + schema?.oneOf?.length, + schema?.allOf?.length, + schema?.items?.anyOf?.length, + schema?.items?.oneOf?.length, + schema?.items?.allOf?.length, + ]); const thisNodeRequiredOverride = isRequiredOverride(path, hideData); const shouldHideAllChildren = @@ -603,9 +610,9 @@ const LazySchemaTreePreviewer: React.FC = ({ schema?.type === 'object' && schema?.title ? schema?.title : schema?.type || root?.title; if (schema?.anyOf && schema?.anyOf.length > 0) { - return `any of ${typeDisplay}`; + return `any of`; } else if (schema?.oneOf && schema?.oneOf.length > 0) { - return `one of ${typeDisplay}`; + return `one of`; } return typeDisplay; From bfb5f26179886251f72954c2465181c224d3738c Mon Sep 17 00:00:00 2001 From: SB-virendrasolanke Date: Wed, 6 Aug 2025 15:49:32 +0530 Subject: [PATCH 4/4] added handling for deep nesting --- .../HttpOperation/LazySchemaTreePreviewer.tsx | 152 +++++++++++++++--- 1 file changed, 134 insertions(+), 18 deletions(-) diff --git a/packages/elements-core/src/components/Docs/HttpOperation/LazySchemaTreePreviewer.tsx b/packages/elements-core/src/components/Docs/HttpOperation/LazySchemaTreePreviewer.tsx index 355787315..cdc5f49e4 100644 --- a/packages/elements-core/src/components/Docs/HttpOperation/LazySchemaTreePreviewer.tsx +++ b/packages/elements-core/src/components/Docs/HttpOperation/LazySchemaTreePreviewer.tsx @@ -176,6 +176,18 @@ const LazySchemaTreePreviewer: React.FC = ({ return initialState; }); + const nestedSchemaKey = schema?.allOf + ? JSON.stringify( + schema.allOf.map((item: any) => { + const resolved = dereference(item, root); + return { + oneOfLength: resolved.oneOf?.length, + anyOfLength: resolved.anyOf?.length, + }; + }), + ) + : null; + useEffect(() => { setSelectedSchemaIndex(0); }, [ @@ -185,6 +197,7 @@ const LazySchemaTreePreviewer: React.FC = ({ schema?.items?.anyOf?.length, schema?.items?.oneOf?.length, schema?.items?.allOf?.length, + nestedSchemaKey, ]); const thisNodeRequiredOverride = isRequiredOverride(path, hideData); @@ -203,10 +216,6 @@ const LazySchemaTreePreviewer: React.FC = ({ } }; - if (!schema || shouldHideNode) { - return null; - } - const renderChildren = () => { if (shouldHideAllChildren) return null; if (!expanded && !isRoot) return null; @@ -218,12 +227,34 @@ const LazySchemaTreePreviewer: React.FC = ({ let requiredFields = schema?.required || []; if (schema?.allOf) { - schema?.allOf.forEach((item: any) => { - if (item.properties) { - props = { ...props, ...item.properties }; + schema?.allOf.forEach((item: any, allOfIndex: number) => { + const resolvedItem = dereference(item, root); + if (resolvedItem.properties) { + props = { ...props, ...resolvedItem.properties }; + } + if (resolvedItem.required) { + requiredFields = [...requiredFields, ...resolvedItem.required]; } - if (item.required) { - requiredFields = [...requiredFields, ...item.required]; + // Handle nested oneOf/anyOf within allOf items + if (resolvedItem.oneOf && resolvedItem.oneOf.length > 0) { + const selectedNestedSchema = resolvedItem.oneOf[selectedSchemaIndex] || resolvedItem.oneOf[0]; + const resolvedNested = dereference(selectedNestedSchema, root); + if (resolvedNested.properties) { + props = { ...props, ...resolvedNested.properties }; + } + if (resolvedNested.required) { + requiredFields = [...requiredFields, ...resolvedNested.required]; + } + } + if (resolvedItem.anyOf && resolvedItem.anyOf.length > 0) { + const selectedNestedSchema = resolvedItem.anyOf[selectedSchemaIndex] || resolvedItem.anyOf[0]; + const resolvedNested = dereference(selectedNestedSchema, root); + if (resolvedNested.properties) { + props = { ...props, ...resolvedNested.properties }; + } + if (resolvedNested.required) { + requiredFields = [...requiredFields, ...resolvedNested.required]; + } } }); } @@ -250,12 +281,42 @@ const LazySchemaTreePreviewer: React.FC = ({ for (const [key, child] of Object.entries(props || {})) { let childPath = `${path}/properties/${key}`; - if (schema?.oneOf && schema?.oneOf.length > 0) { - childPath = `${path}/oneOf/${selectedSchemaIndex}/properties/${key}`; - } else if (schema?.anyOf && schema?.anyOf.length > 0) { - childPath = `${path}/anyOf/${selectedSchemaIndex}/properties/${key}`; - } else if (schema?.allOf && schema?.allOf.length > 0) { - childPath = `${path}/allOf/${selectedSchemaIndex}/properties/${key}`; + let foundInNestedSchema = false; + // Check if this property comes from a nested oneOf/anyOf within allOf + if (schema?.allOf) { + for (let allOfIndex = 0; allOfIndex < schema.allOf.length; allOfIndex++) { + const allOfItem = dereference(schema.allOf[allOfIndex], root); + // Check if property is in a oneOf within this allOf item + if (allOfItem.oneOf && allOfItem.oneOf.length > 0) { + const selectedNestedSchema = allOfItem.oneOf[selectedSchemaIndex] || allOfItem.oneOf[0]; + const resolvedNested = dereference(selectedNestedSchema, root); + if (resolvedNested.properties && resolvedNested.properties[key]) { + childPath = `${path}/allOf/${allOfIndex}/oneOf/${selectedSchemaIndex}/properties/${key}`; + foundInNestedSchema = true; + break; + } + } + // Check if property is in an anyOf within this allOf item + if (allOfItem.anyOf && allOfItem.anyOf.length > 0) { + const selectedNestedSchema = allOfItem.anyOf[selectedSchemaIndex] || allOfItem.anyOf[0]; + const resolvedNested = dereference(selectedNestedSchema, root); + if (resolvedNested.properties && resolvedNested.properties[key]) { + childPath = `${path}/allOf/${allOfIndex}/anyOf/${selectedSchemaIndex}/properties/${key}`; + foundInNestedSchema = true; + break; + } + } + } + } + // Handle top-level oneOf/anyOf if not found in nested schemas + if (!foundInNestedSchema) { + if (schema?.oneOf && schema?.oneOf.length > 0) { + childPath = `${path}/oneOf/${selectedSchemaIndex}/properties/${key}`; + } else if (schema?.anyOf && schema?.anyOf.length > 0) { + childPath = `${path}/anyOf/${selectedSchemaIndex}/properties/${key}`; + } else if (schema?.allOf && schema?.allOf.length > 0) { + childPath = `${path}/allOf/${selectedSchemaIndex}/properties/${key}`; + } } const childRequiredOverride = isRequiredOverride(childPath, hideData); const shouldHideChild = isPathHidden(childPath, hideData) && childRequiredOverride === undefined; @@ -388,9 +449,24 @@ const LazySchemaTreePreviewer: React.FC = ({ const combinedSchemaSelector = () => { let schemaOptions = []; - if (schema?.anyOf) schemaOptions = schema.anyOf; - else if (schema?.oneOf) schemaOptions = schema.oneOf; - else if (schema?.type === 'array' && schema?.items) { + // Check for top-level combinations first + if (schema?.anyOf) { + schemaOptions = schema.anyOf; + } else if (schema?.oneOf) { + schemaOptions = schema.oneOf; + } else if (schema?.allOf) { + // For allOf, check if any items have nested oneOf/anyOf + for (const allOfItem of schema.allOf) { + const resolvedItem = dereference(allOfItem, root); + if (resolvedItem.oneOf && resolvedItem.oneOf.length > 0) { + schemaOptions = resolvedItem.oneOf; + break; + } else if (resolvedItem.anyOf && resolvedItem.anyOf.length > 0) { + schemaOptions = resolvedItem.anyOf; + break; + } + } + } else if (schema?.type === 'array' && schema?.items) { if (schema.items.anyOf) schemaOptions = schema.items.anyOf; else if (schema.items.oneOf) schemaOptions = schema.items.oneOf; else if (schema.items.allOf) schemaOptions = schema.items.allOf; @@ -522,6 +598,11 @@ const LazySchemaTreePreviewer: React.FC = ({ schema = dereference(schema, root); } + // Early return for hidden/invalid schemas + if (!schema || shouldHideNode) { + return null; + } + return (
    @@ -548,6 +629,11 @@ const LazySchemaTreePreviewer: React.FC = ({ (isRoot && (schema?.anyOf || schema?.oneOf || + (schema?.allOf && + schema.allOf.some((item: any) => { + const resolved = dereference(item, root); + return resolved.oneOf || resolved.anyOf; + })) || (schema?.type === 'array' && schema?.items && (schema?.items?.anyOf || schema?.items?.oneOf || schema?.items?.allOf)))) ? ( @@ -559,6 +645,11 @@ const LazySchemaTreePreviewer: React.FC = ({ if ( schema?.anyOf || schema?.oneOf || + (schema?.allOf && + schema.allOf.some((item: any) => { + const resolved = dereference(item, root); + return resolved.oneOf || resolved.anyOf; + })) || (schema?.type === 'array' && schema?.items && (schema?.items?.anyOf || schema?.items?.oneOf || schema?.items?.allOf)) @@ -575,6 +666,11 @@ const LazySchemaTreePreviewer: React.FC = ({ if ( schema?.anyOf || schema?.oneOf || + (schema?.allOf && + schema.allOf.some((item: any) => { + const resolved = dereference(item, root); + return resolved.oneOf || resolved.anyOf; + })) || (schema?.type === 'array' && schema?.items && (schema?.items?.anyOf || schema?.items?.oneOf || schema?.items?.allOf)) @@ -587,6 +683,11 @@ const LazySchemaTreePreviewer: React.FC = ({ cursor: schema?.anyOf || schema?.oneOf || + (schema?.allOf && + schema.allOf.some((item: any) => { + const resolved = dereference(item, root); + return resolved.oneOf || resolved.anyOf; + })) || (schema?.type === 'array' && schema?.items && (schema?.items?.anyOf || schema?.items?.oneOf || schema?.items?.allOf)) @@ -597,6 +698,11 @@ const LazySchemaTreePreviewer: React.FC = ({ {isRoot && (schema?.anyOf || schema?.oneOf || + (schema?.allOf && + schema.allOf.some((item: any) => { + const resolved = dereference(item, root); + return resolved.oneOf || resolved.anyOf; + })) || (schema?.type === 'array' && schema?.items && (schema?.items?.anyOf || schema?.items?.oneOf || schema?.items?.allOf))) && ( @@ -626,6 +732,11 @@ const LazySchemaTreePreviewer: React.FC = ({ {(schema?.anyOf || schema?.oneOf || + (schema?.allOf && + schema.allOf.some((item: any) => { + const resolved = dereference(item, root); + return resolved.oneOf || resolved.anyOf; + })) || (schema?.type === 'array' && schema?.items && (schema?.items?.anyOf || schema?.items?.oneOf || schema?.items?.allOf))) && ( @@ -651,6 +762,11 @@ const LazySchemaTreePreviewer: React.FC = ({ {schema?.format !== undefined ? `<${schema?.format}>` : null} {(schema?.anyOf || schema?.oneOf || + (schema?.allOf && + schema.allOf.some((item: any) => { + const resolved = dereference(item, root); + return resolved.oneOf || resolved.anyOf; + })) || (schema?.type === 'array' && schema?.items && (schema?.items?.anyOf || schema?.items?.oneOf || schema?.items?.allOf))) &&