docusaurus-theme-openapi-docs 4.5.1 → 4.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (133) hide show
  1. package/lib/markdown/schema.js +14 -1
  2. package/lib/theme/ApiExplorer/Accept/slice.d.ts +5 -2
  3. package/lib/theme/ApiExplorer/Authorization/index.js +50 -9
  4. package/lib/theme/ApiExplorer/Authorization/slice.d.ts +145 -3
  5. package/lib/theme/ApiExplorer/Authorization/slice.js +3 -1
  6. package/lib/theme/ApiExplorer/Body/FileArrayFormBodyItem/index.d.ts +7 -0
  7. package/lib/theme/ApiExplorer/Body/FileArrayFormBodyItem/index.js +126 -0
  8. package/lib/theme/ApiExplorer/Body/FormBodyItem/index.d.ts +9 -0
  9. package/lib/theme/ApiExplorer/Body/FormBodyItem/index.js +110 -0
  10. package/lib/theme/ApiExplorer/Body/index.js +322 -193
  11. package/lib/theme/ApiExplorer/Body/resolveSchemaWithSelections.d.ts +13 -0
  12. package/lib/theme/ApiExplorer/Body/resolveSchemaWithSelections.js +133 -0
  13. package/lib/theme/ApiExplorer/Body/slice.d.ts +1056 -11
  14. package/lib/theme/ApiExplorer/Body/slice.js +22 -2
  15. package/lib/theme/ApiExplorer/CodeSnippets/index.d.ts +2 -1
  16. package/lib/theme/ApiExplorer/CodeSnippets/index.js +37 -26
  17. package/lib/theme/ApiExplorer/CodeTabs/_CodeTabs.scss +5 -1
  18. package/lib/theme/ApiExplorer/CodeTabs/index.d.ts +3 -3
  19. package/lib/theme/ApiExplorer/CodeTabs/index.js +2 -2
  20. package/lib/theme/ApiExplorer/ContentType/slice.d.ts +5 -2
  21. package/lib/theme/ApiExplorer/FormFileUpload/index.js +6 -1
  22. package/lib/theme/ApiExplorer/FormItem/index.js +6 -1
  23. package/lib/theme/ApiExplorer/FormTextInput/index.d.ts +2 -0
  24. package/lib/theme/ApiExplorer/FormTextInput/index.js +8 -1
  25. package/lib/theme/ApiExplorer/LiveEditor/index.js +11 -4
  26. package/lib/theme/ApiExplorer/ParamOptions/ParamFormItems/ParamArrayFormItem.js +15 -5
  27. package/lib/theme/ApiExplorer/ParamOptions/ParamFormItems/ParamBooleanFormItem.js +11 -3
  28. package/lib/theme/ApiExplorer/ParamOptions/ParamFormItems/ParamMultiSelectFormItem.js +12 -4
  29. package/lib/theme/ApiExplorer/ParamOptions/ParamFormItems/ParamSelectFormItem.js +11 -2
  30. package/lib/theme/ApiExplorer/ParamOptions/index.js +11 -1
  31. package/lib/theme/ApiExplorer/ParamOptions/slice.d.ts +0 -4
  32. package/lib/theme/ApiExplorer/ParamOptions/slice.js +4 -4
  33. package/lib/theme/ApiExplorer/Request/index.js +110 -17
  34. package/lib/theme/ApiExplorer/Request/makeRequest.d.ts +7 -1
  35. package/lib/theme/ApiExplorer/Request/makeRequest.js +94 -24
  36. package/lib/theme/ApiExplorer/Response/index.js +34 -14
  37. package/lib/theme/ApiExplorer/Response/slice.d.ts +31 -7
  38. package/lib/theme/ApiExplorer/SchemaSelection/index.d.ts +2 -0
  39. package/lib/theme/ApiExplorer/SchemaSelection/index.js +36 -0
  40. package/lib/theme/ApiExplorer/SchemaSelection/slice.d.ts +37 -0
  41. package/lib/theme/ApiExplorer/SchemaSelection/slice.js +39 -0
  42. package/lib/theme/ApiExplorer/SecuritySchemes/index.js +208 -69
  43. package/lib/theme/ApiExplorer/Server/index.js +16 -2
  44. package/lib/theme/ApiExplorer/Server/slice.d.ts +49 -3
  45. package/lib/theme/ApiExplorer/buildPostmanRequest.js +46 -57
  46. package/lib/theme/ApiExplorer/index.js +4 -0
  47. package/lib/theme/ApiExplorer/persistenceMiddleware.d.ts +21 -0
  48. package/lib/theme/ApiExplorer/{persistanceMiddleware.js → persistenceMiddleware.js} +16 -9
  49. package/lib/theme/ApiExplorer/storage-utils.d.ts +2 -2
  50. package/lib/theme/ApiExplorer/storage-utils.js +3 -3
  51. package/lib/theme/ApiItem/Layout/index.d.ts +1 -1
  52. package/lib/theme/ApiItem/hooks.d.ts +10 -9
  53. package/lib/theme/ApiItem/index.js +13 -8
  54. package/lib/theme/ApiItem/store.d.ts +61 -43
  55. package/lib/theme/ApiItem/store.js +6 -2
  56. package/lib/theme/ApiTabs/index.js +6 -1
  57. package/lib/theme/Example/_Example.scss +11 -0
  58. package/lib/theme/Example/index.d.ts +24 -0
  59. package/lib/theme/Example/index.js +170 -0
  60. package/lib/theme/ParamsDetails/index.js +9 -1
  61. package/lib/theme/ParamsItem/index.d.ts +1 -1
  62. package/lib/theme/ParamsItem/index.js +43 -74
  63. package/lib/theme/RequestSchema/index.js +68 -48
  64. package/lib/theme/ResponseExamples/index.js +23 -3
  65. package/lib/theme/ResponseSchema/index.js +97 -82
  66. package/lib/theme/Schema/index.d.ts +6 -0
  67. package/lib/theme/Schema/index.js +240 -31
  68. package/lib/theme/SchemaItem/index.js +64 -36
  69. package/lib/theme/SchemaTabs/index.d.ts +8 -1
  70. package/lib/theme/SchemaTabs/index.js +14 -2
  71. package/lib/theme/StatusCodes/index.d.ts +1 -1
  72. package/lib/theme/StatusCodes/index.js +11 -2
  73. package/lib/theme/styles.scss +15 -0
  74. package/lib/theme/translationIds.d.ts +90 -0
  75. package/lib/theme/translationIds.js +114 -0
  76. package/package.json +28 -28
  77. package/src/markdown/schema.ts +17 -1
  78. package/src/theme/ApiExplorer/Authorization/index.tsx +51 -10
  79. package/src/theme/ApiExplorer/Authorization/slice.ts +1 -1
  80. package/src/theme/ApiExplorer/Body/FileArrayFormBodyItem/index.tsx +77 -0
  81. package/src/theme/ApiExplorer/Body/FormBodyItem/index.tsx +120 -0
  82. package/src/theme/ApiExplorer/Body/index.tsx +262 -198
  83. package/{lib/types.js → src/theme/ApiExplorer/Body/json2xml.d.ts} +2 -2
  84. package/src/theme/ApiExplorer/Body/resolveSchemaWithSelections.ts +155 -0
  85. package/src/theme/ApiExplorer/Body/slice.ts +40 -1
  86. package/src/theme/ApiExplorer/CodeSnippets/index.tsx +43 -29
  87. package/src/theme/ApiExplorer/CodeTabs/_CodeTabs.scss +5 -1
  88. package/src/theme/ApiExplorer/CodeTabs/index.tsx +6 -5
  89. package/src/theme/ApiExplorer/ContentType/index.tsx +1 -1
  90. package/src/theme/ApiExplorer/FormFileUpload/index.tsx +6 -1
  91. package/src/theme/ApiExplorer/FormItem/index.tsx +8 -1
  92. package/src/theme/ApiExplorer/FormTextInput/index.tsx +10 -1
  93. package/src/theme/ApiExplorer/LiveEditor/index.tsx +11 -4
  94. package/src/theme/ApiExplorer/ParamOptions/ParamFormItems/ParamArrayFormItem.tsx +16 -6
  95. package/src/theme/ApiExplorer/ParamOptions/ParamFormItems/ParamBooleanFormItem.tsx +12 -4
  96. package/src/theme/ApiExplorer/ParamOptions/ParamFormItems/ParamMultiSelectFormItem.tsx +12 -4
  97. package/src/theme/ApiExplorer/ParamOptions/ParamFormItems/ParamSelectFormItem.tsx +12 -3
  98. package/src/theme/ApiExplorer/ParamOptions/index.tsx +10 -2
  99. package/src/theme/ApiExplorer/ParamOptions/slice.ts +1 -1
  100. package/src/theme/ApiExplorer/Request/index.tsx +108 -17
  101. package/src/theme/ApiExplorer/Request/makeRequest.ts +106 -25
  102. package/src/theme/ApiExplorer/Response/index.tsx +30 -8
  103. package/src/theme/ApiExplorer/SchemaSelection/index.ts +13 -0
  104. package/src/theme/ApiExplorer/SchemaSelection/slice.ts +46 -0
  105. package/src/theme/ApiExplorer/SecuritySchemes/index.tsx +157 -69
  106. package/src/theme/ApiExplorer/Server/index.tsx +12 -4
  107. package/src/theme/ApiExplorer/buildPostmanRequest.ts +47 -63
  108. package/src/theme/ApiExplorer/index.tsx +5 -0
  109. package/src/theme/ApiExplorer/{persistanceMiddleware.ts → persistenceMiddleware.ts} +23 -13
  110. package/src/theme/ApiExplorer/storage-utils.ts +4 -4
  111. package/src/theme/ApiItem/Layout/index.tsx +1 -1
  112. package/src/theme/ApiItem/index.tsx +13 -7
  113. package/src/theme/ApiItem/store.ts +2 -0
  114. package/src/theme/ApiTabs/index.tsx +6 -1
  115. package/src/theme/Example/_Example.scss +11 -0
  116. package/src/theme/Example/index.tsx +168 -0
  117. package/src/theme/Markdown/index.d.ts +8 -0
  118. package/src/theme/ParamsDetails/index.tsx +10 -1
  119. package/src/theme/ParamsItem/index.tsx +38 -54
  120. package/src/theme/RequestSchema/index.tsx +60 -35
  121. package/src/theme/ResponseExamples/index.tsx +23 -3
  122. package/src/theme/ResponseSchema/index.tsx +73 -61
  123. package/src/theme/Schema/index.tsx +307 -55
  124. package/src/theme/SchemaItem/index.tsx +51 -33
  125. package/src/theme/SchemaTabs/index.tsx +19 -5
  126. package/src/theme/StatusCodes/index.tsx +13 -3
  127. package/src/theme/styles.scss +15 -0
  128. package/src/theme/translationIds.ts +111 -0
  129. package/src/theme-openapi.d.ts +7 -275
  130. package/src/{types.ts → types.d.ts} +9 -1
  131. package/tsconfig.tsbuildinfo +1 -1
  132. package/lib/theme/ApiExplorer/persistanceMiddleware.d.ts +0 -3
  133. package/lib/types.d.ts +0 -46
