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.
- package/lib/theme/ApiExplorer/CodeSnippets/index.js +2 -1
- package/lib/theme/ApiExplorer/CodeTabs/_CodeTabs.scss +50 -0
- package/lib/theme/ApiItem/Layout/index.js +6 -2
- package/lib/theme/ApiItem/index.js +15 -4
- package/lib/theme/ApiTabs/_ApiTabs.scss +0 -1
- package/lib/theme/ArrayBrackets/index.d.ts +3 -0
- package/lib/theme/ArrayBrackets/index.js +50 -0
- package/lib/theme/ParamsDetails/index.d.ts +6 -0
- package/lib/theme/ParamsDetails/index.js +134 -0
- package/lib/theme/ParamsItem/index.d.ts +1 -0
- package/lib/theme/ParamsItem/index.js +10 -6
- package/lib/theme/RequestSchema/index.d.ts +15 -0
- package/lib/theme/RequestSchema/index.js +235 -0
- package/lib/theme/ResponseExamples/index.d.ts +48 -0
- package/lib/theme/ResponseExamples/index.js +290 -0
- package/lib/theme/ResponseSchema/index.d.ts +15 -0
- package/lib/theme/ResponseSchema/index.js +206 -0
- package/lib/theme/Schema/index.d.ts +8 -0
- package/lib/theme/Schema/index.js +879 -0
- package/lib/theme/SchemaItem/index.d.ts +8 -8
- package/lib/theme/SchemaItem/index.js +9 -5
- package/lib/theme/SkeletonLoader/index.d.ts +6 -0
- package/lib/theme/SkeletonLoader/index.js +20 -0
- package/lib/theme/StatusCodes/index.d.ts +9 -0
- package/lib/theme/StatusCodes/index.js +78 -0
- package/lib/theme/styles.scss +56 -9
- package/package.json +6 -5
- package/src/theme/ApiExplorer/CodeSnippets/index.tsx +2 -1
- package/src/theme/ApiExplorer/CodeTabs/_CodeTabs.scss +50 -0
- package/src/theme/ApiItem/Layout/index.tsx +5 -2
- package/src/theme/ApiItem/index.tsx +14 -2
- package/src/theme/ApiTabs/_ApiTabs.scss +0 -1
- package/src/theme/ArrayBrackets/index.tsx +37 -0
- package/src/theme/ParamsDetails/index.tsx +88 -0
- package/src/theme/ParamsItem/index.tsx +10 -7
- package/src/theme/RequestSchema/index.tsx +164 -0
- package/src/theme/ResponseExamples/index.tsx +290 -0
- package/src/theme/ResponseSchema/index.tsx +151 -0
- package/src/theme/Schema/index.tsx +928 -0
- package/src/theme/SchemaItem/index.tsx +15 -13
- package/src/theme/SkeletonLoader/index.tsx +18 -0
- package/src/theme/StatusCodes/index.tsx +72 -0
- 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;
|