@gitbook/react-openapi 1.0.1 → 1.0.2

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 CHANGED
@@ -1,5 +1,17 @@
1
1
  # @gitbook/react-openapi
2
2
 
3
+ ## 1.0.2
4
+
5
+ ### Patch Changes
6
+
7
+ - bb5c6a4: Support multiple response media types and examples
8
+ - a3f1fea: Fix display of OpenAPI header description
9
+ - 6157583: Improve Markdown parsing
10
+ - 7419ee7: Show additional fields in OpenAPI block
11
+ - 82cd9f2: Add support for anchor links in OpenAPI blocks
12
+ - Updated dependencies [6157583]
13
+ - @gitbook/openapi-parser@1.0.1
14
+
3
15
  ## 1.0.1
4
16
 
5
17
  ### Patch Changes
@@ -57,7 +57,9 @@ export function OpenAPICodeSample(props) {
57
57
  (searchParams.size ? "?".concat(searchParams.toString()) : ''),
58
58
  method: data.method,
59
59
  body: requestBodyContent
60
- ? generateMediaTypeExample(requestBodyContent[1], { onlyRequired: true })
60
+ ? generateMediaTypeExample(requestBodyContent[1], {
61
+ omitEmptyAndOptionalProperties: true,
62
+ })
61
63
  : undefined,
62
64
  headers: __assign(__assign(__assign({}, getSecurityHeaders(data.securities)), headersObject), (requestBodyContent
63
65
  ? {
@@ -17,12 +17,15 @@ 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();
20
+ var description = resolveDescription(operation);
21
21
  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>
22
+ <div className="openapi-summary">
23
+ {operation.summary
24
+ ? context.renderHeading({
25
+ deprecated: (_a = operation.deprecated) !== null && _a !== void 0 ? _a : false,
26
+ title: operation.summary,
27
+ })
28
+ : null}
26
29
  {operation.deprecated && <div className="openapi-deprecated">Deprecated</div>}
27
30
  </div>
28
31
  <div className="openapi-columns">
@@ -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,8 @@
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
6
  /**
7
7
  * Display an example of the response content.
8
8
  */
@@ -31,78 +31,187 @@ export function OpenAPIResponseExample(props) {
31
31
  }
32
32
  return Number(a) - Number(b);
33
33
  });
34
- var examples = responses
34
+ var tabs = responses
35
35
  .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) {
36
+ var key = _a[0], responseObject = _a[1];
37
+ var description = resolveDescription(responseObject);
38
+ if (checkIsReference(responseObject)) {
47
39
  return {
48
40
  key: key,
49
41
  label: key,
50
- description: resolveDescription(responseObject),
42
+ description: description,
43
+ body: (<OpenAPIExample example={getExampleFromReference(responseObject)} context={context} syntax="json"/>),
44
+ };
45
+ }
46
+ if (!responseObject.content || Object.keys(responseObject.content).length === 0) {
47
+ return {
48
+ key: key,
49
+ label: key,
50
+ description: description,
51
51
  body: <OpenAPIEmptyResponseExample />,
52
52
  };
53
53
  }
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
54
  return {
76
55
  key: key,
77
56
  label: key,
78
57
  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 />),
58
+ body: <OpenAPIResponse context={context} content={responseObject.content}/>,
82
59
  };
83
60
  })
84
61
  .filter(function (val) {
85
62
  return Boolean(val);
86
63
  });
