@gitbook/react-openapi 1.0.0 → 1.0.2
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 +20 -0
- package/dist/InteractiveSection.d.ts +0 -2
- package/dist/InteractiveSection.jsx +8 -44
- package/dist/OpenAPICodeSample.jsx +12 -12
- package/dist/OpenAPIOperation.jsx +8 -5
- package/dist/OpenAPIRequestBody.d.ts +2 -2
- package/dist/OpenAPIRequestBody.jsx +5 -2
- package/dist/OpenAPIResponse.jsx +17 -25
- package/dist/OpenAPIResponseExample.jsx +157 -48
- package/dist/OpenAPIResponses.jsx +2 -3
- package/dist/OpenAPISchema.d.ts +2 -2
- package/dist/OpenAPISchema.jsx +28 -29
- package/dist/OpenAPISpec.jsx +4 -28
- package/dist/OpenAPITabs.d.ts +1 -0
- package/dist/OpenAPITabs.jsx +52 -16
- package/dist/generateSchemaExample.d.ts +5 -6
- package/dist/generateSchemaExample.js +15 -11
- package/dist/json2xml.d.ts +4 -0
- package/dist/json2xml.js +7 -0
- package/dist/resolveOpenAPIOperation.js +4 -4
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/dist/types.d.ts +4 -0
- package/dist/useSyncedTabsGlobalState.d.ts +1 -0
- package/dist/useSyncedTabsGlobalState.js +16 -0
- package/dist/utils.d.ts +26 -3
- package/dist/utils.js +72 -9
- package/package.json +4 -2
- package/src/InteractiveSection.tsx +4 -41
- package/src/OpenAPICodeSample.tsx +12 -12
- package/src/OpenAPIOperation.tsx +8 -5
- package/src/OpenAPIRequestBody.tsx +7 -3
- package/src/OpenAPIResponse.tsx +7 -27
- package/src/OpenAPIResponseExample.tsx +237 -70
- package/src/OpenAPIResponses.tsx +2 -7
- package/src/OpenAPISchema.tsx +34 -33
- package/src/OpenAPISpec.tsx +4 -22
- package/src/OpenAPITabs.tsx +63 -23
- package/src/__snapshots__/json2xml.test.ts.snap +18 -0
- package/src/generateSchemaExample.ts +11 -10
- package/src/json2xml.test.ts +46 -0
- package/src/json2xml.ts +8 -0
- package/src/resolveOpenAPIOperation.test.ts +1 -1
- package/src/resolveOpenAPIOperation.ts +8 -7
- package/src/types.ts +1 -0
- package/src/useSyncedTabsGlobalState.ts +23 -0
- package/src/utils.ts +81 -13
- package/dist/fetchOpenAPIOperation.d.ts +0 -27
- package/dist/fetchOpenAPIOperation.js +0 -195
- package/dist/tsconfig.tsbuildinfo +0 -1
package/src/OpenAPITabs.tsx
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
|
-
import { createContext, useContext, useMemo, useState } from 'react';
|
|
3
|
+
import { createContext, useContext, useEffect, useMemo, useState } from 'react';
|
|
4
4
|
import { Key, Tab, TabList, TabPanel, Tabs, TabsProps } from 'react-aria-components';
|
|
5
5
|
import { Markdown } from './Markdown';
|
|
6
|
+
import { useSyncedTabsGlobalState } from './useSyncedTabsGlobalState';
|
|
7
|
+
import { useIntersectionObserver } from 'usehooks-ts';
|
|
6
8
|
|
|
7
9
|
export type Tab = {
|
|
8
10
|
key: Key;
|
|
@@ -13,8 +15,7 @@ export type Tab = {
|
|
|
13
15
|
|
|
14
16
|
type OpenAPITabsContextData = {
|
|
15
17
|
items: Tab[];
|
|
16
|
-
|
|
17
|
-
setSelectedKey: (key: Key) => void;
|
|
18
|
+
selectedTab: Tab;
|
|
18
19
|
};
|
|
19
20
|
|
|
20
21
|
const OpenAPITabsContext = createContext<OpenAPITabsContextData | null>(null);
|
|
@@ -30,25 +31,66 @@ function useOpenAPITabsContext() {
|
|
|
30
31
|
/**
|
|
31
32
|
* The OpenAPI Tabs wrapper component.
|
|
32
33
|
*/
|
|
33
|
-
export function OpenAPITabs(
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
const
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
34
|
+
export function OpenAPITabs(
|
|
35
|
+
props: React.PropsWithChildren<TabsProps & { items: Tab[]; stateKey?: string }>,
|
|
36
|
+
) {
|
|
37
|
+
const { children, items, stateKey } = props;
|
|
38
|
+
const isVisible = stateKey
|
|
39
|
+
? useIntersectionObserver({
|
|
40
|
+
threshold: 0.1,
|
|
41
|
+
rootMargin: '200px',
|
|
42
|
+
})
|
|
43
|
+
: true;
|
|
44
|
+
const defaultTab = items[0] as Tab;
|
|
45
|
+
const [syncedTabs, setSyncedTabs] = useSyncedTabsGlobalState<Tab>();
|
|
46
|
+
const [selectedTabKey, setSelectedTabKey] = useState(() => {
|
|
47
|
+
if (isVisible && stateKey && syncedTabs && syncedTabs.has(stateKey)) {
|
|
48
|
+
const tabFromState = syncedTabs.get(stateKey);
|
|
49
|
+
return tabFromState?.key ?? items[0]?.key;
|
|
40
50
|
}
|
|
41
|
-
return
|
|
51
|
+
return items[0]?.key;
|
|
42
52
|
});
|
|
53
|
+
const [selectedTab, setSelectedTab] = useState<Tab>(defaultTab);
|
|
54
|
+
|
|
55
|
+
const handleSelectionChange = (key: Key) => {
|
|
56
|
+
setSelectedTabKey(key);
|
|
57
|
+
if (stateKey) {
|
|
58
|
+
const tab = items.find((item) => item.key === key);
|
|
59
|
+
|
|
60
|
+
if (!tab) {
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
setSyncedTabs((state) => {
|
|
65
|
+
const newState = new Map(state);
|
|
66
|
+
newState.set(stateKey, tab);
|
|
67
|
+
return newState;
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
};
|
|
43
71
|
|
|
44
|
-
|
|
72
|
+
useEffect(() => {
|
|
73
|
+
if (isVisible && stateKey && syncedTabs && syncedTabs.has(stateKey)) {
|
|
74
|
+
const tabFromState = syncedTabs.get(stateKey);
|
|
75
|
+
|
|
76
|
+
if (!items.some((item) => item.key === tabFromState?.key)) {
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
if (tabFromState && tabFromState?.key !== selectedTab?.key) {
|
|
81
|
+
setSelectedTab(tabFromState);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}, [isVisible, stateKey, syncedTabs, selectedTabKey]);
|
|
85
|
+
|
|
86
|
+
const contextValue = useMemo(() => ({ items, selectedTab }), [items, selectedTab]);
|
|
45
87
|
|
|
46
88
|
return (
|
|
47
89
|
<OpenAPITabsContext.Provider value={contextValue}>
|
|
48
90
|
<Tabs
|
|
49
91
|
className="openapi-tabs"
|
|
50
|
-
onSelectionChange={
|
|
51
|
-
selectedKey={
|
|
92
|
+
onSelectionChange={handleSelectionChange}
|
|
93
|
+
selectedKey={selectedTab?.key}
|
|
52
94
|
>
|
|
53
95
|
{children}
|
|
54
96
|
</Tabs>
|
|
@@ -90,23 +132,21 @@ export function OpenAPITabsList() {
|
|
|
90
132
|
* It renders the content of the selected tab.
|
|
91
133
|
*/
|
|
92
134
|
export function OpenAPITabsPanels() {
|
|
93
|
-
const {
|
|
94
|
-
|
|
95
|
-
const tab = useMemo(() => items.find((tab) => tab.key === selectedKey), [items, selectedKey]);
|
|
135
|
+
const { selectedTab } = useOpenAPITabsContext();
|
|
96
136
|
|
|
97
|
-
if (!
|
|
137
|
+
if (!selectedTab) {
|
|
98
138
|
return null;
|
|
99
139
|
}
|
|
100
140
|
|
|
101
141
|
return (
|
|
102
142
|
<TabPanel
|
|
103
|
-
key={`TabPanel-${
|
|
104
|
-
id={
|
|
143
|
+
key={`TabPanel-${selectedTab.key}`}
|
|
144
|
+
id={selectedTab.key.toString()}
|
|
105
145
|
className="openapi-tabs-panel"
|
|
106
146
|
>
|
|
107
|
-
{
|
|
108
|
-
{
|
|
109
|
-
<Markdown source={
|
|
147
|
+
{selectedTab.body}
|
|
148
|
+
{selectedTab.description ? (
|
|
149
|
+
<Markdown source={selectedTab.description} className="openapi-tabs-footer" />
|
|
110
150
|
) : null}
|
|
111
151
|
</TabPanel>
|
|
112
152
|
);
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
// Bun Snapshot v1, https://goo.gl/fbAQLP
|
|
2
|
+
|
|
3
|
+
exports[`getUrlFromServerState indents correctly 1`] = `
|
|
4
|
+
"<?xml version="1.0"?>
|
|
5
|
+
<id>10</id>
|
|
6
|
+
<name>doggie</name>
|
|
7
|
+
<category>
|
|
8
|
+
<id>1</id>
|
|
9
|
+
<name>Dogs</name>
|
|
10
|
+
</category>
|
|
11
|
+
<photoUrls>string</photoUrls>
|
|
12
|
+
<tags>
|
|
13
|
+
<id>0</id>
|
|
14
|
+
<name>string</name>
|
|
15
|
+
</tags>
|
|
16
|
+
<status>available</status>
|
|
17
|
+
"
|
|
18
|
+
`;
|
|
@@ -1,21 +1,23 @@
|
|
|
1
1
|
import type { OpenAPIV3 } from '@gitbook/openapi-parser';
|
|
2
|
-
import { noReference } from './utils';
|
|
3
2
|
import { getExampleFromSchema } from '@scalar/oas-utils/spec-getters';
|
|
4
3
|
|
|
5
4
|
type JSONValue = string | number | boolean | null | JSONValue[] | { [key: string]: JSONValue };
|
|
6
5
|
|
|
6
|
+
type ScalarGetExampleFromSchemaOptions = NonNullable<Parameters<typeof getExampleFromSchema>[1]>;
|
|
7
|
+
type GenerateSchemaExampleOptions = Pick<
|
|
8
|
+
ScalarGetExampleFromSchemaOptions,
|
|
9
|
+
'xml' | 'omitEmptyAndOptionalProperties' | 'mode'
|
|
10
|
+
>;
|
|
11
|
+
|
|
7
12
|
/**
|
|
8
13
|
* Generate a JSON example from a schema
|
|
9
14
|
*/
|
|
10
15
|
export function generateSchemaExample(
|
|
11
16
|
schema: OpenAPIV3.SchemaObject,
|
|
12
|
-
options
|
|
13
|
-
onlyRequired?: boolean;
|
|
14
|
-
} = {},
|
|
17
|
+
options?: GenerateSchemaExampleOptions,
|
|
15
18
|
): JSONValue | undefined {
|
|
16
19
|
return getExampleFromSchema(schema, {
|
|
17
20
|
emptyString: 'text',
|
|
18
|
-
omitEmptyAndOptionalProperties: options.onlyRequired,
|
|
19
21
|
variables: {
|
|
20
22
|
'date-time': new Date().toISOString(),
|
|
21
23
|
date: new Date().toISOString().split('T')[0],
|
|
@@ -29,6 +31,7 @@ export function generateSchemaExample(
|
|
|
29
31
|
byte: 'Ynl0ZXM=',
|
|
30
32
|
password: 'password',
|
|
31
33
|
},
|
|
34
|
+
...options,
|
|
32
35
|
});
|
|
33
36
|
}
|
|
34
37
|
|
|
@@ -37,9 +40,7 @@ export function generateSchemaExample(
|
|
|
37
40
|
*/
|
|
38
41
|
export function generateMediaTypeExample(
|
|
39
42
|
mediaType: OpenAPIV3.MediaTypeObject,
|
|
40
|
-
options
|
|
41
|
-
onlyRequired?: boolean;
|
|
42
|
-
} = {},
|
|
43
|
+
options?: GenerateSchemaExampleOptions,
|
|
43
44
|
): JSONValue | undefined {
|
|
44
45
|
if (mediaType.example) {
|
|
45
46
|
return mediaType.example;
|
|
@@ -50,13 +51,13 @@ export function generateMediaTypeExample(
|
|
|
50
51
|
if (key) {
|
|
51
52
|
const example = mediaType.examples[key];
|
|
52
53
|
if (example) {
|
|
53
|
-
return
|
|
54
|
+
return example.value;
|
|
54
55
|
}
|
|
55
56
|
}
|
|
56
57
|
}
|
|
57
58
|
|
|
58
59
|
if (mediaType.schema) {
|
|
59
|
-
return generateSchemaExample(
|
|
60
|
+
return generateSchemaExample(mediaType.schema, options);
|
|
60
61
|
}
|
|
61
62
|
|
|
62
63
|
return undefined;
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { describe, expect, it } from 'bun:test';
|
|
2
|
+
|
|
3
|
+
import { json2xml } from './json2xml';
|
|
4
|
+
|
|
5
|
+
describe('getUrlFromServerState', () => {
|
|
6
|
+
it('transforms JSON to xml', () => {
|
|
7
|
+
const xml = json2xml({
|
|
8
|
+
foo: 'bar',
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
expect(xml).toBe('<?xml version="1.0"?>\n<foo>bar</foo>\n');
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
it('wraps array items', () => {
|
|
15
|
+
const xml = json2xml({
|
|
16
|
+
urls: {
|
|
17
|
+
url: ['https://example.com', 'https://example.com'],
|
|
18
|
+
},
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
expect(xml).toBe(
|
|
22
|
+
'<?xml version="1.0"?>\n<urls>\n\t<url>https://example.com</url>\n\t<url>https://example.com</url>\n</urls>\n',
|
|
23
|
+
);
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
it('indents correctly', () => {
|
|
27
|
+
const xml = json2xml({
|
|
28
|
+
id: 10,
|
|
29
|
+
name: 'doggie',
|
|
30
|
+
category: {
|
|
31
|
+
id: 1,
|
|
32
|
+
name: 'Dogs',
|
|
33
|
+
},
|
|
34
|
+
photoUrls: ['string'],
|
|
35
|
+
tags: [
|
|
36
|
+
{
|
|
37
|
+
id: 0,
|
|
38
|
+
name: 'string',
|
|
39
|
+
},
|
|
40
|
+
],
|
|
41
|
+
status: 'available',
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
expect(xml).toMatchSnapshot();
|
|
45
|
+
});
|
|
46
|
+
});
|
package/src/json2xml.ts
ADDED
|
@@ -9,7 +9,7 @@ async function fetchFilesystem(url: string) {
|
|
|
9
9
|
const filesystem = await parseOpenAPI({ value: text, rootURL: url });
|
|
10
10
|
const transformedFs = await traverse(filesystem, async (node) => {
|
|
11
11
|
if ('description' in node && typeof node.description === 'string' && node.description) {
|
|
12
|
-
node['x-description-html'] = node.description;
|
|
12
|
+
node['x-gitbook-description-html'] = node.description;
|
|
13
13
|
}
|
|
14
14
|
return node;
|
|
15
15
|
});
|
|
@@ -7,8 +7,8 @@ import {
|
|
|
7
7
|
type OpenAPIV3_1,
|
|
8
8
|
dereference,
|
|
9
9
|
} from '@gitbook/openapi-parser';
|
|
10
|
-
import { noReference } from './utils';
|
|
11
10
|
import { OpenAPIOperationData } from './types';
|
|
11
|
+
import { checkIsReference } from './utils';
|
|
12
12
|
|
|
13
13
|
export { toJSON, fromJSON };
|
|
14
14
|
|
|
@@ -48,8 +48,8 @@ export async function resolveOpenAPIOperation(
|
|
|
48
48
|
const securityKey = Object.keys(entry)[0];
|
|
49
49
|
if (securityKey) {
|
|
50
50
|
const securityScheme = schema.components?.securitySchemes?.[securityKey];
|
|
51
|
-
if (securityScheme) {
|
|
52
|
-
securities.push([securityKey,
|
|
51
|
+
if (securityScheme && !checkIsReference(securityScheme)) {
|
|
52
|
+
securities.push([securityKey, securityScheme]);
|
|
53
53
|
}
|
|
54
54
|
}
|
|
55
55
|
}
|
|
@@ -116,12 +116,13 @@ function getPathObject(
|
|
|
116
116
|
function getPathObjectParameter(
|
|
117
117
|
schema: OpenAPIV3.Document | OpenAPIV3_1.Document,
|
|
118
118
|
path: string,
|
|
119
|
-
):
|
|
119
|
+
):
|
|
120
|
+
| (OpenAPIV3.ReferenceObject | OpenAPIV3.ParameterObject)[]
|
|
121
|
+
| (OpenAPIV3.ParameterObject | OpenAPIV3_1.ReferenceObject)[]
|
|
122
|
+
| null {
|
|
120
123
|
const pathObject = getPathObject(schema, path);
|
|
121
124
|
if (pathObject?.parameters) {
|
|
122
|
-
return pathObject.parameters
|
|
123
|
-
| OpenAPIV3.ParameterObject[]
|
|
124
|
-
| OpenAPIV3_1.ParameterObject[];
|
|
125
|
+
return pathObject.parameters;
|
|
125
126
|
}
|
|
126
127
|
return null;
|
|
127
128
|
}
|
package/src/types.ts
CHANGED
|
@@ -6,6 +6,7 @@ import type {
|
|
|
6
6
|
|
|
7
7
|
export interface OpenAPIContextProps extends OpenAPIClientContext {
|
|
8
8
|
CodeBlock: React.ComponentType<{ code: string; syntax: string }>;
|
|
9
|
+
renderHeading: (props: { deprecated: boolean; title: string }) => React.ReactNode;
|
|
9
10
|
|
|
10
11
|
/** Spec url for the Scalar Api Client */
|
|
11
12
|
specUrl: string;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { create } from 'zustand';
|
|
4
|
+
|
|
5
|
+
interface SyncedTabsState<T> {
|
|
6
|
+
tabs: Map<string, T>;
|
|
7
|
+
setTabs: (updater: (tabs: Map<string, T>) => Map<string, T>) => void;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
const useSyncedTabsStore = create<SyncedTabsState<any>>()((set) => ({
|
|
11
|
+
tabs: new Map<string, any>(),
|
|
12
|
+
setTabs: (updater) =>
|
|
13
|
+
set((state) => ({
|
|
14
|
+
tabs: updater(new Map(state.tabs)), // Ensure a new Map is created for reactivity
|
|
15
|
+
})),
|
|
16
|
+
}));
|
|
17
|
+
|
|
18
|
+
// Selector for better performance - only re-renders when tabs change
|
|
19
|
+
export function useSyncedTabsGlobalState<T>() {
|
|
20
|
+
const tabs = useSyncedTabsStore((state) => state.tabs as Map<string, T>);
|
|
21
|
+
const setTabs = useSyncedTabsStore((state) => state.setTabs as SyncedTabsState<T>['setTabs']);
|
|
22
|
+
return [tabs, setTabs] as const;
|
|
23
|
+
}
|
package/src/utils.ts
CHANGED
|
@@ -1,14 +1,8 @@
|
|
|
1
|
-
import type { AnyObject, OpenAPIV3 } from '@gitbook/openapi-parser';
|
|
1
|
+
import type { AnyObject, OpenAPIV3, OpenAPIV3_1 } from '@gitbook/openapi-parser';
|
|
2
2
|
|
|
3
|
-
export function
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
return input;
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
export function checkIsReference(input: unknown): input is OpenAPIV3.ReferenceObject {
|
|
3
|
+
export function checkIsReference(
|
|
4
|
+
input: unknown,
|
|
5
|
+
): input is OpenAPIV3.ReferenceObject | OpenAPIV3_1.ReferenceObject {
|
|
12
6
|
return typeof input === 'object' && !!input && '$ref' in input;
|
|
13
7
|
}
|
|
14
8
|
|
|
@@ -20,9 +14,83 @@ export function createStateKey(key: string, scope?: string) {
|
|
|
20
14
|
* Resolve the description of an object.
|
|
21
15
|
*/
|
|
22
16
|
export function resolveDescription(object: AnyObject) {
|
|
23
|
-
return 'x-description-html' in object &&
|
|
24
|
-
|
|
17
|
+
return 'x-gitbook-description-html' in object &&
|
|
18
|
+
typeof object['x-gitbook-description-html'] === 'string'
|
|
19
|
+
? object['x-gitbook-description-html'].trim()
|
|
25
20
|
: typeof object.description === 'string'
|
|
26
|
-
? object.description
|
|
21
|
+
? object.description.trim()
|
|
27
22
|
: undefined;
|
|
28
23
|
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Extract descriptions from an object.
|
|
27
|
+
*/
|
|
28
|
+
export function extractDescriptions(object: AnyObject) {
|
|
29
|
+
return {
|
|
30
|
+
description: object.description,
|
|
31
|
+
['x-gitbook-description-html']:
|
|
32
|
+
'x-gitbook-description-html' in object
|
|
33
|
+
? object['x-gitbook-description-html']
|
|
34
|
+
: undefined,
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Resolve the first example from an object.
|
|
40
|
+
*/
|
|
41
|
+
export function resolveFirstExample(object: AnyObject) {
|
|
42
|
+
if ('examples' in object && typeof object.examples === 'object' && object.examples) {
|
|
43
|
+
const keys = Object.keys(object.examples);
|
|
44
|
+
const firstKey = keys[0];
|
|
45
|
+
if (firstKey && object.examples[firstKey]) {
|
|
46
|
+
return object.examples[firstKey];
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
if ('example' in object && object.example !== undefined) {
|
|
50
|
+
return object.example;
|
|
51
|
+
}
|
|
52
|
+
return undefined;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Resolve the schema of a parameter.
|
|
57
|
+
* Extract the description, example and deprecated from parameter.
|
|
58
|
+
*/
|
|
59
|
+
export function resolveParameterSchema(
|
|
60
|
+
parameter: OpenAPIV3.ParameterBaseObject,
|
|
61
|
+
): OpenAPIV3.SchemaObject {
|
|
62
|
+
const schema = checkIsReference(parameter.schema) ? undefined : parameter.schema;
|
|
63
|
+
return {
|
|
64
|
+
// Description of the parameter is defined at the parameter level
|
|
65
|
+
// we use display it if the schema doesn't override it
|
|
66
|
+
...extractDescriptions(parameter),
|
|
67
|
+
example: resolveFirstExample(parameter),
|
|
68
|
+
// Deprecated can be defined at the parameter level
|
|
69
|
+
deprecated: parameter.deprecated,
|
|
70
|
+
...schema,
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Transform a parameter object to a property object.
|
|
76
|
+
*/
|
|
77
|
+
export function parameterToProperty(
|
|
78
|
+
parameter: OpenAPIV3.ParameterObject | OpenAPIV3.ReferenceObject | OpenAPIV3_1.ReferenceObject,
|
|
79
|
+
): {
|
|
80
|
+
propertyName: string | undefined;
|
|
81
|
+
schema: OpenAPIV3.SchemaObject;
|
|
82
|
+
required: boolean | undefined;
|
|
83
|
+
} {
|
|
84
|
+
if (checkIsReference(parameter)) {
|
|
85
|
+
return {
|
|
86
|
+
propertyName: parameter.$ref ?? 'Unknown ref',
|
|
87
|
+
schema: {},
|
|
88
|
+
required: undefined,
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
return {
|
|
92
|
+
propertyName: parameter.name,
|
|
93
|
+
schema: resolveParameterSchema(parameter),
|
|
94
|
+
required: parameter.required,
|
|
95
|
+
};
|
|
96
|
+
}
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
import { toJSON, fromJSON } from 'flatted';
|
|
2
|
-
import { type OpenAPICustomOperationProperties, type OpenAPICustomSpecProperties, type OpenAPIV3xDocument, type Filesystem, type OpenAPIV3 } from '@gitbook/openapi-parser';
|
|
3
|
-
export interface OpenAPIFetcher {
|
|
4
|
-
/**
|
|
5
|
-
* Fetch an OpenAPI file by its URL. It should return a fully parsed OpenAPI v3 document.
|
|
6
|
-
*/
|
|
7
|
-
fetch: (url: string) => Promise<Filesystem<OpenAPIV3xDocument>>;
|
|
8
|
-
}
|
|
9
|
-
export interface OpenAPIOperationData extends OpenAPICustomSpecProperties {
|
|
10
|
-
path: string;
|
|
11
|
-
method: string;
|
|
12
|
-
/** Servers to be used for this operation */
|
|
13
|
-
servers: OpenAPIV3.ServerObject[];
|
|
14
|
-
/** Spec of the operation */
|
|
15
|
-
operation: OpenAPIV3.OperationObject<OpenAPICustomOperationProperties>;
|
|
16
|
-
/** Securities that should be used for this operation */
|
|
17
|
-
securities: [string, OpenAPIV3.SecuritySchemeObject][];
|
|
18
|
-
}
|
|
19
|
-
export { toJSON, fromJSON };
|
|
20
|
-
/**
|
|
21
|
-
* Resolve an OpenAPI operation in a file and compile it to a more usable format.
|
|
22
|
-
*/
|
|
23
|
-
export declare function fetchOpenAPIOperation(input: {
|
|
24
|
-
url: string;
|
|
25
|
-
path: string;
|
|
26
|
-
method: string;
|
|
27
|
-
}, fetcher: OpenAPIFetcher): Promise<OpenAPIOperationData | null>;
|
|
@@ -1,195 +0,0 @@
|
|
|
1
|
-
var __assign = (this && this.__assign) || function () {
|
|
2
|
-
__assign = Object.assign || function(t) {
|
|
3
|
-
for (var s, i = 1, n = arguments.length; i < n; i++) {
|
|
4
|
-
s = arguments[i];
|
|
5
|
-
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
|
|
6
|
-
t[p] = s[p];
|
|
7
|
-
}
|
|
8
|
-
return t;
|
|
9
|
-
};
|
|
10
|
-
return __assign.apply(this, arguments);
|
|
11
|
-
};
|
|
12
|
-
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
13
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
14
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
15
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
16
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
17
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
18
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
19
|
-
});
|
|
20
|
-
};
|
|
21
|
-
var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
22
|
-
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
|
|
23
|
-
return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
|
24
|
-
function verb(n) { return function (v) { return step([n, v]); }; }
|
|
25
|
-
function step(op) {
|
|
26
|
-
if (f) throw new TypeError("Generator is already executing.");
|
|
27
|
-
while (g && (g = 0, op[0] && (_ = 0)), _) try {
|
|
28
|
-
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
|
|
29
|
-
if (y = 0, t) op = [op[0] & 2, t.value];
|
|
30
|
-
switch (op[0]) {
|
|
31
|
-
case 0: case 1: t = op; break;
|
|
32
|
-
case 4: _.label++; return { value: op[1], done: false };
|
|
33
|
-
case 5: _.label++; y = op[1]; op = [0]; continue;
|
|
34
|
-
case 7: op = _.ops.pop(); _.trys.pop(); continue;
|
|
35
|
-
default:
|
|
36
|
-
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
|
|
37
|
-
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
|
|
38
|
-
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
|
|
39
|
-
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
|
|
40
|
-
if (t[2]) _.ops.pop();
|
|
41
|
-
_.trys.pop(); continue;
|
|
42
|
-
}
|
|
43
|
-
op = body.call(thisArg, _);
|
|
44
|
-
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
|
|
45
|
-
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
|
46
|
-
}
|
|
47
|
-
};
|
|
48
|
-
var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
|
|
49
|
-
if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
|
|
50
|
-
if (ar || !(i in from)) {
|
|
51
|
-
if (!ar) ar = Array.prototype.slice.call(from, 0, i);
|
|
52
|
-
ar[i] = from[i];
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
return to.concat(ar || Array.prototype.slice.call(from));
|
|
56
|
-
};
|
|
57
|
-
import { toJSON, fromJSON } from 'flatted';
|
|
58
|
-
import { OpenAPIParseError, dereference, } from '@gitbook/openapi-parser';
|
|
59
|
-
import { noReference } from './utils';
|
|
60
|
-
export { toJSON, fromJSON };
|
|
61
|
-
/**
|
|
62
|
-
* Resolve an OpenAPI operation in a file and compile it to a more usable format.
|
|
63
|
-
*/
|
|
64
|
-
export function fetchOpenAPIOperation(input, fetcher) {
|
|
65
|
-
return __awaiter(this, void 0, void 0, function () {
|
|
66
|
-
var filesystem, schema, operation, commonParameters, servers, security, securities, _i, security_1, entry, securityKey, securityScheme;
|
|
67
|
-
var _a, _b, _c, _d, _e, _f;
|
|
68
|
-
return __generator(this, function (_g) {
|
|
69
|
-
switch (_g.label) {
|
|
70
|
-
case 0: return [4 /*yield*/, fetcher.fetch(input.url)];
|
|
71
|
-
case 1:
|
|
72
|
-
filesystem = _g.sent();
|
|
73
|
-
return [4 /*yield*/, memoDereferenceFilesystem(filesystem, input.url)];
|
|
74
|
-
case 2:
|
|
75
|
-
schema = _g.sent();
|
|
76
|
-
operation = getOperationByPathAndMethod(schema, input.path, input.method);
|
|
77
|
-
if (!operation) {
|
|
78
|
-
return [2 /*return*/, null];
|
|
79
|
-
}
|
|
80
|
-
commonParameters = getPathObjectParameter(schema, input.path);
|
|
81
|
-
if (commonParameters) {
|
|
82
|
-
operation = __assign(__assign({}, operation), { parameters: __spreadArray(__spreadArray([], commonParameters, true), ((_a = operation.parameters) !== null && _a !== void 0 ? _a : []), true) });
|
|
83
|
-
}
|
|
84
|
-
servers = 'servers' in schema ? ((_b = schema.servers) !== null && _b !== void 0 ? _b : []) : [];
|
|
85
|
-
security = flattenSecurities((_d = (_c = operation.security) !== null && _c !== void 0 ? _c : schema.security) !== null && _d !== void 0 ? _d : []);
|
|
86
|
-
securities = [];
|
|
87
|
-
for (_i = 0, security_1 = security; _i < security_1.length; _i++) {
|
|
88
|
-
entry = security_1[_i];
|
|
89
|
-
securityKey = Object.keys(entry)[0];
|
|
90
|
-
if (securityKey) {
|
|
91
|
-
securityScheme = (_f = (_e = schema.components) === null || _e === void 0 ? void 0 : _e.securitySchemes) === null || _f === void 0 ? void 0 : _f[securityKey];
|
|
92
|
-
if (securityScheme) {
|
|
93
|
-
securities.push([securityKey, noReference(securityScheme)]);
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
return [2 /*return*/, {
|
|
98
|
-
servers: servers,
|
|
99
|
-
operation: operation,
|
|
100
|
-
method: input.method,
|
|
101
|
-
path: input.path,
|
|
102
|
-
securities: securities,
|
|
103
|
-
'x-codeSamples': typeof schema['x-codeSamples'] === 'boolean' ? schema['x-codeSamples'] : undefined,
|
|
104
|
-
'x-hideTryItPanel': typeof schema['x-hideTryItPanel'] === 'boolean'
|
|
105
|
-
? schema['x-hideTryItPanel']
|
|
106
|
-
: undefined,
|
|
107
|
-
}];
|
|
108
|
-
}
|
|
109
|
-
});
|
|
110
|
-
});
|
|
111
|
-
}
|
|
112
|
-
var dereferenceCache = new WeakMap();
|
|
113
|
-
/**
|
|
114
|
-
* Memoized version of `dereferenceSchema`.
|
|
115
|
-
*/
|
|
116
|
-
function memoDereferenceFilesystem(filesystem, url) {
|
|
117
|
-
if (dereferenceCache.has(filesystem)) {
|
|
118
|
-
return dereferenceCache.get(filesystem);
|
|
119
|
-
}
|
|
120
|
-
var promise = dereferenceFilesystem(filesystem, url);
|
|
121
|
-
dereferenceCache.set(filesystem, promise);
|
|
122
|
-
return promise;
|
|
123
|
-
}
|
|
124
|
-
/**
|
|
125
|
-
* Dereference an OpenAPI schema.
|
|
126
|
-
*/
|
|
127
|
-
function dereferenceFilesystem(filesystem, url) {
|
|
128
|
-
return __awaiter(this, void 0, void 0, function () {
|
|
129
|
-
var result;
|
|
130
|
-
return __generator(this, function (_a) {
|
|
131
|
-
switch (_a.label) {
|
|
132
|
-
case 0: return [4 /*yield*/, dereference(filesystem)];
|
|
133
|
-
case 1:
|
|
134
|
-
result = _a.sent();
|
|
135
|
-
if (!result.schema) {
|
|
136
|
-
throw new OpenAPIParseError('Failed to dereference OpenAPI document', url, 'failed-dereference');
|
|
137
|
-
}
|
|
138
|
-
return [2 /*return*/, result.schema];
|
|
139
|
-
}
|
|
140
|
-
});
|
|
141
|
-
});
|
|
142
|
-
}
|
|
143
|
-
/**
|
|
144
|
-
* Get a path object from its path.
|
|
145
|
-
*/
|
|
146
|
-
function getPathObject(schema, path) {
|
|
147
|
-
var _a;
|
|
148
|
-
if ((_a = schema.paths) === null || _a === void 0 ? void 0 : _a[path]) {
|
|
149
|
-
return schema.paths[path];
|
|
150
|
-
}
|
|
151
|
-
return null;
|
|
152
|
-
}
|
|
153
|
-
/**
|
|
154
|
-
* Resolve parameters from a path in an OpenAPI schema.
|
|
155
|
-
*/
|
|
156
|
-
function getPathObjectParameter(schema, path) {
|
|
157
|
-
var pathObject = getPathObject(schema, path);
|
|
158
|
-
if (pathObject === null || pathObject === void 0 ? void 0 : pathObject.parameters) {
|
|
159
|
-
return pathObject.parameters.map(noReference);
|
|
160
|
-
}
|
|
161
|
-
return null;
|
|
162
|
-
}
|
|
163
|
-
/**
|
|
164
|
-
* Get an operation by its path and method.
|
|
165
|
-
*/
|
|
166
|
-
function getOperationByPathAndMethod(schema, path, method) {
|
|
167
|
-
// Types are buffy for OpenAPIV3_1.OperationObject, so we use v3
|
|
168
|
-
var pathObject = getPathObject(schema, path);
|
|
169
|
-
if (!pathObject) {
|
|
170
|
-
return null;
|
|
171
|
-
}
|
|
172
|
-
var normalizedMethod = method.toLowerCase();
|
|
173
|
-
if (!pathObject[normalizedMethod]) {
|
|
174
|
-
return null;
|
|
175
|
-
}
|
|
176
|
-
return pathObject[normalizedMethod];
|
|
177
|
-
}
|
|
178
|
-
/**
|
|
179
|
-
* Flatten security objects in case they are nested.
|
|
180
|
-
* @example [{bearerAuth:[], basicAuth:[]}] => [{ bearerAuth: [] }, { basicAuth: [] }]
|
|
181
|
-
*/
|
|
182
|
-
function flattenSecurities(security) {
|
|
183
|
-
if (!Array.isArray(security) || security.length === 0) {
|
|
184
|
-
return [];
|
|
185
|
-
}
|
|
186
|
-
return security.flatMap(function (securityObject) {
|
|
187
|
-
return Object.entries(securityObject).map(function (_a) {
|
|
188
|
-
var _b;
|
|
189
|
-
var authType = _a[0], config = _a[1];
|
|
190
|
-
return (_b = {},
|
|
191
|
-
_b[authType] = config,
|
|
192
|
-
_b);
|
|
193
|
-
});
|
|
194
|
-
});
|
|
195
|
-
}
|