@gitbook/react-openapi 1.0.3 → 1.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/dist/OpenAPICodeSample.jsx +6 -7
  3. package/dist/OpenAPIDisclosure.d.ts +2 -1
  4. package/dist/OpenAPIDisclosure.jsx +1 -1
  5. package/dist/OpenAPIDisclosureGroup.d.ts +1 -1
  6. package/dist/OpenAPIDisclosureGroup.jsx +2 -2
  7. package/dist/OpenAPIOperation.jsx +2 -2
  8. package/dist/OpenAPIPath.d.ts +3 -2
  9. package/dist/OpenAPIPath.jsx +4 -15
  10. package/dist/OpenAPIRequestBody.jsx +1 -1
  11. package/dist/OpenAPIResponse.jsx +1 -1
  12. package/dist/OpenAPIResponseExample.jsx +3 -3
  13. package/dist/OpenAPIResponses.d.ts +1 -1
  14. package/dist/OpenAPIResponses.jsx +2 -2
  15. package/dist/OpenAPISchema.d.ts +5 -1
  16. package/dist/OpenAPISchema.jsx +29 -20
  17. package/dist/OpenAPISchemaName.d.ts +4 -3
  18. package/dist/OpenAPISchemaName.jsx +1 -1
  19. package/dist/OpenAPISecurities.jsx +2 -2
  20. package/dist/OpenAPITabs.d.ts +3 -3
  21. package/dist/OpenAPITabs.jsx +11 -12
  22. package/dist/ScalarApiButton.jsx +1 -1
  23. package/dist/code-samples.js +11 -11
  24. package/dist/generateSchemaExample.js +2 -1
  25. package/dist/resolveOpenAPIOperation.d.ts +3 -3
  26. package/dist/resolveOpenAPIOperation.js +1 -1
  27. package/dist/tsconfig.build.tsbuildinfo +1 -1
  28. package/dist/util/server.d.ts +1 -1
  29. package/dist/util/server.js +1 -3
  30. package/dist/utils.d.ts +1 -1
  31. package/dist/utils.js +4 -6
  32. package/package.json +2 -7
  33. package/src/InteractiveSection.tsx +4 -4
  34. package/src/OpenAPICodeSample.tsx +9 -10
  35. package/src/OpenAPIDisclosure.tsx +4 -3
  36. package/src/OpenAPIDisclosureGroup.tsx +5 -5
  37. package/src/OpenAPIOperation.tsx +3 -3
  38. package/src/OpenAPIOperationContext.tsx +1 -1
  39. package/src/OpenAPIPath.tsx +11 -10
  40. package/src/OpenAPIRequestBody.tsx +2 -2
  41. package/src/OpenAPIResponse.tsx +3 -3
  42. package/src/OpenAPIResponseExample.tsx +5 -5
  43. package/src/OpenAPIResponses.tsx +4 -4
  44. package/src/OpenAPISchema.test.ts +5 -5
  45. package/src/OpenAPISchema.tsx +75 -25
  46. package/src/OpenAPISchemaName.tsx +5 -4
  47. package/src/OpenAPISecurities.tsx +3 -3
  48. package/src/OpenAPITabs.tsx +15 -15
  49. package/src/ScalarApiButton.tsx +3 -3
  50. package/src/code-samples.test.ts +66 -66
  51. package/src/code-samples.ts +14 -14
  52. package/src/generateSchemaExample.ts +3 -3
  53. package/src/json2xml.test.ts +1 -1
  54. package/src/resolveOpenAPIOperation.test.ts +6 -6
  55. package/src/resolveOpenAPIOperation.ts +7 -7
  56. package/src/stringifyOpenAPI.ts +1 -1
  57. package/src/util/server.test.ts +3 -3
  58. package/src/util/server.ts +2 -3
  59. package/src/utils.ts +4 -4
@@ -1,4 +1,4 @@
1
- import { OpenAPIV3 } from '@gitbook/openapi-parser';
1
+ import type { OpenAPIV3 } from '@gitbook/openapi-parser';
2
2
  /**
3
3
  * Get the default URL for the server.
4
4
  */