87
- if (examples.length === 0) {
64
+ if (tabs.length === 0) {
88
65
  return null;
89
66
  }
90
- return (<OpenAPITabs stateKey={createStateKey('response-example')} items={examples}>
67
+ return (<OpenAPITabs stateKey={createStateKey('response-example')} items={tabs}>
91
68
  <InteractiveSection header={<OpenAPITabsList />} className="openapi-response-example">
92
69
  <OpenAPITabsPanels />
93
70
  </InteractiveSection>
94
71
  </OpenAPITabs>);
95
72
  }
73
+ function OpenAPIResponse(props) {
74
+ var context = props.context, content = props.content;
75
+ var entries = Object.entries(content);
76
+ var firstEntry = entries[0];
77
+ if (!firstEntry) {
78
+ throw new Error('One media type is required');
79
+ }
80
+ if (entries.length === 1) {
81
+ var mediaType = firstEntry[0], mediaTypeObject = firstEntry[1];
82
+ return (<OpenAPIResponseMediaType context={context} mediaType={mediaType} mediaTypeObject={mediaTypeObject}/>);
83
+ }
84
+ var tabs = entries.map(function (entry) {
85
+ var mediaType = entry[0], mediaTypeObject = entry[1];
86
+ return {
87
+ key: mediaType,
88
+ label: mediaType,
89
+ body: (<OpenAPIResponseMediaType context={context} mediaType={mediaType} mediaTypeObject={mediaTypeObject}/>),
90
+ };
91
+ });
92
+ return (<OpenAPITabs stateKey={createStateKey('response-media-types')} items={tabs}>
93
+ <InteractiveSection header={<OpenAPITabsList />} className="openapi-response-media-types">
94
+ <OpenAPITabsPanels />
95
+ </InteractiveSection>
96
+ </OpenAPITabs>);
97
+ }
98
+ function OpenAPIResponseMediaType(props) {
99
+ var mediaTypeObject = props.mediaTypeObject, mediaType = props.mediaType;
100
+ var examples = getExamplesFromMediaTypeObject({ mediaTypeObject: mediaTypeObject, mediaType: mediaType });
101
+ var syntax = getSyntaxFromMediaType(mediaType);
102
+ var firstExample = examples[0];
103
+ if (!firstExample) {
104
+ return <OpenAPIEmptyResponseExample />;
105
+ }
106
+ if (examples.length === 1) {
107
+ return (<OpenAPIExample example={firstExample.example} context={props.context} syntax={syntax}/>);
108
+ }
109
+ var tabs = examples.map(function (example) {
110
+ return {
111
+ key: example.key,
112
+ label: example.example.summary || example.key,
113
+ body: (<OpenAPIExample example={firstExample.example} context={props.context} syntax={syntax}/>),
114
+ };
115
+ });
116
+ return (<OpenAPITabs stateKey={createStateKey('response-media-type-examples')} items={tabs}>
117
+ <InteractiveSection header={<OpenAPITabsList />} className="openapi-response-media-type-examples">
118
+ <OpenAPITabsPanels />
119
+ </InteractiveSection>
120
+ </OpenAPITabs>);
121
+ }
122
+ /**
123
+ * Display an example.
124
+ */
125
+ function OpenAPIExample(props) {
126
+ var example = props.example, context = props.context, syntax = props.syntax;
127
+ var code = stringifyExample({ example: example, xml: syntax === 'xml' });
128
+ if (code === null) {
129
+ return <OpenAPIEmptyResponseExample />;
130
+ }
131
+ return <context.CodeBlock code={code} syntax={syntax}/>;
132
+ }
133
+ function stringifyExample(args) {
134
+ var example = args.example, xml = args.xml;
135
+ if (!example.value) {
136
+ return null;
137
+ }
138
+ if (typeof example.value === 'string') {
139
+ return example.value;
140
+ }
141
+ if (xml) {
142
+ return json2xml(example.value);
143
+ }
144
+ return JSON.stringify(example.value, null, 2);
145
+ }
146
+ /**
147
+ * Get the syntax from a media type.
148
+ */
149
+ function getSyntaxFromMediaType(mediaType) {
150
+ if (mediaType.includes('json')) {
151
+ return 'json';
152
+ }
153
+ if (mediaType === 'application/xml') {
154
+ return 'xml';
155
+ }
156
+ return 'text';
157
+ }
158
+ /**
159
+ * Get examples from a media type object.
160
+ */
161
+ function getExamplesFromMediaTypeObject(args) {
162
+ var _a;
163
+ var _b, _c;
164
+ var mediaTypeObject = args.mediaTypeObject, mediaType = args.mediaType;
165
+ if (mediaTypeObject.examples) {
166
+ return Object.entries(mediaTypeObject.examples).map(function (_a) {
167
+ var key = _a[0], example = _a[1];
168
+ return {
169
+ key: key,
170
+ example: checkIsReference(example) ? getExampleFromReference(example) : example,
171
+ };
172
+ });
173
+ }
174
+ if (mediaTypeObject.example) {
175
+ return [{ key: 'default', example: { value: mediaTypeObject.example } }];
176
+ }
177
+ if (mediaTypeObject.schema) {
178
+ if (mediaType === 'application/xml') {
179
+ // @TODO normally we should use the name of the schema but we don't have it
180
+ // fix it when we got the reference name
181
+ var root = (_c = (_b = mediaTypeObject.schema.xml) === null || _b === void 0 ? void 0 : _b.name) !== null && _c !== void 0 ? _c : 'object';
182
+ return [
183
+ {
184
+ key: 'default',
185
+ example: {
186
+ value: (_a = {},
187
+ _a[root] = generateSchemaExample(mediaTypeObject.schema, {
188
+ xml: mediaType === 'application/xml',
189
+ }),
190
+ _a),
191
+ },
192
+ },
193
+ ];
194
+ }
195
+ return [
196
+ {
197
+ key: 'default',
198
+ example: { value: generateSchemaExample(mediaTypeObject.schema) },
199
+ },
200
+ ];
201
+ }
202
+ return [];
203
+ }
204
+ /**
205
+ * Empty response example.
206
+ */
96
207
  function OpenAPIEmptyResponseExample() {
97
208
  return (<pre className="openapi-response-example-empty">
98
209
  <p>No body</p>
99
210
  </pre>);
100
211
  }
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;
212
+ /**
213
+ * Generate an example from a reference object.
214
+ */
215
+ function getExampleFromReference(ref) {
216
+ return { summary: 'Unresolved reference', value: { $ref: ref.$ref } };
108
217
  }
@@ -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,7 +29,7 @@ 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 ((properties && properties.length > 0) || schema.type === 'object') {
33
33
  return (<InteractiveSection id={id} className={clsx('openapi-schema', className)}>
34
34
  <OpenAPISchemaPresentation {...props}/>
35
35
  {properties && properties.length > 0 ? (<OpenAPIDisclosure context={context}>
@@ -251,7 +251,7 @@ discriminator) {
251
251
  // Otherwise try to infer a nice title
252
252
  var type = 'any';
253
253
  if (schema.enum) {
254
- type = 'enum';
254
+ type = "".concat(schema.type, " \u00B7 enum");
255
255
  // check array AND schema.items as this is sometimes null despite what the type indicates
256
256
  }
257
257
  else if (schema.type === 'array' && !!schema.items) {
@@ -263,7 +263,7 @@ discriminator) {
263
263
  else if (schema.type || schema.properties) {
264
264
  type = (_a = schema.type) !== null && _a !== void 0 ? _a : 'object';
265
265
  if (schema.format) {
266
- type += " ".concat(schema.format);
266
+ type += " \u00B7 ".concat(schema.format);
267
267
  }
268
268
  }
269
269
  else if ('anyOf' in schema) {
@@ -278,8 +278,17 @@ discriminator) {
278
278
  else if ('not' in schema) {
279
279
  type = 'not';
280
280
  }
281
+ if (schema.minimum || schema.minLength) {
282
+ type += " \u00B7 min: ".concat(schema.minimum || schema.minLength);
283
+ }
284
+ if (schema.maximum || schema.maxLength) {
285
+ type += " \u00B7 max: ".concat(schema.maximum || schema.maxLength);
286
+ }
287
+ if (schema.default) {
288
+ type += " \u00B7 default: ".concat(schema.default);
289
+ }
281
290
  if (schema.nullable) {
282
- type = "nullable ".concat(type);
291
+ type = "".concat(type, " | nullable");
283
292
  }
284
293
  return type;
285
294
  }
@@ -1,21 +1,10 @@
1
1
  'use client';
2
- var __assign = (this && this.__assign) || function () {
3
- __assign = Object.assign || function(t) {
4
- for (var s, i = 1, n = arguments.length; i < n; i++) {
5
- s = arguments[i];
6
- for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
7
- t[p] = s[p];
8
- }
9
- return t;
10
- };
11
- return __assign.apply(this, arguments);
12
- };
13
2
  import { InteractiveSection } from './InteractiveSection';
14
3
  import { OpenAPIRequestBody } from './OpenAPIRequestBody';
15
4
  import { OpenAPIResponses } from './OpenAPIResponses';
16
5
  import { OpenAPISchemaProperties } from './OpenAPISchema';
17
6
  import { OpenAPISecurities } from './OpenAPISecurities';
18
- import { resolveDescription } from './utils';
7
+ import { parameterToProperty } from './utils';
19
8
  /**
20
9
  * Client component to render the spec for the request and response.
21
10
  *
@@ -33,20 +22,7 @@ export function OpenAPISpec(props) {
33
22
 
34
23
  {parameterGroups.map(function (group) {
35
24
  return (<InteractiveSection key={group.key} className="openapi-parameters" header={group.label}>
36
- <OpenAPISchemaProperties properties={group.parameters.map(function (parameter) {
37
- var _a;
38
- var description = resolveDescription(parameter);
39
- return {
40
- propertyName: parameter.name,
41
- schema: __assign({
42
- // Description of the parameter is defined at the parameter level
43
- // we use display it if the schema doesn't override it
44
- description: description, example: parameter.example,
45
- // Deprecated can be defined at the parameter level
46
- deprecated: parameter.deprecated }, ((_a = parameter.schema) !== null && _a !== void 0 ? _a : {})),
47
- required: parameter.required,
48
- };
49
- })} context={context}/>
25
+ <OpenAPISchemaProperties properties={group.parameters.map(parameterToProperty)} context={context}/>
50
26
  </InteractiveSection>);
51
27
  })}
52
28
 
@@ -1,17 +1,16 @@
1
1
  import type { OpenAPIV3 } from '@gitbook/openapi-parser';
2
+ import { getExampleFromSchema } from '@scalar/oas-utils/spec-getters';
2
3
  type JSONValue = string | number | boolean | null | JSONValue[] | {
3
4
  [key: string]: JSONValue;
4
5
  };
6
+ type ScalarGetExampleFromSchemaOptions = NonNullable<Parameters<typeof getExampleFromSchema>[1]>;
7
+ type GenerateSchemaExampleOptions = Pick<ScalarGetExampleFromSchemaOptions, 'xml' | 'omitEmptyAndOptionalProperties' | 'mode'>;
5
8
  /**
6
9
  * Generate a JSON example from a schema
7
10
  */
8
- export declare function generateSchemaExample(schema: OpenAPIV3.SchemaObject, options?: {
9
- onlyRequired?: boolean;
10
- }): JSONValue | undefined;
11
+ export declare function generateSchemaExample(schema: OpenAPIV3.SchemaObject, options?: GenerateSchemaExampleOptions): JSONValue | undefined;
11
12
  /**
12
13
  * Generate an example for a media type.
13
14
  */
14
- export declare function generateMediaTypeExample(mediaType: OpenAPIV3.MediaTypeObject, options?: {
15
- onlyRequired?: boolean;
16
- }): JSONValue | undefined;
15
+ export declare function generateMediaTypeExample(mediaType: OpenAPIV3.MediaTypeObject, options?: GenerateSchemaExampleOptions): JSONValue | undefined;
17
16
  export {};
@@ -1,13 +1,20 @@
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 { getExampleFromSchema } from '@scalar/oas-utils/spec-getters';
2
13
  /**
3
14
  * Generate a JSON example from a schema
4
15
  */
5
16
  export function generateSchemaExample(schema, options) {
6
- if (options === void 0) { options = {}; }
7
- return getExampleFromSchema(schema, {
8
- emptyString: 'text',
9
- omitEmptyAndOptionalProperties: options.onlyRequired,
10
- variables: {
17
+ return getExampleFromSchema(schema, __assign({ emptyString: 'text', variables: {
11
18
  'date-time': new Date().toISOString(),
12
19
  date: new Date().toISOString().split('T')[0],
13
20
  email: 'name@gmail.com',
@@ -19,14 +26,12 @@ export function generateSchemaExample(schema, options) {
19
26
  binary: 'binary',
20
27
  byte: 'Ynl0ZXM=',
21
28
  password: 'password',
22
- },
23
- });
29
+ } }, options));
24
30
  }
25
31
  /**
26
32
  * Generate an example for a media type.
27
33
  */
28
34
  export function generateMediaTypeExample(mediaType, options) {
29
- if (options === void 0) { options = {}; }
30
35
  if (mediaType.example) {
31
36
  return mediaType.example;
32
37
  }
@@ -0,0 +1,4 @@
1
+ /**
2
+ * This function converts an object to XML.
3
+ */
4
+ export declare function json2xml(data: Record<string, any>): string;
@@ -0,0 +1,7 @@
1
+ import { jsXml } from 'json-xml-parse';
2
+ /**
3
+ * This function converts an object to XML.
4
+ */
5
+ export function json2xml(data) {
6
+ return jsXml.toXmlString(data, { beautify: true });
7
+ }