docusaurus-theme-openapi-docs 5.0.2 → 5.1.1
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.
- package/lib/markdown/schema.js +38 -15
- package/lib/markdown/schema.test.d.ts +1 -0
- package/lib/markdown/schema.test.js +86 -0
- package/lib/theme/ApiExplorer/ApiCodeBlock/Container/index.js +4 -2
- package/lib/theme/ApiExplorer/ApiCodeBlock/Content/String.js +9 -6
- package/lib/theme/ApiExplorer/ApiCodeBlock/Line/index.d.ts +1 -1
- package/lib/theme/ApiExplorer/ApiCodeBlock/index.d.ts +1 -1
- package/lib/theme/ApiExplorer/Authorization/index.js +9 -10
- package/lib/theme/ApiExplorer/Body/index.js +4 -5
- package/lib/theme/ApiExplorer/CodeSnippets/index.js +96 -61
- package/lib/theme/ApiExplorer/CodeSnippets/languages.js +12 -1
- package/lib/theme/ApiExplorer/CodeSnippets/languages.test.d.ts +1 -0
- package/lib/theme/ApiExplorer/CodeSnippets/languages.test.js +102 -0
- package/lib/theme/ApiExplorer/CodeTabs/index.d.ts +1 -1
- package/lib/theme/ApiExplorer/CodeTabs/index.js +6 -5
- package/lib/theme/ApiExplorer/Export/index.js +9 -2
- package/lib/theme/ApiExplorer/FormFileUpload/index.js +1 -2
- package/lib/theme/ApiExplorer/FormLabel/index.js +1 -2
- package/lib/theme/ApiExplorer/FormTextInput/index.js +1 -2
- package/lib/theme/ApiExplorer/LiveEditor/index.js +1 -2
- package/lib/theme/ApiExplorer/ParamOptions/ParamFormItems/ParamArrayFormItem.js +5 -3
- package/lib/theme/ApiExplorer/ParamOptions/ParamFormItems/ParamBooleanFormItem.js +75 -4
- package/lib/theme/ApiExplorer/ParamOptions/ParamFormItems/ParamMultiSelectFormItem.js +1 -2
- package/lib/theme/ApiExplorer/ParamOptions/ParamFormItems/ParamSelectFormItem.js +67 -4
- package/lib/theme/ApiExplorer/ParamOptions/ParamFormItems/ParamTextFormItem.js +65 -1
- package/lib/theme/ApiExplorer/ParamOptions/index.js +2 -3
- package/lib/theme/ApiExplorer/Request/index.js +17 -18
- package/lib/theme/ApiExplorer/Response/index.js +54 -12
- package/lib/theme/ApiExplorer/SecuritySchemes/index.js +57 -50
- package/lib/theme/ApiExplorer/Server/index.js +2 -3
- package/lib/theme/ApiItem/index.js +59 -33
- package/lib/theme/ApiTabs/index.d.ts +1 -1
- package/lib/theme/ApiTabs/index.js +7 -7
- package/lib/theme/DiscriminatorTabs/index.d.ts +1 -1
- package/lib/theme/DiscriminatorTabs/index.js +6 -5
- package/lib/theme/Example/index.js +3 -4
- package/lib/theme/MimeTabs/index.d.ts +1 -1
- package/lib/theme/MimeTabs/index.js +6 -5
- package/lib/theme/OperationTabs/index.d.ts +1 -1
- package/lib/theme/OperationTabs/index.js +6 -5
- package/lib/theme/ParamsDetails/index.js +1 -2
- package/lib/theme/ParamsItem/index.js +7 -8
- package/lib/theme/RequestSchema/index.js +57 -57
- package/lib/theme/ResponseExamples/index.js +3 -4
- package/lib/theme/ResponseSchema/index.js +26 -24
- package/lib/theme/Schema/index.js +148 -110
- package/lib/theme/Schema/normalize.d.ts +41 -0
- package/lib/theme/Schema/normalize.js +210 -0
- package/lib/theme/Schema/normalize.test.d.ts +1 -0
- package/lib/theme/Schema/normalize.test.js +271 -0
- package/lib/theme/SchemaExpansion/_SchemaExpansion.scss +113 -0
- package/lib/theme/SchemaExpansion/context.d.ts +24 -0
- package/lib/theme/SchemaExpansion/context.js +187 -0
- package/lib/theme/SchemaExpansion/index.d.ts +4 -0
- package/lib/theme/SchemaExpansion/index.js +314 -0
- package/lib/theme/SchemaItem/index.js +9 -10
- package/lib/theme/SchemaTabs/index.d.ts +1 -1
- package/lib/theme/SchemaTabs/index.js +6 -5
- package/lib/theme/StatusCodes/index.js +2 -4
- package/lib/theme/TabItem/index.d.ts +5 -0
- package/lib/theme/TabItem/index.js +51 -0
- package/lib/theme/TabItem/styles.module.css +3 -0
- package/lib/theme/Tabs/index.d.ts +5 -0
- package/lib/theme/Tabs/index.js +148 -0
- package/lib/theme/Tabs/styles.module.css +7 -0
- package/lib/theme/styles.scss +1 -0
- package/lib/theme/translationIds.d.ts +1 -93
- package/lib/theme/translationIds.js +0 -109
- package/lib/theme/utils/codeBlockUtils.d.ts +28 -0
- package/lib/theme/utils/codeBlockUtils.js +223 -0
- package/lib/theme/utils/reactUtils.d.ts +1 -0
- package/lib/theme/utils/reactUtils.js +23 -0
- package/lib/theme/utils/scrollUtils.d.ts +7 -0
- package/lib/theme/utils/scrollUtils.js +175 -0
- package/lib/theme/utils/tabsUtils.d.ts +47 -0
- package/lib/theme/utils/tabsUtils.js +299 -0
- package/lib/theme/utils/useCodeWordWrap.d.ts +8 -0
- package/lib/theme/utils/useCodeWordWrap.js +84 -0
- package/lib/theme/utils/useMutationObserver.d.ts +3 -0
- package/lib/theme/utils/useMutationObserver.js +34 -0
- package/package.json +4 -4
- package/src/markdown/schema.test.ts +102 -0
- package/src/markdown/schema.ts +42 -15
- package/src/theme/ApiExplorer/ApiCodeBlock/Container/index.tsx +2 -1
- package/src/theme/ApiExplorer/ApiCodeBlock/Content/String.tsx +8 -7
- package/src/theme/ApiExplorer/ApiCodeBlock/Line/index.tsx +1 -1
- package/src/theme/ApiExplorer/ApiCodeBlock/index.tsx +1 -1
- package/src/theme/ApiExplorer/Authorization/index.tsx +9 -10
- package/src/theme/ApiExplorer/Body/index.tsx +7 -5
- package/src/theme/ApiExplorer/CodeSnippets/index.tsx +103 -59
- package/src/theme/ApiExplorer/CodeSnippets/languages.test.ts +109 -0
- package/src/theme/ApiExplorer/CodeSnippets/languages.ts +13 -1
- package/src/theme/ApiExplorer/CodeTabs/index.tsx +5 -5
- package/src/theme/ApiExplorer/Export/index.tsx +6 -2
- package/src/theme/ApiExplorer/FormFileUpload/index.tsx +1 -2
- package/src/theme/ApiExplorer/FormLabel/index.tsx +1 -2
- package/src/theme/ApiExplorer/FormTextInput/index.tsx +1 -2
- package/src/theme/ApiExplorer/LiveEditor/index.tsx +1 -2
- package/src/theme/ApiExplorer/ParamOptions/ParamFormItems/ParamArrayFormItem.tsx +5 -3
- package/src/theme/ApiExplorer/ParamOptions/ParamFormItems/ParamBooleanFormItem.tsx +20 -4
- package/src/theme/ApiExplorer/ParamOptions/ParamFormItems/ParamMultiSelectFormItem.tsx +1 -2
- package/src/theme/ApiExplorer/ParamOptions/ParamFormItems/ParamSelectFormItem.tsx +15 -4
- package/src/theme/ApiExplorer/ParamOptions/ParamFormItems/ParamTextFormItem.tsx +11 -1
- package/src/theme/ApiExplorer/ParamOptions/index.tsx +2 -3
- package/src/theme/ApiExplorer/Request/index.tsx +23 -18
- package/src/theme/ApiExplorer/Response/index.tsx +63 -9
- package/src/theme/ApiExplorer/SecuritySchemes/index.tsx +60 -52
- package/src/theme/ApiExplorer/Server/index.tsx +8 -3
- package/src/theme/ApiItem/index.tsx +43 -21
- package/src/theme/ApiTabs/index.tsx +8 -8
- package/src/theme/DiscriminatorTabs/index.tsx +6 -5
- package/src/theme/Example/index.tsx +3 -4
- package/src/theme/MimeTabs/index.tsx +9 -8
- package/src/theme/OperationTabs/index.tsx +5 -4
- package/src/theme/ParamsDetails/index.tsx +1 -2
- package/src/theme/ParamsItem/index.tsx +13 -8
- package/src/theme/RequestSchema/index.tsx +38 -40
- package/src/theme/ResponseExamples/index.tsx +3 -4
- package/src/theme/ResponseSchema/index.tsx +16 -17
- package/src/theme/Schema/index.tsx +154 -121
- package/src/theme/Schema/normalize.test.ts +288 -0
- package/src/theme/Schema/normalize.ts +224 -0
- package/src/theme/SchemaExpansion/_SchemaExpansion.scss +113 -0
- package/src/theme/SchemaExpansion/context.tsx +154 -0
- package/src/theme/SchemaExpansion/index.tsx +236 -0
- package/src/theme/SchemaItem/index.tsx +18 -10
- package/src/theme/SchemaTabs/index.tsx +6 -5
- package/src/theme/StatusCodes/index.tsx +2 -3
- package/src/theme/TabItem/index.tsx +61 -0
- package/src/theme/TabItem/styles.module.css +3 -0
- package/src/theme/Tabs/index.tsx +164 -0
- package/src/theme/Tabs/styles.module.css +7 -0
- package/src/theme/styles.scss +1 -0
- package/src/theme/translationIds.ts +37 -106
- package/src/theme/utils/codeBlockUtils.ts +296 -0
- package/src/theme/utils/reactUtils.ts +22 -0
- package/src/theme/utils/scrollUtils.tsx +153 -0
- package/src/theme/utils/tabsUtils.tsx +329 -0
- package/src/theme/utils/useCodeWordWrap.ts +110 -0
- package/src/theme/utils/useMutationObserver.ts +43 -0
- package/src/theme-classic.d.ts +0 -96
- package/src/types.d.ts +27 -0
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* LICENSE file in the root directory of this source tree.
|
|
6
6
|
* ========================================================================== */
|
|
7
7
|
|
|
8
|
-
import React, { useCallback } from "react";
|
|
8
|
+
import React, { useCallback, useMemo } from "react";
|
|
9
9
|
|
|
10
10
|
import { translate } from "@docusaurus/Translate";
|
|
11
11
|
import { setSchemaSelection } from "@theme/ApiExplorer/SchemaSelection/slice";
|
|
@@ -14,105 +14,28 @@ import { ClosingArrayBracket, OpeningArrayBracket } from "@theme/ArrayBrackets";
|
|
|
14
14
|
import Details from "@theme/Details";
|
|
15
15
|
import DiscriminatorTabs from "@theme/DiscriminatorTabs";
|
|
16
16
|
import Markdown from "@theme/Markdown";
|
|
17
|
+
import {
|
|
18
|
+
findPropertyDeep,
|
|
19
|
+
foldSiblingsIntoBranches,
|
|
20
|
+
getDiscriminator,
|
|
21
|
+
isCircularMarker,
|
|
22
|
+
mergeAllOf,
|
|
23
|
+
normalizeSchema,
|
|
24
|
+
} from "@theme/Schema/normalize";
|
|
25
|
+
import {
|
|
26
|
+
SchemaDepthProvider,
|
|
27
|
+
useSchemaDepth,
|
|
28
|
+
useSchemaExpansion,
|
|
29
|
+
} from "@theme/SchemaExpansion";
|
|
17
30
|
import SchemaItem from "@theme/SchemaItem";
|
|
18
31
|
import SchemaTabs from "@theme/SchemaTabs";
|
|
19
32
|
import TabItem from "@theme/TabItem";
|
|
20
|
-
import { OPENAPI_SCHEMA_ITEM } from "@theme/translationIds";
|
|
21
|
-
// eslint-disable-next-line import/no-extraneous-dependencies
|
|
22
|
-
import { merge } from "allof-merge";
|
|
23
33
|
import clsx from "clsx";
|
|
24
34
|
import isEmpty from "lodash/isEmpty";
|
|
25
35
|
|
|
26
36
|
import { getQualifierMessage, getSchemaName } from "../../markdown/schema";
|
|
27
37
|
import type { SchemaObject } from "../../types.d";
|
|
28
38
|
|
|
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
|
-
/**
|
|
43
|
-
* Recursively searches for a property in a schema, including nested
|
|
44
|
-
* oneOf, anyOf, and allOf structures. This is needed for discriminators
|
|
45
|
-
* where the property definition may be in a nested schema.
|
|
46
|
-
*/
|
|
47
|
-
const findProperty = (
|
|
48
|
-
schema: SchemaObject,
|
|
49
|
-
propertyName: string
|
|
50
|
-
): SchemaObject | undefined => {
|
|
51
|
-
// Check direct properties first
|
|
52
|
-
if (schema.properties?.[propertyName]) {
|
|
53
|
-
return schema.properties[propertyName];
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
// Search in oneOf schemas
|
|
57
|
-
if (schema.oneOf) {
|
|
58
|
-
for (const subschema of schema.oneOf) {
|
|
59
|
-
const found = findProperty(subschema as SchemaObject, propertyName);
|
|
60
|
-
if (found) return found;
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
// Search in anyOf schemas
|
|
65
|
-
if (schema.anyOf) {
|
|
66
|
-
for (const subschema of schema.anyOf) {
|
|
67
|
-
const found = findProperty(subschema as SchemaObject, propertyName);
|
|
68
|
-
if (found) return found;
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
// Search in allOf schemas
|
|
73
|
-
if (schema.allOf) {
|
|
74
|
-
for (const subschema of schema.allOf) {
|
|
75
|
-
const found = findProperty(subschema as SchemaObject, propertyName);
|
|
76
|
-
if (found) return found;
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
return undefined;
|
|
81
|
-
};
|
|
82
|
-
|
|
83
|
-
/**
|
|
84
|
-
* Recursively searches for a discriminator in a schema, including nested
|
|
85
|
-
* oneOf, anyOf, and allOf structures.
|
|
86
|
-
*/
|
|
87
|
-
const findDiscriminator = (schema: SchemaObject): any | undefined => {
|
|
88
|
-
if (schema.discriminator) {
|
|
89
|
-
return schema.discriminator;
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
if (schema.oneOf) {
|
|
93
|
-
for (const subschema of schema.oneOf) {
|
|
94
|
-
const found = findDiscriminator(subschema as SchemaObject);
|
|
95
|
-
if (found) return found;
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
if (schema.anyOf) {
|
|
100
|
-
for (const subschema of schema.anyOf) {
|
|
101
|
-
const found = findDiscriminator(subschema as SchemaObject);
|
|
102
|
-
if (found) return found;
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
if (schema.allOf) {
|
|
107
|
-
for (const subschema of schema.allOf) {
|
|
108
|
-
const found = findDiscriminator(subschema as SchemaObject);
|
|
109
|
-
if (found) return found;
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
return undefined;
|
|
114
|
-
};
|
|
115
|
-
|
|
116
39
|
interface MarkdownProps {
|
|
117
40
|
text: string | undefined;
|
|
118
41
|
}
|
|
@@ -165,7 +88,7 @@ const Summary: React.FC<SummaryProps> = ({
|
|
|
165
88
|
{nullable && (
|
|
166
89
|
<span className="openapi-schema__nullable">
|
|
167
90
|
{translate({
|
|
168
|
-
id:
|
|
91
|
+
id: "theme.openapi.schemaItem.nullable",
|
|
169
92
|
message: "nullable",
|
|
170
93
|
})}
|
|
171
94
|
</span>
|
|
@@ -173,7 +96,7 @@ const Summary: React.FC<SummaryProps> = ({
|
|
|
173
96
|
{isRequired && (
|
|
174
97
|
<span className="openapi-schema__required">
|
|
175
98
|
{translate({
|
|
176
|
-
id:
|
|
99
|
+
id: "theme.openapi.schemaItem.required",
|
|
177
100
|
message: "required",
|
|
178
101
|
})}
|
|
179
102
|
</span>
|
|
@@ -181,7 +104,7 @@ const Summary: React.FC<SummaryProps> = ({
|
|
|
181
104
|
{deprecated && (
|
|
182
105
|
<span className="openapi-schema__deprecated">
|
|
183
106
|
{translate({
|
|
184
|
-
id:
|
|
107
|
+
id: "theme.openapi.schemaItem.deprecated",
|
|
185
108
|
message: "deprecated",
|
|
186
109
|
})}
|
|
187
110
|
</span>
|
|
@@ -218,8 +141,8 @@ const AnyOneOf: React.FC<SchemaProps> = ({
|
|
|
218
141
|
}
|
|
219
142
|
|
|
220
143
|
const type = schema.oneOf
|
|
221
|
-
? translate({ id:
|
|
222
|
-
: translate({ id:
|
|
144
|
+
? translate({ id: "theme.openapi.schemaItem.oneOf", message: "oneOf" })
|
|
145
|
+
: translate({ id: "theme.openapi.schemaItem.anyOf", message: "anyOf" });
|
|
223
146
|
|
|
224
147
|
// Generate a unique ID for this anyOf/oneOf to prevent tab value collisions
|
|
225
148
|
const uniqueId = React.useMemo(
|
|
@@ -268,12 +191,12 @@ const AnyOneOf: React.FC<SchemaProps> = ({
|
|
|
268
191
|
if (!label) {
|
|
269
192
|
if (anyOneSchema.oneOf) {
|
|
270
193
|
label = translate({
|
|
271
|
-
id:
|
|
194
|
+
id: "theme.openapi.schemaItem.oneOf",
|
|
272
195
|
message: "oneOf",
|
|
273
196
|
});
|
|
274
197
|
} else if (anyOneSchema.anyOf) {
|
|
275
198
|
label = translate({
|
|
276
|
-
id:
|
|
199
|
+
id: "theme.openapi.schemaItem.anyOf",
|
|
277
200
|
message: "anyOf",
|
|
278
201
|
});
|
|
279
202
|
} else {
|
|
@@ -293,6 +216,11 @@ const AnyOneOf: React.FC<SchemaProps> = ({
|
|
|
293
216
|
label={label}
|
|
294
217
|
value={`${uniqueId}-${index}-item`}
|
|
295
218
|
>
|
|
219
|
+
{anyOneSchema.description && (
|
|
220
|
+
<div style={{ marginLeft: "1rem" }}>
|
|
221
|
+
<MarkdownWrapper text={anyOneSchema.description} />
|
|
222
|
+
</div>
|
|
223
|
+
)}
|
|
296
224
|
{/* Handle primitive types directly */}
|
|
297
225
|
{(isPrimitive(anyOneSchema) || anyOneSchema.const) && (
|
|
298
226
|
<SchemaItem
|
|
@@ -454,7 +382,7 @@ const PropertyDiscriminator: React.FC<SchemaEdgeProps> = ({
|
|
|
454
382
|
{required && (
|
|
455
383
|
<span className="openapi-schema__required">
|
|
456
384
|
{translate({
|
|
457
|
-
id:
|
|
385
|
+
id: "theme.openapi.schemaItem.required",
|
|
458
386
|
message: "required",
|
|
459
387
|
})}
|
|
460
388
|
</span>
|
|
@@ -476,6 +404,13 @@ const PropertyDiscriminator: React.FC<SchemaEdgeProps> = ({
|
|
|
476
404
|
label={key}
|
|
477
405
|
value={`${index}-item-discriminator`}
|
|
478
406
|
>
|
|
407
|
+
{discriminator.mapping[key]?.description && (
|
|
408
|
+
<div style={{ marginLeft: "1rem" }}>
|
|
409
|
+
<MarkdownWrapper
|
|
410
|
+
text={discriminator.mapping[key].description}
|
|
411
|
+
/>
|
|
412
|
+
</div>
|
|
413
|
+
)}
|
|
479
414
|
<SchemaNode
|
|
480
415
|
schema={discriminator.mapping[key]}
|
|
481
416
|
schemaType={schemaType}
|
|
@@ -521,9 +456,11 @@ const DiscriminatorNode: React.FC<DiscriminatorNodeProps> = ({
|
|
|
521
456
|
let discriminatedSchemas: any = {};
|
|
522
457
|
let inferredMapping: any = {};
|
|
523
458
|
|
|
524
|
-
// Search for the discriminator property in the schema, including nested
|
|
459
|
+
// Search for the discriminator property in the schema, including nested
|
|
460
|
+
// structures. Cached recursive lookup replaces the O(subtree) findProperty
|
|
461
|
+
// walk that caused #1525's O(N^2) render cost.
|
|
525
462
|
const discriminatorProperty =
|
|
526
|
-
|
|
463
|
+
findPropertyDeep(schema, discriminator.propertyName) ?? {};
|
|
527
464
|
|
|
528
465
|
if (schema.allOf) {
|
|
529
466
|
const mergedSchemas = mergeAllOf(schema) as SchemaObject;
|
|
@@ -604,6 +541,20 @@ const AdditionalProperties: React.FC<SchemaProps> = ({
|
|
|
604
541
|
|
|
605
542
|
if (!additionalProperties) return null;
|
|
606
543
|
|
|
544
|
+
if (isCircularMarker(additionalProperties)) {
|
|
545
|
+
return (
|
|
546
|
+
<SchemaItem
|
|
547
|
+
name="property name*"
|
|
548
|
+
required={false}
|
|
549
|
+
schemaName={additionalProperties}
|
|
550
|
+
schema={additionalProperties}
|
|
551
|
+
collapsible={false}
|
|
552
|
+
discriminator={false}
|
|
553
|
+
children={null}
|
|
554
|
+
/>
|
|
555
|
+
);
|
|
556
|
+
}
|
|
557
|
+
|
|
607
558
|
// Handle free-form objects
|
|
608
559
|
if (additionalProperties === true || isEmpty(additionalProperties)) {
|
|
609
560
|
return (
|
|
@@ -676,10 +627,15 @@ const SchemaNodeDetails: React.FC<SchemaEdgeProps> = ({
|
|
|
676
627
|
schemaType,
|
|
677
628
|
schemaPath,
|
|
678
629
|
}) => {
|
|
630
|
+
const depth = useSchemaDepth();
|
|
631
|
+
const { level } = useSchemaExpansion();
|
|
632
|
+
const defaultOpen = depth < level;
|
|
679
633
|
return (
|
|
680
634
|
<SchemaItem collapsible={true}>
|
|
681
635
|
<Details
|
|
636
|
+
key={`level-${level}`}
|
|
682
637
|
className="openapi-markdown__details"
|
|
638
|
+
open={defaultOpen}
|
|
683
639
|
summary={
|
|
684
640
|
<Summary
|
|
685
641
|
name={name}
|
|
@@ -694,11 +650,13 @@ const SchemaNodeDetails: React.FC<SchemaEdgeProps> = ({
|
|
|
694
650
|
{getQualifierMessage(schema) && (
|
|
695
651
|
<MarkdownWrapper text={getQualifierMessage(schema)} />
|
|
696
652
|
)}
|
|
697
|
-
<
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
653
|
+
<SchemaDepthProvider depth={depth + 1}>
|
|
654
|
+
<SchemaNode
|
|
655
|
+
schema={schema}
|
|
656
|
+
schemaType={schemaType}
|
|
657
|
+
schemaPath={schemaPath}
|
|
658
|
+
/>
|
|
659
|
+
</SchemaDepthProvider>
|
|
702
660
|
</div>
|
|
703
661
|
</Details>
|
|
704
662
|
</SchemaItem>
|
|
@@ -710,6 +668,23 @@ const Items: React.FC<{
|
|
|
710
668
|
schemaType: "request" | "response";
|
|
711
669
|
schemaPath?: string;
|
|
712
670
|
}> = ({ schema, schemaType, schemaPath }) => {
|
|
671
|
+
if (isCircularMarker(schema.items)) {
|
|
672
|
+
return (
|
|
673
|
+
<div style={{ marginLeft: ".5rem" }}>
|
|
674
|
+
<OpeningArrayBracket />
|
|
675
|
+
<SchemaItem
|
|
676
|
+
collapsible={false}
|
|
677
|
+
name=""
|
|
678
|
+
schemaName={schema.items}
|
|
679
|
+
schema={schema.items}
|
|
680
|
+
discriminator={false}
|
|
681
|
+
children={null}
|
|
682
|
+
/>
|
|
683
|
+
<ClosingArrayBracket />
|
|
684
|
+
</div>
|
|
685
|
+
);
|
|
686
|
+
}
|
|
687
|
+
|
|
713
688
|
// Process schema.items to handle allOf merging
|
|
714
689
|
let itemsSchema = schema.items;
|
|
715
690
|
if (schema.items?.allOf) {
|
|
@@ -725,17 +700,25 @@ const Items: React.FC<{
|
|
|
725
700
|
const itemsSchemaPath = schemaPath ? `${schemaPath}.items` : undefined;
|
|
726
701
|
|
|
727
702
|
if (hasOneOfAnyOf || hasProperties || hasAdditionalProperties) {
|
|
703
|
+
// Fold sibling properties into each oneOf/anyOf branch to avoid duplicate
|
|
704
|
+
// property rendering. See issue #1218.
|
|
705
|
+
const renderSchema =
|
|
706
|
+
hasOneOfAnyOf && hasProperties
|
|
707
|
+
? foldSiblingsIntoBranches(itemsSchema)
|
|
708
|
+
: itemsSchema;
|
|
709
|
+
const renderHasProperties =
|
|
710
|
+
hasOneOfAnyOf && hasProperties ? false : hasProperties;
|
|
728
711
|
return (
|
|
729
712
|
<>
|
|
730
713
|
<OpeningArrayBracket />
|
|
731
714
|
{hasOneOfAnyOf && (
|
|
732
715
|
<AnyOneOf
|
|
733
|
-
schema={
|
|
716
|
+
schema={renderSchema}
|
|
734
717
|
schemaType={schemaType}
|
|
735
718
|
schemaPath={itemsSchemaPath}
|
|
736
719
|
/>
|
|
737
720
|
)}
|
|
738
|
-
{
|
|
721
|
+
{renderHasProperties && (
|
|
739
722
|
<Properties
|
|
740
723
|
schema={itemsSchema}
|
|
741
724
|
schemaType={schemaType}
|
|
@@ -822,6 +805,20 @@ const SchemaEdge: React.FC<SchemaEdgeProps> = ({
|
|
|
822
805
|
return null;
|
|
823
806
|
}
|
|
824
807
|
|
|
808
|
+
if (isCircularMarker(schema)) {
|
|
809
|
+
return (
|
|
810
|
+
<SchemaItem
|
|
811
|
+
collapsible={false}
|
|
812
|
+
name={name}
|
|
813
|
+
required={Array.isArray(required) ? required.includes(name) : required}
|
|
814
|
+
schemaName={schema}
|
|
815
|
+
schema={schema}
|
|
816
|
+
discriminator={false}
|
|
817
|
+
children={null}
|
|
818
|
+
/>
|
|
819
|
+
);
|
|
820
|
+
}
|
|
821
|
+
|
|
825
822
|
const schemaName = getSchemaName(schema);
|
|
826
823
|
|
|
827
824
|
if (discriminator && discriminator.propertyName === name) {
|
|
@@ -908,6 +905,20 @@ const SchemaEdge: React.FC<SchemaEdgeProps> = ({
|
|
|
908
905
|
);
|
|
909
906
|
}
|
|
910
907
|
|
|
908
|
+
if (isCircularMarker(schema.items)) {
|
|
909
|
+
return (
|
|
910
|
+
<SchemaNodeDetails
|
|
911
|
+
name={name}
|
|
912
|
+
schemaName={schemaName}
|
|
913
|
+
required={required}
|
|
914
|
+
nullable={schema.nullable}
|
|
915
|
+
schema={schema}
|
|
916
|
+
schemaType={schemaType}
|
|
917
|
+
schemaPath={schemaPath}
|
|
918
|
+
/>
|
|
919
|
+
);
|
|
920
|
+
}
|
|
921
|
+
|
|
911
922
|
if (schema.allOf) {
|
|
912
923
|
// handle circular properties
|
|
913
924
|
if (
|
|
@@ -1020,23 +1031,31 @@ function renderChildren(
|
|
|
1020
1031
|
schemaType: "request" | "response",
|
|
1021
1032
|
schemaPath?: string
|
|
1022
1033
|
) {
|
|
1034
|
+
// Fold sibling properties into each oneOf/anyOf branch to avoid duplicate
|
|
1035
|
+
// property rendering. See issue #1218.
|
|
1036
|
+
const hasOneOfAnyOf = !!(schema.oneOf || schema.anyOf);
|
|
1037
|
+
const hasProperties = !!schema.properties;
|
|
1038
|
+
const folded =
|
|
1039
|
+
hasOneOfAnyOf && hasProperties ? foldSiblingsIntoBranches(schema) : schema;
|
|
1040
|
+
const renderProperties =
|
|
1041
|
+
hasOneOfAnyOf && hasProperties ? false : hasProperties;
|
|
1023
1042
|
return (
|
|
1024
1043
|
<>
|
|
1025
|
-
{
|
|
1044
|
+
{folded.oneOf && (
|
|
1026
1045
|
<AnyOneOf
|
|
1027
|
-
schema={
|
|
1046
|
+
schema={folded}
|
|
1028
1047
|
schemaType={schemaType}
|
|
1029
1048
|
schemaPath={schemaPath}
|
|
1030
1049
|
/>
|
|
1031
1050
|
)}
|
|
1032
|
-
{
|
|
1051
|
+
{folded.anyOf && (
|
|
1033
1052
|
<AnyOneOf
|
|
1034
|
-
schema={
|
|
1053
|
+
schema={folded}
|
|
1035
1054
|
schemaType={schemaType}
|
|
1036
1055
|
schemaPath={schemaPath}
|
|
1037
1056
|
/>
|
|
1038
1057
|
)}
|
|
1039
|
-
{
|
|
1058
|
+
{renderProperties && (
|
|
1040
1059
|
<Properties
|
|
1041
1060
|
schema={schema}
|
|
1042
1061
|
schemaType={schemaType}
|
|
@@ -1058,10 +1077,12 @@ function renderChildren(
|
|
|
1058
1077
|
}
|
|
1059
1078
|
|
|
1060
1079
|
const SchemaNode: React.FC<SchemaProps> = ({
|
|
1061
|
-
schema,
|
|
1080
|
+
schema: rawSchema,
|
|
1062
1081
|
schemaType,
|
|
1063
1082
|
schemaPath,
|
|
1064
1083
|
}) => {
|
|
1084
|
+
const schema = useMemo(() => normalizeSchema(rawSchema), [rawSchema]);
|
|
1085
|
+
|
|
1065
1086
|
if (
|
|
1066
1087
|
(schemaType === "request" && schema.readOnly) ||
|
|
1067
1088
|
(schemaType === "response" && schema.writeOnly)
|
|
@@ -1070,10 +1091,11 @@ const SchemaNode: React.FC<SchemaProps> = ({
|
|
|
1070
1091
|
}
|
|
1071
1092
|
|
|
1072
1093
|
// Resolve discriminator recursively so nested oneOf/anyOf/allOf compositions
|
|
1073
|
-
// can still render discriminator tabs.
|
|
1094
|
+
// can still render discriminator tabs. Cached via getDiscriminator so per-
|
|
1095
|
+
// render cost is O(1) amortized (see #1525).
|
|
1074
1096
|
let workingSchema = schema;
|
|
1075
1097
|
const resolvedDiscriminator =
|
|
1076
|
-
schema.discriminator ??
|
|
1098
|
+
schema.discriminator ?? getDiscriminator(schema);
|
|
1077
1099
|
if (schema.allOf && !schema.discriminator && resolvedDiscriminator) {
|
|
1078
1100
|
workingSchema = mergeAllOf(schema) as SchemaObject;
|
|
1079
1101
|
}
|
|
@@ -1160,23 +1182,34 @@ const SchemaNode: React.FC<SchemaProps> = ({
|
|
|
1160
1182
|
return null;
|
|
1161
1183
|
}
|
|
1162
1184
|
|
|
1185
|
+
// Fold sibling properties into each oneOf/anyOf branch to avoid duplicate
|
|
1186
|
+
// property rendering. See issue #1218.
|
|
1187
|
+
const hasOneOfAnyOf = !!(mergedSchemas.oneOf || mergedSchemas.anyOf);
|
|
1188
|
+
const hasProperties = !!mergedSchemas.properties;
|
|
1189
|
+
const folded =
|
|
1190
|
+
hasOneOfAnyOf && hasProperties
|
|
1191
|
+
? foldSiblingsIntoBranches(mergedSchemas)
|
|
1192
|
+
: mergedSchemas;
|
|
1193
|
+
const renderProperties =
|
|
1194
|
+
hasOneOfAnyOf && hasProperties ? false : hasProperties;
|
|
1195
|
+
|
|
1163
1196
|
return (
|
|
1164
1197
|
<div>
|
|
1165
|
-
{
|
|
1198
|
+
{folded.oneOf && (
|
|
1166
1199
|
<AnyOneOf
|
|
1167
|
-
schema={
|
|
1200
|
+
schema={folded}
|
|
1168
1201
|
schemaType={schemaType}
|
|
1169
1202
|
schemaPath={schemaPath}
|
|
1170
1203
|
/>
|
|
1171
1204
|
)}
|
|
1172
|
-
{
|
|
1205
|
+
{folded.anyOf && (
|
|
1173
1206
|
<AnyOneOf
|
|
1174
|
-
schema={
|
|
1207
|
+
schema={folded}
|
|
1175
1208
|
schemaType={schemaType}
|
|
1176
1209
|
schemaPath={schemaPath}
|
|
1177
1210
|
/>
|
|
1178
1211
|
)}
|
|
1179
|
-
{
|
|
1212
|
+
{renderProperties && (
|
|
1180
1213
|
<Properties
|
|
1181
1214
|
schema={mergedSchemas}
|
|
1182
1215
|
schemaType={schemaType}
|