@gitbook/react-openapi 1.0.2 → 1.0.3
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 +16 -0
- package/dist/OpenAPICodeSample.jsx +11 -9
- package/dist/OpenAPIOperation.jsx +19 -5
- package/dist/OpenAPIResponseExample.jsx +3 -2
- package/dist/OpenAPISchema.jsx +47 -45
- package/dist/OpenAPISchemaName.d.ts +2 -1
- package/dist/OpenAPISchemaName.jsx +25 -4
- package/dist/OpenAPITabs.jsx +6 -2
- package/dist/code-samples.js +232 -10
- package/dist/contentTypeChecks.d.ts +9 -0
- package/dist/contentTypeChecks.js +27 -0
- package/dist/generateSchemaExample.js +1 -1
- package/dist/stringifyOpenAPI.d.ts +1 -1
- package/dist/stringifyOpenAPI.js +8 -2
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/dist/types.d.ts +14 -2
- package/dist/util/server.d.ts +9 -0
- package/dist/{OpenAPIServerURL.jsx → util/server.js} +7 -28
- package/dist/utils.d.ts +1 -1
- package/dist/utils.js +3 -0
- package/package.json +2 -2
- package/src/OpenAPICodeSample.tsx +11 -9
- package/src/OpenAPIOperation.tsx +30 -8
- package/src/OpenAPIResponseExample.tsx +3 -2
- package/src/OpenAPISchema.tsx +73 -62
- package/src/OpenAPISchemaName.tsx +37 -5
- package/src/OpenAPITabs.tsx +8 -2
- package/src/code-samples.test.ts +594 -2
- package/src/code-samples.ts +231 -10
- package/src/contentTypeChecks.ts +35 -0
- package/src/generateSchemaExample.ts +20 -16
- package/src/stringifyOpenAPI.ts +13 -2
- package/src/types.ts +11 -1
- package/src/util/server.test.ts +58 -0
- package/src/util/server.ts +48 -0
- package/src/utils.ts +5 -1
- package/dist/OpenAPIServerURL.d.ts +0 -11
- package/dist/OpenAPIServerURLVariable.d.ts +0 -8
- package/dist/OpenAPIServerURLVariable.jsx +0 -8
- package/src/OpenAPIServerURL.tsx +0 -73
- package/src/OpenAPIServerURLVariable.tsx +0 -14
package/dist/types.d.ts
CHANGED
|
@@ -1,13 +1,25 @@
|
|
|
1
1
|
import type { OpenAPICustomOperationProperties, OpenAPICustomSpecProperties, OpenAPIV3 } from '@gitbook/openapi-parser';
|
|
2
2
|
export interface OpenAPIContextProps extends OpenAPIClientContext {
|
|
3
|
-
|
|
3
|
+
/**
|
|
4
|
+
* Render a code block.
|
|
5
|
+
*/
|
|
6
|
+
renderCodeBlock: (props: {
|
|
4
7
|
code: string;
|
|
5
8
|
syntax: string;
|
|
6
|
-
}
|
|
9
|
+
}) => React.ReactNode;
|
|
10
|
+
/**
|
|
11
|
+
* Render the heading of the operation.
|
|
12
|
+
*/
|
|
7
13
|
renderHeading: (props: {
|
|
8
14
|
deprecated: boolean;
|
|
9
15
|
title: string;
|
|
10
16
|
}) => React.ReactNode;
|
|
17
|
+
/**
|
|
18
|
+
* Render the document of the operation.
|
|
19
|
+
*/
|
|
20
|
+
renderDocument: (props: {
|
|
21
|
+
document: object;
|
|
22
|
+
}) => React.ReactNode;
|
|
11
23
|
/** Spec url for the Scalar Api Client */
|
|
12
24
|
specUrl: string;
|
|
13
25
|
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { OpenAPIV3 } from '@gitbook/openapi-parser';
|
|
2
|
+
/**
|
|
3
|
+
* Get the default URL for the server.
|
|
4
|
+
*/
|
|
5
|
+
export declare function getDefaultServerURL(servers: OpenAPIV3.ServerObject[]): string;
|
|
6
|
+
/**
|
|
7
|
+
* Interpolate the server URL with the default values of the variables.
|
|
8
|
+
*/
|
|
9
|
+
export declare function interpolateServerURL(server: OpenAPIV3.ServerObject): string;
|
|
@@ -1,40 +1,19 @@
|
|
|
1
|
-
import { OpenAPIServerURLVariable } from './OpenAPIServerURLVariable';
|
|
2
1
|
/**
|
|
3
|
-
*
|
|
2
|
+
* Get the default URL for the server.
|
|
4
3
|
*/
|
|
5
|
-
export function
|
|
6
|
-
var _a;
|
|
7
|
-
var servers = props.servers;
|
|
4
|
+
export function getDefaultServerURL(servers) {
|
|
8
5
|
var server = servers[0];
|
|
9
6
|
if (!server) {
|
|
10
|
-
|
|
7
|
+
// Return empty string if no server is found to display nothing
|
|
8
|
+
return '';
|
|
11
9
|
}
|
|
12
|
-
|
|
13
|
-
return (<span>
|
|
14
|
-
{parts.map(function (part, i) {
|
|
15
|
-
var _a;
|
|
16
|
-
if (part.kind === 'text') {
|
|
17
|
-
return <span key={i}>{part.text}</span>;
|
|
18
|
-
}
|
|
19
|
-
else {
|
|
20
|
-
var variable = (_a = server.variables) === null || _a === void 0 ? void 0 : _a[part.name];
|
|
21
|
-
if (!variable) {
|
|
22
|
-
return <span key={i}>{"{".concat(part.name, "}")}</span>;
|
|
23
|
-
}
|
|
24
|
-
return (<OpenAPIServerURLVariable key={i} name={part.name} variable={variable}/>);
|
|
25
|
-
}
|
|
26
|
-
})}
|
|
27
|
-
</span>);
|
|
10
|
+
return interpolateServerURL(server);
|
|
28
11
|
}
|
|
29
12
|
/**
|
|
30
|
-
*
|
|
13
|
+
* Interpolate the server URL with the default values of the variables.
|
|
31
14
|
*/
|
|
32
|
-
export function
|
|
15
|
+
export function interpolateServerURL(server) {
|
|
33
16
|
var _a;
|
|
34
|
-
var server = servers[0];
|
|
35
|
-
if (!server) {
|
|
36
|
-
return '';
|
|
37
|
-
}
|
|
38
17
|
var parts = parseServerURL((_a = server === null || server === void 0 ? void 0 : server.url) !== null && _a !== void 0 ? _a : '');
|
|
39
18
|
return parts
|
|
40
19
|
.map(function (part) {
|
package/dist/utils.d.ts
CHANGED
|
@@ -4,7 +4,7 @@ export declare function createStateKey(key: string, scope?: string): string;
|
|
|
4
4
|
/**
|
|
5
5
|
* Resolve the description of an object.
|
|
6
6
|
*/
|
|
7
|
-
export declare function resolveDescription(object: AnyObject): string | undefined;
|
|
7
|
+
export declare function resolveDescription(object: OpenAPIV3.SchemaObject | AnyObject): string | undefined;
|
|
8
8
|
/**
|
|
9
9
|
* Extract descriptions from an object.
|
|
10
10
|
*/
|
package/dist/utils.js
CHANGED
|
@@ -19,6 +19,9 @@ export function createStateKey(key, scope) {
|
|
|
19
19
|
* Resolve the description of an object.
|
|
20
20
|
*/
|
|
21
21
|
export function resolveDescription(object) {
|
|
22
|
+
if ('items' in object && object.items) {
|
|
23
|
+
return resolveDescription(object.items);
|
|
24
|
+
}
|
|
22
25
|
return 'x-gitbook-description-html' in object &&
|
|
23
26
|
typeof object['x-gitbook-description-html'] === 'string'
|
|
24
27
|
? object['x-gitbook-description-html'].trim()
|
package/package.json
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
"default": "./dist/index.js"
|
|
9
9
|
}
|
|
10
10
|
},
|
|
11
|
-
"version": "1.0.
|
|
11
|
+
"version": "1.0.3",
|
|
12
12
|
"sideEffects": false,
|
|
13
13
|
"dependencies": {
|
|
14
14
|
"@gitbook/openapi-parser": "workspace:*",
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
"react": "*"
|
|
31
31
|
},
|
|
32
32
|
"scripts": {
|
|
33
|
-
"build": "tsc --project tsconfig.build.json",
|
|
33
|
+
"build": "rm -rf ./dist && tsc --project tsconfig.build.json",
|
|
34
34
|
"typecheck": "tsc --noEmit",
|
|
35
35
|
"unit": "bun test",
|
|
36
36
|
"dev": "bun run build -- --watch",
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { CodeSampleInput, codeSampleGenerators } from './code-samples';
|
|
2
2
|
import { generateMediaTypeExample, generateSchemaExample } from './generateSchemaExample';
|
|
3
3
|
import { InteractiveSection } from './InteractiveSection';
|
|
4
|
-
import { getServersURL } from './OpenAPIServerURL';
|
|
5
4
|
import type { OpenAPIContextProps, OpenAPIOperationData } from './types';
|
|
6
5
|
import { createStateKey } from './utils';
|
|
7
6
|
import { stringifyOpenAPI } from './stringifyOpenAPI';
|
|
8
7
|
import { OpenAPITabs, OpenAPITabsList, OpenAPITabsPanels } from './OpenAPITabs';
|
|
9
8
|
import { checkIsReference } from './utils';
|
|
9
|
+
import { getDefaultServerURL } from './util/server';
|
|
10
10
|
|
|
11
11
|
/**
|
|
12
12
|
* Display code samples to execute the operation.
|
|
@@ -53,15 +53,11 @@ export function OpenAPICodeSample(props: {
|
|
|
53
53
|
|
|
54
54
|
const input: CodeSampleInput = {
|
|
55
55
|
url:
|
|
56
|
-
|
|
56
|
+
getDefaultServerURL(data.servers) +
|
|
57
57
|
data.path +
|
|
58
58
|
(searchParams.size ? `?${searchParams.toString()}` : ''),
|
|
59
59
|
method: data.method,
|
|
60
|
-
body: requestBodyContent
|
|
61
|
-
? generateMediaTypeExample(requestBodyContent[1], {
|
|
62
|
-
omitEmptyAndOptionalProperties: true,
|
|
63
|
-
})
|
|
64
|
-
: undefined,
|
|
60
|
+
body: requestBodyContent ? generateMediaTypeExample(requestBodyContent[1]) : undefined,
|
|
65
61
|
headers: {
|
|
66
62
|
...getSecurityHeaders(data.securities),
|
|
67
63
|
...headersObject,
|
|
@@ -76,7 +72,10 @@ export function OpenAPICodeSample(props: {
|
|
|
76
72
|
const autoCodeSamples = codeSampleGenerators.map((generator) => ({
|
|
77
73
|
key: `default-${generator.id}`,
|
|
78
74
|
label: generator.label,
|
|
79
|
-
body:
|
|
75
|
+
body: context.renderCodeBlock({
|
|
76
|
+
code: generator.generate(input),
|
|
77
|
+
syntax: generator.syntax,
|
|
78
|
+
}),
|
|
80
79
|
}));
|
|
81
80
|
|
|
82
81
|
// Use custom samples if defined
|
|
@@ -99,7 +98,10 @@ export function OpenAPICodeSample(props: {
|
|
|
99
98
|
.map((sample) => ({
|
|
100
99
|
key: `redocly-${sample.lang}`,
|
|
101
100
|
label: sample.label,
|
|
102
|
-
body:
|
|
101
|
+
body: context.renderCodeBlock({
|
|
102
|
+
code: sample.source,
|
|
103
|
+
syntax: sample.lang,
|
|
104
|
+
}),
|
|
103
105
|
}));
|
|
104
106
|
}
|
|
105
107
|
});
|
package/src/OpenAPIOperation.tsx
CHANGED
|
@@ -7,6 +7,7 @@ import { OpenAPISpec } from './OpenAPISpec';
|
|
|
7
7
|
import type { OpenAPIClientContext, OpenAPIContextProps, OpenAPIOperationData } from './types';
|
|
8
8
|
import { OpenAPIPath } from './OpenAPIPath';
|
|
9
9
|
import { resolveDescription } from './utils';
|
|
10
|
+
import { OpenAPICustomOperationProperties, OpenAPIV3 } from '@gitbook/openapi-parser';
|
|
10
11
|
|
|
11
12
|
/**
|
|
12
13
|
* Display an interactive OpenAPI operation.
|
|
@@ -25,11 +26,9 @@ export function OpenAPIOperation(props: {
|
|
|
25
26
|
blockKey: context.blockKey,
|
|
26
27
|
};
|
|
27
28
|
|
|
28
|
-
const description = resolveDescription(operation);
|
|
29
|
-
|
|
30
29
|
return (
|
|
31
30
|
<div className={clsx('openapi-operation', className)}>
|
|
32
|
-
<div className="openapi-summary">
|
|
31
|
+
<div className="openapi-summary" id={operation.summary ? undefined : context.id}>
|
|
33
32
|
{operation.summary
|
|
34
33
|
? context.renderHeading({
|
|
35
34
|
deprecated: operation.deprecated ?? false,
|
|
@@ -49,11 +48,7 @@ export function OpenAPIOperation(props: {
|
|
|
49
48
|
{`.`}
|
|
50
49
|
</div>
|
|
51
50
|
) : null}
|
|
52
|
-
{
|
|
53
|
-
<div className="openapi-intro">
|
|
54
|
-
<Markdown className="openapi-description" source={description} />
|
|
55
|
-
</div>
|
|
56
|
-
) : null}
|
|
51
|
+
<OpenAPIOperationDescription operation={operation} context={context} />
|
|
57
52
|
<OpenAPIPath data={data} context={context} />
|
|
58
53
|
<OpenAPISpec data={data} context={clientContext} />
|
|
59
54
|
</div>
|
|
@@ -67,3 +62,30 @@ export function OpenAPIOperation(props: {
|
|
|
67
62
|
</div>
|
|
68
63
|
);
|
|
69
64
|
}
|
|
65
|
+
|
|
66
|
+
function OpenAPIOperationDescription(props: {
|
|
67
|
+
operation: OpenAPIV3.OperationObject<OpenAPICustomOperationProperties>;
|
|
68
|
+
context: OpenAPIContextProps;
|
|
69
|
+
}) {
|
|
70
|
+
const { operation } = props;
|
|
71
|
+
if (operation['x-gitbook-description-document']) {
|
|
72
|
+
return (
|
|
73
|
+
<div className="openapi-intro">
|
|
74
|
+
{props.context.renderDocument({
|
|
75
|
+
document: operation['x-gitbook-description-document'],
|
|
76
|
+
})}
|
|
77
|
+
</div>
|
|
78
|
+
);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const description = resolveDescription(operation);
|
|
82
|
+
if (!description) {
|
|
83
|
+
return null;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
return (
|
|
87
|
+
<div className="openapi-intro">
|
|
88
|
+
<Markdown className="openapi-description" source={description} />
|
|
89
|
+
</div>
|
|
90
|
+
);
|
|
91
|
+
}
|
|
@@ -5,6 +5,7 @@ import { checkIsReference, createStateKey, resolveDescription } from './utils';
|
|
|
5
5
|
import { OpenAPITabs, OpenAPITabsList, OpenAPITabsPanels } from './OpenAPITabs';
|
|
6
6
|
import { InteractiveSection } from './InteractiveSection';
|
|
7
7
|
import { json2xml } from './json2xml';
|
|
8
|
+
import { stringifyOpenAPI } from './stringifyOpenAPI';
|
|
8
9
|
|
|
9
10
|
/**
|
|
10
11
|
* Display an example of the response content.
|
|
@@ -208,7 +209,7 @@ function OpenAPIExample(props: {
|
|
|
208
209
|
return <OpenAPIEmptyResponseExample />;
|
|
209
210
|
}
|
|
210
211
|
|
|
211
|
-
return
|
|
212
|
+
return context.renderCodeBlock({ code, syntax });
|
|
212
213
|
}
|
|
213
214
|
|
|
214
215
|
function stringifyExample(args: { example: OpenAPIV3.ExampleObject; xml: boolean }): string | null {
|
|
@@ -226,7 +227,7 @@ function stringifyExample(args: { example: OpenAPIV3.ExampleObject; xml: boolean
|
|
|
226
227
|
return json2xml(example.value);
|
|
227
228
|
}
|
|
228
229
|
|
|
229
|
-
return
|
|
230
|
+
return stringifyOpenAPI(example.value, null, 2);
|
|
230
231
|
}
|
|
231
232
|
|
|
232
233
|
/**
|
package/src/OpenAPISchema.tsx
CHANGED
|
@@ -47,23 +47,6 @@ export function OpenAPISchemaProperty(
|
|
|
47
47
|
? null
|
|
48
48
|
: getSchemaAlternatives(schema, new Set(circularRefs.keys()));
|
|
49
49
|
|
|
50
|
-
if ((properties && properties.length > 0) || schema.type === 'object') {
|
|
51
|
-
return (
|
|
52
|
-
<InteractiveSection id={id} className={clsx('openapi-schema', className)}>
|
|
53
|
-
<OpenAPISchemaPresentation {...props} />
|
|
54
|
-
{properties && properties.length > 0 ? (
|
|
55
|
-
<OpenAPIDisclosure context={context}>
|
|
56
|
-
<OpenAPISchemaProperties
|
|
57
|
-
properties={properties}
|
|
58
|
-
circularRefs={circularRefs}
|
|
59
|
-
context={context}
|
|
60
|
-
/>
|
|
61
|
-
</OpenAPIDisclosure>
|
|
62
|
-
) : null}
|
|
63
|
-
</InteractiveSection>
|
|
64
|
-
);
|
|
65
|
-
}
|
|
66
|
-
|
|
67
50
|
if (alternatives?.[0]?.length) {
|
|
68
51
|
return (
|
|
69
52
|
<InteractiveSection id={id} className={clsx('openapi-schema', className)}>
|
|
@@ -76,6 +59,29 @@ export function OpenAPISchemaProperty(
|
|
|
76
59
|
context={context}
|
|
77
60
|
/>
|
|
78
61
|
))}
|
|
62
|
+
{parentCircularRef ? (
|
|
63
|
+
<OpenAPISchemaCircularRef id={parentCircularRef} schema={schema} />
|
|
64
|
+
) : null}
|
|
65
|
+
</InteractiveSection>
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
if ((properties && properties.length > 0) || schema.type === 'object') {
|
|
70
|
+
return (
|
|
71
|
+
<InteractiveSection id={id} className={clsx('openapi-schema', className)}>
|
|
72
|
+
<OpenAPISchemaPresentation {...props} />
|
|
73
|
+
{properties && properties.length > 0 ? (
|
|
74
|
+
<OpenAPIDisclosure context={context} label={getDisclosureLabel(schema)}>
|
|
75
|
+
<OpenAPISchemaProperties
|
|
76
|
+
properties={properties}
|
|
77
|
+
circularRefs={circularRefs}
|
|
78
|
+
context={context}
|
|
79
|
+
/>
|
|
80
|
+
</OpenAPIDisclosure>
|
|
81
|
+
) : null}
|
|
82
|
+
{parentCircularRef ? (
|
|
83
|
+
<OpenAPISchemaCircularRef id={parentCircularRef} schema={schema} />
|
|
84
|
+
) : null}
|
|
79
85
|
</InteractiveSection>
|
|
80
86
|
);
|
|
81
87
|
}
|
|
@@ -166,16 +172,24 @@ function OpenAPISchemaAlternative(props: {
|
|
|
166
172
|
const { schema, circularRefs, context } = props;
|
|
167
173
|
const id = useId();
|
|
168
174
|
const subProperties = getSchemaProperties(schema);
|
|
175
|
+
const description = resolveDescription(schema);
|
|
169
176
|
|
|
170
177
|
return (
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
178
|
+
<>
|
|
179
|
+
{description ? (
|
|
180
|
+
<Markdown source={description} className="openapi-schema-description" />
|
|
181
|
+
) : null}
|
|
182
|
+
<OpenAPIDisclosure context={context} label={getDisclosureLabel(schema)}>
|
|
183
|
+
<OpenAPISchemaProperties
|
|
184
|
+
id={id}
|
|
185
|
+
properties={subProperties ?? [{ schema }]}
|
|
186
|
+
circularRefs={
|
|
187
|
+
subProperties ? new Map(circularRefs).set(schema, id) : circularRefs
|
|
188
|
+
}
|
|
189
|
+
context={context}
|
|
190
|
+
/>
|
|
191
|
+
</OpenAPIDisclosure>
|
|
192
|
+
</>
|
|
179
193
|
);
|
|
180
194
|
}
|
|
181
195
|
|
|
@@ -219,7 +233,7 @@ export function OpenAPISchemaPresentation(props: OpenAPISchemaPropertyEntry) {
|
|
|
219
233
|
|
|
220
234
|
const shouldDisplayExample = (schema: OpenAPIV3.SchemaObject): boolean => {
|
|
221
235
|
return (
|
|
222
|
-
typeof schema.example === 'string' ||
|
|
236
|
+
(typeof schema.example === 'string' && !!schema.example) ||
|
|
223
237
|
typeof schema.example === 'number' ||
|
|
224
238
|
typeof schema.example === 'boolean' ||
|
|
225
239
|
(Array.isArray(schema.example) && schema.example.length > 0) ||
|
|
@@ -234,10 +248,10 @@ export function OpenAPISchemaPresentation(props: OpenAPISchemaPropertyEntry) {
|
|
|
234
248
|
return (
|
|
235
249
|
<div className="openapi-schema-presentation">
|
|
236
250
|
<OpenAPISchemaName
|
|
251
|
+
schema={schema}
|
|
237
252
|
type={getSchemaTitle(schema)}
|
|
238
253
|
propertyName={propertyName}
|
|
239
254
|
required={required}
|
|
240
|
-
deprecated={schema.deprecated}
|
|
241
255
|
/>
|
|
242
256
|
{schema['x-deprecated-sunset'] ? (
|
|
243
257
|
<div className="openapi-deprecated-sunset openapi-schema-description openapi-markdown">
|
|
@@ -252,12 +266,7 @@ export function OpenAPISchemaPresentation(props: OpenAPISchemaPropertyEntry) {
|
|
|
252
266
|
) : null}
|
|
253
267
|
{shouldDisplayExample(schema) ? (
|
|
254
268
|
<div className="openapi-schema-example">
|
|
255
|
-
Example:{
|
|
256
|
-
<code>
|
|
257
|
-
{typeof schema.example === 'string'
|
|
258
|
-
? schema.example
|
|
259
|
-
: stringifyOpenAPI(schema.example)}
|
|
260
|
-
</code>
|
|
269
|
+
Example: <code>{formatExample(schema.example)}</code>
|
|
261
270
|
</div>
|
|
262
271
|
) : null}
|
|
263
272
|
{schema.pattern ? (
|
|
@@ -276,17 +285,6 @@ export function OpenAPISchemaPresentation(props: OpenAPISchemaPropertyEntry) {
|
|
|
276
285
|
* Get the sub-properties of a schema.
|
|
277
286
|
*/
|
|
278
287
|
function getSchemaProperties(schema: OpenAPIV3.SchemaObject): null | OpenAPISchemaPropertyEntry[] {
|
|
279
|
-
if (schema.allOf) {
|
|
280
|
-
return schema.allOf.reduce((acc, subSchema) => {
|
|
281
|
-
const properties = getSchemaProperties(subSchema) ?? [
|
|
282
|
-
{
|
|
283
|
-
schema: subSchema,
|
|
284
|
-
},
|
|
285
|
-
];
|
|
286
|
-
return [...acc, ...properties];
|
|
287
|
-
}, [] as OpenAPISchemaPropertyEntry[]);
|
|
288
|
-
}
|
|
289
|
-
|
|
290
288
|
// check array AND schema.items as this is sometimes null despite what the type indicates
|
|
291
289
|
if (schema.type === 'array' && !!schema.items) {
|
|
292
290
|
const items = schema.items;
|
|
@@ -295,6 +293,11 @@ function getSchemaProperties(schema: OpenAPIV3.SchemaObject): null | OpenAPISche
|
|
|
295
293
|
return itemProperties;
|
|
296
294
|
}
|
|
297
295
|
|
|
296
|
+
// If the items are a primitive type, we don't need to display them
|
|
297
|
+
if (['string', 'number', 'boolean', 'integer'].includes(items.type) && !items.enum) {
|
|
298
|
+
return null;
|
|
299
|
+
}
|
|
300
|
+
|
|
298
301
|
return [
|
|
299
302
|
{
|
|
300
303
|
propertyName: 'items',
|
|
@@ -351,8 +354,7 @@ export function getSchemaAlternatives(
|
|
|
351
354
|
}
|
|
352
355
|
|
|
353
356
|
if (schema.allOf) {
|
|
354
|
-
|
|
355
|
-
return null;
|
|
357
|
+
return [flattenAlternatives('allOf', schema.allOf, downAncestors), schema.discriminator];
|
|
356
358
|
}
|
|
357
359
|
|
|
358
360
|
return null;
|
|
@@ -378,11 +380,6 @@ export function getSchemaTitle(
|
|
|
378
380
|
/** If the title is inferred in a oneOf with discriminator, we can use it to optimize the title */
|
|
379
381
|
discriminator?: OpenAPIV3.DiscriminatorObject,
|
|
380
382
|
): string {
|
|
381
|
-
if (schema.title) {
|
|
382
|
-
// If the schema has a title, use it
|
|
383
|
-
return schema.title;
|
|
384
|
-
}
|
|
385
|
-
|
|
386
383
|
// Try using the discriminator
|
|
387
384
|
if (discriminator?.propertyName && schema.properties) {
|
|
388
385
|
const discriminatorProperty = schema.properties[discriminator.propertyName];
|
|
@@ -419,21 +416,35 @@ export function getSchemaTitle(
|
|
|
419
416
|
type = 'not';
|
|
420
417
|
}
|
|
421
418
|
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
}
|
|
419
|
+
return type;
|
|
420
|
+
}
|
|
425
421
|
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
422
|
+
function getDisclosureLabel(schema: OpenAPIV3.SchemaObject): string | undefined {
|
|
423
|
+
if (schema.type === 'array' && !!schema.items) {
|
|
424
|
+
if (schema.items.oneOf) {
|
|
425
|
+
return 'available items';
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
// Fallback to "child attributes" for enums and objects
|
|
429
|
+
if (schema.items.enum || schema.items.type === 'object') {
|
|
430
|
+
return;
|
|
431
|
+
}
|
|
429
432
|
|
|
430
|
-
|
|
431
|
-
type += ` · default: ${schema.default}`;
|
|
433
|
+
return schema.items.title ?? schema.title ?? getSchemaTitle(schema.items);
|
|
432
434
|
}
|
|
433
435
|
|
|
434
|
-
|
|
435
|
-
|
|
436
|
+
return schema.title;
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
function formatExample(example: any): string {
|
|
440
|
+
if (typeof example === 'string') {
|
|
441
|
+
return example
|
|
442
|
+
.replace(/\n/g, ' ') // Replace newlines with spaces
|
|
443
|
+
.replace(/\s+/g, ' ') // Collapse multiple spaces/newlines into a single space
|
|
444
|
+
.replace(/([\{\}:,])\s+/g, '$1 ') // Ensure a space after {, }, :, and ,
|
|
445
|
+
.replace(/\s+([\{\}:,])/g, ' $1') // Ensure a space before {, }, :, and ,
|
|
446
|
+
.trim();
|
|
436
447
|
}
|
|
437
448
|
|
|
438
|
-
return
|
|
449
|
+
return stringifyOpenAPI(example);
|
|
439
450
|
}
|
|
@@ -1,8 +1,10 @@
|
|
|
1
|
+
import { OpenAPIV3 } from '@gitbook/openapi-parser';
|
|
2
|
+
|
|
1
3
|
interface OpenAPISchemaNameProps {
|
|
4
|
+
schema?: OpenAPIV3.SchemaObject;
|
|
2
5
|
propertyName?: string | JSX.Element;
|
|
3
6
|
required?: boolean;
|
|
4
7
|
type?: string;
|
|
5
|
-
deprecated?: boolean;
|
|
6
8
|
}
|
|
7
9
|
|
|
8
10
|
/**
|
|
@@ -10,18 +12,48 @@ interface OpenAPISchemaNameProps {
|
|
|
10
12
|
* It includes the property name, type, required and deprecated status.
|
|
11
13
|
*/
|
|
12
14
|
export function OpenAPISchemaName(props: OpenAPISchemaNameProps): JSX.Element {
|
|
13
|
-
const { type, propertyName, required
|
|
15
|
+
const { schema, type, propertyName, required } = props;
|
|
16
|
+
|
|
17
|
+
const additionalItems = schema && getAdditionalItems(schema);
|
|
14
18
|
|
|
15
19
|
return (
|
|
16
20
|
<div className="openapi-schema-name">
|
|
17
21
|
{propertyName ? (
|
|
18
|
-
<span data-deprecated={deprecated} className="openapi-schema-propertyname">
|
|
22
|
+
<span data-deprecated={schema?.deprecated} className="openapi-schema-propertyname">
|
|
19
23
|
{propertyName}
|
|
20
24
|
</span>
|
|
21
25
|
) : null}
|
|
22
|
-
|
|
26
|
+
<span>
|
|
27
|
+
{type ? <span className="openapi-schema-type">{type}</span> : null}
|
|
28
|
+
{additionalItems ? (
|
|
29
|
+
<span className="openapi-schema-type">{additionalItems}</span>
|
|
30
|
+
) : null}
|
|
31
|
+
</span>
|
|
23
32
|
{required ? <span className="openapi-schema-required">required</span> : null}
|
|
24
|
-
{deprecated ? <span className="openapi-deprecated">Deprecated</span> : null}
|
|
33
|
+
{schema?.deprecated ? <span className="openapi-deprecated">Deprecated</span> : null}
|
|
25
34
|
</div>
|
|
26
35
|
);
|
|
27
36
|
}
|
|
37
|
+
|
|
38
|
+
function getAdditionalItems(schema: OpenAPIV3.SchemaObject): string {
|
|
39
|
+
let additionalItems = '';
|
|
40
|
+
|
|
41
|
+
if (schema.minimum || schema.minLength) {
|
|
42
|
+
additionalItems += ` · min: ${schema.minimum || schema.minLength}`;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
if (schema.maximum || schema.maxLength) {
|
|
46
|
+
additionalItems += ` · max: ${schema.maximum || schema.maxLength}`;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// If the schema has a default value, we display it
|
|
50
|
+
if (typeof schema.default !== 'undefined') {
|
|
51
|
+
additionalItems += ` · default: ${schema.default}`;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
if (schema.nullable) {
|
|
55
|
+
additionalItems = ` | nullable`;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
return additionalItems;
|
|
59
|
+
}
|
package/src/OpenAPITabs.tsx
CHANGED
|
@@ -74,11 +74,17 @@ export function OpenAPITabs(
|
|
|
74
74
|
const tabFromState = syncedTabs.get(stateKey);
|
|
75
75
|
|
|
76
76
|
if (!items.some((item) => item.key === tabFromState?.key)) {
|
|
77
|
-
return;
|
|
77
|
+
return setSelectedTab(defaultTab);
|
|
78
78
|
}
|
|
79
79
|
|
|
80
80
|
if (tabFromState && tabFromState?.key !== selectedTab?.key) {
|
|
81
|
-
|
|
81
|
+
const tabFromItems = items.find((item) => item.key === tabFromState.key);
|
|
82
|
+
|
|
83
|
+
if (!tabFromItems) {
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
setSelectedTab(tabFromItems);
|
|
82
88
|
}
|
|
83
89
|
}
|
|
84
90
|
}, [isVisible, stateKey, syncedTabs, selectedTabKey]);
|