@gitbook/react-openapi 1.0.1 → 1.0.3

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.
Files changed (53) hide show
  1. package/CHANGELOG.md +28 -0
  2. package/dist/OpenAPICodeSample.jsx +11 -7
  3. package/dist/OpenAPIOperation.jsx +25 -8
  4. package/dist/OpenAPIResponse.jsx +16 -14
  5. package/dist/OpenAPIResponseExample.jsx +157 -47
  6. package/dist/OpenAPISchema.d.ts +2 -2
  7. package/dist/OpenAPISchema.jsx +50 -39
  8. package/dist/OpenAPISchemaName.d.ts +2 -1
  9. package/dist/OpenAPISchemaName.jsx +25 -4
  10. package/dist/OpenAPISpec.jsx +2 -26
  11. package/dist/OpenAPITabs.jsx +6 -2
  12. package/dist/code-samples.js +232 -10
  13. package/dist/contentTypeChecks.d.ts +9 -0
  14. package/dist/contentTypeChecks.js +27 -0
  15. package/dist/generateSchemaExample.d.ts +5 -6
  16. package/dist/generateSchemaExample.js +13 -8
  17. package/dist/json2xml.d.ts +4 -0
  18. package/dist/json2xml.js +7 -0
  19. package/dist/stringifyOpenAPI.d.ts +1 -1
  20. package/dist/stringifyOpenAPI.js +8 -2
  21. package/dist/tsconfig.build.tsbuildinfo +1 -1
  22. package/dist/types.d.ts +18 -2
  23. package/dist/util/server.d.ts +9 -0
  24. package/dist/{OpenAPIServerURL.jsx → util/server.js} +7 -28
  25. package/dist/utils.d.ts +27 -3
  26. package/dist/utils.js +75 -3
  27. package/package.json +3 -2
  28. package/src/OpenAPICodeSample.tsx +11 -7
  29. package/src/OpenAPIOperation.tsx +36 -11
  30. package/src/OpenAPIResponse.tsx +6 -12
  31. package/src/OpenAPIResponseExample.tsx +237 -69
  32. package/src/OpenAPISchema.tsx +81 -58
  33. package/src/OpenAPISchemaName.tsx +37 -5
  34. package/src/OpenAPISpec.tsx +2 -17
  35. package/src/OpenAPITabs.tsx +8 -2
  36. package/src/__snapshots__/json2xml.test.ts.snap +18 -0
  37. package/src/code-samples.test.ts +594 -2
  38. package/src/code-samples.ts +231 -10
  39. package/src/contentTypeChecks.ts +35 -0
  40. package/src/generateSchemaExample.ts +28 -22
  41. package/src/json2xml.test.ts +46 -0
  42. package/src/json2xml.ts +8 -0
  43. package/src/resolveOpenAPIOperation.test.ts +1 -1
  44. package/src/stringifyOpenAPI.ts +13 -2
  45. package/src/types.ts +12 -1
  46. package/src/util/server.test.ts +58 -0
  47. package/src/util/server.ts +48 -0
  48. package/src/utils.ts +86 -6
  49. package/dist/OpenAPIServerURL.d.ts +0 -11
  50. package/dist/OpenAPIServerURLVariable.d.ts +0 -8
  51. package/dist/OpenAPIServerURLVariable.jsx +0 -8
  52. package/src/OpenAPIServerURL.tsx +0 -73
  53. package/src/OpenAPIServerURLVariable.tsx +0 -14
package/CHANGELOG.md CHANGED
@@ -1,5 +1,33 @@
1
1
  # @gitbook/react-openapi
2
2
 
3
+ ## 1.0.3
4
+
5
+ ### Patch Changes
6
+
7
+ - dc2dbc5: Update OpenAPI code examples to support multiple content-type
8
+ - f1d1d2f: Return empty string if no server provided
9
+ - 05e1d8c: Hide x-gitbook-\* symbols in OpenAPI blocks
10
+ - b4a12d6: Fix circularRef in schema + examples OpenAPI
11
+ - 9f0de74: Fix ID not set when there is no operation summary
12
+ - da55fac: Render GitBook blocks in OpenAPI operation description
13
+ - Updated dependencies [c808bb1]
14
+ - Updated dependencies [e24206e]
15
+ - Updated dependencies [a054554]
16
+ - Updated dependencies [da55fac]
17
+ - @gitbook/openapi-parser@2.0.0
18
+
19
+ ## 1.0.2
20
+
21
+ ### Patch Changes
22
+
23
+ - bb5c6a4: Support multiple response media types and examples
24
+ - a3f1fea: Fix display of OpenAPI header description
25
+ - 6157583: Improve Markdown parsing
26
+ - 7419ee7: Show additional fields in OpenAPI block
27
+ - 82cd9f2: Add support for anchor links in OpenAPI blocks
28
+ - Updated dependencies [6157583]
29
+ - @gitbook/openapi-parser@1.0.1
30
+
3
31
  ## 1.0.1
