docusaurus-theme-openapi-docs 4.1.0 → 4.2.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 (43) hide show
  1. package/lib/theme/ApiExplorer/CodeSnippets/index.js +2 -1
  2. package/lib/theme/ApiExplorer/CodeTabs/_CodeTabs.scss +50 -0
  3. package/lib/theme/ApiItem/Layout/index.js +6 -2
  4. package/lib/theme/ApiItem/index.js +15 -4
  5. package/lib/theme/ApiTabs/_ApiTabs.scss +0 -1
  6. package/lib/theme/ArrayBrackets/index.d.ts +3 -0
  7. package/lib/theme/ArrayBrackets/index.js +50 -0
  8. package/lib/theme/ParamsDetails/index.d.ts +6 -0
  9. package/lib/theme/ParamsDetails/index.js +134 -0
  10. package/lib/theme/ParamsItem/index.d.ts +1 -0
  11. package/lib/theme/ParamsItem/index.js +10 -6
  12. package/lib/theme/RequestSchema/index.d.ts +15 -0
  13. package/lib/theme/RequestSchema/index.js +235 -0
  14. package/lib/theme/ResponseExamples/index.d.ts +48 -0
  15. package/lib/theme/ResponseExamples/index.js +290 -0
  16. package/lib/theme/ResponseSchema/index.d.ts +15 -0
  17. package/lib/theme/ResponseSchema/index.js +206 -0
  18. package/lib/theme/Schema/index.d.ts +8 -0
  19. package/lib/theme/Schema/index.js +879 -0
  20. package/lib/theme/SchemaItem/index.d.ts +8 -8
  21. package/lib/theme/SchemaItem/index.js +9 -5
  22. package/lib/theme/SkeletonLoader/index.d.ts +6 -0
  23. package/lib/theme/SkeletonLoader/index.js +20 -0
  24. package/lib/theme/StatusCodes/index.d.ts +9 -0
  25. package/lib/theme/StatusCodes/index.js +78 -0
  26. package/lib/theme/styles.scss +56 -9
  27. package/package.json +6 -5
  28. package/src/theme/ApiExplorer/CodeSnippets/index.tsx +2 -1
  29. package/src/theme/ApiExplorer/CodeTabs/_CodeTabs.scss +50 -0
  30. package/src/theme/ApiItem/Layout/index.tsx +5 -2
  31. package/src/theme/ApiItem/index.tsx +14 -2
  32. package/src/theme/ApiTabs/_ApiTabs.scss +0 -1
  33. package/src/theme/ArrayBrackets/index.tsx +37 -0
  34. package/src/theme/ParamsDetails/index.tsx +88 -0
  35. package/src/theme/ParamsItem/index.tsx +10 -7
  36. package/src/theme/RequestSchema/index.tsx +164 -0
  37. package/src/theme/ResponseExamples/index.tsx +290 -0
  38. package/src/theme/ResponseSchema/index.tsx +151 -0
  39. package/src/theme/Schema/index.tsx +928 -0
  40. package/src/theme/SchemaItem/index.tsx +15 -13
  41. package/src/theme/SkeletonLoader/index.tsx +18 -0
  42. package/src/theme/StatusCodes/index.tsx +72 -0
  43. package/src/theme/styles.scss +56 -9