@@ -21,9 +21,7 @@ export function interpolateServerURL(server) {
21
21
  if (part.kind === 'text') {
22
22
  return part.text;
23
23
  }
24
- else {
25
- return (_c = (_b = (_a = server.variables) === null || _a === void 0 ? void 0 : _a[part.name]) === null || _b === void 0 ? void 0 : _b.default) !== null && _c !== void 0 ? _c : "{".concat(part.name, "}");
26
- }
24
+ return (_c = (_b = (_a = server.variables) === null || _a === void 0 ? void 0 : _a[part.name]) === null || _b === void 0 ? void 0 : _b.default) !== null && _c !== void 0 ? _c : "{".concat(part.name, "}");
27
25
  })
28
26
  .join('');
29
27
  }
package/dist/utils.d.ts CHANGED
@@ -10,7 +10,7 @@ export declare function resolveDescription(object: OpenAPIV3.SchemaObject | AnyO
10
10
  */
11
11
  export declare function extractDescriptions(object: AnyObject): {
12
12
  description: any;
13
- "x-gitbook-description-html": any;
13
+ 'x-gitbook-description-html': any;
14
14
  };
15
15
  /**
16
16
  * Resolve the first example from an object.
package/dist/utils.js CHANGED
@@ -33,14 +33,12 @@ export function resolveDescription(object) {
33
33
  * Extract descriptions from an object.
34
34
  */
35
35
  export function extractDescriptions(object) {
36
- var _a;
37
- return _a = {
38
- description: object.description
39
- },
40
- _a['x-gitbook-description-html'] = 'x-gitbook-description-html' in object
36
+ return {
37
+ description: object.description,
38
+ 'x-gitbook-description-html': 'x-gitbook-description-html' in object
41
39
  ? object['x-gitbook-description-html']
42
40
  : undefined,
43
- _a;
41
+ };
44
42
  }
45
43
  /**
46
44
  * Resolve the first example from an object.
package/package.json CHANGED
@@ -8,7 +8,7 @@
8
8
  "default": "./dist/index.js"
9
9
  }
10
10
  },
11
- "version": "1.0.3",
11
+ "version": "1.0.4",
12
12
  "sideEffects": false,
13
13
  "dependencies": {
14
14
  "@gitbook/openapi-parser": "workspace:*",
@@ -36,10 +36,5 @@
36
36
  "dev": "bun run build -- --watch",
37
37
  "clean": "rm -rf ./dist"
38
38
  },
39
- "files": [
40
- "dist",
41
- "src",
42
- "README.md",
43
- "CHANGELOG.md"
44
- ]
39
+ "files": ["dist", "src", "README.md", "CHANGELOG.md"]
45
40
  }
@@ -69,7 +69,7 @@ export function InteractiveSection(props: {
69
69
  'openapi-section',
70
70
  toggeable ? 'openapi-section-toggeable' : null,
71
71
  className,
72
- toggeable ? `${className}-${state.isExpanded ? 'opened' : 'closed'}` : null,
72
+ toggeable ? `${className}-${state.isExpanded ? 'opened' : 'closed'}` : null
73
73
  )}
74
74
  >
75
75
  {header ? (
@@ -84,7 +84,7 @@ export function InteractiveSection(props: {
84
84
  <div
85
85
  className={clsx(
86
86
  'openapi-section-header-content',
87
- `${className}-header-content`,
87
+ `${className}-header-content`
88
88
  )}
89
89
  >
90
90
  {(children || selectedTab?.body) && toggeable ? (
@@ -106,7 +106,7 @@ export function InteractiveSection(props: {
106
106
  <div
107
107
  className={clsx(
108
108
  'openapi-section-header-controls',
109
- `${className}-header-controls`,
109
+ `${className}-header-controls`
110
110
  )}
111
111
  onClick={(event) => {
112
112
  event.stopPropagation();
@@ -117,7 +117,7 @@ export function InteractiveSection(props: {
117
117
  className={clsx(
118
118
  'openapi-section-select',
119
119
  'openapi-select',
120
- `${className}-tabs-select`,
120
+ `${className}-tabs-select`
121
121
  )}
122
122
  value={selectedTab?.key ?? ''}
123
123
  onChange={(event) => {
@@ -1,12 +1,11 @@
1
- import { CodeSampleInput, codeSampleGenerators } from './code-samples';
2
- import { generateMediaTypeExample, generateSchemaExample } from './generateSchemaExample';
3
1
  import { InteractiveSection } from './InteractiveSection';
4
- import type { OpenAPIContextProps, OpenAPIOperationData } from './types';
5
- import { createStateKey } from './utils';
6
- import { stringifyOpenAPI } from './stringifyOpenAPI';
7
2
  import { OpenAPITabs, OpenAPITabsList, OpenAPITabsPanels } from './OpenAPITabs';
8
- import { checkIsReference } from './utils';
3
+ import { type CodeSampleInput, codeSampleGenerators } from './code-samples';
4
+ import { generateMediaTypeExample, generateSchemaExample } from './generateSchemaExample';
5
+ import { stringifyOpenAPI } from './stringifyOpenAPI';
6
+ import type { OpenAPIContextProps, OpenAPIOperationData } from './types';
9
7
  import { getDefaultServerURL } from './util/server';
8
+ import { checkIsReference, createStateKey } from './utils';
10
9
 
11
10
  /**
12
11
  * Display code samples to execute the operation.
@@ -37,7 +36,7 @@ export function OpenAPICodeSample(props: {
37
36
  if (example !== undefined && param.name) {
38
37
  searchParams.append(
39
38
  param.name,
40
- String(Array.isArray(example) ? example[0] : example),
39
+ String(Array.isArray(example) ? example[0] : example)
41
40
  );
42
41
  }
43
42
  }
@@ -95,8 +94,8 @@ export function OpenAPICodeSample(props: {
95
94
  typeof sample.lang === 'string'
96
95
  );
97
96
  })
98
- .map((sample) => ({
99
- key: `redocly-${sample.lang}`,
97
+ .map((sample, index) => ({
98
+ key: `redocly-${sample.lang}-${index}`,
100
99
  label: sample.label,
101
100
  body: context.renderCodeBlock({
102
101
  code: sample.source,
@@ -149,7 +148,7 @@ function getSecurityHeaders(securities: OpenAPIOperationData['securities']): {
149
148
  }
150
149
 
151
150
  return {
152
- Authorization: scheme + ' ' + format,
151
+ Authorization: `${scheme} ${format}`,
153
152
  };
154
153
  }
155
154
  case 'apiKey': {
@@ -1,7 +1,8 @@
1
+ import type React from 'react';
1
2
  import { useRef } from 'react';
2
- import type { OpenAPIClientContext } from './types';
3
3
  import { mergeProps, useButton, useDisclosure, useFocusRing } from 'react-aria';
4
4
  import { useDisclosureState } from 'react-stately';
5
+ import type { OpenAPIClientContext } from './types';
5
6
 
6
7
  interface Props {
7
8
  context: OpenAPIClientContext;
@@ -13,7 +14,7 @@ interface Props {
13
14
  * Display an interactive OpenAPI disclosure.
14
15
  * The label is optional and defaults to "child attributes".
15
16
  */
16
- export function OpenAPIDisclosure({ context, children, label }: Props): JSX.Element {
17
+ export function OpenAPIDisclosure({ context, children, label }: Props): React.JSX.Element {
17
18
  const state = useDisclosureState({});
18
19
  const panelRef = useRef<HTMLDivElement | null>(null);
19
20
  const triggerRef = useRef<HTMLButtonElement | null>(null);
@@ -36,7 +37,7 @@ export function OpenAPIDisclosure({ context, children, label }: Props): JSX.Elem
36
37
  >
37
38
  {context.icons.plus}
38
39
  <span>
39
- {`${state.isExpanded ? 'Hide' : 'Show'} ${label ? label : `child attributes`}`}
40
+ {`${state.isExpanded ? 'Hide' : 'Show'} ${label ? label : 'child attributes'}`}
40
41
  </span>
41
42
  </button>
42
43
 
@@ -13,14 +13,14 @@ type TDisclosureGroup = {
13
13
  }[];
14
14
  };
15
15
 
16
+ import { createContext, useContext, useRef, useState } from 'react';
16
17
  import { mergeProps, useButton, useDisclosure, useFocusRing, useId } from 'react-aria';
17
18
  import {
18
- DisclosureGroupProps,
19
- DisclosureGroupState,
19
+ type DisclosureGroupProps,
20
+ type DisclosureGroupState,
20
21
  useDisclosureGroupState,
21
22
  useDisclosureState,
22
23
  } from 'react-stately';
23
- import { createContext, useContext, useRef, useState } from 'react';
24
24
 
25
25
  const DisclosureGroupStateContext = createContext<DisclosureGroupState | null>(null);
26
26
 
@@ -67,7 +67,7 @@ function DisclosureItem(props: { group: TDisclosureGroup; icon?: React.ReactNode
67
67
  isDisabled,
68
68
  },
69
69
  state,
70
- panelRef,
70
+ panelRef
71
71
  );
72
72
  const { buttonProps } = useButton(triggerProps, triggerRef);
73
73
  const { isFocusVisible, focusProps } = useFocusRing();
@@ -119,7 +119,7 @@ function DisclosureItem(props: { group: TDisclosureGroup; icon?: React.ReactNode
119
119
  </option>
120
120
  ))}
121
121
  </select>
122
- ) : !!group.tabs[0] ? (
122
+ ) : group.tabs[0] ? (
123
123
  <span>{group.tabs[0].label}</span>
124
124
  ) : null}