@@ -5,8 +5,11 @@
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  * ========================================================================== */
7
7
 
8
- import React from "react";
8
+ import React, { useCallback } from "react";
9
9
 
10
+ import { translate } from "@docusaurus/Translate";
11
+ import { setSchemaSelection } from "@theme/ApiExplorer/SchemaSelection/slice";
12
+ import { useTypedDispatch } from "@theme/ApiItem/hooks";
10
13
  import { ClosingArrayBracket, OpeningArrayBracket } from "@theme/ArrayBrackets";
11
14
  import Details from "@theme/Details";
12
15
  import DiscriminatorTabs from "@theme/DiscriminatorTabs";
@@ -14,6 +17,7 @@ import Markdown from "@theme/Markdown";
14
17
  import SchemaItem from "@theme/SchemaItem";
15
18
  import SchemaTabs from "@theme/SchemaTabs";
16
19
  import TabItem from "@theme/TabItem";
20
+ import { OPENAPI_SCHEMA_ITEM } from "@theme/translationIds";
17
21
  // eslint-disable-next-line import/no-extraneous-dependencies
18
22
  import { merge } from "allof-merge";
19
23
  import clsx from "clsx";
@@ -89,12 +93,29 @@ const Summary: React.FC<SummaryProps> = ({
89
93
  {(isRequired || deprecated || nullable) && (
90
94
  <span className="openapi-schema__divider" />
91
95
  )}
92
- {nullable && <span className="openapi-schema__nullable">nullable</span>}
96
+ {nullable && (
97
+ <span className="openapi-schema__nullable">
98
+ {translate({
99
+ id: OPENAPI_SCHEMA_ITEM.NULLABLE,
100
+ message: "nullable",
101
+ })}
102
+ </span>
103
+ )}
93
104
  {isRequired && (
94
- <span className="openapi-schema__required">required</span>
105
+ <span className="openapi-schema__required">
106
+ {translate({
107
+ id: OPENAPI_SCHEMA_ITEM.REQUIRED,
108
+ message: "required",
109
+ })}
110
+ </span>
95
111
  )}
96
112
  {deprecated && (
97
- <span className="openapi-schema__deprecated">deprecated</span>
113
+ <span className="openapi-schema__deprecated">
114
+ {translate({
115
+ id: OPENAPI_SCHEMA_ITEM.DEPRECATED,
116
+ message: "deprecated",
117
+ })}
118
+ </span>
98
119
  )}
99
120
  </span>
100
121
  </summary>
@@ -105,31 +126,102 @@ const Summary: React.FC<SummaryProps> = ({
105
126
  interface SchemaProps {
106
127
  schema: SchemaObject;
107
128
  schemaType: "request" | "response";
129
+ /**
130
+ * Optional path identifier for tracking anyOf/oneOf selections.
131
+ * When provided, tab selections will be dispatched to Redux state
132
+ * to enable dynamic body example updates.
133
+ */
134
+ schemaPath?: string;
108
135
  }
109
136
 
110
- const AnyOneOf: React.FC<SchemaProps> = ({ schema, schemaType }) => {
111
- const type = schema.oneOf ? "oneOf" : "anyOf";
137
+ const AnyOneOf: React.FC<SchemaProps> = ({
138
+ schema,
139
+ schemaType,
140
+ schemaPath,
141
+ }) => {
142
+ const key = schema.oneOf ? "oneOf" : "anyOf";
143
+ const type = schema.oneOf
144
+ ? translate({ id: OPENAPI_SCHEMA_ITEM.ONE_OF, message: "oneOf" })
145
+ : translate({ id: OPENAPI_SCHEMA_ITEM.ANY_OF, message: "anyOf" });
146
+
147
+ // Generate a unique ID for this anyOf/oneOf to prevent tab value collisions
148
+ const uniqueId = React.useMemo(
149
+ () => Math.random().toString(36).substring(7),
150
+ []
151
+ );
152
+
153
+ // Try to get Redux dispatch - will be undefined if not inside a Provider
154
+ let dispatch: ReturnType<typeof useTypedDispatch> | undefined;
155
+ try {
156
+ // eslint-disable-next-line react-hooks/rules-of-hooks
157
+ dispatch = useTypedDispatch();
158
+ } catch {
159
+ // Not inside a Redux Provider, which is fine for response schemas
160
+ dispatch = undefined;
161
+ }
162
+
163
+ // Handle tab change - dispatch to Redux if schemaPath is provided
164
+ const handleTabChange = useCallback(
165
+ (index: number) => {
166
+ if (schemaPath && dispatch) {
167
+ dispatch(setSchemaSelection({ path: schemaPath, index }));
168
+ }
169
+ },
170
+ [schemaPath, dispatch]
171
+ );
172
+
112
173
  return (
113
174
  <>
114
175
  <span className="badge badge--info" style={{ marginBottom: "1rem" }}>
115
176
  {type}
116
177
  </span>
117
- <SchemaTabs>
118
- {schema[type]?.map((anyOneSchema: any, index: number) => {
119
- const label = anyOneSchema.title || anyOneSchema.type;
178
+ <SchemaTabs
179
+ groupId={`schema-${uniqueId}`}
180
+ lazy
181
+ onChange={handleTabChange}
182
+ >
183
+ {schema[key]?.map((anyOneSchema: any, index: number) => {
184
+ // Use getSchemaName to include format info (e.g., "string<date-time>")
185
+ const computedSchemaName = getSchemaName(anyOneSchema);
186
+
187
+ // Determine label for the tab
188
+ // Prefer explicit title, then computed schema name, then raw type
189
+ let label =
190
+ anyOneSchema.title || computedSchemaName || anyOneSchema.type;
191
+ if (!label) {
192
+ if (anyOneSchema.oneOf) {
193
+ label = translate({
194
+ id: OPENAPI_SCHEMA_ITEM.ONE_OF,
195
+ message: "oneOf",
196
+ });
197
+ } else if (anyOneSchema.anyOf) {
198
+ label = translate({
199
+ id: OPENAPI_SCHEMA_ITEM.ANY_OF,
200
+ message: "anyOf",
201
+ });
202
+ } else {
203
+ label = `Option ${index + 1}`;
204
+ }
205
+ }
206
+
207
+ // Build the nested schemaPath for child anyOf/oneOf
208
+ const childSchemaPath = schemaPath
209
+ ? `${schemaPath}.${index}`
210
+ : undefined;
211
+
120
212
  return (
121
213
  // @ts-ignore
122
214
  <TabItem
123
215
  key={index}
124
216
  label={label}
125
- value={`${index}-item-properties`}
217
+ value={`${uniqueId}-${index}-item`}
126
218
  >
127
219
  {/* Handle primitive types directly */}
128
220
  {(isPrimitive(anyOneSchema) || anyOneSchema.const) && (
129
221
  <SchemaItem
130
222
  collapsible={false}
131
223
  name={undefined}
132
- schemaName={anyOneSchema.type}
224
+ schemaName={computedSchemaName}
133
225
  qualifierMessage={getQualifierMessage(anyOneSchema)}
134
226
  schema={anyOneSchema}
135
227
  discriminator={false}
@@ -146,7 +238,7 @@ const AnyOneOf: React.FC<SchemaProps> = ({ schema, schemaType }) => {
146
238
  <SchemaItem
147
239
  collapsible={false}
148
240
  name={undefined}
149
- schemaName={anyOneSchema.type}
241
+ schemaName={computedSchemaName}
150
242
  qualifierMessage={getQualifierMessage(anyOneSchema)}
151
243
  schema={anyOneSchema}
152
244
  discriminator={false}
@@ -155,20 +247,42 @@ const AnyOneOf: React.FC<SchemaProps> = ({ schema, schemaType }) => {
155
247
  )}
156
248
 
157
249
  {/* Handle actual object types with properties or nested schemas */}
158
- {anyOneSchema.type === "object" && anyOneSchema.properties && (
159
- <Properties schema={anyOneSchema} schemaType={schemaType} />
160
- )}
250
+ {/* Note: In OpenAPI, properties implies type: object even if not explicitly set */}
251
+ {(anyOneSchema.type === "object" || !anyOneSchema.type) &&
252
+ anyOneSchema.properties && (
253
+ <Properties
254
+ schema={anyOneSchema}
255
+ schemaType={schemaType}
256
+ schemaPath={childSchemaPath}
257
+ />
258
+ )}
161
259
  {anyOneSchema.allOf && (
162
- <SchemaNode schema={anyOneSchema} schemaType={schemaType} />
260
+ <SchemaNode
261
+ schema={anyOneSchema}
262
+ schemaType={schemaType}
263
+ schemaPath={childSchemaPath}
264
+ />
163
265
  )}
164
266
  {anyOneSchema.oneOf && (
165
- <SchemaNode schema={anyOneSchema} schemaType={schemaType} />
267
+ <SchemaNode
268
+ schema={anyOneSchema}
269
+ schemaType={schemaType}
270
+ schemaPath={childSchemaPath}
271
+ />
166
272
  )}
167
273
  {anyOneSchema.anyOf && (
168
- <SchemaNode schema={anyOneSchema} schemaType={schemaType} />
274
+ <SchemaNode
275
+ schema={anyOneSchema}
276
+ schemaType={schemaType}
277
+ schemaPath={childSchemaPath}
278
+ />
169
279
  )}
170
280
  {anyOneSchema.items && (
171
- <Items schema={anyOneSchema} schemaType={schemaType} />
281
+ <Items
282
+ schema={anyOneSchema}
283
+ schemaType={schemaType}
284
+ schemaPath={childSchemaPath}
285
+ />
172
286
  )}
173
287
  </TabItem>
174
288
  );
@@ -178,7 +292,11 @@ const AnyOneOf: React.FC<SchemaProps> = ({ schema, schemaType }) => {
178
292
  );
179
293
  };
180
294
 
181
- const Properties: React.FC<SchemaProps> = ({ schema, schemaType }) => {
295
+ const Properties: React.FC<SchemaProps> = ({
296
+ schema,
297
+ schemaType,
298
+ schemaPath,
299
+ }) => {
182
300
  const discriminator = schema.discriminator;
183
301
  if (discriminator && !discriminator.mapping) {
184
302
  const anyOneOf = schema.oneOf ?? schema.anyOf ?? {};
@@ -222,6 +340,7 @@ const Properties: React.FC<SchemaProps> = ({ schema, schemaType }) => {
222
340
  }
223
341
  discriminator={discriminator}
224
342
  schemaType={schemaType}
343
+ schemaPath={schemaPath ? `${schemaPath}.${key}` : undefined}
225
344
  />
226
345
  )
227
346
  )}
@@ -254,7 +373,12 @@ const PropertyDiscriminator: React.FC<SchemaEdgeProps> = ({
254
373
  )}
255
374
  {required && <span className="openapi-schema__divider"></span>}
256
375
  {required && (
257
- <span className="openapi-schema__required">required</span>
376
+ <span className="openapi-schema__required">
377
+ {translate({
378
+ id: OPENAPI_SCHEMA_ITEM.REQUIRED,
379
+ message: "required",
380
+ })}
381
+ </span>
258
382
  )}
259
383
  </span>
260
384
  <div style={{ marginLeft: "1rem" }}>
@@ -474,6 +598,7 @@ const SchemaNodeDetails: React.FC<SchemaEdgeProps> = ({
474
598
  schema,
475
599
  required,
476
600
  schemaType,
601
+ schemaPath,
477
602
  }) => {
478
603
  return (
479
604
  <SchemaItem collapsible={true}>
@@ -493,7 +618,11 @@ const SchemaNodeDetails: React.FC<SchemaEdgeProps> = ({
493
618
  {getQualifierMessage(schema) && (
494
619
  <MarkdownWrapper text={getQualifierMessage(schema)} />
495
620
  )}
496
- <SchemaNode schema={schema} schemaType={schemaType} />
621
+ <SchemaNode
622
+ schema={schema}
623
+ schemaType={schemaType}
624
+ schemaPath={schemaPath}
625
+ />
497
626
  </div>
498
627
  </Details>
499
628
  </SchemaItem>
@@ -503,7 +632,8 @@ const SchemaNodeDetails: React.FC<SchemaEdgeProps> = ({
503
632
  const Items: React.FC<{
504
633
  schema: any;
505
634
  schemaType: "request" | "response";
506
- }> = ({ schema, schemaType }) => {
635
+ schemaPath?: string;
636
+ }> = ({ schema, schemaType, schemaPath }) => {
507
637
  // Process schema.items to handle allOf merging
508
638
  let itemsSchema = schema.items;
509
639
  if (schema.items?.allOf) {
@@ -515,15 +645,26 @@ const Items: React.FC<{
515
645
  const hasProperties = itemsSchema?.properties;
516
646
  const hasAdditionalProperties = itemsSchema?.additionalProperties;
517
647
 
648
+ // Build the items schema path
649
+ const itemsSchemaPath = schemaPath ? `${schemaPath}.items` : undefined;
650
+
518
651
  if (hasOneOfAnyOf || hasProperties || hasAdditionalProperties) {
519
652
  return (
520
653
  <>
521
654
  <OpeningArrayBracket />
522
655
  {hasOneOfAnyOf && (
523
- <AnyOneOf schema={itemsSchema} schemaType={schemaType} />
656
+ <AnyOneOf
657
+ schema={itemsSchema}
658
+ schemaType={schemaType}
659
+ schemaPath={itemsSchemaPath}
660
+ />
524
661
  )}
525
662
  {hasProperties && (
526
- <Properties schema={itemsSchema} schemaType={schemaType} />
663
+ <Properties
664
+ schema={itemsSchema}
665
+ schemaType={schemaType}
666
+ schemaPath={itemsSchemaPath}
667
+ />
527
668
  )}
528
669
  {hasAdditionalProperties && (
529
670
  <AdditionalProperties schema={itemsSchema} schemaType={schemaType} />
@@ -588,6 +729,7 @@ interface SchemaEdgeProps {
588
729
  nullable?: boolean | undefined;
589
730
  discriminator?: any;
590
731
  schemaType: "request" | "response";
732
+ schemaPath?: string;
591
733
  }
592
734
 
593
735
  const SchemaEdge: React.FC<SchemaEdgeProps> = ({
@@ -596,6 +738,7 @@ const SchemaEdge: React.FC<SchemaEdgeProps> = ({
596
738
  required,
597
739
  discriminator,
598
740
  schemaType,
741
+ schemaPath,
599
742
  }) => {
600
743
  if (
601
744
  (schemaType === "request" && schema.readOnly) ||
@@ -629,6 +772,7 @@ const SchemaEdge: React.FC<SchemaEdgeProps> = ({
629
772
  required={required}
630
773
  schema={schema}
631
774
  nullable={schema.nullable}
775
+ schemaPath={schemaPath}
632
776
  />
633
777
  );
634
778
  }
@@ -642,6 +786,7 @@ const SchemaEdge: React.FC<SchemaEdgeProps> = ({
642
786
  required={required}
643
787
  schema={schema}
644
788
  nullable={schema.nullable}
789
+ schemaPath={schemaPath}
645
790
  />
646
791
  );
647
792
  }
@@ -655,6 +800,7 @@ const SchemaEdge: React.FC<SchemaEdgeProps> = ({
655
800
  required={required}
656
801
  schema={schema}
657
802
  nullable={schema.nullable}
803
+ schemaPath={schemaPath}
658
804
  />
659
805
  );
660
806
  }
@@ -668,11 +814,12 @@ const SchemaEdge: React.FC<SchemaEdgeProps> = ({
668
814
  nullable={schema.nullable}
669
815
  schema={schema}
670
816
  schemaType={schemaType}
817
+ schemaPath={schemaPath}
671
818
  />
672
819
  );
673
820
  }
674
821
 
675
- if (schema.items?.anyOf || schema.items?.oneOf) {
822
+ if (schema.items?.anyOf || schema.items?.oneOf || schema.items?.allOf) {
676
823
  return (
677
824
  <SchemaNodeDetails
678
825
  name={name}
@@ -681,6 +828,7 @@ const SchemaEdge: React.FC<SchemaEdgeProps> = ({
681
828
  nullable={schema.nullable}
682
829
  schema={schema}
683
830
  schemaType={schemaType}
831
+ schemaPath={schemaPath}
684
832
  />
685
833
  );
686
834
  }
@@ -725,13 +873,12 @@ const SchemaEdge: React.FC<SchemaEdgeProps> = ({
725
873
  name={name}
726
874
  schemaName={mergedSchemaName}
727
875
  required={
728
- Array.isArray(mergedSchemas.required)
729
- ? mergedSchemas.required.includes(name)
730
- : mergedSchemas.required
876
+ Array.isArray(required) ? required.includes(name) : required
731
877
  }
732
878
  nullable={mergedSchemas.nullable}
733
879
  schema={mergedSchemas}
734
880
  schemaType={schemaType}
881
+ schemaPath={schemaPath}
735
882
  />
736
883
  );
737
884
  }
@@ -742,30 +889,30 @@ const SchemaEdge: React.FC<SchemaEdgeProps> = ({
742
889
  name={name}
743
890
  schemaName={mergedSchemaName}
744
891
  required={
745
- Array.isArray(mergedSchemas.required)
746
- ? mergedSchemas.required.includes(name)
747
- : mergedSchemas.required
892
+ Array.isArray(required) ? required.includes(name) : required
748
893
  }
749
894
  nullable={mergedSchemas.nullable}
750
895
  schema={mergedSchemas}
751
896
  schemaType={schemaType}
897
+ schemaPath={schemaPath}
752
898
  />
753
899
  );
754
900
  }
755
901
 
756
902
  if (mergedSchemas.items?.properties) {
757
- <SchemaNodeDetails
758
- name={name}
759
- schemaName={mergedSchemaName}
760
- required={
761
- Array.isArray(mergedSchemas.required)
762
- ? mergedSchemas.required.includes(name)
763
- : mergedSchemas.required
764
- }
765
- nullable={mergedSchemas.nullable}
766
- schema={mergedSchemas}
767
- schemaType={schemaType}
768
- />;
903
+ return (
904
+ <SchemaNodeDetails
905
+ name={name}
906
+ schemaName={mergedSchemaName}
907
+ required={
908
+ Array.isArray(required) ? required.includes(name) : required
909
+ }
910
+ nullable={mergedSchemas.nullable}
911
+ schema={mergedSchemas}
912
+ schemaType={schemaType}
913
+ schemaPath={schemaPath}
914
+ />
915
+ );
769
916
  }
770
917
 
771
918
  return (
@@ -798,24 +945,51 @@ const SchemaEdge: React.FC<SchemaEdgeProps> = ({
798
945
 
799
946
  function renderChildren(
800
947
  schema: SchemaObject,
801
- schemaType: "request" | "response"
948
+ schemaType: "request" | "response",
949
+ schemaPath?: string
802
950
  ) {
803
951
  return (
804
952
  <>
805
- {schema.oneOf && <AnyOneOf schema={schema} schemaType={schemaType} />}
806
- {schema.anyOf && <AnyOneOf schema={schema} schemaType={schemaType} />}
953
+ {schema.oneOf && (
954
+ <AnyOneOf
955
+ schema={schema}
956
+ schemaType={schemaType}
957
+ schemaPath={schemaPath}
958
+ />
959
+ )}
960
+ {schema.anyOf && (
961
+ <AnyOneOf
962
+ schema={schema}
963
+ schemaType={schemaType}
964
+ schemaPath={schemaPath}
965
+ />
966
+ )}
807
967
  {schema.properties && (
808
- <Properties schema={schema} schemaType={schemaType} />
968
+ <Properties
969
+ schema={schema}
970
+ schemaType={schemaType}
971
+ schemaPath={schemaPath}
972
+ />
809
973
  )}
810
974
  {schema.additionalProperties && (
811
975
  <AdditionalProperties schema={schema} schemaType={schemaType} />
812
976
  )}
813
- {schema.items && <Items schema={schema} schemaType={schemaType} />}
977
+ {schema.items && (
978
+ <Items
979
+ schema={schema}
980
+ schemaType={schemaType}
981
+ schemaPath={schemaPath}
982
+ />
983
+ )}
814
984
  </>
815
985
  );
816
986
  }
817
987
 
818
- const SchemaNode: React.FC<SchemaProps> = ({ schema, schemaType }) => {
988
+ const SchemaNode: React.FC<SchemaProps> = ({
989
+ schema,
990
+ schemaType,
991
+ schemaPath,
992
+ }) => {
819
993
  if (
820
994
  (schemaType === "request" && schema.readOnly) ||
821
995
  (schemaType === "response" && schema.writeOnly)
@@ -836,6 +1010,63 @@ const SchemaNode: React.FC<SchemaProps> = ({ schema, schemaType }) => {
836
1010
 
837
1011
  // Handle allOf, oneOf, anyOf without discriminators
838
1012
  if (schema.allOf) {
1013
+ // Check if allOf contains multiple oneOf/anyOf items that should be rendered separately
1014
+ const oneOfItems = schema.allOf.filter(
1015
+ (item: any) => item.oneOf || item.anyOf
1016
+ );
1017
+ const hasMultipleChoices = oneOfItems.length > 1;
1018
+
1019
+ if (hasMultipleChoices) {
1020
+ // Render each oneOf/anyOf constraint first, then shared properties
1021
+ const mergedSchemas = mergeAllOf(schema) as SchemaObject;
1022
+
1023
+ if (
1024
+ (schemaType === "request" && mergedSchemas.readOnly) ||
1025
+ (schemaType === "response" && mergedSchemas.writeOnly)
1026
+ ) {
1027
+ return null;
1028
+ }
1029
+
1030
+ return (
1031
+ <div>
1032
+ {/* Render all oneOf/anyOf constraints first */}
1033
+ {schema.allOf.map((item: any, index: number) => {
1034
+ if (item.oneOf || item.anyOf) {
1035
+ const itemSchemaPath = schemaPath
1036
+ ? `${schemaPath}.allOf.${index}`
1037
+ : undefined;
1038
+ return (
1039
+ <div key={index}>
1040
+ <AnyOneOf
1041
+ schema={item}
1042
+ schemaType={schemaType}
1043
+ schemaPath={itemSchemaPath}
1044
+ />
1045
+ </div>
1046
+ );
1047
+ }
1048
+ return null;
1049
+ })}
1050
+ {/* Then render shared properties from the merge */}
1051
+ {mergedSchemas.properties && (
1052
+ <Properties
1053
+ schema={mergedSchemas}
1054
+ schemaType={schemaType}
1055
+ schemaPath={schemaPath}
1056
+ />
1057
+ )}
1058
+ {mergedSchemas.items && (
1059
+ <Items
1060
+ schema={mergedSchemas}
1061
+ schemaType={schemaType}
1062
+ schemaPath={schemaPath}
1063
+ />
1064
+ )}
1065
+ </div>
1066
+ );
1067
+ }
1068
+
1069
+ // For other allOf cases, use standard merge behavior
839
1070
  const mergedSchemas = mergeAllOf(schema) as SchemaObject;
840
1071
 
841
1072
  if (
@@ -848,16 +1079,32 @@ const SchemaNode: React.FC<SchemaProps> = ({ schema, schemaType }) => {
848
1079
  return (
849
1080
  <div>
850
1081
  {mergedSchemas.oneOf && (
851
- <AnyOneOf schema={mergedSchemas} schemaType={schemaType} />
1082
+ <AnyOneOf
1083
+ schema={mergedSchemas}
1084
+ schemaType={schemaType}
1085
+ schemaPath={schemaPath}
1086
+ />
852
1087
  )}
853
1088
  {mergedSchemas.anyOf && (
854
- <AnyOneOf schema={mergedSchemas} schemaType={schemaType} />
1089
+ <AnyOneOf
1090
+ schema={mergedSchemas}
1091
+ schemaType={schemaType}
1092
+ schemaPath={schemaPath}
1093
+ />
855
1094
  )}
856
1095
  {mergedSchemas.properties && (
857
- <Properties schema={mergedSchemas} schemaType={schemaType} />
1096
+ <Properties
1097
+ schema={mergedSchemas}
1098
+ schemaType={schemaType}
1099
+ schemaPath={schemaPath}
1100
+ />
858
1101
  )}
859
1102
  {mergedSchemas.items && (
860
- <Items schema={mergedSchemas} schemaType={schemaType} />
1103
+ <Items
1104
+ schema={mergedSchemas}
1105
+ schemaType={schemaType}
1106
+ schemaPath={schemaPath}
1107
+ />
861
1108
  )}
862
1109
  </div>
863
1110
  );
@@ -888,7 +1135,7 @@ const SchemaNode: React.FC<SchemaProps> = ({ schema, schemaType }) => {
888
1135
  );
889
1136
  }
890
1137
 
891
- return renderChildren(schema, schemaType);
1138
+ return renderChildren(schema, schemaType, schemaPath);
892
1139
  };
893
1140
 
894
1141
  export default SchemaNode;
@@ -904,5 +1151,10 @@ const PRIMITIVE_TYPES: Record<PrimitiveSchemaType, true> = {
904
1151
  } as const;
905
1152
 
906
1153
  const isPrimitive = (schema: SchemaObject) => {
1154
+ // Enum-only schemas (without explicit type) should be treated as primitives
1155
+ // This is valid JSON Schema where enum values define the constraints
1156
+ if (schema.enum && !schema.type) {
1157
+ return true;
1158
+ }
907
1159
  return PRIMITIVE_TYPES[schema.type as PrimitiveSchemaType];
908
1160
  };