@gitbook/react-openapi 0.7.1 → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +49 -0
- package/dist/InteractiveSection.d.ts +4 -8
- package/dist/InteractiveSection.jsx +60 -0
- package/dist/Markdown.d.ts +1 -2
- package/dist/Markdown.jsx +5 -0
- package/dist/OpenAPICodeSample.d.ts +2 -4
- package/dist/OpenAPICodeSample.jsx +141 -0
- package/dist/OpenAPIDisclosure.d.ts +12 -0
- package/dist/OpenAPIDisclosure.jsx +32 -0
- package/dist/OpenAPIDisclosureGroup.d.ts +19 -0
- package/dist/OpenAPIDisclosureGroup.jsx +81 -0
- package/dist/OpenAPIOperation.d.ts +2 -4
- package/dist/OpenAPIOperation.jsx +51 -0
- package/dist/OpenAPIOperationContext.d.ts +16 -0
- package/dist/OpenAPIOperationContext.jsx +26 -0
- package/dist/OpenAPIPath.d.ts +8 -0
- package/dist/OpenAPIPath.jsx +54 -0
- package/dist/OpenAPIRequestBody.d.ts +4 -5
- package/dist/OpenAPIRequestBody.jsx +22 -0
- package/dist/OpenAPIResponse.d.ts +4 -4
- package/dist/OpenAPIResponse.jsx +39 -0
- package/dist/OpenAPIResponseExample.d.ts +2 -4
- package/dist/OpenAPIResponseExample.jsx +108 -0
- package/dist/OpenAPIResponses.d.ts +3 -4
- package/dist/OpenAPIResponses.jsx +35 -0
- package/dist/OpenAPISchema.d.ts +11 -8
- package/dist/OpenAPISchema.jsx +285 -0
- package/dist/OpenAPISchemaName.d.ts +12 -0
- package/dist/OpenAPISchemaName.jsx +15 -0
- package/dist/OpenAPISecurities.d.ts +2 -4
- package/dist/OpenAPISecurities.jsx +55 -0
- package/dist/OpenAPIServerURL.d.ts +2 -3
- package/dist/OpenAPIServerURL.jsx +67 -0
- package/dist/OpenAPIServerURLVariable.d.ts +2 -3
- package/dist/OpenAPIServerURLVariable.jsx +8 -0
- package/dist/OpenAPISpec.d.ts +3 -4
- package/dist/OpenAPISpec.jsx +91 -0
- package/dist/OpenAPITabs.d.ts +26 -0
- package/dist/OpenAPITabs.jsx +103 -0
- package/dist/ScalarApiButton.d.ts +3 -3
- package/dist/ScalarApiButton.jsx +51 -0
- package/dist/code-samples.d.ts +4 -0
- package/dist/code-samples.js +103 -38
- package/dist/generateSchemaExample.d.ts +2 -2
- package/dist/generateSchemaExample.js +29 -102
- package/dist/index.d.ts +3 -2
- package/dist/index.js +2 -1
- package/dist/resolveOpenAPIOperation.d.ts +11 -0
- package/dist/resolveOpenAPIOperation.js +194 -0
- package/dist/stringifyOpenAPI.d.ts +4 -0
- package/dist/stringifyOpenAPI.js +6 -0
- package/dist/tsconfig.build.tsbuildinfo +1 -0
- package/dist/types.d.ts +11 -12
- package/dist/useSyncedTabsGlobalState.d.ts +1 -0
- package/dist/useSyncedTabsGlobalState.js +16 -0
- package/dist/utils.d.ts +6 -2
- package/dist/utils.js +13 -6
- package/package.json +12 -10
- package/src/InteractiveSection.tsx +90 -86
- package/src/Markdown.tsx +2 -3
- package/src/OpenAPICodeSample.tsx +43 -31
- package/src/OpenAPIDisclosure.tsx +50 -0
- package/src/OpenAPIDisclosureGroup.tsx +136 -0
- package/src/OpenAPIOperation.tsx +36 -42
- package/src/OpenAPIOperationContext.tsx +45 -0
- package/src/OpenAPIPath.tsx +65 -0
- package/src/OpenAPIRequestBody.tsx +10 -17
- package/src/OpenAPIResponse.tsx +27 -45
- package/src/OpenAPIResponseExample.tsx +89 -31
- package/src/OpenAPIResponses.tsx +48 -17
- package/src/OpenAPISchema.test.ts +1 -1
- package/src/OpenAPISchema.tsx +129 -108
- package/src/OpenAPISchemaName.tsx +27 -0
- package/src/OpenAPISecurities.tsx +45 -24
- package/src/OpenAPIServerURL.tsx +17 -10
- package/src/OpenAPIServerURLVariable.tsx +2 -4
- package/src/OpenAPISpec.tsx +58 -58
- package/src/OpenAPITabs.tsx +153 -0
- package/src/ScalarApiButton.tsx +84 -7
- package/src/code-samples.test.ts +51 -0
- package/src/code-samples.ts +95 -31
- package/src/generateSchemaExample.ts +26 -153
- package/src/index.ts +3 -2
- package/src/resolveOpenAPIOperation.test.ts +177 -0
- package/src/resolveOpenAPIOperation.ts +164 -0
- package/src/stringifyOpenAPI.ts +6 -0
- package/src/types.ts +17 -10
- package/src/useSyncedTabsGlobalState.ts +23 -0
- package/src/utils.ts +14 -7
- package/dist/InteractiveSection.js +0 -47
- package/dist/Markdown.js +0 -6
- package/dist/OpenAPICodeSample.js +0 -110
- package/dist/OpenAPIOperation.js +0 -38
- package/dist/OpenAPIRequestBody.js +0 -18
- package/dist/OpenAPIResponse.js +0 -32
- package/dist/OpenAPIResponseExample.js +0 -54
- package/dist/OpenAPIResponses.js +0 -18
- package/dist/OpenAPISchema.js +0 -235
- package/dist/OpenAPISchema.test.d.ts +0 -1
- package/dist/OpenAPISchema.test.js +0 -91
- package/dist/OpenAPISecurities.js +0 -42
- package/dist/OpenAPIServerURL.js +0 -51
- package/dist/OpenAPIServerURLVariable.js +0 -10
- package/dist/OpenAPISpec.js +0 -70
- package/dist/ScalarApiButton.js +0 -14
- package/dist/fetchOpenAPIOperation.d.ts +0 -72
- package/dist/fetchOpenAPIOperation.js +0 -124
- package/dist/fetchOpenAPIOperation.test.d.ts +0 -1
- package/dist/fetchOpenAPIOperation.test.js +0 -152
- package/dist/resolveOpenAPIPath.d.ts +0 -7
- package/dist/resolveOpenAPIPath.js +0 -112
- package/dist/resolveOpenAPIPath.test.d.ts +0 -1
- package/dist/resolveOpenAPIPath.test.js +0 -39
- package/dist/tsconfig.tsbuildinfo +0 -1
- package/src/fetchOpenAPIOperation.test.ts +0 -185
- package/src/fetchOpenAPIOperation.ts +0 -230
- package/src/resolveOpenAPIPath.test.ts +0 -60
- package/src/resolveOpenAPIPath.ts +0 -145
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { createContext, useContext, useMemo } from 'react';
|
|
4
|
+
import { useEventCallback } from 'usehooks-ts';
|
|
5
|
+
|
|
6
|
+
interface OpenAPIOperationPointer {
|
|
7
|
+
path: string;
|
|
8
|
+
method: string;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
interface OpenAPIOperationContextValue {
|
|
12
|
+
onOpenClient: (pointer: OpenAPIOperationPointer) => void;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const OpenAPIOperationContext = createContext<OpenAPIOperationContextValue>({
|
|
16
|
+
onOpenClient: () => {},
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Provider for the OpenAPIOperationContext.
|
|
21
|
+
*/
|
|
22
|
+
export function OpenAPIOperationContextProvider(
|
|
23
|
+
props: React.PropsWithChildren<Partial<OpenAPIOperationContextValue>>,
|
|
24
|
+
) {
|
|
25
|
+
const { children } = props;
|
|
26
|
+
|
|
27
|
+
const onOpenClient = useEventCallback((pointer: OpenAPIOperationPointer) => {
|
|
28
|
+
props.onOpenClient?.(pointer);
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
const value = useMemo(() => ({ onOpenClient }), [onOpenClient]);
|
|
32
|
+
|
|
33
|
+
return (
|
|
34
|
+
<OpenAPIOperationContext.Provider value={value}>
|
|
35
|
+
{children}
|
|
36
|
+
</OpenAPIOperationContext.Provider>
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Hook to access the OpenAPIOperationContext.
|
|
42
|
+
*/
|
|
43
|
+
export function useOpenAPIOperationContext() {
|
|
44
|
+
return useContext(OpenAPIOperationContext);
|
|
45
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { ScalarApiButton } from './ScalarApiButton';
|
|
2
|
+
import type { OpenAPIOperationData, OpenAPIContextProps } from './types';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Display the path of an operation.
|
|
6
|
+
*/
|
|
7
|
+
export function OpenAPIPath(props: {
|
|
8
|
+
data: OpenAPIOperationData;
|
|
9
|
+
context: OpenAPIContextProps;
|
|
10
|
+
}): JSX.Element {
|
|
11
|
+
const { data, context } = props;
|
|
12
|
+
const { method, path } = data;
|
|
13
|
+
const { specUrl } = context;
|
|
14
|
+
|
|
15
|
+
return (
|
|
16
|
+
<div className="openapi-path">
|
|
17
|
+
<div className={`openapi-method openapi-method-${method}`}>{method}</div>
|
|
18
|
+
<div className="openapi-path-title" data-deprecated={data.operation.deprecated}>
|
|
19
|
+
<p>{formatPath(path)}</p>
|
|
20
|
+
</div>
|
|
21
|
+
{data['x-hideTryItPanel'] || data.operation['x-hideTryItPanel'] ? null : (
|
|
22
|
+
<ScalarApiButton method={method} path={path} specUrl={specUrl} />
|
|
23
|
+
)}
|
|
24
|
+
</div>
|
|
25
|
+
);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// Format the path to highlight placeholders
|
|
29
|
+
function formatPath(path: string) {
|
|
30
|
+
// Matches placeholders like {id}, {userId}, etc.
|
|
31
|
+
const regex = /\{(\w+)\}/g;
|
|
32
|
+
|
|
33
|
+
const parts: (string | JSX.Element)[] = [];
|
|
34
|
+
let lastIndex = 0;
|
|
35
|
+
|
|
36
|
+
// Replace placeholders with <em> tags
|
|
37
|
+
path.replace(regex, (match, key, offset) => {
|
|
38
|
+
parts.push(path.slice(lastIndex, offset));
|
|
39
|
+
parts.push(<em key={key}>{`{${key}}`}</em>);
|
|
40
|
+
lastIndex = offset + match.length;
|
|
41
|
+
return match;
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
// Push remaining text after the last placeholder
|
|
45
|
+
parts.push(path.slice(lastIndex));
|
|
46
|
+
|
|
47
|
+
// Join parts with separators wrapped in <span>
|
|
48
|
+
const formattedPath = parts.reduce(
|
|
49
|
+
(acc, part, index) => {
|
|
50
|
+
if (typeof part === 'string' && index > 0 && part === '/') {
|
|
51
|
+
return [
|
|
52
|
+
...acc,
|
|
53
|
+
<span className="openapi-path-separator" key={`sep-${index}`}>
|
|
54
|
+
/
|
|
55
|
+
</span>,
|
|
56
|
+
part,
|
|
57
|
+
];
|
|
58
|
+
}
|
|
59
|
+
return [...acc, part];
|
|
60
|
+
},
|
|
61
|
+
[] as (string | JSX.Element)[],
|
|
62
|
+
);
|
|
63
|
+
|
|
64
|
+
return <span>{formattedPath}</span>;
|
|
65
|
+
}
|
|
@@ -1,21 +1,22 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
import { OpenAPIV3 } from 'openapi-types';
|
|
1
|
+
import type { OpenAPIV3 } from '@gitbook/openapi-parser';
|
|
4
2
|
import { OpenAPIRootSchema } from './OpenAPISchema';
|
|
5
|
-
import {
|
|
6
|
-
import { OpenAPIClientContext } from './types';
|
|
3
|
+
import type { OpenAPIClientContext } from './types';
|
|
7
4
|
import { InteractiveSection } from './InteractiveSection';
|
|
8
|
-
import {
|
|
5
|
+
import { checkIsReference } from './utils';
|
|
9
6
|
|
|
10
7
|
/**
|
|
11
8
|
* Display an interactive request body.
|
|
12
9
|
*/
|
|
13
10
|
export function OpenAPIRequestBody(props: {
|
|
14
|
-
requestBody: OpenAPIV3.RequestBodyObject;
|
|
11
|
+
requestBody: OpenAPIV3.RequestBodyObject | OpenAPIV3.ReferenceObject;
|
|
15
12
|
context: OpenAPIClientContext;
|
|
16
13
|
}) {
|
|
17
14
|
const { requestBody, context } = props;
|
|
18
15
|
|
|
16
|
+
if (checkIsReference(requestBody)) {
|
|
17
|
+
return null;
|
|
18
|
+
}
|
|
19
|
+
|
|
19
20
|
return (
|
|
20
21
|
<InteractiveSection
|
|
21
22
|
header="Body"
|
|
@@ -27,21 +28,13 @@ export function OpenAPIRequestBody(props: {
|
|
|
27
28
|
label: contentType,
|
|
28
29
|
body: (
|
|
29
30
|
<OpenAPIRootSchema
|
|
30
|
-
schema={
|
|
31
|
+
schema={mediaTypeObject.schema ?? {}}
|
|
31
32
|
context={context}
|
|
32
33
|
/>
|
|
33
34
|
),
|
|
34
35
|
};
|
|
35
36
|
},
|
|
36
37
|
)}
|
|
37
|
-
|
|
38
|
-
>
|
|
39
|
-
{requestBody.description ? (
|
|
40
|
-
<Markdown
|
|
41
|
-
source={requestBody.description}
|
|
42
|
-
className="openapi-requestbody-description"
|
|
43
|
-
/>
|
|
44
|
-
) : null}
|
|
45
|
-
</InteractiveSection>
|
|
38
|
+
/>
|
|
46
39
|
);
|
|
47
40
|
}
|
package/src/OpenAPIResponse.tsx
CHANGED
|
@@ -1,72 +1,54 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import { OpenAPIClientContext } from './types';
|
|
7
|
-
import { InteractiveSection } from './InteractiveSection';
|
|
8
|
-
import { Markdown } from './Markdown';
|
|
1
|
+
import type { OpenAPIV3 } from '@gitbook/openapi-parser';
|
|
2
|
+
import { OpenAPISchemaProperties } from './OpenAPISchema';
|
|
3
|
+
import { resolveDescription } from './utils';
|
|
4
|
+
import type { OpenAPIClientContext } from './types';
|
|
5
|
+
import { OpenAPIDisclosure } from './OpenAPIDisclosure';
|
|
9
6
|
|
|
10
7
|
/**
|
|
11
8
|
* Display an interactive response body.
|
|
12
9
|
*/
|
|
13
10
|
export function OpenAPIResponse(props: {
|
|
14
11
|
response: OpenAPIV3.ResponseObject;
|
|
12
|
+
mediaType: OpenAPIV3.MediaTypeObject;
|
|
15
13
|
context: OpenAPIClientContext;
|
|
16
14
|
}) {
|
|
17
|
-
const { response, context } = props;
|
|
18
|
-
const content = Object.entries(response.content ?? {});
|
|
15
|
+
const { response, context, mediaType } = props;
|
|
19
16
|
const headers = Object.entries(response.headers ?? {}).map(
|
|
20
|
-
([name, header]) => [name,
|
|
17
|
+
([name, header]) => [name, header ?? {}] as const,
|
|
21
18
|
);
|
|
19
|
+
const content = Object.entries(mediaType.schema ?? {});
|
|
22
20
|
|
|
23
|
-
|
|
21
|
+
const description = resolveDescription(response);
|
|
22
|
+
|
|
23
|
+
if (content.length === 0 && !description && headers.length === 0) {
|
|
24
24
|
return null;
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
return (
|
|
28
|
-
|
|
29
|
-
{response.description ? (
|
|
30
|
-
<Markdown source={response.description} className="openapi-response-description" />
|
|
31
|
-
) : null}
|
|
32
|
-
|
|
28
|
+
<div className="openapi-response-body">
|
|
33
29
|
{headers.length > 0 ? (
|
|
34
|
-
<
|
|
35
|
-
toggeable
|
|
36
|
-
defaultOpened={!!context.defaultInteractiveOpened}
|
|
37
|
-
toggleCloseIcon={context.icons.chevronDown}
|
|
38
|
-
toggleOpenIcon={context.icons.chevronRight}
|
|
39
|
-
header="Headers"
|
|
40
|
-
className={classNames('openapi-responseheaders')}
|
|
41
|
-
>
|
|
30
|
+
<OpenAPIDisclosure context={context} label={'Headers'}>
|
|
42
31
|
<OpenAPISchemaProperties
|
|
43
32
|
properties={headers.map(([name, header]) => ({
|
|
44
33
|
propertyName: name,
|
|
45
|
-
schema:
|
|
34
|
+
schema: header.schema ?? {},
|
|
46
35
|
required: header.required,
|
|
47
36
|
}))}
|
|
48
37
|
context={context}
|
|
49
38
|
/>
|
|
50
|
-
</
|
|
39
|
+
</OpenAPIDisclosure>
|
|
51
40
|
) : null}
|
|
52
|
-
|
|
53
|
-
<
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
<OpenAPIRootSchema
|
|
62
|
-
schema={noReference(mediaType.schema) ?? {}}
|
|
63
|
-
context={context}
|
|
64
|
-
/>
|
|
65
|
-
),
|
|
66
|
-
};
|
|
67
|
-
})}
|
|
41
|
+
<div className="openapi-responsebody">
|
|
42
|
+
<OpenAPISchemaProperties
|
|
43
|
+
id={`response-${context.blockKey}`}
|
|
44
|
+
properties={[
|
|
45
|
+
{
|
|
46
|
+
schema: mediaType.schema ?? {},
|
|
47
|
+
},
|
|
48
|
+
]}
|
|
49
|
+
context={context}
|
|
68
50
|
/>
|
|
69
|
-
|
|
70
|
-
|
|
51
|
+
</div>
|
|
52
|
+
</div>
|
|
71
53
|
);
|
|
72
54
|
}
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { InteractiveSection } from './InteractiveSection';
|
|
3
|
-
import { OpenAPIOperationData } from './fetchOpenAPIOperation';
|
|
1
|
+
import type { OpenAPIV3 } from '@gitbook/openapi-parser';
|
|
4
2
|
import { generateSchemaExample } from './generateSchemaExample';
|
|
5
|
-
import { OpenAPIContextProps } from './types';
|
|
6
|
-
import { createStateKey,
|
|
3
|
+
import type { OpenAPIContextProps, OpenAPIOperationData } from './types';
|
|
4
|
+
import { checkIsReference, createStateKey, resolveDescription } from './utils';
|
|
5
|
+
import { stringifyOpenAPI } from './stringifyOpenAPI';
|
|
6
|
+
import { OpenAPITabs, OpenAPITabsList, OpenAPITabsPanels } from './OpenAPITabs';
|
|
7
|
+
import { InteractiveSection } from './InteractiveSection';
|
|
7
8
|
|
|
8
9
|
/**
|
|
9
10
|
* Display an example of the response content.
|
|
@@ -38,50 +39,107 @@ export function OpenAPIResponseExample(props: {
|
|
|
38
39
|
});
|
|
39
40
|
|
|
40
41
|
const examples = responses
|
|
41
|
-
.map((
|
|
42
|
-
const responseObject =
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
42
|
+
.map(([key, value]) => {
|
|
43
|
+
const responseObject = value;
|
|
44
|
+
const mediaTypeObject = (() => {
|
|
45
|
+
if (!responseObject.content) {
|
|
46
|
+
return null;
|
|
47
|
+
}
|
|
48
|
+
const key = Object.keys(responseObject.content)[0];
|
|
49
|
+
return (
|
|
50
|
+
responseObject.content['application/json'] ??
|
|
51
|
+
(key ? responseObject.content[key] : null)
|
|
52
|
+
);
|
|
53
|
+
})();
|
|
50
54
|
|
|
51
|
-
if (!
|
|
52
|
-
return
|
|
55
|
+
if (!mediaTypeObject) {
|
|
56
|
+
return {
|
|
57
|
+
key: key,
|
|
58
|
+
label: key,
|
|
59
|
+
description: resolveDescription(responseObject),
|
|
60
|
+
body: <OpenAPIEmptyResponseExample />,
|
|
61
|
+
};
|
|
53
62
|
}
|
|
54
63
|
|
|
55
|
-
const example =
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
64
|
+
const example = handleUnresolvedReference(
|
|
65
|
+
(() => {
|
|
66
|
+
const { examples, example } = mediaTypeObject;
|
|
67
|
+
if (examples) {
|
|
68
|
+
const key = Object.keys(examples)[0];
|
|
69
|
+
if (key) {
|
|
70
|
+
// @TODO handle multiple examples
|
|
71
|
+
const firstExample = examples[key];
|
|
72
|
+
if (firstExample) {
|
|
73
|
+
return firstExample;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
if (example) {
|
|
79
|
+
return { value: example };
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const schema = mediaTypeObject.schema;
|
|
83
|
+
if (!schema) {
|
|
84
|
+
return null;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
return { value: generateSchemaExample(schema) };
|
|
88
|
+
})(),
|
|
89
|
+
);
|
|
59
90
|
|
|
60
91
|
return {
|
|
61
|
-
key:
|
|
62
|
-
label:
|
|
63
|
-
|
|
92
|
+
key: key,
|
|
93
|
+
label: key,
|
|
94
|
+
description: resolveDescription(responseObject),
|
|
95
|
+
body: example?.value ? (
|
|
64
96
|
<context.CodeBlock
|
|
65
97
|
code={
|
|
66
|
-
typeof example === 'string'
|
|
98
|
+
typeof example.value === 'string'
|
|
99
|
+
? example.value
|
|
100
|
+
: stringifyOpenAPI(example.value, null, 2)
|
|
67
101
|
}
|
|
68
102
|
syntax="json"
|
|
69
103
|
/>
|
|
104
|
+
) : (
|
|
105
|
+
<OpenAPIEmptyResponseExample />
|
|
70
106
|
),
|
|
71
107
|
};
|
|
72
108
|
})
|
|
73
|
-
.filter((val): val is { key: string; label: string; body: any } =>
|
|
109
|
+
.filter((val): val is { key: string; label: string; body: any; description: string } =>
|
|
110
|
+
Boolean(val),
|
|
111
|
+
);
|
|
74
112
|
|
|
75
113
|
if (examples.length === 0) {
|
|
76
114
|
return null;
|
|
77
115
|
}
|
|
78
116
|
|
|
79
117
|
return (
|
|
80
|
-
<
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
/>
|
|
118
|
+
<OpenAPITabs stateKey={createStateKey('response-example')} items={examples}>
|
|
119
|
+
<InteractiveSection header={<OpenAPITabsList />} className="openapi-response-example">
|
|
120
|
+
<OpenAPITabsPanels />
|
|
121
|
+
</InteractiveSection>
|
|
122
|
+
</OpenAPITabs>
|
|
86
123
|
);
|
|
87
124
|
}
|
|
125
|
+
|
|
126
|
+
function OpenAPIEmptyResponseExample() {
|
|
127
|
+
return (
|
|
128
|
+
<pre className="openapi-response-example-empty">
|
|
129
|
+
<p>No body</p>
|
|
130
|
+
</pre>
|
|
131
|
+
);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
function handleUnresolvedReference(
|
|
135
|
+
input: OpenAPIV3.ExampleObject | null,
|
|
136
|
+
): OpenAPIV3.ExampleObject | null {
|
|
137
|
+
const isReference = checkIsReference(input?.value);
|
|
138
|
+
|
|
139
|
+
if (isReference) {
|
|
140
|
+
// If we find a reference that wasn't resolved or needed to be resolved externally, render out the URL
|
|
141
|
+
return { value: input.value.$ref };
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
return input;
|
|
145
|
+
}
|
package/src/OpenAPIResponses.tsx
CHANGED
|
@@ -1,32 +1,63 @@
|
|
|
1
|
-
import
|
|
2
|
-
import classNames from 'classnames';
|
|
3
|
-
import { OpenAPIV3 } from 'openapi-types';
|
|
4
|
-
import { createStateKey, noReference } from './utils';
|
|
1
|
+
import type { OpenAPIV3, OpenAPIV3_1 } from '@gitbook/openapi-parser';
|
|
5
2
|
import { OpenAPIResponse } from './OpenAPIResponse';
|
|
6
3
|
import { OpenAPIClientContext } from './types';
|
|
7
4
|
import { InteractiveSection } from './InteractiveSection';
|
|
5
|
+
import { OpenAPIDisclosureGroup } from './OpenAPIDisclosureGroup';
|
|
6
|
+
import { Markdown } from './Markdown';
|
|
8
7
|
|
|
9
8
|
/**
|
|
10
9
|
* Display an interactive response body.
|
|
11
10
|
*/
|
|
12
11
|
export function OpenAPIResponses(props: {
|
|
13
|
-
responses: OpenAPIV3.ResponsesObject;
|
|
12
|
+
responses: OpenAPIV3.ResponsesObject | OpenAPIV3_1.ResponsesObject;
|
|
14
13
|
context: OpenAPIClientContext;
|
|
15
14
|
}) {
|
|
16
15
|
const { responses, context } = props;
|
|
17
16
|
|
|
18
17
|
return (
|
|
19
|
-
<InteractiveSection
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
18
|
+
<InteractiveSection header="Responses" className="openapi-responses">
|
|
19
|
+
<OpenAPIDisclosureGroup
|
|
20
|
+
allowsMultipleExpanded
|
|
21
|
+
icon={context.icons.chevronRight}
|
|
22
|
+
groups={Object.entries(responses).map(
|
|
23
|
+
([statusCode, response]: [string, OpenAPIV3.ResponseObject]) => {
|
|
24
|
+
const content = Object.entries(response.content ?? {});
|
|
25
|
+
const description = response.description;
|
|
26
|
+
|
|
27
|
+
return {
|
|
28
|
+
id: statusCode,
|
|
29
|
+
label: (
|
|
30
|
+
<div
|
|
31
|
+
className="openapi-response-tab-content"
|
|
32
|
+
key={`response-${statusCode}`}
|
|
33
|
+
>
|
|
34
|
+
<span className="openapi-response-statuscode">
|
|
35
|
+
{statusCode}
|
|
36
|
+
</span>
|
|
37
|
+
{description ? (
|
|
38
|
+
<Markdown
|
|
39
|
+
source={description}
|
|
40
|
+
className="openapi-response-description"
|
|
41
|
+
/>
|
|
42
|
+
) : null}
|
|
43
|
+
</div>
|
|
44
|
+
),
|
|
45
|
+
tabs: content.map(([contentType, mediaType]) => ({
|
|
46
|
+
id: contentType,
|
|
47
|
+
label: contentType,
|
|
48
|
+
body: (
|
|
49
|
+
<OpenAPIResponse
|
|
50
|
+
key={`$response-${statusCode}-${contentType}`}
|
|
51
|
+
response={response}
|
|
52
|
+
mediaType={mediaType}
|
|
53
|
+
context={context}
|
|
54
|
+
/>
|
|
55
|
+
),
|
|
56
|
+
})),
|
|
57
|
+
};
|
|
58
|
+
},
|
|
59
|
+
)}
|
|
60
|
+
/>
|
|
61
|
+
</InteractiveSection>
|
|
31
62
|
);
|
|
32
63
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { it, describe, expect } from 'bun:test';
|
|
2
2
|
import { getSchemaAlternatives } from './OpenAPISchema';
|
|
3
|
-
import { OpenAPIV3 } from 'openapi-
|
|
3
|
+
import type { OpenAPIV3 } from '@gitbook/openapi-parser';
|
|
4
4
|
|
|
5
5
|
describe('getSchemaAlternatives', () => {
|
|
6
6
|
it('should flatten oneOf', () => {
|