125
125
  </div>
@@ -1,13 +1,13 @@
1
1
  import clsx from 'clsx';
2
2
 
3
+ import type { OpenAPICustomOperationProperties, OpenAPIV3 } from '@gitbook/openapi-parser';
3
4
  import { Markdown } from './Markdown';
4
5
  import { OpenAPICodeSample } from './OpenAPICodeSample';
6
+ import { OpenAPIPath } from './OpenAPIPath';
5
7
  import { OpenAPIResponseExample } from './OpenAPIResponseExample';
6
8
  import { OpenAPISpec } from './OpenAPISpec';
7
9
  import type { OpenAPIClientContext, OpenAPIContextProps, OpenAPIOperationData } from './types';
8
- import { OpenAPIPath } from './OpenAPIPath';
9
10
  import { resolveDescription } from './utils';
10
- import { OpenAPICustomOperationProperties, OpenAPIV3 } from '@gitbook/openapi-parser';
11
11
 
12
12
  /**
13
13
  * Display an interactive OpenAPI operation.
@@ -45,7 +45,7 @@ export function OpenAPIOperation(props: {
45
45
  <span className="openapi-deprecated-sunset-date">
46
46
  {operation['x-deprecated-sunset']}
47
47
  </span>
48
- {`.`}
48
+ {'.'}
49
49
  </div>
50
50
  ) : null}
51
51
  <OpenAPIOperationDescription operation={operation} context={context} />
@@ -20,7 +20,7 @@ const OpenAPIOperationContext = createContext<OpenAPIOperationContextValue>({
20
20
  * Provider for the OpenAPIOperationContext.
21
21
  */
