@gitbook/react-openapi 1.1.3 → 1.1.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 +99 -91
- package/dist/OpenAPICodeSample.jsx +6 -2
- package/dist/OpenAPISchemaName.jsx +1 -0
- package/dist/schemas/OpenAPISchemas.d.ts +3 -1
- package/dist/schemas/resolveOpenAPISchemas.d.ts +9 -3
- package/dist/schemas/resolveOpenAPISchemas.js +24 -15
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/src/OpenAPICodeSample.tsx +6 -2
- package/src/OpenAPISchemaName.tsx +1 -0
- package/src/schemas/OpenAPISchemas.tsx +6 -1
- package/src/schemas/resolveOpenAPISchemas.test.ts +174 -0
- package/src/schemas/resolveOpenAPISchemas.ts +31 -9
package/package.json
CHANGED
|
@@ -26,13 +26,17 @@ export function OpenAPICodeSample(props: {
|
|
|
26
26
|
}
|
|
27
27
|
|
|
28
28
|
if (param.in === 'header' && param.required) {
|
|
29
|
-
const example = param.schema
|
|
29
|
+
const example = param.schema
|
|
30
|
+
? generateSchemaExample(param.schema, { mode: 'write' })
|
|
31
|
+
: undefined;
|
|
30
32
|
if (example !== undefined && param.name) {
|
|
31
33
|
headersObject[param.name] =
|
|
32
34
|
typeof example !== 'string' ? stringifyOpenAPI(example) : example;
|
|
33
35
|
}
|
|
34
36
|
} else if (param.in === 'query' && param.required) {
|
|
35
|
-
const example = param.schema
|
|
37
|
+
const example = param.schema
|
|
38
|
+
? generateSchemaExample(param.schema, { mode: 'write' })
|
|
39
|
+
: undefined;
|
|
36
40
|
if (example !== undefined && param.name) {
|
|
37
41
|
searchParams.append(
|
|
38
42
|
param.name,
|
|
@@ -30,6 +30,7 @@ export function OpenAPISchemaName(props: OpenAPISchemaNameProps) {
|
|
|
30
30
|
<span className="openapi-schema-type">{additionalItems}</span>
|
|
31
31
|
) : null}
|
|
32
32
|
</span>
|
|
33
|
+
{schema?.readOnly ? <span className="openapi-schema-readonly">read-only</span> : null}
|
|
33
34
|
{required ? <span className="openapi-schema-required">required</span> : null}
|
|
34
35
|
{schema?.deprecated ? <span className="openapi-deprecated">Deprecated</span> : null}
|
|
35
36
|
</div>
|
|
@@ -4,13 +4,18 @@ import { OpenAPIRootSchema } from '../OpenAPISchema';
|
|
|
4
4
|
import { Section, SectionBody } from '../StaticSection';
|
|
5
5
|
import type { OpenAPIClientContext, OpenAPIContextProps, OpenAPISchemasData } from '../types';
|
|
6
6
|
|
|
7
|
+
type OpenAPISchemasContextProps = Omit<
|
|
8
|
+
OpenAPIContextProps,
|
|
9
|
+
'renderCodeBlock' | 'renderHeading' | 'renderDocument'
|
|
10
|
+
>;
|
|
11
|
+
|
|
7
12
|
/**
|
|
8
13
|
* Display OpenAPI Schemas.
|
|
9
14
|
*/
|
|
10
15
|
export function OpenAPISchemas(props: {
|
|
11
16
|
className?: string;
|
|
12
17
|
data: OpenAPISchemasData;
|
|
13
|
-
context:
|
|
18
|
+
context: OpenAPISchemasContextProps;
|
|
14
19
|
}) {
|
|
15
20
|
const { className, data, context } = props;
|
|
16
21
|
const { schemas } = data;
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
import { describe, expect, it } from 'bun:test';
|
|
2
|
+
|
|
3
|
+
import { parseOpenAPI, traverse } from '@gitbook/openapi-parser';
|
|
4
|
+
import { resolveOpenAPISchemas } from './resolveOpenAPISchemas';
|
|
5
|
+
|
|
6
|
+
async function fetchFilesystem(url: string) {
|
|
7
|
+
const response = await fetch(url);
|
|
8
|
+
const text = await response.text();
|
|
9
|
+
const filesystem = await parseOpenAPI({ value: text, rootURL: url });
|
|
10
|
+
const transformedFs = await traverse(filesystem, async (node) => {
|
|
11
|
+
if ('description' in node && typeof node.description === 'string' && node.description) {
|
|
12
|
+
node['x-gitbook-description-html'] = node.description;
|
|
13
|
+
}
|
|
14
|
+
return node;
|
|
15
|
+
});
|
|
16
|
+
return transformedFs;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
describe('#resolveOpenAPISchemas', () => {
|
|
20
|
+
it('should resolve refs', async () => {
|
|
21
|
+
const filesystem = await fetchFilesystem(
|
|
22
|
+
'https://petstore3.swagger.io/api/v3/openapi.json'
|
|
23
|
+
);
|
|
24
|
+
const resolved = await resolveOpenAPISchemas(filesystem, { schemas: ['Pet', 'Tag'] });
|
|
25
|
+
|
|
26
|
+
expect(resolved).toMatchObject({
|
|
27
|
+
schemas: [
|
|
28
|
+
{
|
|
29
|
+
name: 'Pet',
|
|
30
|
+
schema: {
|
|
31
|
+
properties: {
|
|
32
|
+
tags: {
|
|
33
|
+
type: 'array',
|
|
34
|
+
items: {
|
|
35
|
+
type: 'object',
|
|
36
|
+
properties: {
|
|
37
|
+
id: {
|
|
38
|
+
format: 'int64',
|
|
39
|
+
type: 'integer',
|
|
40
|
+
},
|
|
41
|
+
name: {
|
|
42
|
+
type: 'string',
|
|
43
|
+
},
|
|
44
|
+
},
|
|
45
|
+
},
|
|
46
|
+
},
|
|
47
|
+
},
|
|
48
|
+
},
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
name: 'Tag',
|
|
52
|
+
schema: {
|
|
53
|
+
type: 'object',
|
|
54
|
+
properties: {
|
|
55
|
+
id: {
|
|
56
|
+
type: 'integer',
|
|
57
|
+
format: 'int64',
|
|
58
|
+
},
|
|
59
|
+
name: {
|
|
60
|
+
type: 'string',
|
|
61
|
+
},
|
|
62
|
+
},
|
|
63
|
+
xml: {
|
|
64
|
+
name: 'tag',
|
|
65
|
+
},
|
|
66
|
+
},
|
|
67
|
+
},
|
|
68
|
+
],
|
|
69
|
+
});
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
it('should support yaml', async () => {
|
|
73
|
+
const filesystem = await fetchFilesystem(
|
|
74
|
+
'https://petstore3.swagger.io/api/v3/openapi.yaml'
|
|
75
|
+
);
|
|
76
|
+
const resolved = await resolveOpenAPISchemas(filesystem, { schemas: ['Pet'] });
|
|
77
|
+
|
|
78
|
+
expect(resolved).toMatchObject({
|
|
79
|
+
schemas: [
|
|
80
|
+
{
|
|
81
|
+
name: 'Pet',
|
|
82
|
+
schema: {
|
|
83
|
+
properties: {
|
|
84
|
+
tags: {
|
|
85
|
+
type: 'array',
|
|
86
|
+
items: {
|
|
87
|
+
properties: {
|
|
88
|
+
id: {
|
|
89
|
+
format: 'int64',
|
|
90
|
+
type: 'integer',
|
|
91
|
+
},
|
|
92
|
+
name: {
|
|
93
|
+
type: 'string',
|
|
94
|
+
},
|
|
95
|
+
},
|
|
96
|
+
type: 'object',
|
|
97
|
+
},
|
|
98
|
+
},
|
|
99
|
+
},
|
|
100
|
+
},
|
|
101
|
+
},
|
|
102
|
+
],
|
|
103
|
+
});
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
it('should resolve circular refs', async () => {
|
|
107
|
+
const filesystem = await fetchFilesystem('https://api.gitbook.com/openapi.json');
|
|
108
|
+
const resolved = await resolveOpenAPISchemas(filesystem, {
|
|
109
|
+
schemas: ['DocumentBlockTabs'],
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
expect(resolved).toMatchObject({
|
|
113
|
+
schemas: [
|
|
114
|
+
{
|
|
115
|
+
name: 'DocumentBlockTabs',
|
|
116
|
+
schema: {
|
|
117
|
+
type: 'object',
|
|
118
|
+
properties: {
|
|
119
|
+
object: {
|
|
120
|
+
type: 'string',
|
|
121
|
+
enum: ['block'],
|
|
122
|
+
},
|
|
123
|
+
},
|
|
124
|
+
},
|
|
125
|
+
},
|
|
126
|
+
],
|
|
127
|
+
});
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
it('should resolve to null if the schema does not exist', async () => {
|
|
131
|
+
const filesystem = await fetchFilesystem(
|
|
132
|
+
'https://petstore3.swagger.io/api/v3/openapi.json'
|
|
133
|
+
);
|
|
134
|
+
const resolved = await resolveOpenAPISchemas(filesystem, {
|
|
135
|
+
schemas: ['NonExistentSchema'],
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
expect(resolved).toBe(null);
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
it('should parse Swagger 2.0', async () => {
|
|
142
|
+
const filesystem = await fetchFilesystem('https://petstore.swagger.io/v2/swagger.json');
|
|
143
|
+
const resolved = await resolveOpenAPISchemas(filesystem, {
|
|
144
|
+
schemas: ['Pet'],
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
expect(resolved).toMatchObject({
|
|
148
|
+
schemas: [
|
|
149
|
+
{
|
|
150
|
+
name: 'Pet',
|
|
151
|
+
schema: {
|
|
152
|
+
properties: {
|
|
153
|
+
tags: {
|
|
154
|
+
type: 'array',
|
|
155
|
+
items: {
|
|
156
|
+
properties: {
|
|
157
|
+
id: {
|
|
158
|
+
format: 'int64',
|
|
159
|
+
type: 'integer',
|
|
160
|
+
},
|
|
161
|
+
name: {
|
|
162
|
+
type: 'string',
|
|
163
|
+
},
|
|
164
|
+
},
|
|
165
|
+
type: 'object',
|
|
166
|
+
},
|
|
167
|
+
},
|
|
168
|
+
},
|
|
169
|
+
},
|
|
170
|
+
},
|
|
171
|
+
],
|
|
172
|
+
});
|
|
173
|
+
});
|
|
174
|
+
});
|
|
@@ -15,21 +15,43 @@ import type { OpenAPISchema, OpenAPISchemasData } from '../types';
|
|
|
15
15
|
* Schemas are extracted from the OpenAPI components.schemas
|
|
16
16
|
*/
|
|
17
17
|
export async function resolveOpenAPISchemas(
|
|
18
|
-
filesystem: Filesystem<OpenAPIV3xDocument
|
|
18
|
+
filesystem: Filesystem<OpenAPIV3xDocument>,
|
|
19
|
+
options: {
|
|
20
|
+
schemas: string[];
|
|
21
|
+
}
|
|
19
22
|
): Promise<OpenAPISchemasData | null> {
|
|
23
|
+
const { schemas: selectedSchemas } = options;
|
|
24
|
+
|
|
20
25
|
const schema = await dereferenceFilesystem(filesystem);
|
|
21
26
|
|
|
22
|
-
const schemas =
|
|
27
|
+
const schemas = filterSelectedOpenAPISchemas(schema, selectedSchemas);
|
|
28
|
+
|
|
29
|
+
if (schemas.length === 0) {
|
|
30
|
+
return null;
|
|
31
|
+
}
|
|
23
32
|
|
|
24
33
|
return { schemas };
|
|
25
34
|
}
|
|
26
|
-
|
|
27
35
|
/**
|
|
28
|
-
*
|
|
36
|
+
* Extract selected schemas from the OpenAPI document.
|
|
29
37
|
*/
|
|
30
|
-
function
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
38
|
+
export function filterSelectedOpenAPISchemas(
|
|
39
|
+
schema: OpenAPIV3.Document | OpenAPIV3_1.Document,
|
|
40
|
+
selectedSchemas: string[]
|
|
41
|
+
): OpenAPISchema[] {
|
|
42
|
+
const componentsSchemas = schema.components?.schemas ?? {};
|
|
43
|
+
|
|
44
|
+
// Preserve the order of the selected schemas
|
|
45
|
+
return selectedSchemas
|
|
46
|
+
.map((name) => {
|
|
47
|
+
const schema = componentsSchemas[name];
|
|
48
|
+
if (schema && !shouldIgnoreEntity(schema)) {
|
|
49
|
+
return {
|
|
50
|
+
name,
|
|
51
|
+
schema,
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
return null;
|
|
55
|
+
})
|
|
56
|
+
.filter((schema): schema is OpenAPISchema => !!schema);
|
|
35
57
|
}
|