@gitbook/react-openapi 1.1.9 → 1.2.0
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 +27 -0
- package/dist/InteractiveSection.d.ts +4 -0
- package/dist/InteractiveSection.jsx +14 -13
- package/dist/OpenAPICodeSample.d.ts +3 -2
- package/dist/OpenAPICodeSample.jsx +8 -12
- package/dist/OpenAPICodeSampleInteractive.d.ts +3 -0
- package/dist/OpenAPICodeSampleInteractive.jsx +37 -49
- package/dist/OpenAPICodeSampleSelector.d.ts +14 -0
- package/dist/OpenAPICodeSampleSelector.jsx +44 -0
- package/dist/OpenAPICopyButton.d.ts +2 -0
- package/dist/OpenAPICopyButton.jsx +5 -2
- package/dist/OpenAPIDisclosure.d.ts +4 -3
- package/dist/OpenAPIDisclosure.jsx +8 -11
- package/dist/OpenAPIDisclosureGroup.d.ts +7 -3
- package/dist/OpenAPIDisclosureGroup.jsx +18 -18
- package/dist/OpenAPIExample.d.ts +16 -0
- package/dist/OpenAPIExample.jsx +36 -0
- package/dist/OpenAPIMediaType.d.ts +21 -0
- package/dist/OpenAPIMediaType.jsx +61 -0
- package/dist/OpenAPIOperation.d.ts +3 -2
- package/dist/OpenAPIOperation.jsx +9 -72
- package/dist/OpenAPIOperationDescription.d.ts +9 -0
- package/dist/OpenAPIOperationDescription.jsx +22 -0
- package/dist/OpenAPIOperationStability.d.ts +9 -0
- package/dist/OpenAPIOperationStability.jsx +27 -0
- package/dist/OpenAPIPath.d.ts +12 -2
- package/dist/OpenAPIPath.jsx +10 -4
- package/dist/OpenAPIRequestBody.d.ts +3 -1
- package/dist/OpenAPIRequestBody.jsx +4 -3
- package/dist/OpenAPIResponse.d.ts +1 -1
- package/dist/OpenAPIResponse.jsx +1 -1
- package/dist/OpenAPIResponseExample.d.ts +4 -3
- package/dist/OpenAPIResponseExample.jsx +24 -154
- package/dist/OpenAPIResponseExampleContent.d.ts +19 -0
- package/dist/OpenAPIResponseExampleContent.jsx +57 -0
- package/dist/OpenAPIResponses.d.ts +1 -1
- package/dist/OpenAPIResponses.jsx +49 -36
- package/dist/OpenAPISchema.d.ts +1 -1
- package/dist/OpenAPISchema.jsx +121 -20
- package/dist/OpenAPISchemaName.d.ts +2 -0
- package/dist/OpenAPISchemaName.jsx +21 -17
- package/dist/OpenAPISchemaServer.d.ts +1 -1
- package/dist/OpenAPISecurities.d.ts +2 -1
- package/dist/OpenAPISecurities.jsx +11 -10
- package/dist/OpenAPISelect.d.ts +22 -0
- package/dist/OpenAPISelect.jsx +43 -0
- package/dist/OpenAPISpec.d.ts +3 -2
- package/dist/OpenAPISpec.jsx +11 -9
- package/dist/OpenAPITabs.jsx +9 -9
- package/dist/OpenAPIWebhook.d.ts +10 -0
- package/dist/OpenAPIWebhook.jsx +23 -0
- package/dist/OpenAPIWebhookExample.d.ts +6 -0
- package/dist/OpenAPIWebhookExample.jsx +41 -0
- package/dist/ScalarApiButton.d.ts +2 -0
- package/dist/ScalarApiButton.jsx +4 -3
- package/dist/StaticSection.d.ts +4 -1
- package/dist/StaticSection.jsx +13 -4
- package/dist/code-samples.js +57 -39
- package/dist/common/OpenAPIColumnSpec.d.ts +6 -0
- package/dist/common/OpenAPIColumnSpec.jsx +20 -0
- package/dist/common/OpenAPIOperationDescription.d.ts +6 -0
- package/dist/common/OpenAPIOperationDescription.jsx +19 -0
- package/dist/common/OpenAPIStability.d.ts +4 -0
- package/dist/common/OpenAPIStability.jsx +15 -0
- package/dist/common/OpenAPISummary.d.ts +6 -0
- package/dist/common/OpenAPISummary.jsx +30 -0
- package/dist/context.d.ts +75 -0
- package/dist/context.js +43 -0
- package/dist/generateSchemaExample.js +4 -0
- package/dist/getOrCreateStoreByKey.d.ts +10 -0
- package/dist/getOrCreateStoreByKey.js +19 -0
- package/dist/index.d.ts +5 -1
- package/dist/index.js +3 -0
- package/dist/resolveOpenAPIOperation.js +10 -5
- package/dist/resolveOpenAPIWebhook.d.ts +11 -0
- package/dist/resolveOpenAPIWebhook.js +127 -0
- package/dist/schemas/OpenAPISchemas.d.ts +5 -6
- package/dist/schemas/OpenAPISchemas.jsx +52 -49
- package/dist/schemas/resolveOpenAPISchemas.d.ts +4 -3
- package/dist/schemas/resolveOpenAPISchemas.js +0 -1
- package/dist/stringifyOpenAPI.d.ts +1 -1
- package/dist/stringifyOpenAPI.js +6 -3
- package/dist/translate.d.ts +10 -0
- package/dist/translate.jsx +75 -0
- package/dist/translations/de.d.ts +37 -0
- package/dist/translations/de.js +37 -0
- package/dist/translations/en.d.ts +37 -0
- package/dist/translations/en.js +37 -0
- package/dist/translations/es.d.ts +37 -0
- package/dist/translations/es.js +37 -0
- package/dist/translations/fr.d.ts +37 -0
- package/dist/translations/fr.js +37 -0
- package/dist/translations/index.d.ts +341 -0
- package/dist/translations/index.js +27 -0
- package/dist/translations/ja.d.ts +37 -0
- package/dist/translations/ja.js +37 -0
- package/dist/translations/nl.d.ts +37 -0
- package/dist/translations/nl.js +37 -0
- package/dist/translations/no.d.ts +37 -0
- package/dist/translations/no.js +37 -0
- package/dist/translations/pt-br.d.ts +37 -0
- package/dist/translations/pt-br.js +37 -0
- package/dist/translations/types.d.ts +5 -0
- package/dist/translations/types.js +1 -0
- package/dist/translations/zh.d.ts +37 -0
- package/dist/translations/zh.js +37 -0
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/dist/types.d.ts +12 -48
- package/dist/util/example.d.ts +35 -0
- package/dist/util/example.jsx +103 -0
- package/dist/utils.d.ts +18 -0
- package/dist/utils.js +57 -0
- package/package.json +3 -3
- package/src/InteractiveSection.tsx +22 -18
- package/src/OpenAPICodeSample.tsx +26 -15
- package/src/OpenAPICodeSampleInteractive.tsx +67 -70
- package/src/OpenAPICodeSampleSelector.tsx +94 -0
- package/src/OpenAPICopyButton.tsx +7 -2
- package/src/OpenAPIDisclosure.tsx +20 -22
- package/src/OpenAPIDisclosureGroup.tsx +40 -22
- package/src/OpenAPIExample.tsx +55 -0
- package/src/OpenAPIMediaType.tsx +139 -0
- package/src/OpenAPIOperation.tsx +11 -104
- package/src/OpenAPIOperationDescription.tsx +34 -0
- package/src/OpenAPIOperationStability.tsx +39 -0
- package/src/OpenAPIPath.tsx +26 -6
- package/src/OpenAPIRequestBody.tsx +9 -4
- package/src/OpenAPIResponse.tsx +2 -2
- package/src/OpenAPIResponseExample.tsx +41 -215
- package/src/OpenAPIResponseExampleContent.tsx +123 -0
- package/src/OpenAPIResponses.tsx +83 -62
- package/src/OpenAPISchema.test.ts +80 -0
- package/src/OpenAPISchema.tsx +149 -25
- package/src/OpenAPISchemaName.tsx +28 -19
- package/src/OpenAPISchemaServer.tsx +1 -1
- package/src/OpenAPISecurities.tsx +46 -12
- package/src/OpenAPISelect.tsx +96 -0
- package/src/OpenAPISpec.tsx +21 -10
- package/src/OpenAPITabs.tsx +9 -9
- package/src/OpenAPIWebhook.tsx +33 -0
- package/src/OpenAPIWebhookExample.tsx +60 -0
- package/src/ScalarApiButton.tsx +6 -6
- package/src/StaticSection.tsx +37 -5
- package/src/code-samples.test.ts +3 -1
- package/src/code-samples.ts +67 -54
- package/src/common/OpenAPIColumnSpec.tsx +31 -0
- package/src/common/OpenAPIOperationDescription.tsx +31 -0
- package/src/common/OpenAPIStability.tsx +23 -0
- package/src/common/OpenAPISummary.tsx +45 -0
- package/src/context.ts +99 -0
- package/src/generateSchemaExample.test.ts +1020 -0
- package/src/generateSchemaExample.ts +5 -0
- package/src/getOrCreateStoreByKey.ts +33 -0
- package/src/index.ts +5 -1
- package/src/resolveOpenAPIOperation.ts +14 -3
- package/src/resolveOpenAPIWebhook.ts +99 -0
- package/src/schemas/OpenAPISchemas.tsx +76 -71
- package/src/schemas/resolveOpenAPISchemas.ts +4 -5
- package/src/stringifyOpenAPI.ts +11 -3
- package/src/translate.tsx +80 -0
- package/src/translations/de.ts +37 -0
- package/src/translations/en.ts +37 -0
- package/src/translations/es.ts +37 -0
- package/src/translations/fr.ts +37 -0
- package/src/translations/index.ts +33 -0
- package/src/translations/ja.ts +37 -0
- package/src/translations/nl.ts +37 -0
- package/src/translations/no.ts +37 -0
- package/src/translations/pt-br.ts +37 -0
- package/src/translations/types.ts +7 -0
- package/src/translations/zh.ts +37 -0
- package/src/types.ts +11 -46
- package/src/util/example.tsx +129 -0
- package/src/utils.ts +67 -0
- package/dist/useSyncedTabsGlobalState.d.ts +0 -10
- package/dist/useSyncedTabsGlobalState.js +0 -20
- package/src/useSyncedTabsGlobalState.ts +0 -35
|
@@ -35,6 +35,86 @@ describe('getSchemaAlternatives', () => {
|
|
|
35
35
|
]);
|
|
36
36
|
});
|
|
37
37
|
|
|
38
|
+
it('merges string enum', () => {
|
|
39
|
+
expect(
|
|
40
|
+
getSchemaAlternatives({
|
|
41
|
+
oneOf: [
|
|
42
|
+
{
|
|
43
|
+
oneOf: [
|
|
44
|
+
{
|
|
45
|
+
type: 'string',
|
|
46
|
+
enum: ['a', 'b'],
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
type: 'string',
|
|
50
|
+
enum: ['c', 'd'],
|
|
51
|
+
nullable: true,
|
|
52
|
+
},
|
|
53
|
+
],
|
|
54
|
+
},
|
|
55
|
+
],
|
|
56
|
+
})
|
|
57
|
+
).toEqual([
|
|
58
|
+
{
|
|
59
|
+
type: 'string',
|
|
60
|
+
enum: ['a', 'b', 'c', 'd'],
|
|
61
|
+
nullable: true,
|
|
62
|
+
},
|
|
63
|
+
]);
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
it('merges objects with allOf', () => {
|
|
67
|
+
expect(
|
|
68
|
+
getSchemaAlternatives({
|
|
69
|
+
allOf: [
|
|
70
|
+
{
|
|
71
|
+
type: 'object',
|
|
72
|
+
properties: {
|
|
73
|
+
name: {
|
|
74
|
+
type: 'string',
|
|
75
|
+
},
|
|
76
|
+
map: {
|
|
77
|
+
type: 'string',
|
|
78
|
+
},
|
|
79
|
+
description: {
|
|
80
|
+
type: 'string',
|
|
81
|
+
},
|
|
82
|
+
},
|
|
83
|
+
required: ['name'],
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
type: 'object',
|
|
87
|
+
properties: {
|
|
88
|
+
externalId: {
|
|
89
|
+
type: 'string',
|
|
90
|
+
},
|
|
91
|
+
},
|
|
92
|
+
required: ['map', 'externalId'],
|
|
93
|
+
},
|
|
94
|
+
],
|
|
95
|
+
})
|
|
96
|
+
).toEqual([
|
|
97
|
+
{
|
|
98
|
+
type: 'object',
|
|
99
|
+
properties: {
|
|
100
|
+
name: {
|
|
101
|
+
type: 'string',
|
|
102
|
+
},
|
|
103
|
+
map: {
|
|
104
|
+
type: 'string',
|
|
105
|
+
},
|
|
106
|
+
description: {
|
|
107
|
+
type: 'string',
|
|
108
|
+
},
|
|
109
|
+
externalId: {
|
|
110
|
+
type: 'string',
|
|
111
|
+
},
|
|
112
|
+
},
|
|
113
|
+
required: ['name', 'map', 'externalId'],
|
|
114
|
+
},
|
|
115
|
+
]);
|
|
116
|
+
});
|
|
117
|
+
|
|
38
118
|
it('should not flatten oneOf and allOf', () => {
|
|
39
119
|
expect(
|
|
40
120
|
getSchemaAlternatives({
|
package/src/OpenAPISchema.tsx
CHANGED
|
@@ -10,8 +10,10 @@ import { Markdown } from './Markdown';
|
|
|
10
10
|
import { OpenAPICopyButton } from './OpenAPICopyButton';
|
|
11
11
|
import { OpenAPIDisclosure } from './OpenAPIDisclosure';
|
|
12
12
|
import { OpenAPISchemaName } from './OpenAPISchemaName';
|
|
13
|
+
import type { OpenAPIClientContext } from './context';
|
|
13
14
|
import { retrocycle } from './decycle';
|
|
14
|
-
import
|
|
15
|
+
import { stringifyOpenAPI } from './stringifyOpenAPI';
|
|
16
|
+
import { tString } from './translate';
|
|
15
17
|
import { checkIsReference, resolveDescription, resolveFirstExample } from './utils';
|
|
16
18
|
|
|
17
19
|
type CircularRefsIds = Map<OpenAPIV3.SchemaObject, string>;
|
|
@@ -39,7 +41,7 @@ function OpenAPISchemaProperty(props: {
|
|
|
39
41
|
|
|
40
42
|
return (
|
|
41
43
|
<div id={id} className={clsx('openapi-schema', className)}>
|
|
42
|
-
<OpenAPISchemaPresentation property={property} />
|
|
44
|
+
<OpenAPISchemaPresentation context={context} property={property} />
|
|
43
45
|
{(() => {
|
|
44
46
|
const circularRefId = parentCircularRefs.get(schema);
|
|
45
47
|
// Avoid recursing infinitely, and instead render a link to the parent schema
|
|
@@ -53,7 +55,12 @@ function OpenAPISchemaProperty(props: {
|
|
|
53
55
|
const properties = getSchemaProperties(schema);
|
|
54
56
|
if (properties?.length) {
|
|
55
57
|
return (
|
|
56
|
-
<OpenAPIDisclosure
|
|
58
|
+
<OpenAPIDisclosure
|
|
59
|
+
icon={context.icons.plus}
|
|
60
|
+
label={(isExpanded) =>
|
|
61
|
+
getDisclosureLabel({ schema, isExpanded, context })
|
|
62
|
+
}
|
|
63
|
+
>
|
|
57
64
|
<OpenAPISchemaProperties
|
|
58
65
|
properties={properties}
|
|
59
66
|
circularRefs={circularRefs}
|
|
@@ -145,17 +152,23 @@ function OpenAPIRootSchema(props: {
|
|
|
145
152
|
|
|
146
153
|
const id = useId();
|
|
147
154
|
const properties = getSchemaProperties(schema);
|
|
155
|
+
const description = resolveDescription(schema);
|
|
148
156
|
|
|
149
157
|
if (properties?.length) {
|
|
150
158
|
const circularRefs = new Map(parentCircularRefs);
|
|
151
159
|
circularRefs.set(schema, id);
|
|
152
160
|
|
|
153
161
|
return (
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
162
|
+
<>
|
|
163
|
+
{description ? (
|
|
164
|
+
<Markdown source={description} className="openapi-schema-root-description" />
|
|
165
|
+
) : null}
|
|
166
|
+
<OpenAPISchemaProperties
|
|
167
|
+
properties={properties}
|
|
168
|
+
circularRefs={circularRefs}
|
|
169
|
+
context={context}
|
|
170
|
+
/>
|
|
171
|
+
</>
|
|
159
172
|
);
|
|
160
173
|
}
|
|
161
174
|
|
|
@@ -201,7 +214,10 @@ function OpenAPISchemaAlternative(props: {
|
|
|
201
214
|
{description ? (
|
|
202
215
|
<Markdown source={description} className="openapi-schema-description" />
|
|
203
216
|
) : null}
|
|
204
|
-
<OpenAPIDisclosure
|
|
217
|
+
<OpenAPIDisclosure
|
|
218
|
+
icon={context.icons.plus}
|
|
219
|
+
label={(isExpanded) => getDisclosureLabel({ schema, isExpanded, context })}
|
|
220
|
+
>
|
|
205
221
|
{properties?.length ? (
|
|
206
222
|
<OpenAPISchemaProperties
|
|
207
223
|
properties={properties}
|
|
@@ -239,8 +255,9 @@ function OpenAPISchemaCircularRef(props: { id: string; schema: OpenAPIV3.SchemaO
|
|
|
239
255
|
*/
|
|
240
256
|
function OpenAPISchemaEnum(props: {
|
|
241
257
|
schema: OpenAPIV3.SchemaObject & OpenAPICustomOperationProperties;
|
|
258
|
+
context: OpenAPIClientContext;
|
|
242
259
|
}) {
|
|
243
|
-
const { schema } = props;
|
|
260
|
+
const { schema, context } = props;
|
|
244
261
|
|
|
245
262
|
const enumValues = (() => {
|
|
246
263
|
// Render x-gitbook-enum first, as it has a different format
|
|
@@ -283,6 +300,7 @@ function OpenAPISchemaEnum(props: {
|
|
|
283
300
|
value={item.value}
|
|
284
301
|
label={item.description}
|
|
285
302
|
withTooltip={!!item.description}
|
|
303
|
+
context={context}
|
|
286
304
|
>
|
|
287
305
|
<code>{`${item.value}`}</code>
|
|
288
306
|
</OpenAPICopyButton>
|
|
@@ -295,9 +313,13 @@ function OpenAPISchemaEnum(props: {
|
|
|
295
313
|
/**
|
|
296
314
|
* Render the top row of a schema. e.g: name, type, and required status.
|
|
297
315
|
*/
|
|
298
|
-
function OpenAPISchemaPresentation(props: {
|
|
316
|
+
function OpenAPISchemaPresentation(props: {
|
|
317
|
+
property: OpenAPISchemaPropertyEntry;
|
|
318
|
+
context: OpenAPIClientContext;
|
|
319
|
+
}) {
|
|
299
320
|
const {
|
|
300
321
|
property: { schema, propertyName, required },
|
|
322
|
+
context,
|
|
301
323
|
} = props;
|
|
302
324
|
|
|
303
325
|
const description = resolveDescription(schema);
|
|
@@ -310,6 +332,7 @@ function OpenAPISchemaPresentation(props: { property: OpenAPISchemaPropertyEntry
|
|
|
310
332
|
type={getSchemaTitle(schema)}
|
|
311
333
|
propertyName={propertyName}
|
|
312
334
|
required={required}
|
|
335
|
+
context={context}
|
|
313
336
|
/>
|
|
314
337
|
{typeof schema['x-deprecated-sunset'] === 'string' ? (
|
|
315
338
|
<div className="openapi-deprecated-sunset openapi-schema-description openapi-markdown">
|
|
@@ -322,17 +345,27 @@ function OpenAPISchemaPresentation(props: { property: OpenAPISchemaPropertyEntry
|
|
|
322
345
|
{description ? (
|
|
323
346
|
<Markdown source={description} className="openapi-schema-description" />
|
|
324
347
|
) : null}
|
|
348
|
+
{schema.default !== undefined ? (
|
|
349
|
+
<span className="openapi-schema-default">
|
|
350
|
+
Default:{' '}
|
|
351
|
+
<code>
|
|
352
|
+
{typeof schema.default === 'string' && schema.default
|
|
353
|
+
? schema.default
|
|
354
|
+
: stringifyOpenAPI(schema.default)}
|
|
355
|
+
</code>
|
|
356
|
+
</span>
|
|
357
|
+
) : null}
|
|
325
358
|
{typeof example === 'string' ? (
|
|
326
|
-
<
|
|
359
|
+
<span className="openapi-schema-example">
|
|
327
360
|
Example: <code>{example}</code>
|
|
328
|
-
</
|
|
361
|
+
</span>
|
|
329
362
|
) : null}
|
|
330
363
|
{schema.pattern ? (
|
|
331
|
-
<
|
|
364
|
+
<span className="openapi-schema-pattern">
|
|
332
365
|
Pattern: <code>{schema.pattern}</code>
|
|
333
|
-
</
|
|
366
|
+
</span>
|
|
334
367
|
) : null}
|
|
335
|
-
<OpenAPISchemaEnum schema={schema} />
|
|
368
|
+
<OpenAPISchemaEnum schema={schema} context={context} />
|
|
336
369
|
</div>
|
|
337
370
|
);
|
|
338
371
|
}
|
|
@@ -427,7 +460,91 @@ export function getSchemaAlternatives(
|
|
|
427
460
|
}
|
|
428
461
|
|
|
429
462
|
const [type, schemas] = alternatives;
|
|
430
|
-
return
|
|
463
|
+
return mergeAlternatives(
|
|
464
|
+
type,
|
|
465
|
+
flattenAlternatives(type, schemas, new Set(ancestors).add(schema))
|
|
466
|
+
);
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
/**
|
|
470
|
+
* Merge alternatives of the same type into a single schema.
|
|
471
|
+
* - Merge string enums
|
|
472
|
+
*/
|
|
473
|
+
function mergeAlternatives(
|
|
474
|
+
alternativeType: AlternativeType,
|
|
475
|
+
schemasOrRefs: OpenAPIV3.SchemaObject[]
|
|
476
|
+
): OpenAPIV3.SchemaObject[] | null {
|
|
477
|
+
switch (alternativeType) {
|
|
478
|
+
case 'oneOf': {
|
|
479
|
+
return schemasOrRefs.reduce<OpenAPIV3.SchemaObject[]>((acc, schemaOrRef) => {
|
|
480
|
+
const latest = acc.at(-1);
|
|
481
|
+
|
|
482
|
+
if (
|
|
483
|
+
latest &&
|
|
484
|
+
latest.type === 'string' &&
|
|
485
|
+
latest.enum &&
|
|
486
|
+
schemaOrRef.type === 'string' &&
|
|
487
|
+
schemaOrRef.enum
|
|
488
|
+
) {
|
|
489
|
+
latest.enum = Array.from(new Set([...latest.enum, ...schemaOrRef.enum]));
|
|
490
|
+
latest.nullable = latest.nullable || schemaOrRef.nullable;
|
|
491
|
+
return acc;
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
acc.push(schemaOrRef);
|
|
495
|
+
return acc;
|
|
496
|
+
}, []);
|
|
497
|
+
}
|
|
498
|
+
case 'allOf': {
|
|
499
|
+
return schemasOrRefs.reduce<OpenAPIV3.SchemaObject[]>((acc, schemaOrRef) => {
|
|
500
|
+
const latest = acc.at(-1);
|
|
501
|
+
|
|
502
|
+
if (
|
|
503
|
+
latest &&
|
|
504
|
+
latest.type === 'string' &&
|
|
505
|
+
latest.enum &&
|
|
506
|
+
schemaOrRef.type === 'string' &&
|
|
507
|
+
schemaOrRef.enum
|
|
508
|
+
) {
|
|
509
|
+
const keys = Object.keys(schemaOrRef);
|
|
510
|
+
if (keys.every((key) => ['type', 'enum', 'nullable'].includes(key))) {
|
|
511
|
+
latest.enum = Array.from(new Set([...latest.enum, ...schemaOrRef.enum]));
|
|
512
|
+
latest.nullable = latest.nullable || schemaOrRef.nullable;
|
|
513
|
+
return acc;
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
if (latest && latest.type === 'object' && schemaOrRef.type === 'object') {
|
|
518
|
+
const keys = Object.keys(schemaOrRef);
|
|
519
|
+
if (
|
|
520
|
+
keys.every((key) =>
|
|
521
|
+
['type', 'properties', 'required', 'nullable'].includes(key)
|
|
522
|
+
)
|
|
523
|
+
) {
|
|
524
|
+
latest.properties = {
|
|
525
|
+
...latest.properties,
|
|
526
|
+
...schemaOrRef.properties,
|
|
527
|
+
};
|
|
528
|
+
latest.required = Array.from(
|
|
529
|
+
new Set([
|
|
530
|
+
...(Array.isArray(latest.required) ? latest.required : []),
|
|
531
|
+
...(Array.isArray(schemaOrRef.required)
|
|
532
|
+
? schemaOrRef.required
|
|
533
|
+
: []),
|
|
534
|
+
])
|
|
535
|
+
);
|
|
536
|
+
latest.nullable = latest.nullable || schemaOrRef.nullable;
|
|
537
|
+
return acc;
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
acc.push(schemaOrRef);
|
|
542
|
+
return acc;
|
|
543
|
+
}, []);
|
|
544
|
+
}
|
|
545
|
+
default:
|
|
546
|
+
return schemasOrRefs;
|
|
547
|
+
}
|
|
431
548
|
}
|
|
432
549
|
|
|
433
550
|
function flattenAlternatives(
|
|
@@ -485,19 +602,26 @@ function getSchemaTitle(schema: OpenAPIV3.SchemaObject): string {
|
|
|
485
602
|
return type;
|
|
486
603
|
}
|
|
487
604
|
|
|
488
|
-
function getDisclosureLabel(
|
|
605
|
+
function getDisclosureLabel(props: {
|
|
606
|
+
schema: OpenAPIV3.SchemaObject;
|
|
607
|
+
isExpanded: boolean;
|
|
608
|
+
context: OpenAPIClientContext;
|
|
609
|
+
}) {
|
|
610
|
+
const { schema, isExpanded, context } = props;
|
|
611
|
+
let label: string;
|
|
489
612
|
if (schema.type === 'array' && !!schema.items) {
|
|
490
613
|
if (schema.items.oneOf) {
|
|
491
|
-
|
|
614
|
+
label = tString(context.translation, 'available_items').toLowerCase();
|
|
492
615
|
}
|
|
493
|
-
|
|
494
616
|
// Fallback to "child attributes" for enums and objects
|
|
495
|
-
if (schema.items.enum || schema.items.type === 'object') {
|
|
496
|
-
|
|
617
|
+
else if (schema.items.enum || schema.items.type === 'object') {
|
|
618
|
+
label = tString(context.translation, 'child_attributes').toLowerCase();
|
|
619
|
+
} else {
|
|
620
|
+
label = schema.items.title ?? schema.title ?? getSchemaTitle(schema.items);
|
|
497
621
|
}
|
|
498
|
-
|
|
499
|
-
|
|
622
|
+
} else {
|
|
623
|
+
label = schema.title || tString(context.translation, 'child_attributes').toLowerCase();
|
|
500
624
|
}
|
|
501
625
|
|
|
502
|
-
return
|
|
626
|
+
return `${isExpanded ? tString(context.translation, 'hide') : tString(context.translation, 'show')} ${label}`;
|
|
503
627
|
}
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
import type { OpenAPIV3 } from '@gitbook/openapi-parser';
|
|
2
2
|
import type React from 'react';
|
|
3
|
-
import {
|
|
3
|
+
import type { OpenAPIClientContext } from './context';
|
|
4
|
+
import { t, tString } from './translate';
|
|
4
5
|
|
|
5
6
|
interface OpenAPISchemaNameProps {
|
|
6
7
|
schema?: OpenAPIV3.SchemaObject;
|
|
7
8
|
propertyName?: string | React.JSX.Element;
|
|
8
9
|
required?: boolean;
|
|
9
10
|
type?: string;
|
|
11
|
+
context: OpenAPIClientContext;
|
|
10
12
|
}
|
|
11
13
|
|
|
12
14
|
/**
|
|
@@ -14,12 +16,12 @@ interface OpenAPISchemaNameProps {
|
|
|
14
16
|
* It includes the property name, type, required and deprecated status.
|
|
15
17
|
*/
|
|
16
18
|
export function OpenAPISchemaName(props: OpenAPISchemaNameProps) {
|
|
17
|
-
const { schema, type, propertyName, required } = props;
|
|
19
|
+
const { schema, type, propertyName, required, context } = props;
|
|
18
20
|
|
|
19
|
-
const additionalItems = schema && getAdditionalItems(schema);
|
|
21
|
+
const additionalItems = schema && getAdditionalItems(schema, context);
|
|
20
22
|
|
|
21
23
|
return (
|
|
22
|
-
<
|
|
24
|
+
<span className="openapi-schema-name">
|
|
23
25
|
{propertyName ? (
|
|
24
26
|
<span data-deprecated={schema?.deprecated} className="openapi-schema-propertyname">
|
|
25
27
|
{propertyName}
|
|
@@ -31,38 +33,45 @@ export function OpenAPISchemaName(props: OpenAPISchemaNameProps) {
|
|
|
31
33
|
<span className="openapi-schema-type">{additionalItems}</span>
|
|
32
34
|
) : null}
|
|
33
35
|
</span>
|
|
34
|
-
{schema?.readOnly ?
|
|
36
|
+
{schema?.readOnly ? (
|
|
37
|
+
<span className="openapi-schema-readonly">
|
|
38
|
+
{t(context.translation, 'read_only')}
|
|
39
|
+
</span>
|
|
40
|
+
) : null}
|
|
35
41
|
{schema?.writeOnly ? (
|
|
36
|
-
<span className="openapi-schema-writeonly">
|
|
42
|
+
<span className="openapi-schema-writeonly">
|
|
43
|
+
{t(context.translation, 'write_only')}
|
|
44
|
+
</span>
|
|
37
45
|
) : null}
|
|
38
46
|
{required ? (
|
|
39
|
-
<span className="openapi-schema-required">
|
|
47
|
+
<span className="openapi-schema-required">
|
|
48
|
+
{t(context.translation, 'required')}
|
|
49
|
+
</span>
|
|
40
50
|
) : (
|
|
41
|
-
<span className="openapi-schema-optional">
|
|
51
|
+
<span className="openapi-schema-optional">
|
|
52
|
+
{t(context.translation, 'optional')}
|
|
53
|
+
</span>
|
|
42
54
|
)}
|
|
43
|
-
{schema?.deprecated ?
|
|
44
|
-
|
|
55
|
+
{schema?.deprecated ? (
|
|
56
|
+
<span className="openapi-deprecated">{t(context.translation, 'deprecated')}</span>
|
|
57
|
+
) : null}
|
|
58
|
+
</span>
|
|
45
59
|
);
|
|
46
60
|
}
|
|
47
61
|
|
|
48
|
-
function getAdditionalItems(schema: OpenAPIV3.SchemaObject): string {
|
|
62
|
+
function getAdditionalItems(schema: OpenAPIV3.SchemaObject, context: OpenAPIClientContext): string {
|
|
49
63
|
let additionalItems = '';
|
|
50
64
|
|
|
51
65
|
if (schema.minimum || schema.minLength || schema.minItems) {
|
|
52
|
-
additionalItems += ` · min: ${schema.minimum || schema.minLength || schema.minItems}`;
|
|
66
|
+
additionalItems += ` · ${tString(context.translation, 'min').toLowerCase()}: ${schema.minimum || schema.minLength || schema.minItems}`;
|
|
53
67
|
}
|
|
54
68
|
|
|
55
69
|
if (schema.maximum || schema.maxLength || schema.maxItems) {
|
|
56
|
-
additionalItems += ` · max: ${schema.maximum || schema.maxLength || schema.maxItems}`;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
// If the schema has a default value, we display it
|
|
60
|
-
if (typeof schema.default !== 'undefined') {
|
|
61
|
-
additionalItems += ` · default: ${stringifyOpenAPI(schema.default)}`;
|
|
70
|
+
additionalItems += ` · ${tString(context.translation, 'max').toLowerCase()}: ${schema.maximum || schema.maxLength || schema.maxItems}`;
|
|
62
71
|
}
|
|
63
72
|
|
|
64
73
|
if (schema.nullable) {
|
|
65
|
-
additionalItems =
|
|
74
|
+
additionalItems = ` | ${tString(context.translation, 'nullable').toLowerCase()}`;
|
|
66
75
|
}
|
|
67
76
|
|
|
68
77
|
return additionalItems;
|
|
@@ -4,8 +4,8 @@ import {
|
|
|
4
4
|
OpenAPISchemaPropertiesFromServer,
|
|
5
5
|
type OpenAPISchemaPropertyEntry,
|
|
6
6
|
} from './OpenAPISchema';
|
|
7
|
+
import type { OpenAPIClientContext } from './context';
|
|
7
8
|
import { decycle } from './decycle';
|
|
8
|
-
import type { OpenAPIClientContext } from './types';
|
|
9
9
|
|
|
10
10
|
export function OpenAPISchemaProperties(props: {
|
|
11
11
|
id?: string;
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import type { OpenAPIV3_1 } from '@gitbook/openapi-parser';
|
|
2
1
|
import { InteractiveSection } from './InteractiveSection';
|
|
3
2
|
import { Markdown } from './Markdown';
|
|
4
3
|
import { OpenAPISchemaName } from './OpenAPISchemaName';
|
|
5
|
-
import type { OpenAPIClientContext
|
|
6
|
-
import {
|
|
4
|
+
import type { OpenAPIClientContext } from './context';
|
|
5
|
+
import { t } from './translate';
|
|
6
|
+
import type { OpenAPIOperationData, OpenAPISecurityWithRequired } from './types';
|
|
7
|
+
import { createStateKey, resolveDescription } from './utils';
|
|
7
8
|
|
|
8
9
|
/**
|
|
9
10
|
* Present securities authorization that can be used for this operation.
|
|
@@ -20,10 +21,12 @@ export function OpenAPISecurities(props: {
|
|
|
20
21
|
|
|
21
22
|
return (
|
|
22
23
|
<InteractiveSection
|
|
23
|
-
header=
|
|
24
|
+
header={t(context.translation, 'authorizations')}
|
|
25
|
+
stateKey={createStateKey('securities', context.blockKey)}
|
|
24
26
|
toggeable
|
|
25
27
|
defaultOpened={false}
|
|
26
28
|
toggleIcon={context.icons.chevronRight}
|
|
29
|
+
selectIcon={context.icons.chevronDown}
|
|
27
30
|
className="openapi-securities"
|
|
28
31
|
tabs={securities.map(([key, security]) => {
|
|
29
32
|
const description = resolveDescription(security);
|
|
@@ -33,7 +36,7 @@ export function OpenAPISecurities(props: {
|
|
|
33
36
|
body: (
|
|
34
37
|
<div className="openapi-schema">
|
|
35
38
|
<div className="openapi-schema-presentation">
|
|
36
|
-
{getLabelForType(security)}
|
|
39
|
+
{getLabelForType(security, context)}
|
|
37
40
|
|
|
38
41
|
{description ? (
|
|
39
42
|
<Markdown
|
|
@@ -50,26 +53,39 @@ export function OpenAPISecurities(props: {
|
|
|
50
53
|
);
|
|
51
54
|
}
|
|
52
55
|
|
|
53
|
-
function getLabelForType(security:
|
|
56
|
+
function getLabelForType(security: OpenAPISecurityWithRequired, context: OpenAPIClientContext) {
|
|
54
57
|
switch (security.type) {
|
|
55
58
|
case 'apiKey':
|
|
56
59
|
return (
|
|
57
60
|
<OpenAPISchemaName
|
|
61
|
+
context={context}
|
|
58
62
|
propertyName={security.name ?? 'apiKey'}
|
|
59
63
|
type="string"
|
|
60
|
-
required
|
|
64
|
+
required={security.required}
|
|
61
65
|
/>
|
|
62
66
|
);
|
|
63
67
|
case 'http':
|
|
64
68
|
if (security.scheme === 'basic') {
|
|
65
|
-
return
|
|
69
|
+
return (
|
|
70
|
+
<OpenAPISchemaName
|
|
71
|
+
context={context}
|
|
72
|
+
propertyName="Authorization"
|
|
73
|
+
type="string"
|
|
74
|
+
required={security.required}
|
|
75
|
+
/>
|
|
76
|
+
);
|
|
66
77
|
}
|
|
67
78
|
|
|
68
79
|
if (security.scheme === 'bearer') {
|
|
69
80
|
const description = resolveDescription(security);
|
|
70
81
|
return (
|
|
71
82
|
<>
|
|
72
|
-
<OpenAPISchemaName
|
|
83
|
+
<OpenAPISchemaName
|
|
84
|
+
context={context}
|
|
85
|
+
propertyName="Authorization"
|
|
86
|
+
type="string"
|
|
87
|
+
required={security.required}
|
|
88
|
+
/>
|
|
73
89
|
{/** Show a default description if none is provided */}
|
|
74
90
|
{!description ? (
|
|
75
91
|
<Markdown
|
|
@@ -81,11 +97,29 @@ function getLabelForType(security: OpenAPIV3_1.SecuritySchemeObject) {
|
|
|
81
97
|
);
|
|
82
98
|
}
|
|
83
99
|
|
|
84
|
-
return
|
|
100
|
+
return (
|
|
101
|
+
<OpenAPISchemaName
|
|
102
|
+
context={context}
|
|
103
|
+
propertyName="HTTP"
|
|
104
|
+
required={security.required}
|
|
105
|
+
/>
|
|
106
|
+
);
|
|
85
107
|
case 'oauth2':
|
|
86
|
-
return
|
|
108
|
+
return (
|
|
109
|
+
<OpenAPISchemaName
|
|
110
|
+
context={context}
|
|
111
|
+
propertyName="OAuth2"
|
|
112
|
+
required={security.required}
|
|
113
|
+
/>
|
|
114
|
+
);
|
|
87
115
|
case 'openIdConnect':
|
|
88
|
-
return
|
|
116
|
+
return (
|
|
117
|
+
<OpenAPISchemaName
|
|
118
|
+
context={context}
|
|
119
|
+
propertyName="OpenID Connect"
|
|
120
|
+
required={security.required}
|
|
121
|
+
/>
|
|
122
|
+
);
|
|
89
123
|
default:
|
|
90
124
|
// @ts-ignore
|
|
91
125
|
return security.type;
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import clsx from 'clsx';
|
|
4
|
+
import { useCallback } from 'react';
|
|
5
|
+
import {
|
|
6
|
+
Button,
|
|
7
|
+
type Key,
|
|
8
|
+
ListBox,
|
|
9
|
+
ListBoxItem,
|
|
10
|
+
type ListBoxItemProps,
|
|
11
|
+
Popover,
|
|
12
|
+
type PopoverProps,
|
|
13
|
+
Select,
|
|
14
|
+
type SelectProps,
|
|
15
|
+
SelectValue,
|
|
16
|
+
} from 'react-aria-components';
|
|
17
|
+
import { useStore } from 'zustand';
|
|
18
|
+
import { getOrCreateStoreByKey } from './getOrCreateStoreByKey';
|
|
19
|
+
|
|
20
|
+
export type OpenAPISelectItem = {
|
|
21
|
+
key: Key;
|
|
22
|
+
label: string | React.ReactNode;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
interface OpenAPISelectProps<T extends OpenAPISelectItem> extends Omit<SelectProps<T>, 'children'> {
|
|
26
|
+
items: T[];
|
|
27
|
+
children: React.ReactNode | ((item: T) => React.ReactNode);
|
|
28
|
+
placement?: PopoverProps['placement'];
|
|
29
|
+
stateKey?: string;
|
|
30
|
+
/**
|
|
31
|
+
* Icon to display in the select button.
|
|
32
|
+
*/
|
|
33
|
+
icon?: React.ReactNode;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export function useSelectState(stateKey = 'select-state', initialKey?: Key) {
|
|
37
|
+
const store = useStore(getOrCreateStoreByKey(stateKey, initialKey));
|
|
38
|
+
return {
|
|
39
|
+
key: store.key,
|
|
40
|
+
setKey: useCallback((key: Key | null) => store.setKey(key), [store.setKey]),
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export function OpenAPISelect<T extends OpenAPISelectItem>(props: OpenAPISelectProps<T>) {
|
|
45
|
+
const {
|
|
46
|
+
icon = '▼',
|
|
47
|
+
items,
|
|
48
|
+
children,
|
|
49
|
+
className,
|
|
50
|
+
placement,
|
|
51
|
+
stateKey,
|
|
52
|
+
selectedKey,
|
|
53
|
+
onSelectionChange,
|
|
54
|
+
} = props;
|
|
55
|
+
|
|
56
|
+
const state = useSelectState(stateKey, items[0]?.key);
|
|
57
|
+
|
|
58
|
+
const selected = items.find((item) => item.key === state.key) || items[0];
|
|
59
|
+
|
|
60
|
+
return (
|
|
61
|
+
<Select
|
|
62
|
+
aria-label="OpenAPI Select"
|
|
63
|
+
{...props}
|
|
64
|
+
selectedKey={selectedKey || selected?.key}
|
|
65
|
+
onSelectionChange={(key) => {
|
|
66
|
+
onSelectionChange?.(key);
|
|
67
|
+
state.setKey(key);
|
|
68
|
+
}}
|
|
69
|
+
className={clsx('openapi-select', className)}
|
|
70
|
+
>
|
|
71
|
+
<Button>
|
|
72
|
+
<SelectValue />
|
|
73
|
+
{icon}
|
|
74
|
+
</Button>
|
|
75
|
+
<Popover placement={placement} className="openapi-select-popover">
|
|
76
|
+
<ListBox className="openapi-select-listbox" items={items}>
|
|
77
|
+
{children}
|
|
78
|
+
</ListBox>
|
|
79
|
+
</Popover>
|
|
80
|
+
</Select>
|
|
81
|
+
);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export function OpenAPISelectItem(props: ListBoxItemProps) {
|
|
85
|
+
return (
|
|
86
|
+
<ListBoxItem
|
|
87
|
+
{...props}
|
|
88
|
+
className={({ isFocused, isSelected }) =>
|
|
89
|
+
clsx('openapi-select-item', {
|
|
90
|
+
'openapi-select-item-focused': isFocused,
|
|
91
|
+
'openapi-select-item-selected': isSelected,
|
|
92
|
+
})
|
|
93
|
+
}
|
|
94
|
+
/>
|
|
95
|
+
);
|
|
96
|
+
}
|