docusaurus-theme-openapi-docs 4.0.1 → 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/markdown/utils.d.ts +5 -4
- package/lib/theme/ApiExplorer/CodeSnippets/code-snippets-types.d.ts +1 -1
- package/lib/theme/ApiExplorer/CodeSnippets/index.js +4 -113
- package/lib/theme/ApiExplorer/CodeSnippets/languages.d.ts +1 -0
- package/lib/theme/ApiExplorer/CodeSnippets/languages.js +30 -6
- package/lib/theme/ApiExplorer/CodeTabs/_CodeTabs.scss +196 -2
- package/lib/theme/ApiExplorer/CodeTabs/index.js +34 -8
- package/lib/theme/ApiExplorer/MethodEndpoint/index.d.ts +2 -1
- package/lib/theme/ApiExplorer/MethodEndpoint/index.js +5 -2
- package/lib/theme/ApiExplorer/ParamOptions/index.js +1 -0
- package/lib/theme/ApiExplorer/Request/_Request.scss +5 -0
- package/lib/theme/ApiExplorer/index.js +6 -0
- package/lib/theme/ApiItem/Layout/index.d.ts +3 -0
- package/lib/theme/ApiItem/Layout/index.js +121 -0
- package/lib/theme/ApiItem/Layout/styles.module.css +17 -0
- package/lib/theme/ApiItem/index.js +16 -5
- 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 +3 -1
- package/lib/theme/ParamsItem/index.js +77 -16
- 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 +9 -9
- package/lib/theme/SchemaItem/index.js +110 -20
- 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 +9 -7
- package/src/markdown/utils.ts +7 -6
- package/src/plugin-content-docs.d.ts +2 -0
- package/src/theme/ApiExplorer/CodeSnippets/code-snippets-types.ts +2 -0
- package/src/theme/ApiExplorer/CodeSnippets/index.tsx +8 -113
- package/src/theme/ApiExplorer/CodeSnippets/languages.ts +26 -5
- package/src/theme/ApiExplorer/CodeTabs/_CodeTabs.scss +196 -2
- package/src/theme/ApiExplorer/CodeTabs/index.tsx +40 -9
- package/src/theme/ApiExplorer/MethodEndpoint/index.tsx +7 -3
- package/src/theme/ApiExplorer/ParamOptions/index.tsx +1 -0
- package/src/theme/ApiExplorer/Request/_Request.scss +5 -0
- package/src/theme/ApiExplorer/index.tsx +2 -0
- package/src/theme/ApiItem/Layout/index.tsx +85 -0
- package/src/theme/ApiItem/Layout/styles.module.css +17 -0
- package/src/theme/ApiItem/index.tsx +15 -3
- 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 +80 -17
- 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 +116 -25
- package/src/theme/SkeletonLoader/index.tsx +18 -0
- package/src/theme/StatusCodes/index.tsx +72 -0
- package/src/theme/styles.scss +56 -9
- package/src/theme-classic.d.ts +0 -2
- package/src/theme-openapi.d.ts +4 -0
|
@@ -0,0 +1,88 @@
|
|
|
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, { Suspense } from "react";
|
|
9
|
+
|
|
10
|
+
import BrowserOnly from "@docusaurus/BrowserOnly";
|
|
11
|
+
import Details from "@theme/Details";
|
|
12
|
+
import ParamsItem from "@theme/ParamsItem";
|
|
13
|
+
import SkeletonLoader from "@theme/SkeletonLoader";
|
|
14
|
+
|
|
15
|
+
interface Props {
|
|
16
|
+
parameters: any[];
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const ParamsDetailsComponent: React.FC<Props> = ({ parameters }) => {
|
|
20
|
+
const types = ["path", "query", "header", "cookie"];
|
|
21
|
+
|
|
22
|
+
return (
|
|
23
|
+
<>
|
|
24
|
+
{types.map((type) => {
|
|
25
|
+
const params = parameters?.filter((param: any) => param?.in === type);
|
|
26
|
+
|
|
27
|
+
if (!params || params.length === 0) {
|
|
28
|
+
return null;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const summaryElement = (
|
|
32
|
+
<summary>
|
|
33
|
+
<h3 className="openapi-markdown__details-summary-header-params">
|
|
34
|
+
{`${type.charAt(0).toUpperCase() + type.slice(1)} Parameters`}
|
|
35
|
+
</h3>
|
|
36
|
+
</summary>
|
|
37
|
+
);
|
|
38
|
+
|
|
39
|
+
return (
|
|
40
|
+
<Details
|
|
41
|
+
key={type}
|
|
42
|
+
className="openapi-markdown__details"
|
|
43
|
+
style={{ marginBottom: "1rem" }}
|
|
44
|
+
data-collapsed={false}
|
|
45
|
+
open={true}
|
|
46
|
+
summary={summaryElement}
|
|
47
|
+
>
|
|
48
|
+
<ul>
|
|
49
|
+
{params.map((param: any, index: number) => (
|
|
50
|
+
<ParamsItem
|
|
51
|
+
key={index}
|
|
52
|
+
className="paramsItem"
|
|
53
|
+
param={{
|
|
54
|
+
...param,
|
|
55
|
+
enumDescriptions: Object.entries(
|
|
56
|
+
param?.schema?.["x-enumDescriptions"] ??
|
|
57
|
+
param?.schema?.items?.["x-enumDescriptions"] ??
|
|
58
|
+
{}
|
|
59
|
+
),
|
|
60
|
+
}}
|
|
61
|
+
/>
|
|
62
|
+
))}
|
|
63
|
+
</ul>
|
|
64
|
+
</Details>
|
|
65
|
+
);
|
|
66
|
+
})}
|
|
67
|
+
</>
|
|
68
|
+
);
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
const ParamsDetails: React.FC<Props> = (props) => {
|
|
72
|
+
return (
|
|
73
|
+
<BrowserOnly fallback={<SkeletonLoader size="sm" />}>
|
|
74
|
+
{() => {
|
|
75
|
+
const LazyComponent = React.lazy(() =>
|
|
76
|
+
Promise.resolve({ default: ParamsDetailsComponent })
|
|
77
|
+
);
|
|
78
|
+
return (
|
|
79
|
+
<Suspense fallback={null}>
|
|
80
|
+
<LazyComponent {...props} />
|
|
81
|
+
</Suspense>
|
|
82
|
+
);
|
|
83
|
+
}}
|
|
84
|
+
</BrowserOnly>
|
|
85
|
+
);
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
export default ParamsDetails;
|
|
@@ -14,6 +14,7 @@ import TabItem from "@theme/TabItem";
|
|
|
14
14
|
import clsx from "clsx";
|
|
15
15
|
import ReactMarkdown from "react-markdown";
|
|
16
16
|
import rehypeRaw from "rehype-raw";
|
|
17
|
+
import remarkGfm from "remark-gfm";
|
|
17
18
|
|
|
18
19
|
import { createDescription } from "../../markdown/createDescription";
|
|
19
20
|
import { getQualifierMessage, getSchemaName } from "../../markdown/schema";
|
|
@@ -31,6 +32,7 @@ export interface ExampleObject {
|
|
|
31
32
|
}
|
|
32
33
|
|
|
33
34
|
export interface Props {
|
|
35
|
+
className: string;
|
|
34
36
|
param: {
|
|
35
37
|
description: string;
|
|
36
38
|
example: any;
|
|
@@ -39,15 +41,49 @@ export interface Props {
|
|
|
39
41
|
required: boolean;
|
|
40
42
|
deprecated: boolean;
|
|
41
43
|
schema: any;
|
|
44
|
+
enumDescriptions?: [string, string][];
|
|
42
45
|
};
|
|
43
46
|
}
|
|
44
47
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
+
const getEnumDescriptionMarkdown = (enumDescriptions?: [string, string][]) => {
|
|
49
|
+
if (enumDescriptions?.length) {
|
|
50
|
+
return `| Enum Value | Description |
|
|
51
|
+
| ---- | ----- |
|
|
52
|
+
${enumDescriptions
|
|
53
|
+
.map((desc) => {
|
|
54
|
+
return `| ${desc[0]} | ${desc[1]} | `.replaceAll("\n", "<br/>");
|
|
55
|
+
})
|
|
56
|
+
.join("\n")}
|
|
57
|
+
`;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
return "";
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
function ParamsItem({ param, ...rest }: Props) {
|
|
64
|
+
const {
|
|
65
|
+
description,
|
|
66
|
+
example,
|
|
67
|
+
examples,
|
|
68
|
+
name,
|
|
69
|
+
required,
|
|
70
|
+
deprecated,
|
|
71
|
+
enumDescriptions,
|
|
72
|
+
} = param;
|
|
73
|
+
|
|
74
|
+
let schema = param.schema;
|
|
75
|
+
let defaultValue: string | undefined;
|
|
76
|
+
|
|
48
77
|
if (!schema || !schema?.type) {
|
|
49
78
|
schema = { type: "any" };
|
|
50
79
|
}
|
|
80
|
+
if (schema) {
|
|
81
|
+
if (schema.items) {
|
|
82
|
+
defaultValue = schema.items.default;
|
|
83
|
+
} else {
|
|
84
|
+
defaultValue = schema.default;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
51
87
|
|
|
52
88
|
const renderSchemaName = guard(schema, (schema) => (
|
|
53
89
|
<span className="openapi-schema__type"> {getSchemaName(schema)}</span>
|
|
@@ -71,7 +107,7 @@ function ParamsItem({
|
|
|
71
107
|
));
|
|
72
108
|
|
|
73
109
|
const renderDescription = guard(description, (description) => (
|
|
74
|
-
|
|
110
|
+
<>
|
|
75
111
|
<ReactMarkdown
|
|
76
112
|
children={createDescription(description)}
|
|
77
113
|
components={{
|
|
@@ -88,22 +124,48 @@ function ParamsItem({
|
|
|
88
124
|
}}
|
|
89
125
|
rehypePlugins={[rehypeRaw]}
|
|
90
126
|
/>
|
|
91
|
-
|
|
127
|
+
</>
|
|
92
128
|
));
|
|
93
129
|
|
|
94
|
-
const
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
130
|
+
const renderEnumDescriptions = guard(
|
|
131
|
+
getEnumDescriptionMarkdown(enumDescriptions),
|
|
132
|
+
(value) => {
|
|
133
|
+
return (
|
|
134
|
+
<div style={{ marginTop: ".5rem" }}>
|
|
135
|
+
<ReactMarkdown
|
|
136
|
+
rehypePlugins={[rehypeRaw]}
|
|
137
|
+
remarkPlugins={[remarkGfm]}
|
|
138
|
+
children={value}
|
|
139
|
+
/>
|
|
140
|
+
</div>
|
|
141
|
+
);
|
|
142
|
+
}
|
|
105
143
|
);
|
|
106
144
|
|
|
145
|
+
function renderDefaultValue() {
|
|
146
|
+
if (defaultValue !== undefined) {
|
|
147
|
+
if (typeof defaultValue === "string") {
|
|
148
|
+
return (
|
|
149
|
+
<div>
|
|
150
|
+
<strong>Default value: </strong>
|
|
151
|
+
<span>
|
|
152
|
+
<code>{defaultValue}</code>
|
|
153
|
+
</span>
|
|
154
|
+
</div>
|
|
155
|
+
);
|
|
156
|
+
}
|
|
157
|
+
return (
|
|
158
|
+
<div>
|
|
159
|
+
<strong>Default value: </strong>
|
|
160
|
+
<span>
|
|
161
|
+
<code>{JSON.stringify(defaultValue)}</code>
|
|
162
|
+
</span>
|
|
163
|
+
</div>
|
|
164
|
+
);
|
|
165
|
+
}
|
|
166
|
+
return undefined;
|
|
167
|
+
}
|
|
168
|
+
|
|
107
169
|
const renderExample = guard(toString(example), (example) => (
|
|
108
170
|
<div>
|
|
109
171
|
<strong>Example: </strong>
|
|
@@ -156,8 +218,9 @@ function ParamsItem({
|
|
|
156
218
|
{renderDeprecated}
|
|
157
219
|
</span>
|
|
158
220
|
{renderSchema}
|
|
159
|
-
{renderDefaultValue}
|
|
160
221
|
{renderDescription}
|
|
222
|
+
{renderEnumDescriptions}
|
|
223
|
+
{renderDefaultValue()}
|
|
161
224
|
{renderExample}
|
|
162
225
|
{renderExamples}
|
|
163
226
|
</div>
|
|
@@ -0,0 +1,164 @@
|
|
|
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, { Suspense } from "react";
|
|
9
|
+
|
|
10
|
+
import BrowserOnly from "@docusaurus/BrowserOnly";
|
|
11
|
+
import Details from "@theme/Details";
|
|
12
|
+
import MimeTabs from "@theme/MimeTabs"; // Assume these components exist
|
|
13
|
+
import SchemaNode from "@theme/Schema";
|
|
14
|
+
import SkeletonLoader from "@theme/SkeletonLoader";
|
|
15
|
+
import TabItem from "@theme/TabItem";
|
|
16
|
+
import { createDescription } from "docusaurus-plugin-openapi-docs/lib/markdown/createDescription";
|
|
17
|
+
import { MediaTypeObject } from "docusaurus-plugin-openapi-docs/lib/openapi/types";
|
|
18
|
+
|
|
19
|
+
interface Props {
|
|
20
|
+
style?: React.CSSProperties;
|
|
21
|
+
title: string;
|
|
22
|
+
body: {
|
|
23
|
+
content?: {
|
|
24
|
+
[key: string]: MediaTypeObject;
|
|
25
|
+
};
|
|
26
|
+
description?: string;
|
|
27
|
+
required?: string[] | boolean;
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const RequestSchemaComponent: React.FC<Props> = ({ title, body, style }) => {
|
|
32
|
+
if (
|
|
33
|
+
body === undefined ||
|
|
34
|
+
body.content === undefined ||
|
|
35
|
+
Object.keys(body).length === 0 ||
|
|
36
|
+
Object.keys(body.content).length === 0
|
|
37
|
+
) {
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const mimeTypes = Object.keys(body.content);
|
|
42
|
+
|
|
43
|
+
if (mimeTypes.length > 1) {
|
|
44
|
+
return (
|
|
45
|
+
<MimeTabs className="openapi-tabs__mime" schemaType="request">
|
|
46
|
+
{mimeTypes.map((mimeType) => {
|
|
47
|
+
const firstBody = body.content![mimeType].schema;
|
|
48
|
+
if (
|
|
49
|
+
firstBody === undefined ||
|
|
50
|
+
(firstBody.properties &&
|
|
51
|
+
Object.keys(firstBody.properties).length === 0)
|
|
52
|
+
) {
|
|
53
|
+
return null;
|
|
54
|
+
}
|
|
55
|
+
return (
|
|
56
|
+
// @ts-ignore
|
|
57
|
+
<TabItem key={mimeType} label={mimeType} value={mimeType}>
|
|
58
|
+
<Details
|
|
59
|
+
className="openapi-markdown__details mime"
|
|
60
|
+
data-collapsed={false}
|
|
61
|
+
open={true}
|
|
62
|
+
style={style}
|
|
63
|
+
summary={
|
|
64
|
+
<>
|
|
65
|
+
<summary>
|
|
66
|
+
<h3 className="openapi-markdown__details-summary-header-body">
|
|
67
|
+
{title}
|
|
68
|
+
{body.required === true && (
|
|
69
|
+
<span className="openapi-schema__required">
|
|
70
|
+
required
|
|
71
|
+
</span>
|
|
72
|
+
)}
|
|
73
|
+
</h3>
|
|
74
|
+
</summary>
|
|
75
|
+
</>
|
|
76
|
+
}
|
|
77
|
+
>
|
|
78
|
+
<div style={{ textAlign: "left", marginLeft: "1rem" }}>
|
|
79
|
+
{body.description && (
|
|
80
|
+
<div style={{ marginTop: "1rem", marginBottom: "1rem" }}>
|
|
81
|
+
{createDescription(body.description)}
|
|
82
|
+
</div>
|
|
83
|
+
)}
|
|
84
|
+
</div>
|
|
85
|
+
<ul style={{ marginLeft: "1rem" }}>
|
|
86
|
+
<SchemaNode schema={firstBody} schemaType="request" />
|
|
87
|
+
</ul>
|
|
88
|
+
</Details>
|
|
89
|
+
</TabItem>
|
|
90
|
+
);
|
|
91
|
+
})}
|
|
92
|
+
</MimeTabs>
|
|
93
|
+
);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
const randomFirstKey = mimeTypes[0];
|
|
97
|
+
const firstBody =
|
|
98
|
+
body.content[randomFirstKey].schema ?? body.content![randomFirstKey];
|
|
99
|
+
|
|
100
|
+
if (firstBody === undefined) {
|
|
101
|
+
return null;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
return (
|
|
105
|
+
<MimeTabs className="openapi-tabs__mime" schemaType="request">
|
|
106
|
+
{/* @ts-ignore */}
|
|
107
|
+
<TabItem label={randomFirstKey} value={`${randomFirstKey}-schema`}>
|
|
108
|
+
<Details
|
|
109
|
+
className="openapi-markdown__details mime"
|
|
110
|
+
data-collapsed={false}
|
|
111
|
+
open={true}
|
|
112
|
+
style={style}
|
|
113
|
+
summary={
|
|
114
|
+
<>
|
|
115
|
+
<summary>
|
|
116
|
+
<h3 className="openapi-markdown__details-summary-header-body">
|
|
117
|
+
{title}
|
|
118
|
+
{firstBody.type === "array" && (
|
|
119
|
+
<span style={{ opacity: "0.6" }}> array</span>
|
|
120
|
+
)}
|
|
121
|
+
{body.required && (
|
|
122
|
+
<strong className="openapi-schema__required">
|
|
123
|
+
required
|
|
124
|
+
</strong>
|
|
125
|
+
)}
|
|
126
|
+
</h3>
|
|
127
|
+
</summary>
|
|
128
|
+
</>
|
|
129
|
+
}
|
|
130
|
+
>
|
|
131
|
+
<div style={{ textAlign: "left", marginLeft: "1rem" }}>
|
|
132
|
+
{body.description && (
|
|
133
|
+
<div style={{ marginTop: "1rem", marginBottom: "1rem" }}>
|
|
134
|
+
{createDescription(body.description)}
|
|
135
|
+
</div>
|
|
136
|
+
)}
|
|
137
|
+
</div>
|
|
138
|
+
<ul style={{ marginLeft: "1rem" }}>
|
|
139
|
+
<SchemaNode schema={firstBody} schemaType="request" />
|
|
140
|
+
</ul>
|
|
141
|
+
</Details>
|
|
142
|
+
</TabItem>
|
|
143
|
+
</MimeTabs>
|
|
144
|
+
);
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
const RequestSchema: React.FC<Props> = (props) => {
|
|
148
|
+
return (
|
|
149
|
+
<BrowserOnly fallback={<SkeletonLoader size="sm" />}>
|
|
150
|
+
{() => {
|
|
151
|
+
const LazyComponent = React.lazy(() =>
|
|
152
|
+
Promise.resolve({ default: RequestSchemaComponent })
|
|
153
|
+
);
|
|
154
|
+
return (
|
|
155
|
+
<Suspense fallback={null}>
|
|
156
|
+
<LazyComponent {...props} />
|
|
157
|
+
</Suspense>
|
|
158
|
+
);
|
|
159
|
+
}}
|
|
160
|
+
</BrowserOnly>
|
|
161
|
+
);
|
|
162
|
+
};
|
|
163
|
+
|
|
164
|
+
export default RequestSchema;
|
|
@@ -0,0 +1,290 @@
|
|
|
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 ParamsItem from "@theme/ParamsItem";
|
|
11
|
+
import ResponseSamples from "@theme/ResponseSamples";
|
|
12
|
+
import TabItem from "@theme/TabItem";
|
|
13
|
+
import { createDescription } from "docusaurus-plugin-openapi-docs/lib/markdown/createDescription";
|
|
14
|
+
import { sampleResponseFromSchema } from "docusaurus-plugin-openapi-docs/lib/openapi/createResponseExample";
|
|
15
|
+
import format from "xml-formatter";
|
|
16
|
+
|
|
17
|
+
// Utility function
|
|
18
|
+
export function json2xml(o: Record<string, any>, tab: string): string {
|
|
19
|
+
const toXml = (v: any, name: string, ind: string): string => {
|
|
20
|
+
let xml = "";
|
|
21
|
+
if (v instanceof Array) {
|
|
22
|
+
for (let i = 0, n = v.length; i < n; i++) {
|
|
23
|
+
xml += ind + toXml(v[i], name, ind + "\t") + "\n";
|
|
24
|
+
}
|
|
25
|
+
} else if (typeof v === "object") {
|
|
26
|
+
let hasChild = false;
|
|
27
|
+
xml += ind + "<" + name;
|
|
28
|
+
for (const m in v) {
|
|
29
|
+
if (m.charAt(0) === "@") {
|
|
30
|
+
xml += " " + m.substr(1) + '="' + v[m].toString() + '"';
|
|
31
|
+
} else {
|
|
32
|
+
hasChild = true;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
xml += hasChild ? ">" : "/>";
|
|
36
|
+
if (hasChild) {
|
|
37
|
+
for (const m2 in v) {
|
|
38
|
+
if (m2 === "#text") xml += v[m2];
|
|
39
|
+
else if (m2 === "#cdata") xml += "<![CDATA[" + v[m2] + "]]>";
|
|
40
|
+
else if (m2.charAt(0) !== "@") xml += toXml(v[m2], m2, ind + "\t");
|
|
41
|
+
}
|
|
42
|
+
xml +=
|
|
43
|
+
(xml.charAt(xml.length - 1) === "\n" ? ind : "") + "</" + name + ">";
|
|
44
|
+
}
|
|
45
|
+
} else {
|
|
46
|
+
xml += ind + "<" + name + ">" + v.toString() + "</" + name + ">";
|
|
47
|
+
}
|
|
48
|
+
return xml;
|
|
49
|
+
};
|
|
50
|
+
let xml = "";
|
|
51
|
+
for (const m3 in o) xml += toXml(o[m3], m3, "");
|
|
52
|
+
return tab ? xml.replace(/\t/g, tab) : xml.replace(/\t|\n/g, "");
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
interface ParameterProps {
|
|
56
|
+
in: string;
|
|
57
|
+
name: string;
|
|
58
|
+
schema?: {
|
|
59
|
+
type?: string;
|
|
60
|
+
items?: Record<string, any>;
|
|
61
|
+
};
|
|
62
|
+
enumDescriptions?: [string, string][];
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
interface ResponseHeaderProps {
|
|
66
|
+
description?: string;
|
|
67
|
+
example?: string;
|
|
68
|
+
schema?: {
|
|
69
|
+
type?: string;
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
interface ResponseExampleProps {
|
|
74
|
+
value: any;
|
|
75
|
+
summary?: string;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
interface Props {
|
|
79
|
+
parameters?: ParameterProps[];
|
|
80
|
+
type: string;
|
|
81
|
+
responseHeaders?: Record<string, ResponseHeaderProps>;
|
|
82
|
+
responseExamples?: Record<string, ResponseExampleProps>;
|
|
83
|
+
responseExample?: any;
|
|
84
|
+
schema?: any;
|
|
85
|
+
mimeType: string;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// React components
|
|
89
|
+
export const ParamsDetails: React.FC<Props> = ({ parameters, type }) => {
|
|
90
|
+
const params = parameters?.filter((param) => param?.in === type);
|
|
91
|
+
|
|
92
|
+
if (!params || params.length === 0) {
|
|
93
|
+
return null;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
return (
|
|
97
|
+
<details
|
|
98
|
+
className="openapi-markdown__details"
|
|
99
|
+
data-collapsed={false}
|
|
100
|
+
open={true}
|
|
101
|
+
style={{ marginBottom: "1rem" }}
|
|
102
|
+
>
|
|
103
|
+
<summary>
|
|
104
|
+
<h3 className="openapi-markdown__details-summary-header-params">
|
|
105
|
+
{`${type.charAt(0).toUpperCase() + type.slice(1)} Parameters`}
|
|
106
|
+
</h3>
|
|
107
|
+
</summary>
|
|
108
|
+
<div>
|
|
109
|
+
<ul>
|
|
110
|
+
{params.map((param, index) => (
|
|
111
|
+
<ParamsItem
|
|
112
|
+
key={index}
|
|
113
|
+
className="paramsItem"
|
|
114
|
+
// @ts-ignore
|
|
115
|
+
param={{
|
|
116
|
+
...param,
|
|
117
|
+
enumDescriptions: Object.entries(
|
|
118
|
+
param?.schema?.items?.["x-enumDescriptions"] ?? {}
|
|
119
|
+
),
|
|
120
|
+
}}
|
|
121
|
+
/>
|
|
122
|
+
))}
|
|
123
|
+
</ul>
|
|
124
|
+
</div>
|
|
125
|
+
</details>
|
|
126
|
+
);
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
export const ResponseHeaders: React.FC<{
|
|
130
|
+
responseHeaders?: Record<string, ResponseHeaderProps>;
|
|
131
|
+
}> = ({ responseHeaders }) => {
|
|
132
|
+
if (!responseHeaders) {
|
|
133
|
+
return null;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
return (
|
|
137
|
+
<ul style={{ marginLeft: "1rem" }}>
|
|
138
|
+
{Object.entries(responseHeaders).map(([headerName, headerObj]) => {
|
|
139
|
+
const { description, example, schema } = headerObj;
|
|
140
|
+
const type = schema?.type ?? "any";
|
|
141
|
+
|
|
142
|
+
return (
|
|
143
|
+
<li className="schemaItem" key={headerName}>
|
|
144
|
+
<details>
|
|
145
|
+
<summary>
|
|
146
|
+
<strong>{headerName}</strong>
|
|
147
|
+
{type && <span style={{ opacity: "0.6" }}> {type}</span>}
|
|
148
|
+
</summary>
|
|
149
|
+
<div>
|
|
150
|
+
{description && (
|
|
151
|
+
<div style={{ marginTop: ".5rem", marginBottom: ".5rem" }}>
|
|
152
|
+
{example && `Example: ${example}`}
|
|
153
|
+
{createDescription(description)}
|
|
154
|
+
</div>
|
|
155
|
+
)}
|
|
156
|
+
</div>
|
|
157
|
+
</details>
|
|
158
|
+
</li>
|
|
159
|
+
);
|
|
160
|
+
})}
|
|
161
|
+
</ul>
|
|
162
|
+
);
|
|
163
|
+
};
|
|
164
|
+
|
|
165
|
+
export const ResponseExamples: React.FC<{
|
|
166
|
+
responseExamples: any;
|
|
167
|
+
mimeType: string;
|
|
168
|
+
}> = ({ responseExamples, mimeType }): any => {
|
|
169
|
+
let language = "shell";
|
|
170
|
+
if (mimeType.endsWith("json")) language = "json";
|
|
171
|
+
if (mimeType.endsWith("xml")) language = "xml";
|
|
172
|
+
|
|
173
|
+
// Map response examples to an array of TabItem elements
|
|
174
|
+
const examplesArray = Object.entries(responseExamples).map(
|
|
175
|
+
([exampleName, exampleValue]: any) => {
|
|
176
|
+
const isObject = typeof exampleValue.value === "object";
|
|
177
|
+
const responseExample = isObject
|
|
178
|
+
? JSON.stringify(exampleValue.value, null, 2)
|
|
179
|
+
: exampleValue.value;
|
|
180
|
+
|
|
181
|
+
return (
|
|
182
|
+
// @ts-ignore
|
|
183
|
+
<TabItem label={exampleName} value={exampleName} key={exampleName}>
|
|
184
|
+
{exampleValue.summary && (
|
|
185
|
+
<div className="openapi-example__summary">
|
|
186
|
+
{exampleValue.summary}
|
|
187
|
+
</div>
|
|
188
|
+
)}
|
|
189
|
+
<ResponseSamples
|
|
190
|
+
responseExample={responseExample}
|
|
191
|
+
language={language}
|
|
192
|
+
/>
|
|
193
|
+
</TabItem>
|
|
194
|
+
);
|
|
195
|
+
}
|
|
196
|
+
);
|
|
197
|
+
|
|
198
|
+
return examplesArray;
|
|
199
|
+
};
|
|
200
|
+
|
|
201
|
+
export const ResponseExample: React.FC<{
|
|
202
|
+
responseExample: any;
|
|
203
|
+
mimeType: string;
|
|
204
|
+
}> = ({ responseExample, mimeType }) => {
|
|
205
|
+
let language = "shell";
|
|
206
|
+
if (mimeType.endsWith("json")) {
|
|
207
|
+
language = "json";
|
|
208
|
+
}
|
|
209
|
+
if (mimeType.endsWith("xml")) {
|
|
210
|
+
language = "xml";
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
const isObject = typeof responseExample === "object";
|
|
214
|
+
const exampleContent = isObject
|
|
215
|
+
? JSON.stringify(responseExample, null, 2)
|
|
216
|
+
: responseExample;
|
|
217
|
+
|
|
218
|
+
return (
|
|
219
|
+
// @ts-ignore
|
|
220
|
+
<TabItem label="Example" value="Example">
|
|
221
|
+
{responseExample.summary && (
|
|
222
|
+
<div className="openapi-example__summary">
|
|
223
|
+
{responseExample.summary}
|
|
224
|
+
</div>
|
|
225
|
+
)}
|
|
226
|
+
<ResponseSamples responseExample={exampleContent} language={language} />
|
|
227
|
+
</TabItem>
|
|
228
|
+
);
|
|
229
|
+
};
|
|
230
|
+
|
|
231
|
+
export const ExampleFromSchema: React.FC<{ schema: any; mimeType: string }> = ({
|
|
232
|
+
schema,
|
|
233
|
+
mimeType,
|
|
234
|
+
}) => {
|
|
235
|
+
const responseExample = sampleResponseFromSchema(schema);
|
|
236
|
+
|
|
237
|
+
if (mimeType.endsWith("xml")) {
|
|
238
|
+
let responseExampleObject;
|
|
239
|
+
try {
|
|
240
|
+
responseExampleObject = JSON.parse(JSON.stringify(responseExample));
|
|
241
|
+
} catch {
|
|
242
|
+
return null;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
if (typeof responseExampleObject === "object") {
|
|
246
|
+
let xmlExample;
|
|
247
|
+
try {
|
|
248
|
+
xmlExample = format(json2xml(responseExampleObject, ""), {
|
|
249
|
+
indentation: " ",
|
|
250
|
+
lineSeparator: "\n",
|
|
251
|
+
collapseContent: true,
|
|
252
|
+
});
|
|
253
|
+
} catch {
|
|
254
|
+
const xmlExampleWithRoot = { root: responseExampleObject };
|
|
255
|
+
try {
|
|
256
|
+
xmlExample = format(json2xml(xmlExampleWithRoot, ""), {
|
|
257
|
+
indentation: " ",
|
|
258
|
+
lineSeparator: "\n",
|
|
259
|
+
collapseContent: true,
|
|
260
|
+
});
|
|
261
|
+
} catch {
|
|
262
|
+
xmlExample = json2xml(responseExampleObject, "");
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
return (
|
|
266
|
+
// @ts-ignore
|
|
267
|
+
<TabItem label="Example (auto)" value="Example (auto)">
|
|
268
|
+
<ResponseSamples responseExample={xmlExample} language="xml" />
|
|
269
|
+
</TabItem>
|
|
270
|
+
);
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
if (
|
|
275
|
+
typeof responseExample === "object" ||
|
|
276
|
+
typeof responseExample === "string"
|
|
277
|
+
) {
|
|
278
|
+
return (
|
|
279
|
+
// @ts-ignore
|
|
280
|
+
<TabItem label="Example (auto)" value="Example (auto)">
|
|
281
|
+
<ResponseSamples
|
|
282
|
+
responseExample={JSON.stringify(responseExample, null, 2)}
|
|
283
|
+
language="json"
|
|
284
|
+
/>
|
|
285
|
+
</TabItem>
|
|
286
|
+
);
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
return null;
|
|
290
|
+
};
|