4
32
 
5
33
  ### Patch Changes
@@ -12,11 +12,11 @@ var __assign = (this && this.__assign) || function () {
12
12
  import { codeSampleGenerators } from './code-samples';
13
13
  import { generateMediaTypeExample, generateSchemaExample } from './generateSchemaExample';
14
14
  import { InteractiveSection } from './InteractiveSection';
15
- import { getServersURL } from './OpenAPIServerURL';
16
15
  import { createStateKey } from './utils';
17
16
  import { stringifyOpenAPI } from './stringifyOpenAPI';
18
17
  import { OpenAPITabs, OpenAPITabsList, OpenAPITabsPanels } from './OpenAPITabs';
19
18
  import { checkIsReference } from './utils';
19
+ import { getDefaultServerURL } from './util/server';
20
20
  /**
21
21
  * Display code samples to execute the operation.
22
22
  * It supports the Redocly custom syntax as well (https://redocly.com/docs/api-reference-docs/specification-extensions/x-code-samples/)
@@ -52,13 +52,11 @@ export function OpenAPICodeSample(props) {
52
52
  : undefined;
53
53
  var requestBodyContent = requestBodyContentEntries === null || requestBodyContentEntries === void 0 ? void 0 : requestBodyContentEntries[0];
54
54
  var input = {
55
- url: getServersURL(data.servers) +
55
+ url: getDefaultServerURL(data.servers) +
56
56
  data.path +
57
57
  (searchParams.size ? "?".concat(searchParams.toString()) : ''),
58
58
  method: data.method,
59
- body: requestBodyContent
60
- ? generateMediaTypeExample(requestBodyContent[1], { onlyRequired: true })
61
- : undefined,
59
+ body: requestBodyContent ? generateMediaTypeExample(requestBodyContent[1]) : undefined,
62
60
  headers: __assign(__assign(__assign({}, getSecurityHeaders(data.securities)), headersObject), (requestBodyContent
63
61
  ? {
64
62
  'Content-Type': requestBodyContent[0],
@@ -68,7 +66,10 @@ export function OpenAPICodeSample(props) {
68
66
  var autoCodeSamples = codeSampleGenerators.map(function (generator) { return ({
69
67
  key: "default-".concat(generator.id),
70
68
  label: generator.label,
71
- body: <context.CodeBlock code={generator.generate(input)} syntax={generator.syntax}/>,
69
+ body: context.renderCodeBlock({
70
+ code: generator.generate(input),
71
+ syntax: generator.syntax,
72
+ }),
72
73
  }); });
73
74
  // Use custom samples if defined
74
75
  var customCodeSamples = null;
@@ -84,7 +85,10 @@ export function OpenAPICodeSample(props) {
84
85
  .map(function (sample) { return ({
85
86
  key: "redocly-".concat(sample.lang),
86
87
  label: sample.label,
87
- body: <context.CodeBlock code={sample.source} syntax={sample.lang}/>,
88
+ body: context.renderCodeBlock({
89
+ code: sample.source,
90
+ syntax: sample.lang,
91
+ }),
88
92
  }); });
89
93
  }
90
94
  });
@@ -17,12 +17,14 @@ export function OpenAPIOperation(props) {
17
17
  icons: context.icons,
18
18
  blockKey: context.blockKey,
19
19
  };
20
- var description = (_a = resolveDescription(operation)) === null || _a === void 0 ? void 0 : _a.trim();
21
20
  return (<div className={clsx('openapi-operation', className)}>
22
- <div className="openapi-summary" id={context.id}>
23
- <h2 className="openapi-summary-title" data-deprecated={operation.deprecated}>
24
- {operation.summary}
25
- </h2>
21
+ <div className="openapi-summary" id={operation.summary ? undefined : context.id}>
22
+ {operation.summary
23
+ ? context.renderHeading({
24
+ deprecated: (_a = operation.deprecated) !== null && _a !== void 0 ? _a : false,
25
+ title: operation.summary,
26
+ })
27
+ : null}
26
28
  {operation.deprecated && <div className="openapi-deprecated">Deprecated</div>}
27
29
  </div>
28
30
  <div className="openapi-columns">
@@ -34,9 +36,7 @@ export function OpenAPIOperation(props) {
34
36
  </span>
35
37
  {"."}
36
38
  </div>) : null}
37
- {description ? (<div className="openapi-intro">
38
- <Markdown className="openapi-description" source={description}/>
39
- </div>) : null}
39
+ <OpenAPIOperationDescription operation={operation} context={context}/>
40
40
  <OpenAPIPath data={data} context={context}/>
41
41
  <OpenAPISpec data={data} context={clientContext}/>
42
42
  </div>
@@ -49,3 +49,20 @@ export function OpenAPIOperation(props) {
49
49
  </div>
50
50
  </div>);
51
51
  }
52
+ function OpenAPIOperationDescription(props) {
53
+ var operation = props.operation;
54
+ if (operation['x-gitbook-description-document']) {
55
+ return (<div className="openapi-intro">
56
+ {props.context.renderDocument({
57
+ document: operation['x-gitbook-description-document'],
58
+ })}
59
+ </div>);
60
+ }
61
+ var description = resolveDescription(operation);
62
+ if (!description) {
63
+ return null;
64
+ }
65
+ return (<div className="openapi-intro">
66
+ <Markdown className="openapi-description" source={description}/>
67
+ </div>);
68
+ }
@@ -1,11 +1,22 @@
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
+ };
1
12
  import { OpenAPISchemaProperties } from './OpenAPISchema';
2
- import { resolveDescription } from './utils';
13
+ import { parameterToProperty, resolveDescription } from './utils';
3
14
  import { OpenAPIDisclosure } from './OpenAPIDisclosure';
4
15
  /**
5
16
  * Display an interactive response body.
6
17
  */
7
18
  export function OpenAPIResponse(props) {
8
- var _a, _b, _c;
19
+ var _a, _b;
9
20
  var response = props.response, context = props.context, mediaType = props.mediaType;
10
21
  var headers = Object.entries((_a = response.headers) !== null && _a !== void 0 ? _a : {}).map(function (_a) {
11
22
  var name = _a[0], header = _a[1];
@@ -17,23 +28,14 @@ export function OpenAPIResponse(props) {
17
28
  return null;
18
29
  }
19
30
  return (<div className="openapi-response-body">
20
- {headers.length > 0 ? (<OpenAPIDisclosure context={context} label={'Headers'}>
31
+ {headers.length > 0 ? (<OpenAPIDisclosure context={context} label="Headers">
21
32
  <OpenAPISchemaProperties properties={headers.map(function (_a) {
22
- var _b;
23
33
  var name = _a[0], header = _a[1];
24
- return ({
25
- propertyName: name,
26
- schema: (_b = header.schema) !== null && _b !== void 0 ? _b : {},
27
- required: header.required,
28
- });
34
+ return parameterToProperty(__assign({ name: name }, header));
29
35
  })} context={context}/>
30
36
  </OpenAPIDisclosure>) : null}
31
37
  <div className="openapi-responsebody">
32
- <OpenAPISchemaProperties id={"response-".concat(context.blockKey)} properties={[
33
- {
34
- schema: (_c = mediaType.schema) !== null && _c !== void 0 ? _c : {},
35
- },
36
- ]} context={context}/>
38
+ <OpenAPISchemaProperties id={"response-".concat(context.blockKey)} properties={mediaType.schema ? [{ schema: mediaType.schema }] : []} context={context}/>
37
39
  </div>
38
40
  </div>);
39
41
  }
@@ -1,8 +1,9 @@
1
1
  import { generateSchemaExample } from './generateSchemaExample';
2
2
  import { checkIsReference, createStateKey, resolveDescription } from './utils';
3
- import { stringifyOpenAPI } from './stringifyOpenAPI';
4
3
  import { OpenAPITabs, OpenAPITabsList, OpenAPITabsPanels } from './OpenAPITabs';
5
4
  import { InteractiveSection } from './InteractiveSection';
5
+ import { json2xml } from './json2xml';
6
+ import { stringifyOpenAPI } from './stringifyOpenAPI';
6
7
  /**
7
8
  * Display an example of the response content.
8
9
  */
@@ -31,78 +32,187 @@ export function OpenAPIResponseExample(props) {
31
32
  }
32
33
  return Number(a) - Number(b);
33
34
  });
34
- var examples = responses
35
+ var tabs = responses
35
36
  .map(function (_a) {
36
- var key = _a[0], value = _a[1];
37
- var responseObject = value;
38
- var mediaTypeObject = (function () {
39
- var _a;
40
- if (!responseObject.content) {
41
- return null;
42
- }
43
- var key = Object.keys(responseObject.content)[0];
44
- return ((_a = responseObject.content['application/json']) !== null && _a !== void 0 ? _a : (key ? responseObject.content[key] : null));
45
- })();
46
- if (!mediaTypeObject) {
37
+ var key = _a[0], responseObject = _a[1];
38
+ var description = resolveDescription(responseObject);
39
+ if (checkIsReference(responseObject)) {
40
+ return {
41
+ key: key,
42
+ label: key,
43
+ description: description,
44
+ body: (<OpenAPIExample example={getExampleFromReference(responseObject)} context={context} syntax="json"/>),
45
+ };
46
+ }
47
+ if (!responseObject.content || Object.keys(responseObject.content).length === 0) {
47
48
  return {
48
49
  key: key,
49
50
  label: key,
50
- description: resolveDescription(responseObject),
51
+ description: description,
51
52
  body: <OpenAPIEmptyResponseExample />,
52
53
  };
53
54
  }
54
- var example = handleUnresolvedReference((function () {
55
- var examples = mediaTypeObject.examples, example = mediaTypeObject.example;
56
- if (examples) {
57
- var key_1 = Object.keys(examples)[0];
58
- if (key_1) {
59
- // @TODO handle multiple examples
60
- var firstExample = examples[key_1];
61
- if (firstExample) {
62
- return firstExample;
63
- }
64
- }
65
- }
66
- if (example) {
67
- return { value: example };
68
- }
69
- var schema = mediaTypeObject.schema;
70
- if (!schema) {
71
- return null;
72
- }
73
- return { value: generateSchemaExample(schema) };
74
- })());
75
55
  return {
76
56
  key: key,
77
57
  label: key,
78
58
  description: resolveDescription(responseObject),
79
- body: (example === null || example === void 0 ? void 0 : example.value) ? (<context.CodeBlock code={typeof example.value === 'string'
80
- ? example.value
81
- : stringifyOpenAPI(example.value, null, 2)} syntax="json"/>) : (<OpenAPIEmptyResponseExample />),
59
+ body: <OpenAPIResponse context={context} content={responseObject.content}/>,
82
60
  };
83
61
  })
84
62
  .filter(function (val) {
85
63
  return Boolean(val);
86
64
  });
87
- if (examples.length === 0) {
65
+ if (tabs.length === 0) {
88
66
  return null;
89
67
  }
90
- return (<OpenAPITabs stateKey={createStateKey('response-example')} items={examples}>
68
+ return (<OpenAPITabs stateKey={createStateKey('response-example')} items={tabs}>
91
69
  <InteractiveSection header={<OpenAPITabsList />} className="openapi-response-example">
92
70
  <OpenAPITabsPanels />
93
71
  </InteractiveSection>
94
72
  </OpenAPITabs>);
95
73
  }
74
+ function OpenAPIResponse(props) {
75
+ var context = props.context, content = props.content;
76
+ var entries = Object.entries(content);
77
+ var firstEntry = entries[0];
78
+ if (!firstEntry) {
79
+ throw new Error('One media type is required');
80
+ }
81
+ if (entries.length === 1) {
82
+ var mediaType = firstEntry[0], mediaTypeObject = firstEntry[1];
83
+ return (<OpenAPIResponseMediaType context={context} mediaType={mediaType} mediaTypeObject={mediaTypeObject}/>);
84
+ }
85
+ var tabs = entries.map(function (entry) {
86
+ var mediaType = entry[0], mediaTypeObject = entry[1];
87
+ return {
88
+ key: mediaType,
89
+ label: mediaType,
90
+ body: (<OpenAPIResponseMediaType context={context} mediaType={mediaType} mediaTypeObject={mediaTypeObject}/>),
91
+ };
92
+ });
93
+ return (<OpenAPITabs stateKey={createStateKey('response-media-types')} items={tabs}>
94
+ <InteractiveSection header={<OpenAPITabsList />} className="openapi-response-media-types">
95
+ <OpenAPITabsPanels />
96
+ </InteractiveSection>
97
+ </OpenAPITabs>);
98
+ }
99
+ function OpenAPIResponseMediaType(props) {
100
+ var mediaTypeObject = props.mediaTypeObject, mediaType = props.mediaType;
101
+ var examples = getExamplesFromMediaTypeObject({ mediaTypeObject: mediaTypeObject, mediaType: mediaType });
102
+ var syntax = getSyntaxFromMediaType(mediaType);
103
+ var firstExample = examples[0];
104
+ if (!firstExample) {
105
+ return <OpenAPIEmptyResponseExample />;
106
+ }
107
+ if (examples.length === 1) {
108
+ return (<OpenAPIExample example={firstExample.example} context={props.context} syntax={syntax}/>);
109
+ }
110
+ var tabs = examples.map(function (example) {
111
+ return {
112
+ key: example.key,
113
+ label: example.example.summary || example.key,
114
+ body: (<OpenAPIExample example={firstExample.example} context={props.context} syntax={syntax}/>),
115
+ };
116
+ });
117
+ return (<OpenAPITabs stateKey={createStateKey('response-media-type-examples')} items={tabs}>
118
+ <InteractiveSection header={<OpenAPITabsList />} className="openapi-response-media-type-examples">
119
+ <OpenAPITabsPanels />
120
+ </InteractiveSection>
121
+ </OpenAPITabs>);
122
+ }
123
+ /**
124
+ * Display an example.
125
+ */
126
+ function OpenAPIExample(props) {
127
+ var example = props.example, context = props.context, syntax = props.syntax;
128
+ var code = stringifyExample({ example: example, xml: syntax === 'xml' });
129
+ if (code === null) {
130
+ return <OpenAPIEmptyResponseExample />;
131
+ }
132
+ return context.renderCodeBlock({ code: code, syntax: syntax });
133
+ }
134
+ function stringifyExample(args) {
135
+ var example = args.example, xml = args.xml;
136
+ if (!example.value) {
137
+ return null;
138
+ }
139
+ if (typeof example.value === 'string') {
140
+ return example.value;
141
+ }
142
+ if (xml) {
143
+ return json2xml(example.value);
144
+ }
145
+ return stringifyOpenAPI(example.value, null, 2);
146
+ }
147
+ /**
148
+ * Get the syntax from a media type.
149
+ */
150
+ function getSyntaxFromMediaType(mediaType) {
151
+ if (mediaType.includes('json')) {
152
+ return 'json';
153
+ }
154
+ if (mediaType === 'application/xml') {
155
+ return 'xml';
156
+ }
157
+ return 'text';
158
+ }
159
+ /**
160
+ * Get examples from a media type object.
161
+ */
162
+ function getExamplesFromMediaTypeObject(args) {
163
+ var _a;
164
+ var _b, _c;
165
+ var mediaTypeObject = args.mediaTypeObject, mediaType = args.mediaType;
166
+ if (mediaTypeObject.examples) {
167
+ return Object.entries(mediaTypeObject.examples).map(function (_a) {
168
+ var key = _a[0], example = _a[1];
169
+ return {
170
+ key: key,
171
+ example: checkIsReference(example) ? getExampleFromReference(example) : example,
172
+ };
173
+ });
174
+ }
175
+ if (mediaTypeObject.example) {
176
+ return [{ key: 'default', example: { value: mediaTypeObject.example } }];
177
+ }
178
+ if (mediaTypeObject.schema) {
179
+ if (mediaType === 'application/xml') {
180
+ // @TODO normally we should use the name of the schema but we don't have it
181
+ // fix it when we got the reference name
182
+ var root = (_c = (_b = mediaTypeObject.schema.xml) === null || _b === void 0 ? void 0 : _b.name) !== null && _c !== void 0 ? _c : 'object';
183
+ return [
184
+ {
185
+ key: 'default',
186
+ example: {
187
+ value: (_a = {},
188
+ _a[root] = generateSchemaExample(mediaTypeObject.schema, {
189
+ xml: mediaType === 'application/xml',
190
+ }),
191
+ _a),
192
+ },
193
+ },
194
+ ];
195
+ }
196
+ return [
197
+ {
198
+ key: 'default',
199
+ example: { value: generateSchemaExample(mediaTypeObject.schema) },
200
+ },
201
+ ];
202
+ }
203
+ return [];
204
+ }
205
+ /**
206
+ * Empty response example.
207
+ */
96
208
  function OpenAPIEmptyResponseExample() {
97
209
  return (<pre className="openapi-response-example-empty">
98
210
  <p>No body</p>
99
211
  </pre>);
100
212
  }
101
- function handleUnresolvedReference(input) {
102
- var isReference = checkIsReference(input === null || input === void 0 ? void 0 : input.value);
103
- if (isReference) {
104
- // If we find a reference that wasn't resolved or needed to be resolved externally, render out the URL
105
- return { value: input.value.$ref };
106
- }
107
- return input;
213
+ /**
214
+ * Generate an example from a reference object.
215
+ */
216
+ function getExampleFromReference(ref) {
217
+ return { summary: 'Unresolved reference', value: { $ref: ref.$ref } };
108
218
  }
@@ -2,8 +2,8 @@ import type { OpenAPIV3 } from '@gitbook/openapi-parser';
2
2
  import type { OpenAPIClientContext } from './types';
3
3
  type CircularRefsIds = Map<OpenAPIV3.SchemaObject, string>;
4
4
  export interface OpenAPISchemaPropertyEntry {
5
- propertyName?: string;
6
- required?: boolean;
5
+ propertyName?: string | undefined;
6
+ required?: boolean | undefined;
7
7
  schema: OpenAPIV3.SchemaObject;
8
8
  }
9
9
  /**
@@ -29,18 +29,20 @@ export function OpenAPISchemaProperty(props) {
29
29
  var alternatives = parentCircularRef
30
30
  ? null
31
31
  : getSchemaAlternatives(schema, new Set(circularRefs.keys()));
32
- if ((properties && !!properties.length) || schema.type === 'object') {
32
+ if ((_a = alternatives === null || alternatives === void 0 ? void 0 : alternatives[0]) === null || _a === void 0 ? void 0 : _a.length) {
33
33
  return (<InteractiveSection id={id} className={clsx('openapi-schema', className)}>
34
34
  <OpenAPISchemaPresentation {...props}/>
35
- {properties && properties.length > 0 ? (<OpenAPIDisclosure context={context}>
36
- <OpenAPISchemaProperties properties={properties} circularRefs={circularRefs} context={context}/>
37
- </OpenAPIDisclosure>) : null}
35
+ {alternatives[0].map(function (alternative, index) { return (<OpenAPISchemaAlternative key={"alternative-".concat(index)} schema={alternative} circularRefs={circularRefs} context={context}/>); })}
36
+ {parentCircularRef ? (<OpenAPISchemaCircularRef id={parentCircularRef} schema={schema}/>) : null}
38
37
  </InteractiveSection>);
39
38
  }
40
- if ((_a = alternatives === null || alternatives === void 0 ? void 0 : alternatives[0]) === null || _a === void 0 ? void 0 : _a.length) {
39
+ if ((properties && properties.length > 0) || schema.type === 'object') {
41
40
  return (<InteractiveSection id={id} className={clsx('openapi-schema', className)}>
42
41
  <OpenAPISchemaPresentation {...props}/>
43
- {alternatives[0].map(function (alternative, index) { return (<OpenAPISchemaAlternative key={"alternative-".concat(index)} schema={alternative} circularRefs={circularRefs} context={context}/>); })}
42
+ {properties && properties.length > 0 ? (<OpenAPIDisclosure context={context} label={getDisclosureLabel(schema)}>
43
+ <OpenAPISchemaProperties properties={properties} circularRefs={circularRefs} context={context}/>
44
+ </OpenAPIDisclosure>) : null}
45
+ {parentCircularRef ? (<OpenAPISchemaCircularRef id={parentCircularRef} schema={schema}/>) : null}
44
46
  </InteractiveSection>);
45
47
  }
46
48
  return (<InteractiveSection id={id} className={clsx('openapi-schema', className)}>
@@ -86,9 +88,13 @@ function OpenAPISchemaAlternative(props) {
86
88
  var schema = props.schema, circularRefs = props.circularRefs, context = props.context;
87
89
  var id = useId();
88
90
  var subProperties = getSchemaProperties(schema);
89
- return (<OpenAPIDisclosure context={context}>
90
- <OpenAPISchemaProperties id={id} properties={subProperties !== null && subProperties !== void 0 ? subProperties : [{ schema: schema }]} circularRefs={subProperties ? new Map(circularRefs).set(schema, id) : circularRefs} context={context}/>
91
- </OpenAPIDisclosure>);
91
+ var description = resolveDescription(schema);
92
+ return (<>
93
+ {description ? (<Markdown source={description} className="openapi-schema-description"/>) : null}
94
+ <OpenAPIDisclosure context={context} label={getDisclosureLabel(schema)}>
95
+ <OpenAPISchemaProperties id={id} properties={subProperties !== null && subProperties !== void 0 ? subProperties : [{ schema: schema }]} circularRefs={subProperties ? new Map(circularRefs).set(schema, id) : circularRefs} context={context}/>
96
+ </OpenAPIDisclosure>
97
+ </>);
92
98
  }
93
99
  /**
94
100
  * Render a circular reference to a schema.
@@ -118,7 +124,7 @@ export function OpenAPISchemaEnum(props) {
118
124
  export function OpenAPISchemaPresentation(props) {
119
125
  var schema = props.schema, propertyName = props.propertyName, required = props.required;
120
126
  var shouldDisplayExample = function (schema) {
121
- return (typeof schema.example === 'string' ||
127
+ return ((typeof schema.example === 'string' && !!schema.example) ||
122
128
  typeof schema.example === 'number' ||
123
129
  typeof schema.example === 'boolean' ||
124
130
  (Array.isArray(schema.example) && schema.example.length > 0) ||
@@ -128,7 +134,7 @@ export function OpenAPISchemaPresentation(props) {
128
134
  };
129
135
  var description = resolveDescription(schema);
130
136
  return (<div className="openapi-schema-presentation">
131
- <OpenAPISchemaName type={getSchemaTitle(schema)} propertyName={propertyName} required={required} deprecated={schema.deprecated}/>
137
+ <OpenAPISchemaName schema={schema} type={getSchemaTitle(schema)} propertyName={propertyName} required={required}/>
132
138
  {schema['x-deprecated-sunset'] ? (<div className="openapi-deprecated-sunset openapi-schema-description openapi-markdown">
133
139
  Sunset date:{' '}
134
140
  <span className="openapi-deprecated-sunset-date">
@@ -137,12 +143,7 @@ export function OpenAPISchemaPresentation(props) {
137
143
  </div>) : null}
138
144
  {description ? (<Markdown source={description} className="openapi-schema-description"/>) : null}
139
145
  {shouldDisplayExample(schema) ? (<div className="openapi-schema-example">
140
- Example:{' '}
141
- <code>
142
- {typeof schema.example === 'string'
143
- ? schema.example
144
- : stringifyOpenAPI(schema.example)}
145
- </code>
146
+ Example: <code>{formatExample(schema.example)}</code>
146
147
  </div>) : null}
147
148
  {schema.pattern ? (<div className="openapi-schema-pattern">
148
149
  Pattern: <code>{schema.pattern}</code>
@@ -154,17 +155,6 @@ export function OpenAPISchemaPresentation(props) {
154
155
  * Get the sub-properties of a schema.
155
156
  */
156
157
  function getSchemaProperties(schema) {
157
- if (schema.allOf) {
158
- return schema.allOf.reduce(function (acc, subSchema) {
159
- var _a;
160
- var properties = (_a = getSchemaProperties(subSchema)) !== null && _a !== void 0 ? _a : [
161
- {
162
- schema: subSchema,
163
- },
164
- ];
165
- return __spreadArray(__spreadArray([], acc, true), properties, true);
166
- }, []);
167
- }
168
158
  // check array AND schema.items as this is sometimes null despite what the type indicates
169
159
  if (schema.type === 'array' && !!schema.items) {
170
160
  var items = schema.items;
@@ -172,6 +162,10 @@ function getSchemaProperties(schema) {
172
162
  if (itemProperties) {
173
163
  return itemProperties;
174
164
  }
165
+ // If the items are a primitive type, we don't need to display them
166
+ if (['string', 'number', 'boolean', 'integer'].includes(items.type) && !items.enum) {
167
+ return null;
168
+ }
175
169
  return [
176
170
  {
177
171
  propertyName: 'items',
@@ -217,8 +211,7 @@ export function getSchemaAlternatives(schema, ancestors) {
217
211
  return [flattenAlternatives('oneOf', schema.oneOf, downAncestors), schema.discriminator];
218
212
  }
219
213
  if (schema.allOf) {
220
- // allOf is managed in `getSchemaProperties`
221
- return null;
214
+ return [flattenAlternatives('allOf', schema.allOf, downAncestors), schema.discriminator];
222
215
  }
223
216
  return null;
224
217
  }
@@ -235,10 +228,6 @@ export function getSchemaTitle(schema,
235
228
  /** If the title is inferred in a oneOf with discriminator, we can use it to optimize the title */
236
229
  discriminator) {
237
230
  var _a;
238
- if (schema.title) {
239
- // If the schema has a title, use it
240
- return schema.title;
241
- }
242
231
  // Try using the discriminator
243
232
  if ((discriminator === null || discriminator === void 0 ? void 0 : discriminator.propertyName) && schema.properties) {
244
233
  var discriminatorProperty = schema.properties[discriminator.propertyName];
@@ -251,7 +240,7 @@ discriminator) {
251
240
  // Otherwise try to infer a nice title
252
241
  var type = 'any';
253
242
  if (schema.enum) {
254
- type = 'enum';
243
+ type = "".concat(schema.type, " \u00B7 enum");
255
244
  // check array AND schema.items as this is sometimes null despite what the type indicates
256
245
  }
257
246
  else if (schema.type === 'array' && !!schema.items) {
@@ -263,7 +252,7 @@ discriminator) {
263
252
  else if (schema.type || schema.properties) {
264
253
  type = (_a = schema.type) !== null && _a !== void 0 ? _a : 'object';
265
254
  if (schema.format) {
266
- type += " ".concat(schema.format);
255
+ type += " \u00B7 ".concat(schema.format);
267
256
  }
268
257
  }
269
258
  else if ('anyOf' in schema) {
@@ -278,8 +267,30 @@ discriminator) {
278
267
  else if ('not' in schema) {
279
268
  type = 'not';
280
269
  }
281
- if (schema.nullable) {
282
- type = "nullable ".concat(type);
283
- }
284
270
  return type;
285
271
  }
272
+ function getDisclosureLabel(schema) {
273
+ var _a, _b;
274
+ if (schema.type === 'array' && !!schema.items) {
275
+ if (schema.items.oneOf) {
276
+ return 'available items';
277
+ }
278
+ // Fallback to "child attributes" for enums and objects
279
+ if (schema.items.enum || schema.items.type === 'object') {
280
+ return;
281
+ }
282
+ return (_b = (_a = schema.items.title) !== null && _a !== void 0 ? _a : schema.title) !== null && _b !== void 0 ? _b : getSchemaTitle(schema.items);
283
+ }
284
+ return schema.title;
285
+ }
286
+ function formatExample(example) {
287
+ if (typeof example === 'string') {
288
+ return example
289
+ .replace(/\n/g, ' ') // Replace newlines with spaces
290
+ .replace(/\s+/g, ' ') // Collapse multiple spaces/newlines into a single space
291
+ .replace(/([\{\}:,])\s+/g, '$1 ') // Ensure a space after {, }, :, and ,
292
+ .replace(/\s+([\{\}:,])/g, ' $1') // Ensure a space before {, }, :, and ,
293
+ .trim();
294
+ }
295
+ return stringifyOpenAPI(example);
296
+ }
@@ -1,8 +1,9 @@
1
+ import { OpenAPIV3 } from '@gitbook/openapi-parser';
1
2
  interface OpenAPISchemaNameProps {
3
+ schema?: OpenAPIV3.SchemaObject;
2
4
  propertyName?: string | JSX.Element;
3
5
  required?: boolean;
4
6
  type?: string;
5
- deprecated?: boolean;
6
7
  }
7
8
  /**
8
9
  * Display the schema name row.