@@ -0,0 +1,928 @@
1
+ /* ============================================================================
2
+ * Copyright (c) Palo Alto Networks
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ * ========================================================================== */
7
+
8
+ import React from "react";
9
+
10
+ import { ClosingArrayBracket, OpeningArrayBracket } from "@theme/ArrayBrackets";
11
+ import Details from "@theme/Details";
12
+ import DiscriminatorTabs from "@theme/DiscriminatorTabs";
13
+ import SchemaItem from "@theme/SchemaItem";
14
+ import SchemaTabs from "@theme/SchemaTabs";
15
+ import TabItem from "@theme/TabItem";
16
+ // eslint-disable-next-line import/no-extraneous-dependencies
17
+ import { merge } from "allof-merge";
18
+ import clsx from "clsx";
19
+ import { createDescription } from "docusaurus-plugin-openapi-docs/lib/markdown/createDescription";
20
+ import {
21
+ getQualifierMessage,
22
+ getSchemaName,
23
+ } from "docusaurus-plugin-openapi-docs/lib/markdown/schema";
24
+ import { SchemaObject } from "docusaurus-plugin-openapi-docs/lib/openapi/types";
25
+ import isEmpty from "lodash/isEmpty";
26
+ import ReactMarkdown from "react-markdown";
27
+ import rehypeRaw from "rehype-raw";
28
+
29
+ // eslint-disable-next-line import/no-extraneous-dependencies
30
+ // const jsonSchemaMergeAllOf = require("json-schema-merge-allof");
31
+
32
+ const mergeAllOf = (allOf: any) => {
33
+ const onMergeError = (msg: string) => {
34
+ console.warn(msg);
35
+ };
36
+
37
+ const mergedSchemas = merge(allOf, { onMergeError });
38
+
39
+ return mergedSchemas;
40
+ };
41
+
42
+ interface MarkdownProps {
43
+ text: string | undefined;
44
+ }
45
+
46
+ // Renders string as markdown, useful for descriptions and qualifiers
47
+ const Markdown: React.FC<MarkdownProps> = ({ text }) => {
48
+ return (
49
+ <div style={{ marginTop: ".5rem", marginBottom: ".5rem" }}>
50
+ <ReactMarkdown
51
+ children={createDescription(text)}
52
+ rehypePlugins={[rehypeRaw]}
53
+ />
54
+ </div>
55
+ );
56
+ };
57
+
58
+ interface SummaryProps {
59
+ name: string;
60
+ schemaName: string | undefined;
61
+ schema: {
62
+ deprecated?: boolean;
63
+ nullable?: boolean;
64
+ };
65
+ required?: boolean | string[];
66
+ }
67
+
68
+ const Summary: React.FC<SummaryProps> = ({
69
+ name,
70
+ schemaName,
71
+ schema,
72
+ required,
73
+ }) => {
74
+ const { deprecated, nullable } = schema;
75
+
76
+ const isRequired = Array.isArray(required)
77
+ ? required.includes(name)
78
+ : required === true;
79
+
80
+ return (
81
+ <summary>
82
+ <span className="openapi-schema__container">
83
+ <strong
84
+ className={clsx("openapi-schema__property", {
85
+ "openapi-schema__strikethrough": deprecated,
86
+ })}
87
+ >
88
+ {name}
89
+ </strong>
90
+ <span className="openapi-schema__name"> {schemaName}</span>
91
+ {(isRequired || deprecated || nullable) && (
92
+ <span className="openapi-schema__divider" />
93
+ )}
94
+ {nullable && <span className="openapi-schema__nullable">nullable</span>}
95
+ {isRequired && (
96
+ <span className="openapi-schema__required">required</span>
97
+ )}
98
+ {deprecated && (
99
+ <span className="openapi-schema__deprecated">deprecated</span>
100
+ )}
101
+ </span>
102
+ </summary>
103
+ );
104
+ };
105
+
106
+ // Common props interface
107
+ interface SchemaProps {
108
+ schema: SchemaObject;
109
+ schemaType: "request" | "response";
110
+ }
111
+
112
+ const AnyOneOf: React.FC<SchemaProps> = ({ schema, schemaType }) => {
113
+ const type = schema.oneOf ? "oneOf" : "anyOf";
114
+ return (
115
+ <>
116
+ <span className="badge badge--info" style={{ marginBottom: "1rem" }}>
117
+ {type}
118
+ </span>
119
+ <SchemaTabs>
120
+ {schema[type]?.map((anyOneSchema: any, index: number) => {
121
+ const label = anyOneSchema.title || `MOD${index + 1}`;
122
+ return (
123
+ // @ts-ignore
124
+ <TabItem
125
+ key={index}
126
+ label={label}
127
+ value={`${index}-item-properties`}
128
+ >
129
+ {/* Handle primitive types directly */}
130
+ {["string", "number", "integer", "boolean"].includes(
131
+ anyOneSchema.type
132
+ ) && (
133
+ <SchemaItem
134
+ collapsible={false}
135
+ name={undefined}
136
+ schemaName={anyOneSchema.type}
137
+ qualifierMessage={getQualifierMessage(anyOneSchema)}
138
+ schema={anyOneSchema}
139
+ discriminator={false}
140
+ children={null}
141
+ />
142
+ )}
143
+
144
+ {/* Handle empty object as a primitive type */}
145
+ {anyOneSchema.type === "object" &&
146
+ !anyOneSchema.properties &&
147
+ !anyOneSchema.allOf &&
148
+ !anyOneSchema.oneOf &&
149
+ !anyOneSchema.anyOf && (
150
+ <SchemaItem
151
+ collapsible={false}
152
+ name={undefined}
153
+ schemaName={anyOneSchema.type}
154
+ qualifierMessage={getQualifierMessage(anyOneSchema)}
155
+ schema={anyOneSchema}
156
+ discriminator={false}
157
+ children={null}
158
+ />
159
+ )}
160
+
161
+ {/* Handle actual object types with properties or nested schemas */}
162
+ {anyOneSchema.type === "object" && anyOneSchema.properties && (
163
+ <Properties schema={anyOneSchema} schemaType={schemaType} />
164
+ )}
165
+ {anyOneSchema.allOf && (
166
+ <SchemaNode schema={anyOneSchema} schemaType={schemaType} />
167
+ )}
168
+ {anyOneSchema.oneOf && (
169
+ <SchemaNode schema={anyOneSchema} schemaType={schemaType} />
170
+ )}
171
+ {anyOneSchema.anyOf && (
172
+ <SchemaNode schema={anyOneSchema} schemaType={schemaType} />
173
+ )}
174
+ {anyOneSchema.items && (
175
+ <Items schema={anyOneSchema} schemaType={schemaType} />
176
+ )}
177
+ </TabItem>
178
+ );
179
+ })}
180
+ </SchemaTabs>
181
+ </>
182
+ );
183
+ };
184
+
185
+ const Properties: React.FC<SchemaProps> = ({ schema, schemaType }) => {
186
+ const discriminator = schema.discriminator;
187
+ if (discriminator && !discriminator.mapping) {
188
+ const anyOneOf = schema.oneOf ?? schema.anyOf ?? {};
189
+ const inferredMapping = {} as any;
190
+ Object.entries(anyOneOf).map(([_, anyOneSchema]: [string, any]) => {
191
+ // ensure discriminated property only renders once
192
+ if (
193
+ schema.properties![discriminator.propertyName] &&
194
+ anyOneSchema.properties[discriminator.propertyName]
195
+ )
196
+ delete anyOneSchema.properties[discriminator.propertyName];
197
+ return (inferredMapping[anyOneSchema.title] = anyOneSchema);
198
+ });
199
+ discriminator["mapping"] = inferredMapping;
200
+ }
201
+ if (Object.keys(schema.properties as {}).length === 0) {
202
+ return (
203
+ <SchemaItem
204
+ collapsible={false}
205
+ name=""
206
+ required={false}
207
+ schemaName="object"
208
+ qualifierMessage={undefined}
209
+ schema={{}}
210
+ />
211
+ );
212
+ }
213
+
214
+ return (
215
+ <>
216
+ {Object.entries(schema.properties as {}).map(
217
+ ([key, val]: [string, any]) => (
218
+ <SchemaEdge
219
+ key={key}
220
+ name={key}
221
+ schema={val}
222
+ required={
223
+ Array.isArray(schema.required)
224
+ ? schema.required.includes(key)
225
+ : false
226
+ }
227
+ discriminator={discriminator}
228
+ schemaType={schemaType}
229
+ />
230
+ )
231
+ )}
232
+ </>
233
+ );
234
+ };
235
+
236
+ const PropertyDiscriminator: React.FC<SchemaEdgeProps> = ({
237
+ name,
238
+ schemaName,
239
+ schema,
240
+ schemaType,
241
+ discriminator,
242
+ required,
243
+ }) => {
244
+ if (!schema) {
245
+ return null;
246
+ }
247
+
248
+ return (
249
+ <>
250
+ <div className="openapi-discriminator__item openapi-schema__list-item">
251
+ <div>
252
+ <span className="openapi-schema__container">
253
+ <strong className="openapi-discriminator__name openapi-schema__property">
254
+ {name}
255
+ </strong>
256
+ {schemaName && (
257
+ <span className="openapi-schema__name"> {schemaName}</span>
258
+ )}
259
+ {required && <span className="openapi-schema__divider"></span>}
260
+ {required && (
261
+ <span className="openapi-schema__required">required</span>
262
+ )}
263
+ </span>
264
+ <div style={{ marginLeft: "1rem" }}>
265
+ {schema.description && <Markdown text={schema.description} />}
266
+ {getQualifierMessage(discriminator) && (
267
+ <Markdown text={getQualifierMessage(discriminator)} />
268
+ )}
269
+ </div>
270
+ <DiscriminatorTabs className="openapi-tabs__discriminator">
271
+ {Object.keys(discriminator.mapping).map((key, index) => (
272
+ // @ts-ignore
273
+ <TabItem
274
+ key={index}
275
+ label={key}
276
+ value={`${index}-item-discriminator`}
277
+ >
278
+ <SchemaNode
279
+ schema={discriminator.mapping[key]}
280
+ schemaType={schemaType}
281
+ />
282
+ </TabItem>
283
+ ))}
284
+ </DiscriminatorTabs>
285
+ </div>
286
+ </div>
287
+ {schema.properties &&
288
+ Object.entries(schema.properties as {}).map(
289
+ ([key, val]: [string, any]) =>
290
+ key !== discriminator.propertyName && (
291
+ <SchemaEdge
292
+ key={key}
293
+ name={key}
294
+ schema={val}
295
+ required={
296
+ Array.isArray(schema.required)
297
+ ? schema.required.includes(key)
298
+ : false
299
+ }
300
+ discriminator={false}
301
+ schemaType={schemaType}
302
+ />
303
+ )
304
+ )}
305
+ </>
306
+ );
307
+ };
308
+
309
+ interface DiscriminatorNodeProps {
310
+ discriminator: any;
311
+ schema: SchemaObject;
312
+ schemaType: "request" | "response";
313
+ }
314
+
315
+ const DiscriminatorNode: React.FC<DiscriminatorNodeProps> = ({
316
+ discriminator,
317
+ schema,
318
+ schemaType,
319
+ }) => {
320
+ let discriminatedSchemas: any = {};
321
+ let inferredMapping: any = {};
322
+
323
+ const discriminatorProperty = schema.properties![discriminator.propertyName];
324
+
325
+ if (schema.allOf) {
326
+ const mergedSchemas = mergeAllOf(schema) as SchemaObject;
327
+ if (mergedSchemas.oneOf || mergedSchemas.anyOf) {
328
+ discriminatedSchemas = mergedSchemas.oneOf || mergedSchemas.anyOf;
329
+ }
330
+ } else if (schema.oneOf || schema.anyOf) {
331
+ discriminatedSchemas = schema.oneOf || schema.anyOf;
332
+ }
333
+
334
+ // Handle case where no mapping is defined
335
+ if (!discriminator.mapping) {
336
+ Object.entries(discriminatedSchemas).forEach(
337
+ ([_, subschema]: [string, any], index) => {
338
+ inferredMapping[subschema.title ?? `PROP${index}`] = subschema;
339
+ }
340
+ );
341
+ discriminator.mapping = inferredMapping;
342
+ }
343
+
344
+ // Merge sub schema discriminator property with parent
345
+ Object.keys(discriminator.mapping).forEach((key) => {
346
+ const subSchema = discriminator.mapping[key];
347
+
348
+ // Handle discriminated schema with allOf
349
+ let mergedSubSchema = {} as SchemaObject;
350
+ if (subSchema.allOf) {
351
+ mergedSubSchema = mergeAllOf(subSchema) as SchemaObject;
352
+ }
353
+
354
+ const subProperties = subSchema.properties || mergedSubSchema.properties;
355
+ if (subProperties[discriminator.propertyName]) {
356
+ schema.properties![discriminator.propertyName] = {
357
+ ...schema.properties![discriminator.propertyName],
358
+ ...subProperties[discriminator.propertyName],
359
+ };
360
+ if (subSchema.required && !schema.required) {
361
+ schema.required = subSchema.required;
362
+ }
363
+ // Avoid duplicating property
364
+ delete subProperties[discriminator.propertyName];
365
+ }
366
+ });
367
+
368
+ const name = discriminator.propertyName;
369
+ const schemaName = getSchemaName(discriminatorProperty);
370
+
371
+ // Default case for discriminator without oneOf/anyOf/allOf
372
+ return (
373
+ <PropertyDiscriminator
374
+ name={name}
375
+ schemaName={schemaName}
376
+ schema={schema}
377
+ schemaType={schemaType}
378
+ discriminator={discriminator}
379
+ required={
380
+ Array.isArray(schema.required)
381
+ ? schema.required.includes(name)
382
+ : schema.required
383
+ }
384
+ />
385
+ );
386
+ };
387
+
388
+ const AdditionalProperties: React.FC<SchemaProps> = ({
389
+ schema,
390
+ schemaType,
391
+ }) => {
392
+ const additionalProperties = schema.additionalProperties;
393
+
394
+ if (!additionalProperties) return null;
395
+
396
+ // Handle free-form objects
397
+ if (additionalProperties === true || isEmpty(additionalProperties)) {
398
+ return (
399
+ <SchemaItem
400
+ name="property name*"
401
+ required={false}
402
+ schemaName="any"
403
+ qualifierMessage={getQualifierMessage(schema)}
404
+ schema={schema}
405
+ collapsible={false}
406
+ discriminator={false}
407
+ />
408
+ );
409
+ }
410
+
411
+ // Handle objects, arrays, complex schemas
412
+ if (
413
+ additionalProperties.properties ||
414
+ additionalProperties.items ||
415
+ additionalProperties.allOf ||
416
+ additionalProperties.additionalProperties ||
417
+ additionalProperties.oneOf ||
418
+ additionalProperties.anyOf
419
+ ) {
420
+ const title =
421
+ additionalProperties.title || getSchemaName(additionalProperties);
422
+ const required = schema.required || false;
423
+ return (
424
+ <SchemaNodeDetails
425
+ name="property name*"
426
+ schemaName={title}
427
+ required={required}
428
+ nullable={schema.nullable}
429
+ schema={additionalProperties}
430
+ schemaType={schemaType}
431
+ />
432
+ );
433
+ }
434
+
435
+ // Handle primitive types
436
+ if (
437
+ additionalProperties.type === "string" ||
438
+ additionalProperties.type === "boolean" ||
439
+ additionalProperties.type === "integer" ||
440
+ additionalProperties.type === "number" ||
441
+ additionalProperties.type === "object"
442
+ ) {
443
+ const schemaName = getSchemaName(additionalProperties);
444
+ return (
445
+ <SchemaItem
446
+ name="property name*"
447
+ required={false}
448
+ schemaName={schemaName}
449
+ qualifierMessage={getQualifierMessage(schema)}
450
+ schema={additionalProperties}
451
+ collapsible={false}
452
+ discriminator={false}
453
+ children={null}
454
+ />
455
+ );
456
+ }
457
+
458
+ // Unknown type
459
+ return null;
460
+ };
461
+
462
+ const SchemaNodeDetails: React.FC<SchemaEdgeProps> = ({
463
+ name,
464
+ schemaName,
465
+ schema,
466
+ required,
467
+ schemaType,
468
+ }) => {
469
+ return (
470
+ <SchemaItem collapsible={true}>
471
+ <Details
472
+ className="openapi-markdown__details"
473
+ summary={
474
+ <Summary
475
+ name={name}
476
+ schemaName={schemaName}
477
+ schema={schema}
478
+ required={required}
479
+ />
480
+ }
481
+ >
482
+ <div style={{ marginLeft: "1rem" }}>
483
+ {schema.description && <Markdown text={schema.description} />}
484
+ {getQualifierMessage(schema) && (
485
+ <Markdown text={getQualifierMessage(schema)} />
486
+ )}
487
+ <SchemaNode schema={schema} schemaType={schemaType} />
488
+ </div>
489
+ </Details>
490
+ </SchemaItem>
491
+ );
492
+ };
493
+
494
+ const Items: React.FC<{
495
+ schema: any;
496
+ schemaType: "request" | "response";
497
+ }> = ({ schema, schemaType }) => {
498
+ // Handles case when schema.items has properties
499
+ if (schema.items?.properties) {
500
+ return (
501
+ <>
502
+ <OpeningArrayBracket />
503
+ <Properties schema={schema.items} schemaType={schemaType} />
504
+ <ClosingArrayBracket />
505
+ </>
506
+ );
507
+ }
508
+
509
+ // Handles case when schema.items has additionalProperties
510
+ if (schema.items?.additionalProperties) {
511
+ return (
512
+ <>
513
+ <OpeningArrayBracket />
514
+ <AdditionalProperties schema={schema.items} schemaType={schemaType} />
515
+ <ClosingArrayBracket />
516
+ </>
517
+ );
518
+ }
519
+
520
+ // Handles case when schema.items has oneOf or anyOf
521
+ if (schema.items?.oneOf || schema.items?.anyOf) {
522
+ return (
523
+ <>
524
+ <OpeningArrayBracket />
525
+ <AnyOneOf schema={schema.items} schemaType={schemaType} />
526
+ <ClosingArrayBracket />
527
+ </>
528
+ );
529
+ }
530
+
531
+ // Handles case when schema.items has allOf
532
+ if (schema.items?.allOf) {
533
+ const mergedSchemas = mergeAllOf(schema.items) as SchemaObject;
534
+
535
+ // Handles combo anyOf/oneOf + properties
536
+ if (
537
+ (mergedSchemas.oneOf || mergedSchemas.anyOf) &&
538
+ mergedSchemas.properties
539
+ ) {
540
+ return (
541
+ <>
542
+ <OpeningArrayBracket />
543
+ <AnyOneOf schema={mergedSchemas} schemaType={schemaType} />
544
+ <Properties schema={mergedSchemas} schemaType={schemaType} />
545
+ <ClosingArrayBracket />
546
+ </>
547
+ );
548
+ }
549
+
550
+ // Handles only anyOf/oneOf
551
+ if (mergedSchemas.oneOf || mergedSchemas.anyOf) {
552
+ return (
553
+ <>
554
+ <OpeningArrayBracket />
555
+ <AnyOneOf schema={mergedSchemas} schemaType={schemaType} />
556
+ <ClosingArrayBracket />
557
+ </>
558
+ );
559
+ }
560
+
561
+ // Handles properties
562
+ if (mergedSchemas.properties) {
563
+ return (
564
+ <>
565
+ <OpeningArrayBracket />
566
+ <Properties schema={mergedSchemas} schemaType={schemaType} />
567
+ <ClosingArrayBracket />
568
+ </>
569
+ );
570
+ }
571
+ }
572
+
573
+ // Handles basic types (string, number, integer, boolean, object)
574
+ if (
575
+ schema.items?.type === "string" ||
576
+ schema.items?.type === "number" ||
577
+ schema.items?.type === "integer" ||
578
+ schema.items?.type === "boolean" ||
579
+ schema.items?.type === "object"
580
+ ) {
581
+ return (
582
+ <div style={{ marginLeft: ".5rem" }}>
583
+ <OpeningArrayBracket />
584
+ <SchemaItem
585
+ collapsible={false}
586
+ name="" // No name for array items
587
+ schemaName={getSchemaName(schema.items)}
588
+ qualifierMessage={getQualifierMessage(schema.items)}
589
+ schema={schema.items}
590
+ discriminator={false}
591
+ children={null}
592
+ />
593
+ <ClosingArrayBracket />
594
+ </div>
595
+ );
596
+ }
597
+
598
+ // Handles fallback case (use createEdges logic)
599
+ return (
600
+ <>
601
+ <OpeningArrayBracket />
602
+ {Object.entries(schema.items || {}).map(([key, val]: [string, any]) => (
603
+ <SchemaEdge
604
+ key={key}
605
+ name={key}
606
+ schema={val}
607
+ schemaType={schemaType}
608
+ required={
609
+ Array.isArray(schema.required)
610
+ ? schema.required.includes(key)
611
+ : false
612
+ }
613
+ />
614
+ ))}
615
+ <ClosingArrayBracket />
616
+ </>
617
+ );
618
+ };
619
+
620
+ interface SchemaEdgeProps {
621
+ name: string;
622
+ schemaName?: string;
623
+ schema: SchemaObject;
624
+ required?: boolean | string[];
625
+ nullable?: boolean | undefined;
626
+ discriminator?: any;
627
+ schemaType: "request" | "response";
628
+ }
629
+
630
+ const SchemaEdge: React.FC<SchemaEdgeProps> = ({
631
+ name,
632
+ schema,
633
+ required,
634
+ discriminator,
635
+ schemaType,
636
+ }) => {
637
+ if (
638
+ (schemaType === "request" && schema.readOnly) ||
639
+ (schemaType === "response" && schema.writeOnly)
640
+ ) {
641
+ return null;
642
+ }
643
+
644
+ const schemaName = getSchemaName(schema);
645
+
646
+ if (discriminator && discriminator.propertyName === name) {
647
+ return (
648
+ <PropertyDiscriminator
649
+ name={name}
650
+ schemaName={schemaName}
651
+ schema={schema}
652
+ schemaType={schemaType}
653
+ discriminator={discriminator}
654
+ required={required}
655
+ />
656
+ );
657
+ }
658
+
659
+ if (schema.oneOf || schema.anyOf) {
660
+ // return <AnyOneOf schema={schema} schemaType={schemaType} />;
661
+ return (
662
+ <SchemaNodeDetails
663
+ name={name}
664
+ schemaName={schemaName}
665
+ schemaType={schemaType}
666
+ required={required}
667
+ schema={schema}
668
+ nullable={schema.nullable}
669
+ />
670
+ );
671
+ }
672
+
673
+ if (schema.properties) {
674
+ return (
675
+ <SchemaNodeDetails
676
+ name={name}
677
+ schemaName={schemaName}
678
+ schemaType={schemaType}
679
+ required={required}
680
+ schema={schema}
681
+ nullable={schema.nullable}
682
+ />
683
+ );
684
+ }
685
+
686
+ if (schema.additionalProperties) {
687
+ return (
688
+ <SchemaNodeDetails
689
+ name={name}
690
+ schemaName={schemaName}
691
+ schemaType={schemaType}
692
+ required={required}
693
+ schema={schema}
694
+ nullable={schema.nullable}
695
+ />
696
+ );
697
+ }
698
+
699
+ if (schema.items?.properties) {
700
+ return (
701
+ <SchemaNodeDetails
702
+ name={name}
703
+ schemaName={schemaName}
704
+ required={required}
705
+ nullable={schema.nullable}
706
+ schema={schema}
707
+ schemaType={schemaType}
708
+ />
709
+ );
710
+ }
711
+
712
+ if (schema.items?.anyOf || schema.items?.oneOf) {
713
+ return (
714
+ <SchemaNodeDetails
715
+ name={name}
716
+ schemaName={schemaName}
717
+ required={required}
718
+ nullable={schema.nullable}
719
+ schema={schema}
720
+ schemaType={schemaType}
721
+ />
722
+ );
723
+ }
724
+
725
+ if (schema.allOf) {
726
+ // handle circular properties
727
+ if (
728
+ schema.allOf &&
729
+ schema.allOf.length &&
730
+ schema.allOf.length === 1 &&
731
+ typeof schema.allOf[0] === "string"
732
+ ) {
733
+ return (
734
+ <SchemaItem
735
+ collapsible={false}
736
+ name={name}
737
+ required={
738
+ Array.isArray(required) ? required.includes(name) : required
739
+ }
740
+ schemaName={schema.allOf[0]}
741
+ qualifierMessage={undefined}
742
+ schema={schema.allOf[0]}
743
+ discriminator={false}
744
+ children={null}
745
+ />
746
+ );
747
+ }
748
+ const mergedSchemas = mergeAllOf(schema) as SchemaObject;
749
+
750
+ if (
751
+ (schemaType === "request" && mergedSchemas.readOnly) ||
752
+ (schemaType === "response" && mergedSchemas.writeOnly)
753
+ ) {
754
+ return null;
755
+ }
756
+
757
+ const mergedSchemaName = getSchemaName(mergedSchemas);
758
+
759
+ if (mergedSchemas.oneOf || mergedSchemas.anyOf) {
760
+ return (
761
+ <SchemaNodeDetails
762
+ name={name}
763
+ schemaName={mergedSchemaName}
764
+ required={
765
+ Array.isArray(mergedSchemas.required)
766
+ ? mergedSchemas.required.includes(name)
767
+ : mergedSchemas.required
768
+ }
769
+ nullable={mergedSchemas.nullable}
770
+ schema={mergedSchemas}
771
+ schemaType={schemaType}
772
+ />
773
+ );
774
+ }
775
+
776
+ if (mergedSchemas.properties !== undefined) {
777
+ return (
778
+ <SchemaNodeDetails
779
+ name={name}
780
+ schemaName={mergedSchemaName}
781
+ required={
782
+ Array.isArray(mergedSchemas.required)
783
+ ? mergedSchemas.required.includes(name)
784
+ : mergedSchemas.required
785
+ }
786
+ nullable={mergedSchemas.nullable}
787
+ schema={mergedSchemas}
788
+ schemaType={schemaType}
789
+ />
790
+ );
791
+ }
792
+
793
+ if (mergedSchemas.items?.properties) {
794
+ <SchemaNodeDetails
795
+ name={name}
796
+ schemaName={mergedSchemaName}
797
+ required={
798
+ Array.isArray(mergedSchemas.required)
799
+ ? mergedSchemas.required.includes(name)
800
+ : mergedSchemas.required
801
+ }
802
+ nullable={mergedSchemas.nullable}
803
+ schema={mergedSchemas}
804
+ schemaType={schemaType}
805
+ />;
806
+ }
807
+
808
+ return (
809
+ <SchemaItem
810
+ collapsible={false}
811
+ name={name}
812
+ required={Array.isArray(required) ? required.includes(name) : required}
813
+ schemaName={mergedSchemaName}
814
+ qualifierMessage={getQualifierMessage(mergedSchemas)}
815
+ schema={mergedSchemas}
816
+ discriminator={false}
817
+ children={null}
818
+ />
819
+ );
820
+ }
821
+
822
+ return (
823
+ <SchemaItem
824
+ collapsible={false}
825
+ name={name}
826
+ required={Array.isArray(required) ? required.includes(name) : required}
827
+ schemaName={schemaName}
828
+ qualifierMessage={getQualifierMessage(schema)}
829
+ schema={schema}
830
+ discriminator={false}
831
+ children={null}
832
+ />
833
+ );
834
+ };
835
+
836
+ const SchemaNode: React.FC<SchemaProps> = ({ schema, schemaType }) => {
837
+ if (
838
+ (schemaType === "request" && schema.readOnly) ||
839
+ (schemaType === "response" && schema.writeOnly)
840
+ ) {
841
+ return null;
842
+ }
843
+
844
+ if (schema.discriminator) {
845
+ const { discriminator } = schema;
846
+ return (
847
+ <DiscriminatorNode
848
+ discriminator={discriminator}
849
+ schema={schema}
850
+ schemaType={schemaType}
851
+ />
852
+ );
853
+ }
854
+
855
+ // Handle allOf, oneOf, anyOf without discriminators
856
+ if (schema.allOf) {
857
+ const mergedSchemas = mergeAllOf(schema) as SchemaObject;
858
+
859
+ if (
860
+ (schemaType === "request" && mergedSchemas.readOnly) ||
861
+ (schemaType === "response" && mergedSchemas.writeOnly)
862
+ ) {
863
+ return null;
864
+ }
865
+
866
+ return (
867
+ <div>
868
+ {mergedSchemas.oneOf && (
869
+ <AnyOneOf schema={mergedSchemas} schemaType={schemaType} />
870
+ )}
871
+ {mergedSchemas.anyOf && (
872
+ <AnyOneOf schema={mergedSchemas} schemaType={schemaType} />
873
+ )}
874
+ {mergedSchemas.properties && (
875
+ <Properties schema={mergedSchemas} schemaType={schemaType} />
876
+ )}
877
+ {mergedSchemas.items && (
878
+ <Items schema={mergedSchemas} schemaType={schemaType} />
879
+ )}
880
+ </div>
881
+ );
882
+ }
883
+
884
+ if (schema.oneOf || schema.anyOf) {
885
+ return <AnyOneOf schema={schema} schemaType={schemaType} />;
886
+ }
887
+
888
+ // Handle primitives
889
+ if (
890
+ schema.type &&
891
+ !schema.oneOf &&
892
+ !schema.anyOf &&
893
+ !schema.properties &&
894
+ !schema.allOf &&
895
+ !schema.items &&
896
+ !schema.additionalProperties
897
+ ) {
898
+ const schemaName = getSchemaName(schema);
899
+ return (
900
+ <SchemaItem
901
+ collapsible={false}
902
+ name={schema.type}
903
+ required={Boolean(schema.required)}
904
+ schemaName={schemaName}
905
+ qualifierMessage={getQualifierMessage(schema)}
906
+ schema={schema}
907
+ discriminator={false}
908
+ children={null}
909
+ />
910
+ );
911
+ }
912
+
913
+ return (
914
+ <div>
915
+ {schema.oneOf && <AnyOneOf schema={schema} schemaType={schemaType} />}
916
+ {schema.anyOf && <AnyOneOf schema={schema} schemaType={schemaType} />}
917
+ {schema.properties && (
918
+ <Properties schema={schema} schemaType={schemaType} />
919
+ )}
920
+ {schema.additionalProperties && (
921
+ <AdditionalProperties schema={schema} schemaType={schemaType} />
922
+ )}
923
+ {schema.items && <Items schema={schema} schemaType={schemaType} />}
924
+ </div>
925
+ );
926
+ };
927
+
928
+ export default SchemaNode;