@gitbook/react-openapi 1.1.5 → 1.1.7
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/CHANGELOG.md +34 -0
- package/dist/InteractiveSection.d.ts +0 -2
- package/dist/InteractiveSection.jsx +3 -4
- package/dist/OpenAPICodeSample.d.ts +9 -0
- package/dist/OpenAPICodeSample.jsx +117 -58
- package/dist/OpenAPICodeSampleInteractive.d.ts +11 -0
- package/dist/OpenAPICodeSampleInteractive.jsx +85 -0
- package/dist/OpenAPICopyButton.d.ts +7 -0
- package/dist/OpenAPICopyButton.jsx +6 -6
- package/dist/OpenAPIOperation.jsx +21 -1
- package/dist/OpenAPIPath.jsx +2 -2
- package/dist/OpenAPIRequestBody.jsx +1 -1
- package/dist/OpenAPIResponse.jsx +1 -1
- package/dist/OpenAPIResponses.jsx +2 -2
- package/dist/OpenAPISchema.d.ts +5 -14
- package/dist/OpenAPISchema.jsx +79 -28
- package/dist/OpenAPISchemaName.jsx +8 -6
- package/dist/OpenAPISchemaServer.d.ts +12 -0
- package/dist/OpenAPISchemaServer.jsx +8 -0
- package/dist/OpenAPISpec.d.ts +0 -6
- package/dist/OpenAPISpec.jsx +5 -11
- package/dist/OpenAPITabs.jsx +3 -11
- package/dist/code-samples.d.ts +1 -2
- package/dist/code-samples.js +46 -11
- package/dist/decycle.d.ts +2 -0
- package/dist/decycle.js +70 -0
- package/dist/generateSchemaExample.d.ts +31 -2
- package/dist/generateSchemaExample.js +307 -24
- package/dist/schemas/OpenAPISchemas.jsx +1 -1
- package/dist/schemas/resolveOpenAPISchemas.d.ts +2 -6
- package/dist/schemas/resolveOpenAPISchemas.js +1 -21
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/dist/types.d.ts +2 -5
- package/dist/utils.d.ts +1 -1
- package/dist/utils.js +11 -7
- package/package.json +3 -3
- package/src/InteractiveSection.tsx +2 -6
- package/src/OpenAPICodeSample.tsx +187 -78
- package/src/OpenAPICodeSampleInteractive.tsx +139 -0
- package/src/OpenAPICopyButton.tsx +17 -4
- package/src/OpenAPIOperation.tsx +39 -2
- package/src/OpenAPIPath.tsx +2 -2
- package/src/OpenAPIRequestBody.tsx +1 -1
- package/src/OpenAPIResponse.tsx +4 -4
- package/src/OpenAPIResponses.tsx +1 -5
- package/src/OpenAPISchema.tsx +152 -58
- package/src/OpenAPISchemaName.tsx +14 -6
- package/src/OpenAPISchemaServer.tsx +34 -0
- package/src/OpenAPISpec.tsx +13 -11
- package/src/OpenAPITabs.tsx +3 -13
- package/src/code-samples.test.ts +69 -1
- package/src/code-samples.ts +48 -12
- package/src/decycle.ts +68 -0
- package/src/generateSchemaExample.ts +412 -25
- package/src/resolveOpenAPIOperation.test.ts +6 -6
- package/src/schemas/OpenAPISchemas.tsx +1 -1
- package/src/schemas/resolveOpenAPISchemas.ts +3 -31
- package/src/types.ts +6 -6
- package/src/utils.ts +13 -10
package/src/OpenAPIOperation.tsx
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
import clsx from 'clsx';
|
|
2
2
|
|
|
3
|
-
import type {
|
|
3
|
+
import type {
|
|
4
|
+
OpenAPICustomOperationProperties,
|
|
5
|
+
OpenAPIStability,
|
|
6
|
+
OpenAPIV3,
|
|
7
|
+
} from '@gitbook/openapi-parser';
|
|
4
8
|
import { Markdown } from './Markdown';
|
|
5
9
|
import { OpenAPICodeSample } from './OpenAPICodeSample';
|
|
6
10
|
import { OpenAPIPath } from './OpenAPIPath';
|
|
@@ -29,14 +33,24 @@ export function OpenAPIOperation(props: {
|
|
|
29
33
|
return (
|
|
30
34
|
<div className={clsx('openapi-operation', className)}>
|
|
31
35
|
<div className="openapi-summary" id={operation.summary ? undefined : context.id}>
|
|
36
|
+
{(operation.deprecated || operation['x-stability']) && (
|
|
37
|
+
<div className="openapi-summary-tags">
|
|
38
|
+
{operation.deprecated && (
|
|
39
|
+
<div className="openapi-deprecated">Deprecated</div>
|
|
40
|
+
)}
|
|
41
|
+
{operation['x-stability'] && (
|
|
42
|
+
<OpenAPIOperationStability stability={operation['x-stability']} />
|
|
43
|
+
)}
|
|
44
|
+
</div>
|
|
45
|
+
)}
|
|
32
46
|
{operation.summary
|
|
33
47
|
? context.renderHeading({
|
|
34
48
|
deprecated: operation.deprecated ?? false,
|
|
49
|
+
stability: operation['x-stability'],
|
|
35
50
|
title: operation.summary,
|
|
36
51
|
})
|
|
37
52
|
: null}
|
|
38
53
|
<OpenAPIPath data={data} context={context} />
|
|
39
|
-
{operation.deprecated && <div className="openapi-deprecated">Deprecated</div>}
|
|
40
54
|
</div>
|
|
41
55
|
<div className="openapi-columns">
|
|
42
56
|
<div className="openapi-column-spec">
|
|
@@ -89,3 +103,26 @@ function OpenAPIOperationDescription(props: {
|
|
|
89
103
|
</div>
|
|
90
104
|
);
|
|
91
105
|
}
|
|
106
|
+
|
|
107
|
+
const stabilityEnum = {
|
|
108
|
+
experimental: 'Experimental',
|
|
109
|
+
alpha: 'Alpha',
|
|
110
|
+
beta: 'Beta',
|
|
111
|
+
stable: 'Stable',
|
|
112
|
+
} as const;
|
|
113
|
+
|
|
114
|
+
function OpenAPIOperationStability(props: { stability: OpenAPIStability }) {
|
|
115
|
+
const { stability } = props;
|
|
116
|
+
|
|
117
|
+
const foundStability = stabilityEnum[stability];
|
|
118
|
+
|
|
119
|
+
if (!foundStability) {
|
|
120
|
+
return null;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
return (
|
|
124
|
+
<div className={`openapi-stability openapi-stability-${foundStability.toLowerCase()}`}>
|
|
125
|
+
{foundStability}
|
|
126
|
+
</div>
|
|
127
|
+
);
|
|
128
|
+
}
|
package/src/OpenAPIPath.tsx
CHANGED
|
@@ -47,7 +47,7 @@ function formatPath(path: string) {
|
|
|
47
47
|
parts.push(path.slice(lastIndex, offset));
|
|
48
48
|
}
|
|
49
49
|
parts.push(
|
|
50
|
-
<span key={offset} className="openapi-path-variable">
|
|
50
|
+
<span key={`offset-${offset}`} className="openapi-path-variable">
|
|
51
51
|
{match}
|
|
52
52
|
</span>
|
|
53
53
|
);
|
|
@@ -61,7 +61,7 @@ function formatPath(path: string) {
|
|
|
61
61
|
|
|
62
62
|
const formattedPath = parts.map((part, index) => {
|
|
63
63
|
if (typeof part === 'string') {
|
|
64
|
-
return <span key={index}>{part}</span>;
|
|
64
|
+
return <span key={`part-${index}`}>{part}</span>;
|
|
65
65
|
}
|
|
66
66
|
return part;
|
|
67
67
|
});
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { OpenAPIV3 } from '@gitbook/openapi-parser';
|
|
2
2
|
import { InteractiveSection } from './InteractiveSection';
|
|
3
|
-
import { OpenAPIRootSchema } from './
|
|
3
|
+
import { OpenAPIRootSchema } from './OpenAPISchemaServer';
|
|
4
4
|
import type { OpenAPIClientContext } from './types';
|
|
5
5
|
import { checkIsReference } from './utils';
|
|
6
6
|
|
package/src/OpenAPIResponse.tsx
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { OpenAPIV3 } from '@gitbook/openapi-parser';
|
|
2
2
|
import { OpenAPIDisclosure } from './OpenAPIDisclosure';
|
|
3
|
-
import { OpenAPISchemaProperties } from './
|
|
3
|
+
import { OpenAPISchemaProperties } from './OpenAPISchemaServer';
|
|
4
4
|
import type { OpenAPIClientContext } from './types';
|
|
5
5
|
import { parameterToProperty, resolveDescription } from './utils';
|
|
6
6
|
|
|
@@ -29,9 +29,9 @@ export function OpenAPIResponse(props: {
|
|
|
29
29
|
{headers.length > 0 ? (
|
|
30
30
|
<OpenAPIDisclosure context={context} label="Headers">
|
|
31
31
|
<OpenAPISchemaProperties
|
|
32
|
-
properties={headers.map(([name, header]) =>
|
|
33
|
-
|
|
34
|
-
|
|
32
|
+
properties={headers.map(([name, header]) =>
|
|
33
|
+
parameterToProperty({ name, ...header })
|
|
34
|
+
)}
|
|
35
35
|
context={context}
|
|
36
36
|
/>
|
|
37
37
|
</OpenAPIDisclosure>
|
package/src/OpenAPIResponses.tsx
CHANGED
|
@@ -27,10 +27,7 @@ export function OpenAPIResponses(props: {
|
|
|
27
27
|
return {
|
|
28
28
|
id: statusCode,
|
|
29
29
|
label: (
|
|
30
|
-
<div
|
|
31
|
-
className="openapi-response-tab-content"
|
|
32
|
-
key={`response-${statusCode}`}
|
|
33
|
-
>
|
|
30
|
+
<div className="openapi-response-tab-content">
|
|
34
31
|
<span className="openapi-response-statuscode">
|
|
35
32
|
{statusCode}
|
|
36
33
|
</span>
|
|
@@ -47,7 +44,6 @@ export function OpenAPIResponses(props: {
|
|
|
47
44
|
label: contentType,
|
|
48
45
|
body: (
|
|
49
46
|
<OpenAPIResponse
|
|
50
|
-
key={`$response-${statusCode}-${contentType}`}
|
|
51
47
|
response={response}
|
|
52
48
|
mediaType={mediaType}
|
|
53
49
|
context={context}
|
package/src/OpenAPISchema.tsx
CHANGED
|
@@ -1,16 +1,22 @@
|
|
|
1
|
-
|
|
1
|
+
'use client';
|
|
2
|
+
// This component does not use any client feature but we don't want to
|
|
3
|
+
// render it server-side because it has recursion.
|
|
4
|
+
|
|
5
|
+
import type { OpenAPICustomOperationProperties, OpenAPIV3 } from '@gitbook/openapi-parser';
|
|
2
6
|
import { useId } from 'react';
|
|
3
7
|
|
|
4
8
|
import clsx from 'clsx';
|
|
5
9
|
import { Markdown } from './Markdown';
|
|
10
|
+
import { OpenAPICopyButton } from './OpenAPICopyButton';
|
|
6
11
|
import { OpenAPIDisclosure } from './OpenAPIDisclosure';
|
|
7
12
|
import { OpenAPISchemaName } from './OpenAPISchemaName';
|
|
13
|
+
import { retrocycle } from './decycle';
|
|
8
14
|
import type { OpenAPIClientContext } from './types';
|
|
9
15
|
import { checkIsReference, resolveDescription, resolveFirstExample } from './utils';
|
|
10
16
|
|
|
11
17
|
type CircularRefsIds = Map<OpenAPIV3.SchemaObject, string>;
|
|
12
18
|
|
|
13
|
-
interface OpenAPISchemaPropertyEntry {
|
|
19
|
+
export interface OpenAPISchemaPropertyEntry {
|
|
14
20
|
propertyName?: string | undefined;
|
|
15
21
|
required?: boolean | undefined;
|
|
16
22
|
schema: OpenAPIV3.SchemaObject;
|
|
@@ -22,15 +28,10 @@ interface OpenAPISchemaPropertyEntry {
|
|
|
22
28
|
function OpenAPISchemaProperty(props: {
|
|
23
29
|
property: OpenAPISchemaPropertyEntry;
|
|
24
30
|
context: OpenAPIClientContext;
|
|
25
|
-
circularRefs
|
|
31
|
+
circularRefs: CircularRefsIds;
|
|
26
32
|
className?: string;
|
|
27
33
|
}) {
|
|
28
|
-
const {
|
|
29
|
-
property,
|
|
30
|
-
circularRefs: parentCircularRefs = new Map<OpenAPIV3.SchemaObject, string>(),
|
|
31
|
-
context,
|
|
32
|
-
className,
|
|
33
|
-
} = props;
|
|
34
|
+
const { circularRefs: parentCircularRefs, context, className, property } = props;
|
|
34
35
|
|
|
35
36
|
const { schema } = property;
|
|
36
37
|
|
|
@@ -40,37 +41,43 @@ function OpenAPISchemaProperty(props: {
|
|
|
40
41
|
<div id={id} className={clsx('openapi-schema', className)}>
|
|
41
42
|
<OpenAPISchemaPresentation property={property} />
|
|
42
43
|
{(() => {
|
|
43
|
-
const
|
|
44
|
-
|
|
44
|
+
const circularRefId = parentCircularRefs.get(schema);
|
|
45
45
|
// Avoid recursing infinitely, and instead render a link to the parent schema
|
|
46
|
-
if (
|
|
47
|
-
return <OpenAPISchemaCircularRef id={
|
|
46
|
+
if (circularRefId) {
|
|
47
|
+
return <OpenAPISchemaCircularRef id={circularRefId} schema={schema} />;
|
|
48
48
|
}
|
|
49
49
|
|
|
50
|
-
const circularRefs = parentCircularRefs
|
|
50
|
+
const circularRefs = new Map(parentCircularRefs);
|
|
51
|
+
circularRefs.set(schema, id);
|
|
52
|
+
|
|
51
53
|
const properties = getSchemaProperties(schema);
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
key={index}
|
|
58
|
-
schema={schema}
|
|
54
|
+
if (properties?.length) {
|
|
55
|
+
return (
|
|
56
|
+
<OpenAPIDisclosure context={context} label={getDisclosureLabel(schema)}>
|
|
57
|
+
<OpenAPISchemaProperties
|
|
58
|
+
properties={properties}
|
|
59
59
|
circularRefs={circularRefs}
|
|
60
60
|
context={context}
|
|
61
61
|
/>
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
62
|
+
</OpenAPIDisclosure>
|
|
63
|
+
);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const ancestors = new Set(circularRefs.keys());
|
|
67
|
+
const alternatives = getSchemaAlternatives(schema, ancestors);
|
|
68
|
+
|
|
69
|
+
if (alternatives) {
|
|
70
|
+
return alternatives.map((schema, index) => (
|
|
71
|
+
<OpenAPISchemaAlternative
|
|
72
|
+
key={index}
|
|
73
|
+
schema={schema}
|
|
74
|
+
circularRefs={circularRefs}
|
|
75
|
+
context={context}
|
|
76
|
+
/>
|
|
77
|
+
));
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
return null;
|
|
74
81
|
})()}
|
|
75
82
|
</div>
|
|
76
83
|
);
|
|
@@ -79,41 +86,77 @@ function OpenAPISchemaProperty(props: {
|
|
|
79
86
|
/**
|
|
80
87
|
* Render a set of properties of an OpenAPI schema.
|
|
81
88
|
*/
|
|
82
|
-
|
|
89
|
+
function OpenAPISchemaProperties(props: {
|
|
83
90
|
id?: string;
|
|
84
91
|
properties: OpenAPISchemaPropertyEntry[];
|
|
85
92
|
circularRefs?: CircularRefsIds;
|
|
86
93
|
context: OpenAPIClientContext;
|
|
87
94
|
}) {
|
|
88
|
-
const {
|
|
95
|
+
const {
|
|
96
|
+
id,
|
|
97
|
+
properties,
|
|
98
|
+
circularRefs = new Map<OpenAPIV3.SchemaObject, string>(),
|
|
99
|
+
context,
|
|
100
|
+
} = props;
|
|
89
101
|
|
|
90
102
|
return (
|
|
91
103
|
<div id={id} className="openapi-schema-properties">
|
|
92
|
-
{properties.map((property, index) =>
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
104
|
+
{properties.map((property, index) => {
|
|
105
|
+
return (
|
|
106
|
+
<OpenAPISchemaProperty
|
|
107
|
+
key={index}
|
|
108
|
+
circularRefs={circularRefs}
|
|
109
|
+
property={property}
|
|
110
|
+
context={context}
|
|
111
|
+
/>
|
|
112
|
+
);
|
|
113
|
+
})}
|
|
100
114
|
</div>
|
|
101
115
|
);
|
|
102
116
|
}
|
|
103
117
|
|
|
118
|
+
export function OpenAPISchemaPropertiesFromServer(props: {
|
|
119
|
+
id?: string;
|
|
120
|
+
properties: string;
|
|
121
|
+
context: OpenAPIClientContext;
|
|
122
|
+
}) {
|
|
123
|
+
return (
|
|
124
|
+
<OpenAPISchemaProperties
|
|
125
|
+
id={props.id}
|
|
126
|
+
properties={JSON.parse(props.properties, retrocycle())}
|
|
127
|
+
context={props.context}
|
|
128
|
+
/>
|
|
129
|
+
);
|
|
130
|
+
}
|
|
131
|
+
|
|
104
132
|
/**
|
|
105
133
|
* Render a root schema (such as the request body or response body).
|
|
106
134
|
*/
|
|
107
|
-
|
|
135
|
+
function OpenAPIRootSchema(props: {
|
|
108
136
|
schema: OpenAPIV3.SchemaObject;
|
|
109
137
|
context: OpenAPIClientContext;
|
|
138
|
+
circularRefs?: CircularRefsIds;
|
|
110
139
|
}) {
|
|
111
|
-
const {
|
|
140
|
+
const {
|
|
141
|
+
schema,
|
|
142
|
+
context,
|
|
143
|
+
circularRefs: parentCircularRefs = new Map<OpenAPIV3.SchemaObject, string>(),
|
|
144
|
+
} = props;
|
|
112
145
|
|
|
146
|
+
const id = useId();
|
|
113
147
|
const properties = getSchemaProperties(schema);
|
|
114
148
|
|
|
115
149
|
if (properties?.length) {
|
|
116
|
-
|
|
150
|
+
const circularRefs = new Map(parentCircularRefs);
|
|
151
|
+
circularRefs.set(schema, id);
|
|
152
|
+
|
|
153
|
+
return (
|
|
154
|
+
<OpenAPISchemaProperties
|
|
155
|
+
properties={properties}
|
|
156
|
+
circularRefs={circularRefs}
|
|
157
|
+
context={context}
|
|
158
|
+
/>
|
|
159
|
+
);
|
|
117
160
|
}
|
|
118
161
|
|
|
119
162
|
return (
|
|
@@ -121,6 +164,19 @@ export function OpenAPIRootSchema(props: {
|
|
|
121
164
|
className="openapi-schema-root"
|
|
122
165
|
property={{ schema }}
|
|
123
166
|
context={context}
|
|
167
|
+
circularRefs={parentCircularRefs}
|
|
168
|
+
/>
|
|
169
|
+
);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
export function OpenAPIRootSchemaFromServer(props: {
|
|
173
|
+
schema: string;
|
|
174
|
+
context: OpenAPIClientContext;
|
|
175
|
+
}) {
|
|
176
|
+
return (
|
|
177
|
+
<OpenAPIRootSchema
|
|
178
|
+
schema={JSON.parse(props.schema, retrocycle())}
|
|
179
|
+
context={props.context}
|
|
124
180
|
/>
|
|
125
181
|
);
|
|
126
182
|
}
|
|
@@ -136,6 +192,7 @@ function OpenAPISchemaAlternative(props: {
|
|
|
136
192
|
context: OpenAPIClientContext;
|
|
137
193
|
}) {
|
|
138
194
|
const { schema, circularRefs, context } = props;
|
|
195
|
+
|
|
139
196
|
const description = resolveDescription(schema);
|
|
140
197
|
const properties = getSchemaProperties(schema);
|
|
141
198
|
|
|
@@ -180,20 +237,59 @@ function OpenAPISchemaCircularRef(props: { id: string; schema: OpenAPIV3.SchemaO
|
|
|
180
237
|
/**
|
|
181
238
|
* Render the enum value for a schema.
|
|
182
239
|
*/
|
|
183
|
-
function OpenAPISchemaEnum(props: {
|
|
184
|
-
|
|
240
|
+
function OpenAPISchemaEnum(props: {
|
|
241
|
+
schema: OpenAPIV3.SchemaObject & OpenAPICustomOperationProperties;
|
|
242
|
+
}) {
|
|
243
|
+
const { schema } = props;
|
|
244
|
+
|
|
245
|
+
const enumValues = (() => {
|
|
246
|
+
// Render x-gitbook-enum first, as it has a different format
|
|
247
|
+
if (schema['x-gitbook-enum']) {
|
|
248
|
+
return Object.entries(schema['x-gitbook-enum']).map(([name, { description }]) => {
|
|
249
|
+
return {
|
|
250
|
+
value: name,
|
|
251
|
+
description,
|
|
252
|
+
};
|
|
253
|
+
});
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
if (schema['x-enumDescriptions']) {
|
|
257
|
+
return Object.entries(schema['x-enumDescriptions']).map(([value, description]) => {
|
|
258
|
+
return {
|
|
259
|
+
value,
|
|
260
|
+
description,
|
|
261
|
+
};
|
|
262
|
+
});
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
return schema.enum?.map((value) => {
|
|
266
|
+
return {
|
|
267
|
+
value,
|
|
268
|
+
description: undefined,
|
|
269
|
+
};
|
|
270
|
+
});
|
|
271
|
+
})();
|
|
272
|
+
|
|
273
|
+
if (!enumValues?.length) {
|
|
274
|
+
return null;
|
|
275
|
+
}
|
|
185
276
|
|
|
186
277
|
return (
|
|
187
278
|
<div className="openapi-schema-enum">
|
|
188
|
-
<span>
|
|
189
|
-
|
|
190
|
-
{enumValues.map((
|
|
279
|
+
<span>Available options:</span>
|
|
280
|
+
<div className="openapi-schema-enum-list">
|
|
281
|
+
{enumValues.map((item, index) => (
|
|
191
282
|
<span key={index} className="openapi-schema-enum-value">
|
|
192
|
-
<
|
|
193
|
-
|
|
283
|
+
<OpenAPICopyButton
|
|
284
|
+
value={item.value}
|
|
285
|
+
label={item.description}
|
|
286
|
+
withTooltip={!!item.description}
|
|
287
|
+
>
|
|
288
|
+
<code>{`${item.value}`}</code>
|
|
289
|
+
</OpenAPICopyButton>
|
|
194
290
|
</span>
|
|
195
291
|
))}
|
|
196
|
-
</
|
|
292
|
+
</div>
|
|
197
293
|
</div>
|
|
198
294
|
);
|
|
199
295
|
}
|
|
@@ -238,9 +334,7 @@ function OpenAPISchemaPresentation(props: { property: OpenAPISchemaPropertyEntry
|
|
|
238
334
|
Pattern: <code>{schema.pattern}</code>
|
|
239
335
|
</div>
|
|
240
336
|
) : null}
|
|
241
|
-
{schema
|
|
242
|
-
<OpenAPISchemaEnum enumValues={schema.enum} />
|
|
243
|
-
) : null}
|
|
337
|
+
<OpenAPISchemaEnum schema={schema} />
|
|
244
338
|
</div>
|
|
245
339
|
);
|
|
246
340
|
}
|
|
@@ -365,7 +459,7 @@ function getSchemaTitle(schema: OpenAPIV3.SchemaObject): string {
|
|
|
365
459
|
// Otherwise try to infer a nice title
|
|
366
460
|
let type = 'any';
|
|
367
461
|
|
|
368
|
-
if (schema.enum) {
|
|
462
|
+
if (schema.enum || schema['x-enumDescriptions'] || schema['x-gitbook-enum']) {
|
|
369
463
|
type = `${schema.type} · enum`;
|
|
370
464
|
// check array AND schema.items as this is sometimes null despite what the type indicates
|
|
371
465
|
} else if (schema.type === 'array' && !!schema.items) {
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { OpenAPIV3 } from '@gitbook/openapi-parser';
|
|
2
2
|
import type React from 'react';
|
|
3
|
+
import { stringifyOpenAPI } from './stringifyOpenAPI';
|
|
3
4
|
|
|
4
5
|
interface OpenAPISchemaNameProps {
|
|
5
6
|
schema?: OpenAPIV3.SchemaObject;
|
|
@@ -31,7 +32,14 @@ export function OpenAPISchemaName(props: OpenAPISchemaNameProps) {
|
|
|
31
32
|
) : null}
|
|
32
33
|
</span>
|
|
33
34
|
{schema?.readOnly ? <span className="openapi-schema-readonly">read-only</span> : null}
|
|
34
|
-
{
|
|
35
|
+
{schema?.writeOnly ? (
|
|
36
|
+
<span className="openapi-schema-writeonly">write-only</span>
|
|
37
|
+
) : null}
|
|
38
|
+
{required ? (
|
|
39
|
+
<span className="openapi-schema-required">required</span>
|
|
40
|
+
) : (
|
|
41
|
+
<span className="openapi-schema-optional">optional</span>
|
|
42
|
+
)}
|
|
35
43
|
{schema?.deprecated ? <span className="openapi-deprecated">Deprecated</span> : null}
|
|
36
44
|
</div>
|
|
37
45
|
);
|
|
@@ -40,17 +48,17 @@ export function OpenAPISchemaName(props: OpenAPISchemaNameProps) {
|
|
|
40
48
|
function getAdditionalItems(schema: OpenAPIV3.SchemaObject): string {
|
|
41
49
|
let additionalItems = '';
|
|
42
50
|
|
|
43
|
-
if (schema.minimum || schema.minLength) {
|
|
44
|
-
additionalItems += ` · min: ${schema.minimum || schema.minLength}`;
|
|
51
|
+
if (schema.minimum || schema.minLength || schema.minItems) {
|
|
52
|
+
additionalItems += ` · min: ${schema.minimum || schema.minLength || schema.minItems}`;
|
|
45
53
|
}
|
|
46
54
|
|
|
47
|
-
if (schema.maximum || schema.maxLength) {
|
|
48
|
-
additionalItems += ` · max: ${schema.maximum || schema.maxLength}`;
|
|
55
|
+
if (schema.maximum || schema.maxLength || schema.maxItems) {
|
|
56
|
+
additionalItems += ` · max: ${schema.maximum || schema.maxLength || schema.maxItems}`;
|
|
49
57
|
}
|
|
50
58
|
|
|
51
59
|
// If the schema has a default value, we display it
|
|
52
60
|
if (typeof schema.default !== 'undefined') {
|
|
53
|
-
additionalItems += ` · default: ${schema.default}`;
|
|
61
|
+
additionalItems += ` · default: ${stringifyOpenAPI(schema.default)}`;
|
|
54
62
|
}
|
|
55
63
|
|
|
56
64
|
if (schema.nullable) {
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { OpenAPIV3 } from '@gitbook/openapi-parser';
|
|
2
|
+
import {
|
|
3
|
+
OpenAPIRootSchemaFromServer,
|
|
4
|
+
OpenAPISchemaPropertiesFromServer,
|
|
5
|
+
type OpenAPISchemaPropertyEntry,
|
|
6
|
+
} from './OpenAPISchema';
|
|
7
|
+
import { decycle } from './decycle';
|
|
8
|
+
import type { OpenAPIClientContext } from './types';
|
|
9
|
+
|
|
10
|
+
export function OpenAPISchemaProperties(props: {
|
|
11
|
+
id?: string;
|
|
12
|
+
properties: OpenAPISchemaPropertyEntry[];
|
|
13
|
+
context: OpenAPIClientContext;
|
|
14
|
+
}) {
|
|
15
|
+
return (
|
|
16
|
+
<OpenAPISchemaPropertiesFromServer
|
|
17
|
+
id={props.id}
|
|
18
|
+
properties={JSON.stringify(props.properties, decycle())}
|
|
19
|
+
context={props.context}
|
|
20
|
+
/>
|
|
21
|
+
);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function OpenAPIRootSchema(props: {
|
|
25
|
+
schema: OpenAPIV3.SchemaObject;
|
|
26
|
+
context: OpenAPIClientContext;
|
|
27
|
+
}) {
|
|
28
|
+
return (
|
|
29
|
+
<OpenAPIRootSchemaFromServer
|
|
30
|
+
schema={JSON.stringify(props.schema, decycle())}
|
|
31
|
+
context={props.context}
|
|
32
|
+
/>
|
|
33
|
+
);
|
|
34
|
+
}
|
package/src/OpenAPISpec.tsx
CHANGED
|
@@ -2,18 +2,12 @@ import type { OpenAPI } from '@gitbook/openapi-parser';
|
|
|
2
2
|
|
|
3
3
|
import { OpenAPIRequestBody } from './OpenAPIRequestBody';
|
|
4
4
|
import { OpenAPIResponses } from './OpenAPIResponses';
|
|
5
|
-
import { OpenAPISchemaProperties } from './
|
|
5
|
+
import { OpenAPISchemaProperties } from './OpenAPISchemaServer';
|
|
6
6
|
import { OpenAPISecurities } from './OpenAPISecurities';
|
|
7
7
|
import { StaticSection } from './StaticSection';
|
|
8
8
|
import type { OpenAPIClientContext, OpenAPIOperationData } from './types';
|
|
9
9
|
import { parameterToProperty } from './utils';
|
|
10
10
|
|
|
11
|
-
/**
|
|
12
|
-
* Client component to render the spec for the request and response.
|
|
13
|
-
*
|
|
14
|
-
* We use a client component as rendering recursive JSON schema in the server is expensive
|
|
15
|
-
* (the entire schema is rendered at once, while the client component only renders the visible part)
|
|
16
|
-
*/
|
|
17
11
|
export function OpenAPISpec(props: { data: OpenAPIOperationData; context: OpenAPIClientContext }) {
|
|
18
12
|
const { data, context } = props;
|
|
19
13
|
|
|
@@ -25,13 +19,13 @@ export function OpenAPISpec(props: { data: OpenAPIOperationData; context: OpenAP
|
|
|
25
19
|
return (
|
|
26
20
|
<>
|
|
27
21
|
{securities.length > 0 ? (
|
|
28
|
-
<OpenAPISecurities securities={securities} context={context} />
|
|
22
|
+
<OpenAPISecurities key="securities" securities={securities} context={context} />
|
|
29
23
|
) : null}
|
|
30
24
|
|
|
31
25
|
{parameterGroups.map((group) => {
|
|
32
26
|
return (
|
|
33
27
|
<StaticSection
|
|
34
|
-
key={group.key}
|
|
28
|
+
key={`parameter-${group.key}`}
|
|
35
29
|
className="openapi-parameters"
|
|
36
30
|
header={group.label}
|
|
37
31
|
>
|
|
@@ -44,10 +38,18 @@ export function OpenAPISpec(props: { data: OpenAPIOperationData; context: OpenAP
|
|
|
44
38
|
})}
|
|
45
39
|
|
|
46
40
|
{operation.requestBody ? (
|
|
47
|
-
<OpenAPIRequestBody
|
|
41
|
+
<OpenAPIRequestBody
|
|
42
|
+
key="body"
|
|
43
|
+
requestBody={operation.requestBody}
|
|
44
|
+
context={context}
|
|
45
|
+
/>
|
|
48
46
|
) : null}
|
|
49
47
|
{operation.responses ? (
|
|
50
|
-
<OpenAPIResponses
|
|
48
|
+
<OpenAPIResponses
|
|
49
|
+
key="responses"
|
|
50
|
+
responses={operation.responses}
|
|
51
|
+
context={context}
|
|
52
|
+
/>
|
|
51
53
|
) : null}
|
|
52
54
|
</>
|
|
53
55
|
);
|
package/src/OpenAPITabs.tsx
CHANGED
|
@@ -137,21 +137,11 @@ export function OpenAPITabsPanels() {
|
|
|
137
137
|
const key = selectedTab.key.toString();
|
|
138
138
|
|
|
139
139
|
return (
|
|
140
|
-
<TabPanel
|
|
141
|
-
{selectedTab.body}
|
|
140
|
+
<TabPanel id={key} className="openapi-tabs-panel">
|
|
141
|
+
<div className="openapi-tabs-body">{selectedTab.body}</div>
|
|
142
142
|
{selectedTab.footer ? (
|
|
143
|
-
<
|
|
143
|
+
<div className="openapi-tabs-footer">{selectedTab.footer}</div>
|
|
144
144
|
) : null}
|
|
145
145
|
</TabPanel>
|
|
146
146
|
);
|
|
147
147
|
}
|
|
148
|
-
|
|
149
|
-
/**
|
|
150
|
-
* The OpenAPI Tabs panel footer component.
|
|
151
|
-
* This component should be used as a child of the OpenAPITabs component.
|
|
152
|
-
*/
|
|
153
|
-
function OpenAPITabsPanelFooter(props: { children: React.ReactNode }) {
|
|
154
|
-
const { children } = props;
|
|
155
|
-
|
|
156
|
-
return <div className="openapi-tabs-footer">{children}</div>;
|
|
157
|
-
}
|