@gitbook/react-openapi 1.1.2 → 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/package.json CHANGED
@@ -8,7 +8,7 @@
8
8
  "default": "./dist/index.js"
9
9
  }
10
10
  },
11
- "version": "1.1.2",
11
+ "version": "1.1.4",
12
12
  "sideEffects": false,
13
13
  "dependencies": {
14
14
  "@gitbook/openapi-parser": "workspace:*",
@@ -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 ? generateSchemaExample(param.schema) : undefined;
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 ? generateSchemaExample(param.schema) : undefined;
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>
@@ -31,7 +31,7 @@ export function OpenAPISecurities(props: {
31
31
  key: key,
32
32
  label: key,
33
33
  body: (
34
- <div className="openapi-schema-body">
34
+ <div className="openapi-schema">
35
35
  <div className="openapi-schema-presentation">
36
36
  {getLabelForType(security)}
37
37
 
@@ -80,8 +80,8 @@ describe('#resolveOpenAPIOperation', () => {
80
80
  it('should resolve circular refs', async () => {
81
81
  const filesystem = await fetchFilesystem('https://api.gitbook.com/openapi.json');
82
82
  const resolved = await resolveOpenAPIOperation(filesystem, {
83
- method: 'post',
84
- path: '/search/ask',
83
+ method: 'get',
84
+ path: '/spaces/{spaceId}/content/page/{pageId}',
85
85
  });
86
86
 
87
87
  expect(resolved).toMatchObject({
@@ -91,7 +91,7 @@ describe('#resolveOpenAPIOperation', () => {
91
91
  },
92
92
  ],
93
93
  operation: {
94
- operationId: 'askQuery',
94
+ operationId: 'getPageById',
95
95
  },
96
96
  });
97
97
  });
@@ -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: OpenAPIContextProps;
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 = getOpenAPIComponents(schema);
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
- * Get OpenAPI components.schemas that are not ignored.
36
+ * Extract selected schemas from the OpenAPI document.
29
37
  */
30
- function getOpenAPIComponents(schema: OpenAPIV3.Document | OpenAPIV3_1.Document): OpenAPISchema[] {
31
- const schemas = schema.components?.schemas ?? {};
32
- return Object.entries(schemas)
33
- .filter(([, schema]) => !shouldIgnoreEntity(schema))
34
- .map(([key, schema]) => ({ name: key, schema }));
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
  }