@gitbook/react-openapi 1.0.3 → 1.0.4
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 +8 -0
- package/dist/OpenAPICodeSample.jsx +6 -7
- package/dist/OpenAPIDisclosure.d.ts +2 -1
- package/dist/OpenAPIDisclosure.jsx +1 -1
- package/dist/OpenAPIDisclosureGroup.d.ts +1 -1
- package/dist/OpenAPIDisclosureGroup.jsx +2 -2
- package/dist/OpenAPIOperation.jsx +2 -2
- package/dist/OpenAPIPath.d.ts +3 -2
- package/dist/OpenAPIPath.jsx +4 -15
- package/dist/OpenAPIRequestBody.jsx +1 -1
- package/dist/OpenAPIResponse.jsx +1 -1
- package/dist/OpenAPIResponseExample.jsx +3 -3
- package/dist/OpenAPIResponses.d.ts +1 -1
- package/dist/OpenAPIResponses.jsx +2 -2
- package/dist/OpenAPISchema.d.ts +5 -1
- package/dist/OpenAPISchema.jsx +29 -20
- package/dist/OpenAPISchemaName.d.ts +4 -3
- package/dist/OpenAPISchemaName.jsx +1 -1
- package/dist/OpenAPISecurities.jsx +2 -2
- package/dist/OpenAPITabs.d.ts +3 -3
- package/dist/OpenAPITabs.jsx +11 -12
- package/dist/ScalarApiButton.jsx +1 -1
- package/dist/code-samples.js +11 -11
- package/dist/generateSchemaExample.js +2 -1
- package/dist/resolveOpenAPIOperation.d.ts +3 -3
- package/dist/resolveOpenAPIOperation.js +1 -1
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/dist/util/server.d.ts +1 -1
- package/dist/util/server.js +1 -3
- package/dist/utils.d.ts +1 -1
- package/dist/utils.js +4 -6
- package/package.json +2 -7
- package/src/InteractiveSection.tsx +4 -4
- package/src/OpenAPICodeSample.tsx +9 -10
- package/src/OpenAPIDisclosure.tsx +4 -3
- package/src/OpenAPIDisclosureGroup.tsx +5 -5
- package/src/OpenAPIOperation.tsx +3 -3
- package/src/OpenAPIOperationContext.tsx +1 -1
- package/src/OpenAPIPath.tsx +11 -10
- package/src/OpenAPIRequestBody.tsx +2 -2
- package/src/OpenAPIResponse.tsx +3 -3
- package/src/OpenAPIResponseExample.tsx +5 -5
- package/src/OpenAPIResponses.tsx +4 -4
- package/src/OpenAPISchema.test.ts +5 -5
- package/src/OpenAPISchema.tsx +75 -25
- package/src/OpenAPISchemaName.tsx +5 -4
- package/src/OpenAPISecurities.tsx +3 -3
- package/src/OpenAPITabs.tsx +15 -15
- package/src/ScalarApiButton.tsx +3 -3
- package/src/code-samples.test.ts +66 -66
- package/src/code-samples.ts +14 -14
- package/src/generateSchemaExample.ts +3 -3
- package/src/json2xml.test.ts +1 -1
- package/src/resolveOpenAPIOperation.test.ts +6 -6
- package/src/resolveOpenAPIOperation.ts +7 -7
- package/src/stringifyOpenAPI.ts +1 -1
- package/src/util/server.test.ts +3 -3
- package/src/util/server.ts +2 -3
- package/src/utils.ts +4 -4
package/dist/util/server.d.ts
CHANGED
package/dist/util/server.js
CHANGED
|
@@ -21,9 +21,7 @@ export function interpolateServerURL(server) {
|
|
|
21
21
|
if (part.kind === 'text') {
|
|
22
22
|
return part.text;
|
|
23
23
|
}
|
|
24
|
-
|
|
25
|
-
return (_c = (_b = (_a = server.variables) === null || _a === void 0 ? void 0 : _a[part.name]) === null || _b === void 0 ? void 0 : _b.default) !== null && _c !== void 0 ? _c : "{".concat(part.name, "}");
|
|
26
|
-
}
|
|
24
|
+
return (_c = (_b = (_a = server.variables) === null || _a === void 0 ? void 0 : _a[part.name]) === null || _b === void 0 ? void 0 : _b.default) !== null && _c !== void 0 ? _c : "{".concat(part.name, "}");
|
|
27
25
|
})
|
|
28
26
|
.join('');
|
|
29
27
|
}
|
package/dist/utils.d.ts
CHANGED
|
@@ -10,7 +10,7 @@ export declare function resolveDescription(object: OpenAPIV3.SchemaObject | AnyO
|
|
|
10
10
|
*/
|
|
11
11
|
export declare function extractDescriptions(object: AnyObject): {
|
|
12
12
|
description: any;
|
|
13
|
-
|
|
13
|
+
'x-gitbook-description-html': any;
|
|
14
14
|
};
|
|
15
15
|
/**
|
|
16
16
|
* Resolve the first example from an object.
|
package/dist/utils.js
CHANGED
|
@@ -33,14 +33,12 @@ export function resolveDescription(object) {
|
|
|
33
33
|
* Extract descriptions from an object.
|
|
34
34
|
*/
|
|
35
35
|
export function extractDescriptions(object) {
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
},
|
|
40
|
-
_a['x-gitbook-description-html'] = 'x-gitbook-description-html' in object
|
|
36
|
+
return {
|
|
37
|
+
description: object.description,
|
|
38
|
+
'x-gitbook-description-html': 'x-gitbook-description-html' in object
|
|
41
39
|
? object['x-gitbook-description-html']
|
|
42
40
|
: undefined,
|
|
43
|
-
|
|
41
|
+
};
|
|
44
42
|
}
|
|
45
43
|
/**
|
|
46
44
|
* Resolve the first example from an object.
|
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.4",
|
|
12
12
|
"sideEffects": false,
|
|
13
13
|
"dependencies": {
|
|
14
14
|
"@gitbook/openapi-parser": "workspace:*",
|
|
@@ -36,10 +36,5 @@
|
|
|
36
36
|
"dev": "bun run build -- --watch",
|
|
37
37
|
"clean": "rm -rf ./dist"
|
|
38
38
|
},
|
|
39
|
-
"files": [
|
|
40
|
-
"dist",
|
|
41
|
-
"src",
|
|
42
|
-
"README.md",
|
|
43
|
-
"CHANGELOG.md"
|
|
44
|
-
]
|
|
39
|
+
"files": ["dist", "src", "README.md", "CHANGELOG.md"]
|
|
45
40
|
}
|
|
@@ -69,7 +69,7 @@ export function InteractiveSection(props: {
|
|
|
69
69
|
'openapi-section',
|
|
70
70
|
toggeable ? 'openapi-section-toggeable' : null,
|
|
71
71
|
className,
|
|
72
|
-
toggeable ? `${className}-${state.isExpanded ? 'opened' : 'closed'}` : null
|
|
72
|
+
toggeable ? `${className}-${state.isExpanded ? 'opened' : 'closed'}` : null
|
|
73
73
|
)}
|
|
74
74
|
>
|
|
75
75
|
{header ? (
|
|
@@ -84,7 +84,7 @@ export function InteractiveSection(props: {
|
|
|
84
84
|
<div
|
|
85
85
|
className={clsx(
|
|
86
86
|
'openapi-section-header-content',
|
|
87
|
-
`${className}-header-content
|
|
87
|
+
`${className}-header-content`
|
|
88
88
|
)}
|
|
89
89
|
>
|
|
90
90
|
{(children || selectedTab?.body) && toggeable ? (
|
|
@@ -106,7 +106,7 @@ export function InteractiveSection(props: {
|
|
|
106
106
|
<div
|
|
107
107
|
className={clsx(
|
|
108
108
|
'openapi-section-header-controls',
|
|
109
|
-
`${className}-header-controls
|
|
109
|
+
`${className}-header-controls`
|
|
110
110
|
)}
|
|
111
111
|
onClick={(event) => {
|
|
112
112
|
event.stopPropagation();
|
|
@@ -117,7 +117,7 @@ export function InteractiveSection(props: {
|
|
|
117
117
|
className={clsx(
|
|
118
118
|
'openapi-section-select',
|
|
119
119
|
'openapi-select',
|
|
120
|
-
`${className}-tabs-select
|
|
120
|
+
`${className}-tabs-select`
|
|
121
121
|
)}
|
|
122
122
|
value={selectedTab?.key ?? ''}
|
|
123
123
|
onChange={(event) => {
|
|
@@ -1,12 +1,11 @@
|
|
|
1
|
-
import { CodeSampleInput, codeSampleGenerators } from './code-samples';
|
|
2
|
-
import { generateMediaTypeExample, generateSchemaExample } from './generateSchemaExample';
|
|
3
1
|
import { InteractiveSection } from './InteractiveSection';
|
|
4
|
-
import type { OpenAPIContextProps, OpenAPIOperationData } from './types';
|
|
5
|
-
import { createStateKey } from './utils';
|
|
6
|
-
import { stringifyOpenAPI } from './stringifyOpenAPI';
|
|
7
2
|
import { OpenAPITabs, OpenAPITabsList, OpenAPITabsPanels } from './OpenAPITabs';
|
|
8
|
-
import {
|
|
3
|
+
import { type CodeSampleInput, codeSampleGenerators } from './code-samples';
|
|
4
|
+
import { generateMediaTypeExample, generateSchemaExample } from './generateSchemaExample';
|
|
5
|
+
import { stringifyOpenAPI } from './stringifyOpenAPI';
|
|
6
|
+
import type { OpenAPIContextProps, OpenAPIOperationData } from './types';
|
|
9
7
|
import { getDefaultServerURL } from './util/server';
|
|
8
|
+
import { checkIsReference, createStateKey } from './utils';
|
|
10
9
|
|
|
11
10
|
/**
|
|
12
11
|
* Display code samples to execute the operation.
|
|
@@ -37,7 +36,7 @@ export function OpenAPICodeSample(props: {
|
|
|
37
36
|
if (example !== undefined && param.name) {
|
|
38
37
|
searchParams.append(
|
|
39
38
|
param.name,
|
|
40
|
-
String(Array.isArray(example) ? example[0] : example)
|
|
39
|
+
String(Array.isArray(example) ? example[0] : example)
|
|
41
40
|
);
|
|
42
41
|
}
|
|
43
42
|
}
|
|
@@ -95,8 +94,8 @@ export function OpenAPICodeSample(props: {
|
|
|
95
94
|
typeof sample.lang === 'string'
|
|
96
95
|
);
|
|
97
96
|
})
|
|
98
|
-
.map((sample) => ({
|
|
99
|
-
key: `redocly-${sample.lang}`,
|
|
97
|
+
.map((sample, index) => ({
|
|
98
|
+
key: `redocly-${sample.lang}-${index}`,
|
|
100
99
|
label: sample.label,
|
|
101
100
|
body: context.renderCodeBlock({
|
|
102
101
|
code: sample.source,
|
|
@@ -149,7 +148,7 @@ function getSecurityHeaders(securities: OpenAPIOperationData['securities']): {
|
|
|
149
148
|
}
|
|
150
149
|
|
|
151
150
|
return {
|
|
152
|
-
Authorization: scheme
|
|
151
|
+
Authorization: `${scheme} ${format}`,
|
|
153
152
|
};
|
|
154
153
|
}
|
|
155
154
|
case 'apiKey': {
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
+
import type React from 'react';
|
|
1
2
|
import { useRef } from 'react';
|
|
2
|
-
import type { OpenAPIClientContext } from './types';
|
|
3
3
|
import { mergeProps, useButton, useDisclosure, useFocusRing } from 'react-aria';
|
|
4
4
|
import { useDisclosureState } from 'react-stately';
|
|
5
|
+
import type { OpenAPIClientContext } from './types';
|
|
5
6
|
|
|
6
7
|
interface Props {
|
|
7
8
|
context: OpenAPIClientContext;
|
|
@@ -13,7 +14,7 @@ interface Props {
|
|
|
13
14
|
* Display an interactive OpenAPI disclosure.
|
|
14
15
|
* The label is optional and defaults to "child attributes".
|
|
15
16
|
*/
|
|
16
|
-
export function OpenAPIDisclosure({ context, children, label }: Props): JSX.Element {
|
|
17
|
+
export function OpenAPIDisclosure({ context, children, label }: Props): React.JSX.Element {
|
|
17
18
|
const state = useDisclosureState({});
|
|
18
19
|
const panelRef = useRef<HTMLDivElement | null>(null);
|
|
19
20
|
const triggerRef = useRef<HTMLButtonElement | null>(null);
|
|
@@ -36,7 +37,7 @@ export function OpenAPIDisclosure({ context, children, label }: Props): JSX.Elem
|
|
|
36
37
|
>
|
|
37
38
|
{context.icons.plus}
|
|
38
39
|
<span>
|
|
39
|
-
{`${state.isExpanded ? 'Hide' : 'Show'} ${label ? label :
|
|
40
|
+
{`${state.isExpanded ? 'Hide' : 'Show'} ${label ? label : 'child attributes'}`}
|
|
40
41
|
</span>
|
|
41
42
|
</button>
|
|
42
43
|
|
|
@@ -13,14 +13,14 @@ type TDisclosureGroup = {
|
|
|
13
13
|
}[];
|
|
14
14
|
};
|
|
15
15
|
|
|
16
|
+
import { createContext, useContext, useRef, useState } from 'react';
|
|
16
17
|
import { mergeProps, useButton, useDisclosure, useFocusRing, useId } from 'react-aria';
|
|
17
18
|
import {
|
|
18
|
-
DisclosureGroupProps,
|
|
19
|
-
DisclosureGroupState,
|
|
19
|
+
type DisclosureGroupProps,
|
|
20
|
+
type DisclosureGroupState,
|
|
20
21
|
useDisclosureGroupState,
|
|
21
22
|
useDisclosureState,
|
|
22
23
|
} from 'react-stately';
|
|
23
|
-
import { createContext, useContext, useRef, useState } from 'react';
|
|
24
24
|
|
|
25
25
|
const DisclosureGroupStateContext = createContext<DisclosureGroupState | null>(null);
|
|
26
26
|
|
|
@@ -67,7 +67,7 @@ function DisclosureItem(props: { group: TDisclosureGroup; icon?: React.ReactNode
|
|
|
67
67
|
isDisabled,
|
|
68
68
|
},
|
|
69
69
|
state,
|
|
70
|
-
panelRef
|
|
70
|
+
panelRef
|
|
71
71
|
);
|
|
72
72
|
const { buttonProps } = useButton(triggerProps, triggerRef);
|
|
73
73
|
const { isFocusVisible, focusProps } = useFocusRing();
|
|
@@ -119,7 +119,7 @@ function DisclosureItem(props: { group: TDisclosureGroup; icon?: React.ReactNode
|
|
|
119
119
|
</option>
|
|
120
120
|
))}
|
|
121
121
|
</select>
|
|
122
|
-
) :
|
|
122
|
+
) : group.tabs[0] ? (
|
|
123
123
|
<span>{group.tabs[0].label}</span>
|
|
124
124
|
) : null}
|
|
125
125
|
</div>
|
package/src/OpenAPIOperation.tsx
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import clsx from 'clsx';
|
|
2
2
|
|
|
3
|
+
import type { OpenAPICustomOperationProperties, OpenAPIV3 } from '@gitbook/openapi-parser';
|
|
3
4
|
import { Markdown } from './Markdown';
|
|
4
5
|
import { OpenAPICodeSample } from './OpenAPICodeSample';
|
|
6
|
+
import { OpenAPIPath } from './OpenAPIPath';
|
|
5
7
|
import { OpenAPIResponseExample } from './OpenAPIResponseExample';
|
|
6
8
|
import { OpenAPISpec } from './OpenAPISpec';
|
|
7
9
|
import type { OpenAPIClientContext, OpenAPIContextProps, OpenAPIOperationData } from './types';
|
|
8
|
-
import { OpenAPIPath } from './OpenAPIPath';
|
|
9
10
|
import { resolveDescription } from './utils';
|
|
10
|
-
import { OpenAPICustomOperationProperties, OpenAPIV3 } from '@gitbook/openapi-parser';
|
|
11
11
|
|
|
12
12
|
/**
|
|
13
13
|
* Display an interactive OpenAPI operation.
|
|
@@ -45,7 +45,7 @@ export function OpenAPIOperation(props: {
|
|
|
45
45
|
<span className="openapi-deprecated-sunset-date">
|
|
46
46
|
{operation['x-deprecated-sunset']}
|
|
47
47
|
</span>
|
|
48
|
-
{
|
|
48
|
+
{'.'}
|
|
49
49
|
</div>
|
|
50
50
|
) : null}
|
|
51
51
|
<OpenAPIOperationDescription operation={operation} context={context} />
|
|
@@ -20,7 +20,7 @@ const OpenAPIOperationContext = createContext<OpenAPIOperationContextValue>({
|
|
|
20
20
|
* Provider for the OpenAPIOperationContext.
|
|
21
21
|
*/
|
|
22
22
|
export function OpenAPIOperationContextProvider(
|
|
23
|
-
props: React.PropsWithChildren<Partial<OpenAPIOperationContextValue
|
|
23
|
+
props: React.PropsWithChildren<Partial<OpenAPIOperationContextValue>>
|
|
24
24
|
) {
|
|
25
25
|
const { children } = props;
|
|
26
26
|
|
package/src/OpenAPIPath.tsx
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
import type React from 'react';
|
|
1
2
|
import { ScalarApiButton } from './ScalarApiButton';
|
|
2
|
-
import type {
|
|
3
|
+
import type { OpenAPIContextProps, OpenAPIOperationData } from './types';
|
|
3
4
|
|
|
4
5
|
/**
|
|
5
6
|
* Display the path of an operation.
|
|
@@ -7,7 +8,7 @@ import type { OpenAPIOperationData, OpenAPIContextProps } from './types';
|
|
|
7
8
|
export function OpenAPIPath(props: {
|
|
8
9
|
data: OpenAPIOperationData;
|
|
9
10
|
context: OpenAPIContextProps;
|
|
10
|
-
})
|
|
11
|
+
}) {
|
|
11
12
|
const { data, context } = props;
|
|
12
13
|
const { method, path } = data;
|
|
13
14
|
const { specUrl } = context;
|
|
@@ -30,7 +31,7 @@ function formatPath(path: string) {
|
|
|
30
31
|
// Matches placeholders like {id}, {userId}, etc.
|
|
31
32
|
const regex = /\{(\w+)\}/g;
|
|
32
33
|
|
|
33
|
-
const parts: (string | JSX.Element)[] = [];
|
|
34
|
+
const parts: (string | React.JSX.Element)[] = [];
|
|
34
35
|
let lastIndex = 0;
|
|
35
36
|
|
|
36
37
|
// Replace placeholders with <em> tags
|
|
@@ -48,17 +49,17 @@ function formatPath(path: string) {
|
|
|
48
49
|
const formattedPath = parts.reduce(
|
|
49
50
|
(acc, part, index) => {
|
|
50
51
|
if (typeof part === 'string' && index > 0 && part === '/') {
|
|
51
|
-
|
|
52
|
-
...acc,
|
|
52
|
+
acc.push(
|
|
53
53
|
<span className="openapi-path-separator" key={`sep-${index}`}>
|
|
54
54
|
/
|
|
55
|
-
</span
|
|
56
|
-
|
|
57
|
-
];
|
|
55
|
+
</span>
|
|
56
|
+
);
|
|
58
57
|
}
|
|
59
|
-
|
|
58
|
+
|
|
59
|
+
acc.push(part);
|
|
60
|
+
return acc;
|
|
60
61
|
},
|
|
61
|
-
[] as (string | JSX.Element)[]
|
|
62
|
+
[] as (string | React.JSX.Element)[]
|
|
62
63
|
);
|
|
63
64
|
|
|
64
65
|
return <span>{formattedPath}</span>;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { OpenAPIV3 } from '@gitbook/openapi-parser';
|
|
2
|
+
import { InteractiveSection } from './InteractiveSection';
|
|
2
3
|
import { OpenAPIRootSchema } from './OpenAPISchema';
|
|
3
4
|
import type { OpenAPIClientContext } from './types';
|
|
4
|
-
import { InteractiveSection } from './InteractiveSection';
|
|
5
5
|
import { checkIsReference } from './utils';
|
|
6
6
|
|
|
7
7
|
/**
|
|
@@ -33,7 +33,7 @@ export function OpenAPIRequestBody(props: {
|
|
|
33
33
|
/>
|
|
34
34
|
),
|
|
35
35
|
};
|
|
36
|
-
}
|
|
36
|
+
}
|
|
37
37
|
)}
|
|
38
38
|
/>
|
|
39
39
|
);
|
package/src/OpenAPIResponse.tsx
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import type { OpenAPIV3 } from '@gitbook/openapi-parser';
|
|
2
|
+
import { OpenAPIDisclosure } from './OpenAPIDisclosure';
|
|
2
3
|
import { OpenAPISchemaProperties } from './OpenAPISchema';
|
|
3
|
-
import { parameterToProperty, resolveDescription } from './utils';
|
|
4
4
|
import type { OpenAPIClientContext } from './types';
|
|
5
|
-
import {
|
|
5
|
+
import { parameterToProperty, resolveDescription } from './utils';
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* Display an interactive response body.
|
|
@@ -14,7 +14,7 @@ export function OpenAPIResponse(props: {
|
|
|
14
14
|
}) {
|
|
15
15
|
const { response, context, mediaType } = props;
|
|
16
16
|
const headers = Object.entries(response.headers ?? {}).map(
|
|
17
|
-
([name, header]) => [name, header ?? {}] as const
|
|
17
|
+
([name, header]) => [name, header ?? {}] as const
|
|
18
18
|
);
|
|
19
19
|
const content = Object.entries(mediaType.schema ?? {});
|
|
20
20
|
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import type { OpenAPIV3 } from '@gitbook/openapi-parser';
|
|
2
|
-
import { generateSchemaExample } from './generateSchemaExample';
|
|
3
|
-
import type { OpenAPIContextProps, OpenAPIOperationData } from './types';
|
|
4
|
-
import { checkIsReference, createStateKey, resolveDescription } from './utils';
|
|
5
|
-
import { OpenAPITabs, OpenAPITabsList, OpenAPITabsPanels } from './OpenAPITabs';
|
|
6
2
|
import { InteractiveSection } from './InteractiveSection';
|
|
3
|
+
import { OpenAPITabs, OpenAPITabsList, OpenAPITabsPanels } from './OpenAPITabs';
|
|
4
|
+
import { generateSchemaExample } from './generateSchemaExample';
|
|
7
5
|
import { json2xml } from './json2xml';
|
|
8
6
|
import { stringifyOpenAPI } from './stringifyOpenAPI';
|
|
7
|
+
import type { OpenAPIContextProps, OpenAPIOperationData } from './types';
|
|
8
|
+
import { checkIsReference, createStateKey, resolveDescription } from './utils';
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
11
|
* Display an example of the response content.
|
|
@@ -75,7 +75,7 @@ export function OpenAPIResponseExample(props: {
|
|
|
75
75
|
};
|
|
76
76
|
})
|
|
77
77
|
.filter((val): val is { key: string; label: string; body: any; description: string } =>
|
|
78
|
-
Boolean(val)
|
|
78
|
+
Boolean(val)
|
|
79
79
|
);
|
|
80
80
|
|
|
81
81
|
if (tabs.length === 0) {
|
package/src/OpenAPIResponses.tsx
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import type { OpenAPIV3, OpenAPIV3_1 } from '@gitbook/openapi-parser';
|
|
2
|
-
import { OpenAPIResponse } from './OpenAPIResponse';
|
|
3
|
-
import { OpenAPIClientContext } from './types';
|
|
4
2
|
import { InteractiveSection } from './InteractiveSection';
|
|
5
|
-
import { OpenAPIDisclosureGroup } from './OpenAPIDisclosureGroup';
|
|
6
3
|
import { Markdown } from './Markdown';
|
|
4
|
+
import { OpenAPIDisclosureGroup } from './OpenAPIDisclosureGroup';
|
|
5
|
+
import { OpenAPIResponse } from './OpenAPIResponse';
|
|
6
|
+
import type { OpenAPIClientContext } from './types';
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
9
|
* Display an interactive response body.
|
|
@@ -55,7 +55,7 @@ export function OpenAPIResponses(props: {
|
|
|
55
55
|
),
|
|
56
56
|
})),
|
|
57
57
|
};
|
|
58
|
-
}
|
|
58
|
+
}
|
|
59
59
|
)}
|
|
60
60
|
/>
|
|
61
61
|
</InteractiveSection>
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { getSchemaAlternatives } from './OpenAPISchema';
|
|
1
|
+
import { describe, expect, it } from 'bun:test';
|
|
3
2
|
import type { OpenAPIV3 } from '@gitbook/openapi-parser';
|
|
3
|
+
import { getSchemaAlternatives } from './OpenAPISchema';
|
|
4
4
|
|
|
5
5
|
describe('getSchemaAlternatives', () => {
|
|
6
6
|
it('should flatten oneOf', () => {
|
|
@@ -21,7 +21,7 @@ describe('getSchemaAlternatives', () => {
|
|
|
21
21
|
type: 'string',
|
|
22
22
|
},
|
|
23
23
|
],
|
|
24
|
-
})
|
|
24
|
+
})
|
|
25
25
|
).toEqual([
|
|
26
26
|
[
|
|
27
27
|
{
|
|
@@ -56,7 +56,7 @@ describe('getSchemaAlternatives', () => {
|
|
|
56
56
|
type: 'string',
|
|
57
57
|
},
|
|
58
58
|
],
|
|
59
|
-
})
|
|
59
|
+
})
|
|
60
60
|
).toEqual([
|
|
61
61
|
[
|
|
62
62
|
{
|
|
@@ -86,7 +86,7 @@ describe('getSchemaAlternatives', () => {
|
|
|
86
86
|
],
|
|
87
87
|
};
|
|
88
88
|
|
|
89
|
-
a.anyOf
|
|
89
|
+
a.anyOf?.push(a);
|
|
90
90
|
|
|
91
91
|
expect(getSchemaAlternatives(a)).toEqual([
|
|
92
92
|
[
|
package/src/OpenAPISchema.tsx
CHANGED
|
@@ -4,11 +4,11 @@ import { useId } from 'react';
|
|
|
4
4
|
|
|
5
5
|
import { InteractiveSection } from './InteractiveSection';
|
|
6
6
|
import { Markdown } from './Markdown';
|
|
7
|
+
import { OpenAPIDisclosure } from './OpenAPIDisclosure';
|
|
8
|
+
import { OpenAPISchemaName } from './OpenAPISchemaName';
|
|
9
|
+
import { stringifyOpenAPI } from './stringifyOpenAPI';
|
|
7
10
|
import type { OpenAPIClientContext } from './types';
|
|
8
11
|
import { checkIsReference, resolveDescription } from './utils';
|
|
9
|
-
import { stringifyOpenAPI } from './stringifyOpenAPI';
|
|
10
|
-
import { OpenAPISchemaName } from './OpenAPISchemaName';
|
|
11
|
-
import { OpenAPIDisclosure } from './OpenAPIDisclosure';
|
|
12
12
|
|
|
13
13
|
type CircularRefsIds = Map<OpenAPIV3.SchemaObject, string>;
|
|
14
14
|
|
|
@@ -27,7 +27,7 @@ export function OpenAPISchemaProperty(
|
|
|
27
27
|
circularRefs?: CircularRefsIds;
|
|
28
28
|
context: OpenAPIClientContext;
|
|
29
29
|
className?: string;
|
|
30
|
-
}
|
|
30
|
+
}
|
|
31
31
|
) {
|
|
32
32
|
const {
|
|
33
33
|
schema,
|
|
@@ -49,20 +49,13 @@ export function OpenAPISchemaProperty(
|
|
|
49
49
|
|
|
50
50
|
if (alternatives?.[0]?.length) {
|
|
51
51
|
return (
|
|
52
|
-
<
|
|
53
|
-
|
|
54
|
-
{
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
context={context}
|
|
60
|
-
/>
|
|
61
|
-
))}
|
|
62
|
-
{parentCircularRef ? (
|
|
63
|
-
<OpenAPISchemaCircularRef id={parentCircularRef} schema={schema} />
|
|
64
|
-
) : null}
|
|
65
|
-
</InteractiveSection>
|
|
52
|
+
<OpenAPISchemaAlternativesItem
|
|
53
|
+
{...props}
|
|
54
|
+
circularRefs={circularRefs}
|
|
55
|
+
context={context}
|
|
56
|
+
alternatives={alternatives}
|
|
57
|
+
parentCircularRef={parentCircularRef}
|
|
58
|
+
/>
|
|
66
59
|
);
|
|
67
60
|
}
|
|
68
61
|
|
|
@@ -173,6 +166,25 @@ function OpenAPISchemaAlternative(props: {
|
|
|
173
166
|
const id = useId();
|
|
174
167
|
const subProperties = getSchemaProperties(schema);
|
|
175
168
|
const description = resolveDescription(schema);
|
|
169
|
+
const alternatives = getSchemaAlternatives(schema, new Set(circularRefs?.keys()));
|
|
170
|
+
|
|
171
|
+
if (alternatives?.[0]?.length && !subProperties?.length) {
|
|
172
|
+
return (
|
|
173
|
+
<>
|
|
174
|
+
{description ? (
|
|
175
|
+
<Markdown source={description} className="openapi-schema-description" />
|
|
176
|
+
) : null}
|
|
177
|
+
<OpenAPIDisclosure context={context} label={getDisclosureLabel(schema)}>
|
|
178
|
+
<OpenAPISchemaAlternativesItem
|
|
179
|
+
schema={schema}
|
|
180
|
+
circularRefs={circularRefs}
|
|
181
|
+
context={context}
|
|
182
|
+
alternatives={alternatives}
|
|
183
|
+
/>
|
|
184
|
+
</OpenAPIDisclosure>
|
|
185
|
+
</>
|
|
186
|
+
);
|
|
187
|
+
}
|
|
176
188
|
|
|
177
189
|
return (
|
|
178
190
|
<>
|
|
@@ -193,6 +205,35 @@ function OpenAPISchemaAlternative(props: {
|
|
|
193
205
|
);
|
|
194
206
|
}
|
|
195
207
|
|
|
208
|
+
function OpenAPISchemaAlternativesItem(
|
|
209
|
+
props: OpenAPISchemaPropertyEntry & {
|
|
210
|
+
circularRefs?: CircularRefsIds;
|
|
211
|
+
context: OpenAPIClientContext;
|
|
212
|
+
alternatives: OpenAPISchemaAlternatives;
|
|
213
|
+
parentCircularRef?: string;
|
|
214
|
+
}
|
|
215
|
+
) {
|
|
216
|
+
const id = useId();
|
|
217
|
+
const { schema, circularRefs, context, alternatives, parentCircularRef } = props;
|
|
218
|
+
|
|
219
|
+
return (
|
|
220
|
+
<InteractiveSection id={id} className={clsx('openapi-schema')}>
|
|
221
|
+
<OpenAPISchemaPresentation {...props} />
|
|
222
|
+
{alternatives[0].map((alternative, index) => (
|
|
223
|
+
<OpenAPISchemaAlternative
|
|
224
|
+
key={`alternative-${index}`}
|
|
225
|
+
schema={alternative}
|
|
226
|
+
circularRefs={circularRefs}
|
|
227
|
+
context={context}
|
|
228
|
+
/>
|
|
229
|
+
))}
|
|
230
|
+
{parentCircularRef ? (
|
|
231
|
+
<OpenAPISchemaCircularRef id={parentCircularRef} schema={schema} />
|
|
232
|
+
) : null}
|
|
233
|
+
</InteractiveSection>
|
|
234
|
+
);
|
|
235
|
+
}
|
|
236
|
+
|
|
196
237
|
/**
|
|
197
238
|
* Render a circular reference to a schema.
|
|
198
239
|
*/
|
|
@@ -336,13 +377,18 @@ function getSchemaProperties(schema: OpenAPIV3.SchemaObject): null | OpenAPISche
|
|
|
336
377
|
return null;
|
|
337
378
|
}
|
|
338
379
|
|
|
380
|
+
type OpenAPISchemaAlternatives = [
|
|
381
|
+
OpenAPIV3.SchemaObject[],
|
|
382
|
+
OpenAPIV3.DiscriminatorObject | undefined,
|
|
383
|
+
];
|
|
384
|
+
|
|
339
385
|
/**
|
|
340
386
|
* Get the alternatives to display for a schema.
|
|
341
387
|
*/
|
|
342
388
|
export function getSchemaAlternatives(
|
|
343
389
|
schema: OpenAPIV3.SchemaObject,
|
|
344
|
-
ancestors: Set<OpenAPIV3.SchemaObject> = new Set()
|
|
345
|
-
): null |
|
|
390
|
+
ancestors: Set<OpenAPIV3.SchemaObject> = new Set()
|
|
391
|
+
): null | OpenAPISchemaAlternatives {
|
|
346
392
|
const downAncestors = new Set(ancestors).add(schema);
|
|
347
393
|
|
|
348
394
|
if (schema.anyOf) {
|
|
@@ -363,14 +409,16 @@ export function getSchemaAlternatives(
|
|
|
363
409
|
function flattenAlternatives(
|
|
364
410
|
alternativeType: 'oneOf' | 'allOf' | 'anyOf',
|
|
365
411
|
alternatives: OpenAPIV3.SchemaObject[],
|
|
366
|
-
ancestors: Set<OpenAPIV3.SchemaObject
|
|
412
|
+
ancestors: Set<OpenAPIV3.SchemaObject>
|
|
367
413
|
): OpenAPIV3.SchemaObject[] {
|
|
368
414
|
return alternatives.reduce((acc, alternative) => {
|
|
369
415
|
if (!!alternative[alternativeType] && !ancestors.has(alternative)) {
|
|
370
|
-
|
|
416
|
+
acc.push(...(getSchemaAlternatives(alternative, ancestors)?.[0] || []));
|
|
417
|
+
} else {
|
|
418
|
+
acc.push(alternative);
|
|
371
419
|
}
|
|
372
420
|
|
|
373
|
-
return
|
|
421
|
+
return acc;
|
|
374
422
|
}, [] as OpenAPIV3.SchemaObject[]);
|
|
375
423
|
}
|
|
376
424
|
|
|
@@ -378,7 +426,7 @@ export function getSchemaTitle(
|
|
|
378
426
|
schema: OpenAPIV3.SchemaObject,
|
|
379
427
|
|
|
380
428
|
/** If the title is inferred in a oneOf with discriminator, we can use it to optimize the title */
|
|
381
|
-
discriminator?: OpenAPIV3.DiscriminatorObject
|
|
429
|
+
discriminator?: OpenAPIV3.DiscriminatorObject
|
|
382
430
|
): string {
|
|
383
431
|
// Try using the discriminator
|
|
384
432
|
if (discriminator?.propertyName && schema.properties) {
|
|
@@ -406,7 +454,9 @@ export function getSchemaTitle(
|
|
|
406
454
|
if (schema.format) {
|
|
407
455
|
type += ` · ${schema.format}`;
|
|
408
456
|
}
|
|
409
|
-
}
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
if ('anyOf' in schema) {
|
|
410
460
|
type = 'any of';
|
|
411
461
|
} else if ('oneOf' in schema) {
|
|
412
462
|
type = 'one of';
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import { OpenAPIV3 } from '@gitbook/openapi-parser';
|
|
1
|
+
import type { OpenAPIV3 } from '@gitbook/openapi-parser';
|
|
2
|
+
import type React from 'react';
|
|
2
3
|
|
|
3
4
|
interface OpenAPISchemaNameProps {
|
|
4
5
|
schema?: OpenAPIV3.SchemaObject;
|
|
5
|
-
propertyName?: string | JSX.Element;
|
|
6
|
+
propertyName?: string | React.JSX.Element;
|
|
6
7
|
required?: boolean;
|
|
7
8
|
type?: string;
|
|
8
9
|
}
|
|
@@ -11,7 +12,7 @@ interface OpenAPISchemaNameProps {
|
|
|
11
12
|
* Display the schema name row.
|
|
12
13
|
* It includes the property name, type, required and deprecated status.
|
|
13
14
|
*/
|
|
14
|
-
export function OpenAPISchemaName(props: OpenAPISchemaNameProps)
|
|
15
|
+
export function OpenAPISchemaName(props: OpenAPISchemaNameProps) {
|
|
15
16
|
const { schema, type, propertyName, required } = props;
|
|
16
17
|
|
|
17
18
|
const additionalItems = schema && getAdditionalItems(schema);
|
|
@@ -52,7 +53,7 @@ function getAdditionalItems(schema: OpenAPIV3.SchemaObject): string {
|
|
|
52
53
|
}
|
|
53
54
|
|
|
54
55
|
if (schema.nullable) {
|
|
55
|
-
additionalItems =
|
|
56
|
+
additionalItems = ' | nullable';
|
|
56
57
|
}
|
|
57
58
|
|
|
58
59
|
return additionalItems;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import type { OpenAPIV3_1 } from '@gitbook/openapi-parser';
|
|
2
|
-
import type { OpenAPIClientContext, OpenAPIOperationData } from './types';
|
|
3
2
|
import { InteractiveSection } from './InteractiveSection';
|
|
4
3
|
import { Markdown } from './Markdown';
|
|
5
4
|
import { OpenAPISchemaName } from './OpenAPISchemaName';
|
|
5
|
+
import type { OpenAPIClientContext, OpenAPIOperationData } from './types';
|
|
6
6
|
import { resolveDescription } from './utils';
|
|
7
7
|
|
|
8
8
|
/**
|
|
@@ -65,7 +65,7 @@ function getLabelForType(security: OpenAPIV3_1.SecuritySchemeObject) {
|
|
|
65
65
|
return <OpenAPISchemaName propertyName="Authorization" type="string" required />;
|
|
66
66
|
}
|
|
67
67
|
|
|
68
|
-
if (security.scheme
|
|
68
|
+
if (security.scheme === 'bearer') {
|
|
69
69
|
const description = resolveDescription(security);
|
|
70
70
|
return (
|
|
71
71
|
<>
|
|
@@ -73,7 +73,7 @@ function getLabelForType(security: OpenAPIV3_1.SecuritySchemeObject) {
|
|
|
73
73
|
{/** Show a default description if none is provided */}
|
|
74
74
|
{!description ? (
|
|
75
75
|
<Markdown
|
|
76
|
-
source={`Bearer authentication header of the form Bearer ${
|
|
76
|
+
source={`Bearer authentication header of the form Bearer ${'<token>'}.`}
|
|
77
77
|
className="openapi-securities-description"
|
|
78
78
|
/>
|
|
79
79
|
) : null}
|