22
22
  export function OpenAPIOperationContextProvider(
23
- props: React.PropsWithChildren<Partial<OpenAPIOperationContextValue>>,
23
+ props: React.PropsWithChildren<Partial<OpenAPIOperationContextValue>>
24
24
  ) {
25
25
  const { children } = props;
26
26
 
@@ -1,5 +1,6 @@
1
+ import type React from 'react';
1
2
  import { ScalarApiButton } from './ScalarApiButton';
2
- import type { OpenAPIOperationData, OpenAPIContextProps } from './types';
3
+ import type { OpenAPIContextProps, OpenAPIOperationData } from './types';
3
4
 
4
5
  /**
5
6
  * Display the path of an operation.
@@ -7,7 +8,7 @@ import type { OpenAPIOperationData, OpenAPIContextProps } from './types';
7
8
  export function OpenAPIPath(props: {
8
9
  data: OpenAPIOperationData;
9
10
  context: OpenAPIContextProps;
10
- }): JSX.Element {
11
+ }) {
11
12
  const { data, context } = props;
12
13
  const { method, path } = data;
13
14
  const { specUrl } = context;
@@ -30,7 +31,7 @@ function formatPath(path: string) {
30
31
  // Matches placeholders like {id}, {userId}, etc.
31
32
  const regex = /\{(\w+)\}/g;
32
33
 
33
- const parts: (string | JSX.Element)[] = [];
34
+ const parts: (string | React.JSX.Element)[] = [];
34
35
  let lastIndex = 0;
35
36
 
36
37
  // Replace placeholders with <em> tags
@@ -48,17 +49,17 @@ function formatPath(path: string) {
48
49
  const formattedPath = parts.reduce(
49
50
  (acc, part, index) => {
50
51
  if (typeof part === 'string' && index > 0 && part === '/') {
51
- return [
52
- ...acc,
52
+ acc.push(
53
53
  <span className="openapi-path-separator" key={`sep-${index}`}>
54
54
  /
55
- </span>,
56
- part,
57
- ];
55
+ </span>
56
+ );
58
57
  }
59
- return [...acc, part];
58
+
59
+ acc.push(part);
60
+ return acc;
60
61
  },
61
- [] as (string | JSX.Element)[],
62
+ [] as (string | React.JSX.Element)[]
62
63
  );
63
64
 
64
65
  return <span>{formattedPath}</span>;
@@ -1,7 +1,7 @@
1
1
  import type { OpenAPIV3 } from '@gitbook/openapi-parser';
2
+ import { InteractiveSection } from './InteractiveSection';
2
3
  import { OpenAPIRootSchema } from './OpenAPISchema';
3
4
  import type { OpenAPIClientContext } from './types';
4
- import { InteractiveSection } from './InteractiveSection';
5
5
  import { checkIsReference } from './utils';
6
6
 
7
7
  /**
@@ -33,7 +33,7 @@ export function OpenAPIRequestBody(props: {
33
33
  />
34
34
  ),
35
35
  };
36
- },
36
+ }
37
37
  )}
38
38
  />
39
39
  );
@@ -1,8 +1,8 @@
1
1
  import type { OpenAPIV3 } from '@gitbook/openapi-parser';
2
+ import { OpenAPIDisclosure } from './OpenAPIDisclosure';
2
3
  import { OpenAPISchemaProperties } from './OpenAPISchema';
3
- import { parameterToProperty, resolveDescription } from './utils';
4
4
  import type { OpenAPIClientContext } from './types';
5
- import { OpenAPIDisclosure } from './OpenAPIDisclosure';
5
+ import { parameterToProperty, resolveDescription } from './utils';
6
6
 
7
7
  /**
8
8
  * Display an interactive response body.
@@ -14,7 +14,7 @@ export function OpenAPIResponse(props: {
14
14
  }) {
15
15
  const { response, context, mediaType } = props;
16
16
  const headers = Object.entries(response.headers ?? {}).map(
17
- ([name, header]) => [name, header ?? {}] as const,
17
+ ([name, header]) => [name, header ?? {}] as const
18
18
  );
19
19
  const content = Object.entries(mediaType.schema ?? {});
20
20
 
@@ -1,11 +1,11 @@
1
1
  import type { OpenAPIV3 } from '@gitbook/openapi-parser';
2
- import { generateSchemaExample } from './generateSchemaExample';
3
- import type { OpenAPIContextProps, OpenAPIOperationData } from './types';
4
- import { checkIsReference, createStateKey, resolveDescription } from './utils';
5
- import { OpenAPITabs, OpenAPITabsList, OpenAPITabsPanels } from './OpenAPITabs';
6
2
  import { InteractiveSection } from './InteractiveSection';
3
+ import { OpenAPITabs, OpenAPITabsList, OpenAPITabsPanels } from './OpenAPITabs';
4
+ import { generateSchemaExample } from './generateSchemaExample';
7
5
  import { json2xml } from './json2xml';
8
6
  import { stringifyOpenAPI } from './stringifyOpenAPI';
7
+ import type { OpenAPIContextProps, OpenAPIOperationData } from './types';
8
+ import { checkIsReference, createStateKey, resolveDescription } from './utils';
9
9
 
10
10
  /**
11
11
  * Display an example of the response content.
@@ -75,7 +75,7 @@ export function OpenAPIResponseExample(props: {
75
75
  };
76
76
  })
77
77
  .filter((val): val is { key: string; label: string; body: any; description: string } =>
78
- Boolean(val),
78
+ Boolean(val)
79
79
  );
80
80
 
81
81
  if (tabs.length === 0) {
@@ -1,9 +1,9 @@
1
1
  import type { OpenAPIV3, OpenAPIV3_1 } from '@gitbook/openapi-parser';
2
- import { OpenAPIResponse } from './OpenAPIResponse';
3
- import { OpenAPIClientContext } from './types';
4
2
  import { InteractiveSection } from './InteractiveSection';
5
- import { OpenAPIDisclosureGroup } from './OpenAPIDisclosureGroup';
6
3
  import { Markdown } from './Markdown';
4
+ import { OpenAPIDisclosureGroup } from './OpenAPIDisclosureGroup';
5
+ import { OpenAPIResponse } from './OpenAPIResponse';
6
+ import type { OpenAPIClientContext } from './types';
7
7
 
8
8
  /**
9
9
  * Display an interactive response body.
@@ -55,7 +55,7 @@ export function OpenAPIResponses(props: {
55
55
  ),
56
56
  })),
57
57
  };
58
- },
58
+ }
59
59
  )}
60
60
  />
61
61
  </InteractiveSection>
@@ -1,6 +1,6 @@
1
- import { it, describe, expect } from 'bun:test';
2
- import { getSchemaAlternatives } from './OpenAPISchema';
1
+ import { describe, expect, it } from 'bun:test';
3
2
  import type { OpenAPIV3 } from '@gitbook/openapi-parser';
3
+ import { getSchemaAlternatives } from './OpenAPISchema';
4
4
 
5
5
  describe('getSchemaAlternatives', () => {
6
6
  it('should flatten oneOf', () => {
@@ -21,7 +21,7 @@ describe('getSchemaAlternatives', () => {
21
21
  type: 'string',
22
22
  },
23
23
  ],
24
- }),
24
+ })
25
25
  ).toEqual([
26
26
  [
27
27
  {
@@ -56,7 +56,7 @@ describe('getSchemaAlternatives', () => {
56
56
  type: 'string',
57
57
  },
58
58
  ],
59
- }),
59
+ })
60
60
  ).toEqual([
61
61
  [
62
62
  {
@@ -86,7 +86,7 @@ describe('getSchemaAlternatives', () => {
86
86
  ],
87
87
  };
88
88
 
89
- a.anyOf!.push(a);
89
+ a.anyOf?.push(a);
90
90
 
91
91
  expect(getSchemaAlternatives(a)).toEqual([
92
92
  [
@@ -4,11 +4,11 @@ import { useId } from 'react';
4
4
 
5
5
  import { InteractiveSection } from './InteractiveSection';
6
6
  import { Markdown } from './Markdown';
7
+ import { OpenAPIDisclosure } from './OpenAPIDisclosure';
8
+ import { OpenAPISchemaName } from './OpenAPISchemaName';
9
+ import { stringifyOpenAPI } from './stringifyOpenAPI';
7
10
  import type { OpenAPIClientContext } from './types';
8
11
  import { checkIsReference, resolveDescription } from './utils';
9
- import { stringifyOpenAPI } from './stringifyOpenAPI';
10
- import { OpenAPISchemaName } from './OpenAPISchemaName';
11
- import { OpenAPIDisclosure } from './OpenAPIDisclosure';
12
12
 
13
13
  type CircularRefsIds = Map<OpenAPIV3.SchemaObject, string>;
14
14
 
@@ -27,7 +27,7 @@ export function OpenAPISchemaProperty(
27
27
  circularRefs?: CircularRefsIds;
28
28
  context: OpenAPIClientContext;
29
29
  className?: string;
30
- },
30
+ }
31
31
  ) {
32
32
  const {
33
33
  schema,
@@ -49,20 +49,13 @@ export function OpenAPISchemaProperty(
49
49
 
50
50
  if (alternatives?.[0]?.length) {
51
51
  return (
52
- <InteractiveSection id={id} className={clsx('openapi-schema', className)}>
53
- <OpenAPISchemaPresentation {...props} />
54
- {alternatives[0].map((alternative, index) => (
55
- <OpenAPISchemaAlternative
56
- key={`alternative-${index}`}
57
- schema={alternative}
58
- circularRefs={circularRefs}
59
- context={context}
60
- />
61
- ))}
62
- {parentCircularRef ? (
63
- <OpenAPISchemaCircularRef id={parentCircularRef} schema={schema} />
64
- ) : null}
65
- </InteractiveSection>
52
+ <OpenAPISchemaAlternativesItem
53
+ {...props}
54
+ circularRefs={circularRefs}
55
+ context={context}
56
+ alternatives={alternatives}
57
+ parentCircularRef={parentCircularRef}
58
+ />
66
59
  );
67
60
  }
68
61
 
@@ -173,6 +166,25 @@ function OpenAPISchemaAlternative(props: {
173
166
  const id = useId();
174
167
  const subProperties = getSchemaProperties(schema);
175
168
  const description = resolveDescription(schema);
169
+ const alternatives = getSchemaAlternatives(schema, new Set(circularRefs?.keys()));
170
+
171
+ if (alternatives?.[0]?.length && !subProperties?.length) {
172
+ return (
173
+ <>
174
+ {description ? (
175
+ <Markdown source={description} className="openapi-schema-description" />
176
+ ) : null}
177
+ <OpenAPIDisclosure context={context} label={getDisclosureLabel(schema)}>
178
+ <OpenAPISchemaAlternativesItem
179
+ schema={schema}
180
+ circularRefs={circularRefs}
181
+ context={context}
182
+ alternatives={alternatives}
183
+ />
184
+ </OpenAPIDisclosure>
185
+ </>
186
+ );
187
+ }
176
188
 
177
189
  return (
178
190
  <>
@@ -193,6 +205,35 @@ function OpenAPISchemaAlternative(props: {
193
205
  );
194
206
  }
195
207
 
208
+ function OpenAPISchemaAlternativesItem(
209
+ props: OpenAPISchemaPropertyEntry & {
210
+ circularRefs?: CircularRefsIds;
211
+ context: OpenAPIClientContext;
212
+ alternatives: OpenAPISchemaAlternatives;
213
+ parentCircularRef?: string;
214
+ }
215
+ ) {
216
+ const id = useId();
217
+ const { schema, circularRefs, context, alternatives, parentCircularRef } = props;
218
+
219
+ return (
220
+ <InteractiveSection id={id} className={clsx('openapi-schema')}>
221
+ <OpenAPISchemaPresentation {...props} />
222
+ {alternatives[0].map((alternative, index) => (
223
+ <OpenAPISchemaAlternative
224
+ key={`alternative-${index}`}
225
+ schema={alternative}
226
+ circularRefs={circularRefs}
227
+ context={context}
228
+ />
229
+ ))}
230
+ {parentCircularRef ? (
231
+ <OpenAPISchemaCircularRef id={parentCircularRef} schema={schema} />
232
+ ) : null}
233
+ </InteractiveSection>
234
+ );
235
+ }
236
+
196
237
  /**
197
238
  * Render a circular reference to a schema.
198
239
  */
@@ -336,13 +377,18 @@ function getSchemaProperties(schema: OpenAPIV3.SchemaObject): null | OpenAPISche
336
377
  return null;
337
378
  }
