|
1 | 1 | import { useState, useEffect, useRef, useMemo } from 'react'; |
2 | | -import $RefParser from '@apidevtools/json-schema-ref-parser'; |
3 | 2 |
|
4 | 3 | interface JSONSchemaViewerProps { |
5 | 4 | schema: any; |
@@ -101,16 +100,107 @@ function mergeAllOfSchemas(schemaWithProcessor: any): any { |
101 | 100 | return mergedSchema; |
102 | 101 | } |
103 | 102 |
|
104 | | -async function processSchema(schema: any, rootSchema?: any): Promise<any> { |
| 103 | +function processSchema(schema: any, rootSchema?: any): any { |
105 | 104 | if (!schema) return schema; |
106 | 105 |
|
107 | | - let dereferencedSchema = await $RefParser.dereference(schema, { |
108 | | - dereference: { |
109 | | - circular: true, // Don't allow circular $refs |
110 | | - }, |
111 | | - }); |
112 | | - console.log(dereferencedSchema); |
113 | | - return dereferencedSchema; |
| 106 | + const root = rootSchema || schema; |
| 107 | + |
| 108 | + // Handle $ref |
| 109 | + if (schema.$ref) { |
| 110 | + const refPath = schema.$ref; |
| 111 | + let resolvedSchema = null; |
| 112 | + let defName = ''; |
| 113 | + |
| 114 | + // Try draft-7 style first: #/definitions/ |
| 115 | + if (refPath.startsWith('#/definitions/')) { |
| 116 | + defName = refPath.replace('#/definitions/', ''); |
| 117 | + if (root.definitions && root.definitions[defName]) { |
| 118 | + resolvedSchema = root.definitions[defName]; |
| 119 | + } |
| 120 | + } |
| 121 | + // Try 2020-12 style: #/$defs/ |
| 122 | + else if (refPath.startsWith('#/$defs/')) { |
| 123 | + defName = refPath.replace('#/$defs/', ''); |
| 124 | + if (root.$defs && root.$defs[defName]) { |
| 125 | + resolvedSchema = root.$defs[defName]; |
| 126 | + } |
| 127 | + } |
| 128 | + // Try other common patterns |
| 129 | + else if (refPath.startsWith('#/components/schemas/')) { |
| 130 | + defName = refPath.replace('#/components/schemas/', ''); |
| 131 | + if (root.components && root.components.schemas && root.components.schemas[defName]) { |
| 132 | + resolvedSchema = root.components.schemas[defName]; |
| 133 | + } |
| 134 | + } |
| 135 | + |
| 136 | + if (resolvedSchema) { |
| 137 | + const processedSchema = processSchema(resolvedSchema, root); |
| 138 | + return { |
| 139 | + ...processedSchema, |
| 140 | + _refPath: refPath, |
| 141 | + _refName: defName, |
| 142 | + _originalRef: schema.$ref, |
| 143 | + }; |
| 144 | + } |
| 145 | + |
| 146 | + return { |
| 147 | + type: 'string', |
| 148 | + description: `Reference to ${refPath} (definition not found in root schema)`, |
| 149 | + title: defName || refPath.split('/').pop(), |
| 150 | + _refPath: refPath, |
| 151 | + _refName: defName, |
| 152 | + _refNotFound: true, |
| 153 | + }; |
| 154 | + } |
| 155 | + |
| 156 | + if (schema.allOf) { |
| 157 | + return mergeAllOfSchemas({ ...schema, processSchema: (s: any) => processSchema(s, root) }); |
| 158 | + } |
| 159 | + |
| 160 | + if (schema.oneOf) { |
| 161 | + const processedVariants = schema.oneOf.map((variant: any) => { |
| 162 | + const processedVariant = processSchema(variant, root); |
| 163 | + return { |
| 164 | + title: processedVariant.title || variant.title || 'Unnamed Variant', |
| 165 | + required: processedVariant.required || variant.required || [], |
| 166 | + properties: processedVariant.properties || {}, |
| 167 | + ...processedVariant, |
| 168 | + }; |
| 169 | + }); |
| 170 | + |
| 171 | + const allProperties: Record<string, any> = {}; |
| 172 | + processedVariants.forEach((variant: any) => { |
| 173 | + if (variant.properties) { |
| 174 | + Object.assign(allProperties, variant.properties); |
| 175 | + } |
| 176 | + }); |
| 177 | + |
| 178 | + return { |
| 179 | + ...schema, |
| 180 | + type: schema.type || 'object', |
| 181 | + properties: { |
| 182 | + ...(schema.properties || {}), |
| 183 | + ...allProperties, |
| 184 | + }, |
| 185 | + variants: processedVariants, |
| 186 | + }; |
| 187 | + } |
| 188 | + |
| 189 | + // Process nested schemas in properties |
| 190 | + if (schema.properties) { |
| 191 | + const processedProperties: Record<string, any> = {}; |
| 192 | + Object.entries(schema.properties).forEach(([key, prop]: [string, any]) => { |
| 193 | + processedProperties[key] = processSchema(prop, root); |
| 194 | + }); |
| 195 | + schema = { ...schema, properties: processedProperties }; |
| 196 | + } |
| 197 | + |
| 198 | + // Process array items |
| 199 | + if (schema.type === 'array' && schema.items) { |
| 200 | + schema = { ...schema, items: processSchema(schema.items, root) }; |
| 201 | + } |
| 202 | + |
| 203 | + return schema; |
114 | 204 | } |
115 | 205 |
|
116 | 206 | // SchemaProperty component |
|
0 commit comments