@gitbook/react-openapi 1.2.0 → 1.3.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 +26 -0
- package/dist/OpenAPIDisclosure.d.ts +1 -0
- package/dist/OpenAPIDisclosure.jsx +6 -3
- package/dist/OpenAPIDisclosureGroup.jsx +17 -16
- package/dist/OpenAPIResponse.jsx +18 -2
- package/dist/OpenAPIResponseExample.jsx +8 -3
- package/dist/OpenAPIResponses.jsx +7 -2
- package/dist/OpenAPISchema.d.ts +9 -2
- package/dist/OpenAPISchema.jsx +93 -59
- package/dist/OpenAPISchemaName.d.ts +1 -1
- package/dist/OpenAPISchemaName.jsx +1 -1
- package/dist/StaticSection.jsx +1 -1
- package/dist/code-samples.js +5 -2
- package/dist/generateSchemaExample.js +5 -0
- package/dist/getDisclosureLabel.d.ts +7 -0
- package/dist/getDisclosureLabel.js +18 -0
- package/dist/schemas/OpenAPISchemaItem.d.ts +7 -0
- package/dist/schemas/OpenAPISchemaItem.jsx +16 -0
- package/dist/schemas/OpenAPISchemas.jsx +3 -9
- package/dist/translations/de.d.ts +6 -1
- package/dist/translations/de.js +9 -4
- package/dist/translations/en.d.ts +6 -1
- package/dist/translations/en.js +8 -3
- package/dist/translations/es.d.ts +6 -1
- package/dist/translations/es.js +9 -4
- package/dist/translations/fr.d.ts +6 -1
- package/dist/translations/fr.js +10 -5
- package/dist/translations/index.d.ts +54 -9
- package/dist/translations/ja.d.ts +6 -1
- package/dist/translations/ja.js +8 -3
- package/dist/translations/nl.d.ts +6 -1
- package/dist/translations/nl.js +8 -3
- package/dist/translations/no.d.ts +6 -1
- package/dist/translations/no.js +9 -4
- package/dist/translations/pt-br.d.ts +6 -1
- package/dist/translations/pt-br.js +9 -4
- package/dist/translations/zh.d.ts +6 -1
- package/dist/translations/zh.js +9 -4
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/src/OpenAPIDisclosure.tsx +7 -3
- package/src/OpenAPIDisclosureGroup.tsx +49 -47
- package/src/OpenAPIResponse.tsx +34 -2
- package/src/OpenAPIResponseExample.tsx +36 -34
- package/src/OpenAPIResponses.tsx +5 -4
- package/src/OpenAPISchema.tsx +167 -103
- package/src/OpenAPISchemaName.tsx +2 -2
- package/src/StaticSection.tsx +1 -1
- package/src/code-samples.test.ts +2 -1
- package/src/code-samples.ts +5 -2
- package/src/generateSchemaExample.ts +8 -0
- package/src/getDisclosureLabel.ts +25 -0
- package/src/schemas/OpenAPISchemaItem.tsx +34 -0
- package/src/schemas/OpenAPISchemas.tsx +7 -13
- package/src/translations/de.ts +9 -4
- package/src/translations/en.ts +8 -3
- package/src/translations/es.ts +9 -4
- package/src/translations/fr.ts +10 -5
- package/src/translations/ja.ts +8 -3
- package/src/translations/nl.ts +8 -3
- package/src/translations/no.ts +9 -4
- package/src/translations/pt-br.ts +9 -4
- package/src/translations/zh.ts +9 -4
package/src/OpenAPISchema.tsx
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
import type { OpenAPICustomOperationProperties, OpenAPIV3 } from '@gitbook/openapi-parser';
|
|
6
6
|
import { useId } from 'react';
|
|
7
|
+
import type { ComponentPropsWithoutRef } from 'react';
|
|
7
8
|
|
|
8
9
|
import clsx from 'clsx';
|
|
9
10
|
import { Markdown } from './Markdown';
|
|
@@ -12,6 +13,7 @@ import { OpenAPIDisclosure } from './OpenAPIDisclosure';
|
|
|
12
13
|
import { OpenAPISchemaName } from './OpenAPISchemaName';
|
|
13
14
|
import type { OpenAPIClientContext } from './context';
|
|
14
15
|
import { retrocycle } from './decycle';
|
|
16
|
+
import { getDisclosureLabel } from './getDisclosureLabel';
|
|
15
17
|
import { stringifyOpenAPI } from './stringifyOpenAPI';
|
|
16
18
|
import { tString } from './translate';
|
|
17
19
|
import { checkIsReference, resolveDescription, resolveFirstExample } from './utils';
|
|
@@ -19,73 +21,97 @@ import { checkIsReference, resolveDescription, resolveFirstExample } from './uti
|
|
|
19
21
|
type CircularRefsIds = Map<OpenAPIV3.SchemaObject, string>;
|
|
20
22
|
|
|
21
23
|
export interface OpenAPISchemaPropertyEntry {
|
|
22
|
-
propertyName?: string
|
|
23
|
-
required?: boolean |
|
|
24
|
+
propertyName?: string;
|
|
25
|
+
required?: boolean | null;
|
|
24
26
|
schema: OpenAPIV3.SchemaObject;
|
|
25
27
|
}
|
|
26
28
|
|
|
27
29
|
/**
|
|
28
30
|
* Render a property of an OpenAPI schema.
|
|
29
31
|
*/
|
|
30
|
-
function OpenAPISchemaProperty(
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
32
|
+
function OpenAPISchemaProperty(
|
|
33
|
+
props: {
|
|
34
|
+
property: OpenAPISchemaPropertyEntry;
|
|
35
|
+
context: OpenAPIClientContext;
|
|
36
|
+
circularRefs: CircularRefsIds;
|
|
37
|
+
className?: string;
|
|
38
|
+
} & Omit<ComponentPropsWithoutRef<'div'>, 'property' | 'context' | 'circularRefs' | 'className'>
|
|
39
|
+
) {
|
|
40
|
+
const { circularRefs: parentCircularRefs, context, className, property, ...rest } = props;
|
|
37
41
|
|
|
38
42
|
const { schema } = property;
|
|
39
43
|
|
|
40
44
|
const id = useId();
|
|
41
45
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
46
|
+
const circularRefId = parentCircularRefs.get(schema);
|
|
47
|
+
// Avoid recursing infinitely, and instead render a link to the parent schema
|
|
48
|
+
if (circularRefId) {
|
|
49
|
+
return <OpenAPISchemaCircularRef id={circularRefId} schema={schema} />;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const circularRefs = new Map(parentCircularRefs);
|
|
53
|
+
circularRefs.set(schema, id);
|
|
54
|
+
|
|
55
|
+
const properties = getSchemaProperties(schema);
|
|
56
|
+
|
|
57
|
+
const ancestors = new Set(circularRefs.keys());
|
|
58
|
+
const alternatives = getSchemaAlternatives(schema, ancestors);
|
|
59
|
+
|
|
60
|
+
const header = <OpenAPISchemaPresentation context={context} property={property} />;
|
|
61
|
+
const content = (() => {
|
|
62
|
+
if (properties?.length) {
|
|
63
|
+
return (
|
|
64
|
+
<OpenAPISchemaProperties
|
|
65
|
+
properties={properties}
|
|
66
|
+
circularRefs={circularRefs}
|
|
67
|
+
context={context}
|
|
68
|
+
/>
|
|
69
|
+
);
|
|
70
|
+
}
|
|
51
71
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
icon={context.icons.plus}
|
|
60
|
-
label={(isExpanded) =>
|
|
61
|
-
getDisclosureLabel({ schema, isExpanded, context })
|
|
62
|
-
}
|
|
63
|
-
>
|
|
64
|
-
<OpenAPISchemaProperties
|
|
65
|
-
properties={properties}
|
|
72
|
+
if (alternatives) {
|
|
73
|
+
return (
|
|
74
|
+
<div className="openapi-schema-alternatives">
|
|
75
|
+
{alternatives.map((alternativeSchema, index) => (
|
|
76
|
+
<div key={index} className="openapi-schema-alternative">
|
|
77
|
+
<OpenAPISchemaAlternative
|
|
78
|
+
schema={alternativeSchema}
|
|
66
79
|
circularRefs={circularRefs}
|
|
67
80
|
context={context}
|
|
68
81
|
/>
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
82
|
+
{index < alternatives.length - 1 ? (
|
|
83
|
+
<OpenAPISchemaAlternativeSeparator
|
|
84
|
+
schema={schema}
|
|
85
|
+
context={context}
|
|
86
|
+
/>
|
|
87
|
+
) : null}
|
|
88
|
+
</div>
|
|
89
|
+
))}
|
|
90
|
+
</div>
|
|
91
|
+
);
|
|
92
|
+
}
|
|
72
93
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
if (alternatives) {
|
|
77
|
-
return alternatives.map((schema, index) => (
|
|
78
|
-
<OpenAPISchemaAlternative
|
|
79
|
-
key={index}
|
|
80
|
-
schema={schema}
|
|
81
|
-
circularRefs={circularRefs}
|
|
82
|
-
context={context}
|
|
83
|
-
/>
|
|
84
|
-
));
|
|
85
|
-
}
|
|
94
|
+
return null;
|
|
95
|
+
})();
|
|
86
96
|
|
|
87
|
-
|
|
88
|
-
|
|
97
|
+
if (properties?.length) {
|
|
98
|
+
return (
|
|
99
|
+
<OpenAPIDisclosure
|
|
100
|
+
icon={context.icons.plus}
|
|
101
|
+
className={clsx('openapi-schema', className)}
|
|
102
|
+
header={header}
|
|
103
|
+
label={(isExpanded) => getDisclosureLabel({ schema, isExpanded, context })}
|
|
104
|
+
{...rest}
|
|
105
|
+
>
|
|
106
|
+
{content}
|
|
107
|
+
</OpenAPIDisclosure>
|
|
108
|
+
);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
return (
|
|
112
|
+
<div id={id} {...rest} className={clsx('openapi-schema', className)}>
|
|
113
|
+
{header}
|
|
114
|
+
{content}
|
|
89
115
|
</div>
|
|
90
116
|
);
|
|
91
117
|
}
|
|
@@ -115,6 +141,7 @@ function OpenAPISchemaProperties(props: {
|
|
|
115
141
|
circularRefs={circularRefs}
|
|
116
142
|
property={property}
|
|
117
143
|
context={context}
|
|
144
|
+
style={{ animationDelay: `${index * 0.02}s` }}
|
|
118
145
|
/>
|
|
119
146
|
);
|
|
120
147
|
})}
|
|
@@ -205,34 +232,48 @@ function OpenAPISchemaAlternative(props: {
|
|
|
205
232
|
context: OpenAPIClientContext;
|
|
206
233
|
}) {
|
|
207
234
|
const { schema, circularRefs, context } = props;
|
|
208
|
-
|
|
209
|
-
const description = resolveDescription(schema);
|
|
210
235
|
const properties = getSchemaProperties(schema);
|
|
211
236
|
|
|
237
|
+
return properties?.length ? (
|
|
238
|
+
<OpenAPIDisclosure
|
|
239
|
+
icon={context.icons.plus}
|
|
240
|
+
header={<OpenAPISchemaPresentation property={{ schema }} context={context} />}
|
|
241
|
+
label={(isExpanded) => getDisclosureLabel({ schema, isExpanded, context })}
|
|
242
|
+
>
|
|
243
|
+
<OpenAPISchemaProperties
|
|
244
|
+
properties={properties}
|
|
245
|
+
circularRefs={circularRefs}
|
|
246
|
+
context={context}
|
|
247
|
+
/>
|
|
248
|
+
</OpenAPIDisclosure>
|
|
249
|
+
) : (
|
|
250
|
+
<OpenAPISchemaProperty
|
|
251
|
+
property={{ schema }}
|
|
252
|
+
circularRefs={circularRefs}
|
|
253
|
+
context={context}
|
|
254
|
+
/>
|
|
255
|
+
);
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
function OpenAPISchemaAlternativeSeparator(props: {
|
|
259
|
+
schema: OpenAPIV3.SchemaObject;
|
|
260
|
+
context: OpenAPIClientContext;
|
|
261
|
+
}) {
|
|
262
|
+
const { schema, context } = props;
|
|
263
|
+
|
|
264
|
+
const anyOf = schema.anyOf || schema.items?.anyOf;
|
|
265
|
+
const oneOf = schema.oneOf || schema.items?.oneOf;
|
|
266
|
+
const allOf = schema.allOf || schema.items?.allOf;
|
|
267
|
+
|
|
268
|
+
if (!anyOf && !oneOf && !allOf) {
|
|
269
|
+
return null;
|
|
270
|
+
}
|
|
271
|
+
|
|
212
272
|
return (
|
|
213
|
-
|
|
214
|
-
{
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
<OpenAPIDisclosure
|
|
218
|
-
icon={context.icons.plus}
|
|
219
|
-
label={(isExpanded) => getDisclosureLabel({ schema, isExpanded, context })}
|
|
220
|
-
>
|
|
221
|
-
{properties?.length ? (
|
|
222
|
-
<OpenAPISchemaProperties
|
|
223
|
-
properties={properties}
|
|
224
|
-
circularRefs={circularRefs}
|
|
225
|
-
context={context}
|
|
226
|
-
/>
|
|
227
|
-
) : (
|
|
228
|
-
<OpenAPISchemaProperty
|
|
229
|
-
property={{ schema }}
|
|
230
|
-
circularRefs={circularRefs}
|
|
231
|
-
context={context}
|
|
232
|
-
/>
|
|
233
|
-
)}
|
|
234
|
-
</OpenAPIDisclosure>
|
|
235
|
-
</>
|
|
273
|
+
<span className="openapi-schema-alternative-separator">
|
|
274
|
+
{(anyOf || oneOf) && tString(context.translation, 'or')}
|
|
275
|
+
{allOf && tString(context.translation, 'and')}
|
|
276
|
+
</span>
|
|
236
277
|
);
|
|
237
278
|
}
|
|
238
279
|
|
|
@@ -293,7 +334,7 @@ function OpenAPISchemaEnum(props: {
|
|
|
293
334
|
|
|
294
335
|
return (
|
|
295
336
|
<span className="openapi-schema-enum">
|
|
296
|
-
|
|
337
|
+
{tString(context.translation, 'possible_values')}:{' '}
|
|
297
338
|
{enumValues.map((item, index) => (
|
|
298
339
|
<span key={index} className="openapi-schema-enum-value">
|
|
299
340
|
<OpenAPICopyButton
|
|
@@ -313,7 +354,7 @@ function OpenAPISchemaEnum(props: {
|
|
|
313
354
|
/**
|
|
314
355
|
* Render the top row of a schema. e.g: name, type, and required status.
|
|
315
356
|
*/
|
|
316
|
-
function OpenAPISchemaPresentation(props: {
|
|
357
|
+
export function OpenAPISchemaPresentation(props: {
|
|
317
358
|
property: OpenAPISchemaPropertyEntry;
|
|
318
359
|
context: OpenAPIClientContext;
|
|
319
360
|
}) {
|
|
@@ -437,6 +478,14 @@ export function getSchemaAlternatives(
|
|
|
437
478
|
schema: OpenAPIV3.SchemaObject,
|
|
438
479
|
ancestors: Set<OpenAPIV3.SchemaObject> = new Set()
|
|
439
480
|
): OpenAPIV3.SchemaObject[] | null {
|
|
481
|
+
// Search for alternatives in the items property if it exists
|
|
482
|
+
if (
|
|
483
|
+
schema.items &&
|
|
484
|
+
('oneOf' in schema.items || 'allOf' in schema.items || 'anyOf' in schema.items)
|
|
485
|
+
) {
|
|
486
|
+
return getSchemaAlternatives(schema.items, ancestors);
|
|
487
|
+
}
|
|
488
|
+
|
|
440
489
|
const alternatives:
|
|
441
490
|
| [AlternativeType, (OpenAPIV3.SchemaObject | OpenAPIV3.ReferenceObject)[]]
|
|
442
491
|
| null = (() => {
|
|
@@ -552,6 +601,9 @@ function flattenAlternatives(
|
|
|
552
601
|
schemasOrRefs: (OpenAPIV3.SchemaObject | OpenAPIV3.ReferenceObject)[],
|
|
553
602
|
ancestors: Set<OpenAPIV3.SchemaObject>
|
|
554
603
|
): OpenAPIV3.SchemaObject[] {
|
|
604
|
+
// Get the parent schema's required fields from the most recent ancestor
|
|
605
|
+
const latestAncestor = Array.from(ancestors).pop();
|
|
606
|
+
|
|
555
607
|
return schemasOrRefs.reduce<OpenAPIV3.SchemaObject[]>((acc, schemaOrRef) => {
|
|
556
608
|
if (checkIsReference(schemaOrRef)) {
|
|
557
609
|
return acc;
|
|
@@ -560,16 +612,47 @@ function flattenAlternatives(
|
|
|
560
612
|
if (schemaOrRef[alternativeType] && !ancestors.has(schemaOrRef)) {
|
|
561
613
|
const schemas = getSchemaAlternatives(schemaOrRef, ancestors);
|
|
562
614
|
if (schemas) {
|
|
563
|
-
acc.push(
|
|
615
|
+
acc.push(
|
|
616
|
+
...schemas.map((schema) => ({
|
|
617
|
+
...schema,
|
|
618
|
+
required: mergeRequiredFields(schema, latestAncestor),
|
|
619
|
+
}))
|
|
620
|
+
);
|
|
564
621
|
}
|
|
565
622
|
return acc;
|
|
566
623
|
}
|
|
567
624
|
|
|
568
|
-
|
|
625
|
+
// For direct schemas, handle required fields
|
|
626
|
+
const schema = {
|
|
627
|
+
...schemaOrRef,
|
|
628
|
+
required: mergeRequiredFields(schemaOrRef, latestAncestor),
|
|
629
|
+
};
|
|
630
|
+
|
|
631
|
+
acc.push(schema);
|
|
569
632
|
return acc;
|
|
570
633
|
}, []);
|
|
571
634
|
}
|
|
572
635
|
|
|
636
|
+
/**
|
|
637
|
+
* Merge the required fields of a schema with the required fields of its latest ancestor.
|
|
638
|
+
*/
|
|
639
|
+
function mergeRequiredFields(
|
|
640
|
+
schemaOrRef: OpenAPIV3.SchemaObject | OpenAPIV3.ReferenceObject,
|
|
641
|
+
latestAncestor: OpenAPIV3.SchemaObject | undefined
|
|
642
|
+
) {
|
|
643
|
+
if (!schemaOrRef.required && !latestAncestor?.required) {
|
|
644
|
+
return undefined;
|
|
645
|
+
}
|
|
646
|
+
|
|
647
|
+
if (checkIsReference(schemaOrRef)) {
|
|
648
|
+
return latestAncestor?.required;
|
|
649
|
+
}
|
|
650
|
+
|
|
651
|
+
return Array.from(
|
|
652
|
+
new Set([...(latestAncestor?.required || []), ...(schemaOrRef.required || [])])
|
|
653
|
+
);
|
|
654
|
+
}
|
|
655
|
+
|
|
573
656
|
function getSchemaTitle(schema: OpenAPIV3.SchemaObject): string {
|
|
574
657
|
// Otherwise try to infer a nice title
|
|
575
658
|
let type = 'any';
|
|
@@ -587,6 +670,11 @@ function getSchemaTitle(schema: OpenAPIV3.SchemaObject): string {
|
|
|
587
670
|
if (schema.format) {
|
|
588
671
|
type += ` · ${schema.format}`;
|
|
589
672
|
}
|
|
673
|
+
|
|
674
|
+
// Only add the title if it's an object (no need for the title of a string, number, etc.)
|
|
675
|
+
if (type === 'object' && schema.title) {
|
|
676
|
+
type += ` · ${schema.title.replaceAll(' ', '')}`;
|
|
677
|
+
}
|
|
590
678
|
}
|
|
591
679
|
|
|
592
680
|
if ('anyOf' in schema) {
|
|
@@ -601,27 +689,3 @@ function getSchemaTitle(schema: OpenAPIV3.SchemaObject): string {
|
|
|
601
689
|
|
|
602
690
|
return type;
|
|
603
691
|
}
|
|
604
|
-
|
|
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;
|
|
612
|
-
if (schema.type === 'array' && !!schema.items) {
|
|
613
|
-
if (schema.items.oneOf) {
|
|
614
|
-
label = tString(context.translation, 'available_items').toLowerCase();
|
|
615
|
-
}
|
|
616
|
-
// Fallback to "child attributes" for enums and objects
|
|
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);
|
|
621
|
-
}
|
|
622
|
-
} else {
|
|
623
|
-
label = schema.title || tString(context.translation, 'child_attributes').toLowerCase();
|
|
624
|
-
}
|
|
625
|
-
|
|
626
|
-
return `${isExpanded ? tString(context.translation, 'hide') : tString(context.translation, 'show')} ${label}`;
|
|
627
|
-
}
|
|
@@ -6,7 +6,7 @@ import { t, tString } from './translate';
|
|
|
6
6
|
interface OpenAPISchemaNameProps {
|
|
7
7
|
schema?: OpenAPIV3.SchemaObject;
|
|
8
8
|
propertyName?: string | React.JSX.Element;
|
|
9
|
-
required?: boolean;
|
|
9
|
+
required?: boolean | null;
|
|
10
10
|
type?: string;
|
|
11
11
|
context: OpenAPIClientContext;
|
|
12
12
|
}
|
|
@@ -43,7 +43,7 @@ export function OpenAPISchemaName(props: OpenAPISchemaNameProps) {
|
|
|
43
43
|
{t(context.translation, 'write_only')}
|
|
44
44
|
</span>
|
|
45
45
|
) : null}
|
|
46
|
-
{required ? (
|
|
46
|
+
{required === null ? null : required ? (
|
|
47
47
|
<span className="openapi-schema-required">
|
|
48
48
|
{t(context.translation, 'required')}
|
|
49
49
|
</span>
|
package/src/StaticSection.tsx
CHANGED
|
@@ -11,7 +11,7 @@ export function SectionHeader(props: ComponentPropsWithoutRef<'div'>) {
|
|
|
11
11
|
{...props}
|
|
12
12
|
className={clsx(
|
|
13
13
|
'openapi-section-header',
|
|
14
|
-
props.className
|
|
14
|
+
props.className ? `${props.className}-header` : undefined
|
|
15
15
|
)}
|
|
16
16
|
/>
|
|
17
17
|
);
|
package/src/code-samples.test.ts
CHANGED
|
@@ -415,13 +415,14 @@ describe('python code sample generator', () => {
|
|
|
415
415
|
key: 'value',
|
|
416
416
|
truethy: true,
|
|
417
417
|
falsey: false,
|
|
418
|
+
nullish: null,
|
|
418
419
|
},
|
|
419
420
|
};
|
|
420
421
|
|
|
421
422
|
const output = generator?.generate(input);
|
|
422
423
|
|
|
423
424
|
expect(output).toBe(
|
|
424
|
-
'import requests\n\nresponse = requests.get(\n "https://example.com/path",\n headers={"Content-Type":"application/json"},\n data=json.dumps({"key":"value","truethy":True,"falsey":False})\n)\n\ndata = response.json()'
|
|
425
|
+
'import requests\n\nresponse = requests.get(\n "https://example.com/path",\n headers={"Content-Type":"application/json"},\n data=json.dumps({"key":"value","truethy":True,"falsey":False,"nullish":None})\n)\n\ndata = response.json()'
|
|
425
426
|
);
|
|
426
427
|
});
|
|
427
428
|
|
package/src/code-samples.ts
CHANGED
|
@@ -30,7 +30,7 @@ export const codeSampleGenerators: CodeSampleGenerator[] = [
|
|
|
30
30
|
{
|
|
31
31
|
id: 'http',
|
|
32
32
|
label: 'HTTP',
|
|
33
|
-
syntax: '
|
|
33
|
+
syntax: 'http',
|
|
34
34
|
generate: ({ method, url, headers = {}, body }: CodeSampleInput) => {
|
|
35
35
|
const { host, path } = parseHostAndPath(url);
|
|
36
36
|
|
|
@@ -362,12 +362,15 @@ const BodyGenerators = {
|
|
|
362
362
|
return '$$__TRUE__$$';
|
|
363
363
|
case false:
|
|
364
364
|
return '$$__FALSE__$$';
|
|
365
|
+
case null:
|
|
366
|
+
return '$$__NULL__$$';
|
|
365
367
|
default:
|
|
366
368
|
return value;
|
|
367
369
|
}
|
|
368
370
|
})
|
|
369
371
|
.replaceAll('"$$__TRUE__$$"', 'True')
|
|
370
|
-
.replaceAll('"$$__FALSE__$$"', 'False')
|
|
372
|
+
.replaceAll('"$$__FALSE__$$"', 'False')
|
|
373
|
+
.replaceAll('"$$__NULL__$$"', 'None');
|
|
371
374
|
}
|
|
372
375
|
|
|
373
376
|
return { body, code, headers };
|
|
@@ -204,6 +204,14 @@ const getExampleFromSchema = (
|
|
|
204
204
|
return cache(schema, schema.example);
|
|
205
205
|
}
|
|
206
206
|
|
|
207
|
+
// Use a default value, if there’s one and it’s a string or number
|
|
208
|
+
if (
|
|
209
|
+
schema.default !== undefined &&
|
|
210
|
+
['string', 'number', 'boolean'].includes(typeof schema.default)
|
|
211
|
+
) {
|
|
212
|
+
return cache(schema, schema.default);
|
|
213
|
+
}
|
|
214
|
+
|
|
207
215
|
// enum: [ 'available', 'pending', 'sold' ]
|
|
208
216
|
if (Array.isArray(schema.enum) && schema.enum.length > 0) {
|
|
209
217
|
return cache(schema, schema.enum[0]);
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import type { OpenAPIV3 } from '@gitbook/openapi-parser';
|
|
4
|
+
import type { OpenAPIClientContext } from './context';
|
|
5
|
+
import { tString } from './translate';
|
|
6
|
+
|
|
7
|
+
export function getDisclosureLabel(props: {
|
|
8
|
+
schema: OpenAPIV3.SchemaObject;
|
|
9
|
+
isExpanded: boolean;
|
|
10
|
+
context: OpenAPIClientContext;
|
|
11
|
+
}) {
|
|
12
|
+
const { schema, isExpanded, context } = props;
|
|
13
|
+
let label: string;
|
|
14
|
+
if (schema.type === 'array' && !!schema.items) {
|
|
15
|
+
if (schema.items.oneOf) {
|
|
16
|
+
label = tString(context.translation, 'available_items').toLowerCase();
|
|
17
|
+
} else {
|
|
18
|
+
label = tString(context.translation, 'properties').toLowerCase();
|
|
19
|
+
}
|
|
20
|
+
} else {
|
|
21
|
+
label = tString(context.translation, 'properties').toLowerCase();
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
return tString(context.translation, isExpanded ? 'hide' : 'show', label);
|
|
25
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { SectionBody } from '../StaticSection';
|
|
4
|
+
|
|
5
|
+
import type { OpenAPIV3 } from '@gitbook/openapi-parser';
|
|
6
|
+
import { OpenAPIDisclosure } from '../OpenAPIDisclosure';
|
|
7
|
+
import { OpenAPIRootSchema } from '../OpenAPISchemaServer';
|
|
8
|
+
import { Section } from '../StaticSection';
|
|
9
|
+
import type { OpenAPIClientContext } from '../context';
|
|
10
|
+
import { getDisclosureLabel } from '../getDisclosureLabel';
|
|
11
|
+
|
|
12
|
+
export function OpenAPISchemaItem(props: {
|
|
13
|
+
name: string;
|
|
14
|
+
schema: OpenAPIV3.SchemaObject;
|
|
15
|
+
context: OpenAPIClientContext;
|
|
16
|
+
}) {
|
|
17
|
+
const { schema, context, name } = props;
|
|
18
|
+
|
|
19
|
+
return (
|
|
20
|
+
<OpenAPIDisclosure
|
|
21
|
+
className="openapi-schemas-disclosure"
|
|
22
|
+
key={name}
|
|
23
|
+
icon={context.icons.plus}
|
|
24
|
+
header={name}
|
|
25
|
+
label={(isExpanded) => getDisclosureLabel({ schema, isExpanded, context })}
|
|
26
|
+
>
|
|
27
|
+
<Section className="openapi-section-schemas">
|
|
28
|
+
<SectionBody>
|
|
29
|
+
<OpenAPIRootSchema schema={schema} context={context} />
|
|
30
|
+
</SectionBody>
|
|
31
|
+
</Section>
|
|
32
|
+
</OpenAPIDisclosure>
|
|
33
|
+
);
|
|
34
|
+
}
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import type { OpenAPISchema } from '@gitbook/openapi-parser';
|
|
2
2
|
import clsx from 'clsx';
|
|
3
|
-
import { OpenAPIDisclosure } from '../OpenAPIDisclosure';
|
|
4
3
|
import { OpenAPIExample } from '../OpenAPIExample';
|
|
5
4
|
import { OpenAPIRootSchema } from '../OpenAPISchemaServer';
|
|
6
|
-
import {
|
|
5
|
+
import { StaticSection } from '../StaticSection';
|
|
7
6
|
import {
|
|
8
7
|
type OpenAPIContextInput,
|
|
9
8
|
getOpenAPIClientContext,
|
|
@@ -11,6 +10,7 @@ import {
|
|
|
11
10
|
} from '../context';
|
|
12
11
|
import { t } from '../translate';
|
|
13
12
|
import { getExampleFromSchema } from '../util/example';
|
|
13
|
+
import { OpenAPISchemaItem } from './OpenAPISchemaItem';
|
|
14
14
|
|
|
15
15
|
/**
|
|
16
16
|
* OpenAPI Schemas component.
|
|
@@ -85,18 +85,12 @@ export function OpenAPISchemas(props: {
|
|
|
85
85
|
<div className={clsx('openapi-schemas', className)}>
|
|
86
86
|
{schemas.map(({ name, schema }) => {
|
|
87
87
|
return (
|
|
88
|
-
<
|
|
89
|
-
className="openapi-schemas-disclosure"
|
|
88
|
+
<OpenAPISchemaItem
|
|
90
89
|
key={name}
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
<SectionBody>
|
|
96
|
-
<OpenAPIRootSchema schema={schema} context={clientContext} />
|
|
97
|
-
</SectionBody>
|
|
98
|
-
</Section>
|
|
99
|
-
</OpenAPIDisclosure>
|
|
90
|
+
name={name}
|
|
91
|
+
context={clientContext}
|
|
92
|
+
schema={schema}
|
|
93
|
+
/>
|
|
100
94
|
);
|
|
101
95
|
})}
|
|
102
96
|
</div>
|
package/src/translations/de.ts
CHANGED
|
@@ -18,9 +18,11 @@ export const de = {
|
|
|
18
18
|
nullable: 'Nullfähig',
|
|
19
19
|
body: 'Rumpf',
|
|
20
20
|
payload: 'Nutzlast',
|
|
21
|
-
headers: '
|
|
21
|
+
headers: 'Header',
|
|
22
|
+
header: 'Header',
|
|
22
23
|
authorizations: 'Autorisierungen',
|
|
23
24
|
responses: 'Antworten',
|
|
25
|
+
response: 'Antwort',
|
|
24
26
|
path_parameters: 'Pfadparameter',
|
|
25
27
|
query_parameters: 'Abfrageparameter',
|
|
26
28
|
header_parameters: 'Header-Parameter',
|
|
@@ -30,8 +32,11 @@ export const de = {
|
|
|
30
32
|
success: 'Erfolg',
|
|
31
33
|
redirect: 'Umleitung',
|
|
32
34
|
error: 'Fehler',
|
|
33
|
-
show: '
|
|
34
|
-
hide: '
|
|
35
|
+
show: 'Zeige ${1}',
|
|
36
|
+
hide: 'Verstecke ${1}',
|
|
35
37
|
available_items: 'Verfügbare Elemente',
|
|
36
|
-
|
|
38
|
+
properties: 'Eigenschaften',
|
|
39
|
+
or: 'oder',
|
|
40
|
+
and: 'und',
|
|
41
|
+
possible_values: 'Mögliche Werte',
|
|
37
42
|
};
|
package/src/translations/en.ts
CHANGED
|
@@ -19,8 +19,10 @@ export const en = {
|
|
|
19
19
|
body: 'Body',
|
|
20
20
|
payload: 'Payload',
|
|
21
21
|
headers: 'Headers',
|
|
22
|
+
header: 'Header',
|
|
22
23
|
authorizations: 'Authorizations',
|
|
23
24
|
responses: 'Responses',
|
|
25
|
+
response: 'Response',
|
|
24
26
|
path_parameters: 'Path parameters',
|
|
25
27
|
query_parameters: 'Query parameters',
|
|
26
28
|
header_parameters: 'Header parameters',
|
|
@@ -30,8 +32,11 @@ export const en = {
|
|
|
30
32
|
success: 'Success',
|
|
31
33
|
redirect: 'Redirect',
|
|
32
34
|
error: 'Error',
|
|
33
|
-
show: 'Show',
|
|
34
|
-
hide: 'Hide',
|
|
35
|
+
show: 'Show ${1}',
|
|
36
|
+
hide: 'Hide ${1}',
|
|
35
37
|
available_items: 'Available items',
|
|
36
|
-
|
|
38
|
+
possible_values: 'Possible values',
|
|
39
|
+
properties: 'Properties',
|
|
40
|
+
or: 'or',
|
|
41
|
+
and: 'and',
|
|
37
42
|
};
|
package/src/translations/es.ts
CHANGED
|
@@ -18,9 +18,11 @@ export const es = {
|
|
|
18
18
|
nullable: 'Nulo',
|
|
19
19
|
body: 'Cuerpo',
|
|
20
20
|
payload: 'Caga útil',
|
|
21
|
-
headers: '
|
|
21
|
+
headers: 'Headers',
|
|
22
|
+
header: 'Header',
|
|
22
23
|
authorizations: 'Autorizaciones',
|
|
23
24
|
responses: 'Respuestas',
|
|
25
|
+
response: 'Respuesta',
|
|
24
26
|
path_parameters: 'Parámetros de ruta',
|
|
25
27
|
query_parameters: 'Parámetros de consulta',
|
|
26
28
|
header_parameters: 'Parámetros de encabezado',
|
|
@@ -30,8 +32,11 @@ export const es = {
|
|
|
30
32
|
success: 'Éxito',
|
|
31
33
|
redirect: 'Redirección',
|
|
32
34
|
error: 'Error',
|
|
33
|
-
show: 'Mostrar',
|
|
34
|
-
hide: 'Ocultar',
|
|
35
|
+
show: 'Mostrar ${1}',
|
|
36
|
+
hide: 'Ocultar ${1}',
|
|
35
37
|
available_items: 'Elementos disponibles',
|
|
36
|
-
|
|
38
|
+
properties: 'Propiedades',
|
|
39
|
+
or: 'o',
|
|
40
|
+
and: 'y',
|
|
41
|
+
possible_values: 'Valores posibles',
|
|
37
42
|
};
|