338
379
 
380
+ type OpenAPISchemaAlternatives = [
381
+ OpenAPIV3.SchemaObject[],
382
+ OpenAPIV3.DiscriminatorObject | undefined,
383
+ ];
384
+
339
385
  /**
340
386
  * Get the alternatives to display for a schema.
341
387
  */
342
388
  export function getSchemaAlternatives(
343
389
  schema: OpenAPIV3.SchemaObject,
344
- ancestors: Set<OpenAPIV3.SchemaObject> = new Set(),
345
- ): null | [OpenAPIV3.SchemaObject[], OpenAPIV3.DiscriminatorObject | undefined] {
390
+ ancestors: Set<OpenAPIV3.SchemaObject> = new Set()
391
+ ): null | OpenAPISchemaAlternatives {
346
392
  const downAncestors = new Set(ancestors).add(schema);
347
393
 
348
394
  if (schema.anyOf) {
@@ -363,14 +409,16 @@ export function getSchemaAlternatives(
363
409
  function flattenAlternatives(
364
410
  alternativeType: 'oneOf' | 'allOf' | 'anyOf',
365
411
  alternatives: OpenAPIV3.SchemaObject[],
366
- ancestors: Set<OpenAPIV3.SchemaObject>,
412
+ ancestors: Set<OpenAPIV3.SchemaObject>
367
413
  ): OpenAPIV3.SchemaObject[] {
368
414
  return alternatives.reduce((acc, alternative) => {
369
415
  if (!!alternative[alternativeType] && !ancestors.has(alternative)) {
370
- return [...acc, ...(getSchemaAlternatives(alternative, ancestors)?.[0] || [])];
416
+ acc.push(...(getSchemaAlternatives(alternative, ancestors)?.[0] || []));
417
+ } else {
418
+ acc.push(alternative);
371
419
  }
372
420
 
373
- return [...acc, alternative];
421
+ return acc;
374
422
  }, [] as OpenAPIV3.SchemaObject[]);
375
423
  }
376
424
 
@@ -378,7 +426,7 @@ export function getSchemaTitle(
378
426
  schema: OpenAPIV3.SchemaObject,
379
427
 
380
428
  /** If the title is inferred in a oneOf with discriminator, we can use it to optimize the title */
381
- discriminator?: OpenAPIV3.DiscriminatorObject,
429
+ discriminator?: OpenAPIV3.DiscriminatorObject
382
430
  ): string {
383
431
  // Try using the discriminator
384
432
  if (discriminator?.propertyName && schema.properties) {
@@ -406,7 +454,9 @@ export function getSchemaTitle(
406
454
  if (schema.format) {
407
455
  type += ` · ${schema.format}`;
408
456
  }
409
- } else if ('anyOf' in schema) {
457
+ }
458
+
459
+ if ('anyOf' in schema) {
410
460
  type = 'any of';
411
461
  } else if ('oneOf' in schema) {
412
462
  type = 'one of';
@@ -1,8 +1,9 @@
1
- import { OpenAPIV3 } from '@gitbook/openapi-parser';
1
+ import type { OpenAPIV3 } from '@gitbook/openapi-parser';
2
+ import type React from 'react';
2
3
 
3
4
  interface OpenAPISchemaNameProps {
4
5
  schema?: OpenAPIV3.SchemaObject;
5
- propertyName?: string | JSX.Element;
6
+ propertyName?: string | React.JSX.Element;
6
7
  required?: boolean;
7
8
  type?: string;
8
9
  }
@@ -11,7 +12,7 @@ interface OpenAPISchemaNameProps {
11
12
  * Display the schema name row.
12
13
  * It includes the property name, type, required and deprecated status.
13
14
  */
14
- export function OpenAPISchemaName(props: OpenAPISchemaNameProps): JSX.Element {
15
+ export function OpenAPISchemaName(props: OpenAPISchemaNameProps) {
15
16
  const { schema, type, propertyName, required } = props;
16
17
 
17
18
  const additionalItems = schema && getAdditionalItems(schema);
@@ -52,7 +53,7 @@ function getAdditionalItems(schema: OpenAPIV3.SchemaObject): string {
52
53
  }
53
54
 
54
55
  if (schema.nullable) {
55
- additionalItems = ` | nullable`;
56
+ additionalItems = ' | nullable';
56
57
  }
57
58
 
58
59
  return additionalItems;
@@ -1,8 +1,8 @@
1
1
  import type { OpenAPIV3_1 } from '@gitbook/openapi-parser';
2
- import type { OpenAPIClientContext, OpenAPIOperationData } from './types';
3
2
  import { InteractiveSection } from './InteractiveSection';
4
3
  import { Markdown } from './Markdown';
5
4
  import { OpenAPISchemaName } from './OpenAPISchemaName';
5
+ import type { OpenAPIClientContext, OpenAPIOperationData } from './types';
6
6
  import { resolveDescription } from './utils';
7
7
 
8
8
  /**
@@ -65,7 +65,7 @@ function getLabelForType(security: OpenAPIV3_1.SecuritySchemeObject) {
65
65
  return <OpenAPISchemaName propertyName="Authorization" type="string" required />;
66
66
  }
67
67
 
68
- if (security.scheme == 'bearer') {
68
+ if (security.scheme === 'bearer') {
69
69
  const description = resolveDescription(security);
70
70
  return (
71
71
  <>
@@ -73,7 +73,7 @@ function getLabelForType(security: OpenAPIV3_1.SecuritySchemeObject) {
73
73
  {/** Show a default description if none is provided */}
74
74
  {!description ? (
75
75
  <Markdown
76
- source={`Bearer authentication header of the form Bearer ${`&lt;token&gt;`}.`}
76
+ source={`Bearer authentication header of the form Bearer ${'&lt;token&gt;'}.`}
77
77
  className="openapi-securities-description"
78
78
  />
79
79
  ) : null}