@gitbook/react-openapi 0.7.0 → 1.0.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.
Files changed (115) hide show
  1. package/CHANGELOG.md +51 -0
  2. package/dist/InteractiveSection.d.ts +4 -6
  3. package/dist/InteractiveSection.jsx +96 -0
  4. package/dist/Markdown.d.ts +1 -2
  5. package/dist/Markdown.jsx +5 -0
  6. package/dist/OpenAPICodeSample.d.ts +2 -4
  7. package/dist/OpenAPICodeSample.jsx +143 -0
  8. package/dist/OpenAPIDisclosure.d.ts +12 -0
  9. package/dist/OpenAPIDisclosure.jsx +32 -0
  10. package/dist/OpenAPIDisclosureGroup.d.ts +19 -0
  11. package/dist/OpenAPIDisclosureGroup.jsx +81 -0
  12. package/dist/OpenAPIOperation.d.ts +2 -4
  13. package/dist/OpenAPIOperation.jsx +51 -0
  14. package/dist/OpenAPIOperationContext.d.ts +16 -0
  15. package/dist/OpenAPIOperationContext.jsx +26 -0
  16. package/dist/OpenAPIPath.d.ts +8 -0
  17. package/dist/OpenAPIPath.jsx +54 -0
  18. package/dist/OpenAPIRequestBody.d.ts +3 -4
  19. package/dist/OpenAPIRequestBody.jsx +19 -0
  20. package/dist/OpenAPIResponse.d.ts +4 -4
  21. package/dist/OpenAPIResponse.jsx +49 -0
  22. package/dist/OpenAPIResponseExample.d.ts +2 -4
  23. package/dist/OpenAPIResponseExample.jsx +108 -0
  24. package/dist/OpenAPIResponses.d.ts +3 -4
  25. package/dist/OpenAPIResponses.jsx +36 -0
  26. package/dist/OpenAPISchema.d.ts +11 -8
  27. package/dist/OpenAPISchema.jsx +295 -0
  28. package/dist/OpenAPISchemaName.d.ts +12 -0
  29. package/dist/OpenAPISchemaName.jsx +15 -0
  30. package/dist/OpenAPISecurities.d.ts +2 -4
  31. package/dist/OpenAPISecurities.jsx +55 -0
  32. package/dist/OpenAPIServerURL.d.ts +2 -3
  33. package/dist/OpenAPIServerURL.jsx +67 -0
  34. package/dist/OpenAPIServerURLVariable.d.ts +2 -3
  35. package/dist/OpenAPIServerURLVariable.jsx +8 -0
  36. package/dist/OpenAPISpec.d.ts +3 -4
  37. package/dist/OpenAPISpec.jsx +91 -0
  38. package/dist/OpenAPITabs.d.ts +25 -0
  39. package/dist/OpenAPITabs.jsx +67 -0
  40. package/dist/ScalarApiButton.d.ts +5 -2
  41. package/dist/ScalarApiButton.jsx +51 -0
  42. package/dist/code-samples.d.ts +4 -0
  43. package/dist/code-samples.js +103 -38
  44. package/dist/fetchOpenAPIOperation.d.ts +9 -54
  45. package/dist/fetchOpenAPIOperation.js +178 -107
  46. package/dist/generateSchemaExample.d.ts +2 -2
  47. package/dist/generateSchemaExample.js +28 -100
  48. package/dist/index.d.ts +3 -2
  49. package/dist/index.js +2 -1
  50. package/dist/resolveOpenAPIOperation.d.ts +11 -0
  51. package/dist/resolveOpenAPIOperation.js +194 -0
  52. package/dist/stringifyOpenAPI.d.ts +4 -0
  53. package/dist/stringifyOpenAPI.js +6 -0
  54. package/dist/tsconfig.build.tsbuildinfo +1 -0
  55. package/dist/tsconfig.tsbuildinfo +1 -1
  56. package/dist/types.d.ts +11 -12
  57. package/dist/utils.d.ts +6 -1
  58. package/dist/utils.js +15 -2
  59. package/package.json +12 -11
  60. package/src/InteractiveSection.tsx +119 -78
  61. package/src/Markdown.tsx +2 -3
  62. package/src/OpenAPICodeSample.tsx +35 -21
  63. package/src/OpenAPIDisclosure.tsx +50 -0
  64. package/src/OpenAPIDisclosureGroup.tsx +136 -0
  65. package/src/OpenAPIOperation.tsx +36 -42
  66. package/src/OpenAPIOperationContext.tsx +45 -0
  67. package/src/OpenAPIPath.tsx +65 -0
  68. package/src/OpenAPIRequestBody.tsx +3 -14
  69. package/src/OpenAPIResponse.tsx +39 -43
  70. package/src/OpenAPIResponseExample.tsx +89 -31
  71. package/src/OpenAPIResponses.tsx +51 -15
  72. package/src/OpenAPISchema.test.ts +1 -1
  73. package/src/OpenAPISchema.tsx +124 -92
  74. package/src/OpenAPISchemaName.tsx +27 -0
  75. package/src/OpenAPISecurities.tsx +45 -24
  76. package/src/OpenAPIServerURL.tsx +17 -10
  77. package/src/OpenAPIServerURLVariable.tsx +2 -4
  78. package/src/OpenAPISpec.tsx +56 -53
  79. package/src/OpenAPITabs.tsx +113 -0
  80. package/src/ScalarApiButton.tsx +86 -6
  81. package/src/code-samples.test.ts +51 -0
  82. package/src/code-samples.ts +95 -31
  83. package/src/generateSchemaExample.ts +25 -151
  84. package/src/index.ts +3 -2
  85. package/src/resolveOpenAPIOperation.test.ts +177 -0
  86. package/src/resolveOpenAPIOperation.ts +163 -0
  87. package/src/stringifyOpenAPI.ts +6 -0
  88. package/src/types.ts +17 -10
  89. package/src/utils.ts +17 -2
  90. package/dist/InteractiveSection.js +0 -47
  91. package/dist/Markdown.js +0 -6
  92. package/dist/OpenAPICodeSample.js +0 -110
  93. package/dist/OpenAPIOperation.js +0 -38
  94. package/dist/OpenAPIRequestBody.js +0 -18
  95. package/dist/OpenAPIResponse.js +0 -32
  96. package/dist/OpenAPIResponseExample.js +0 -54
  97. package/dist/OpenAPIResponses.js +0 -18
  98. package/dist/OpenAPISchema.js +0 -235
  99. package/dist/OpenAPISchema.test.d.ts +0 -1
  100. package/dist/OpenAPISchema.test.js +0 -91
  101. package/dist/OpenAPISecurities.js +0 -42
  102. package/dist/OpenAPIServerURL.js +0 -51
  103. package/dist/OpenAPIServerURLVariable.js +0 -10
  104. package/dist/OpenAPISpec.js +0 -70
  105. package/dist/ScalarApiButton.js +0 -14
  106. package/dist/fetchOpenAPIOperation.test.d.ts +0 -1
  107. package/dist/fetchOpenAPIOperation.test.js +0 -152
  108. package/dist/resolveOpenAPIPath.d.ts +0 -7
  109. package/dist/resolveOpenAPIPath.js +0 -112
  110. package/dist/resolveOpenAPIPath.test.d.ts +0 -1
  111. package/dist/resolveOpenAPIPath.test.js +0 -39
  112. package/src/fetchOpenAPIOperation.test.ts +0 -185
  113. package/src/fetchOpenAPIOperation.ts +0 -230
  114. package/src/resolveOpenAPIPath.test.ts +0 -60
  115. package/src/resolveOpenAPIPath.ts +0 -145
@@ -1,110 +0,0 @@
1
- import * as React from 'react';
2
- import { codeSampleGenerators } from './code-samples';
3
- import { generateMediaTypeExample, generateSchemaExample } from './generateSchemaExample';
4
- import { InteractiveSection } from './InteractiveSection';
5
- import { getServersURL } from './OpenAPIServerURL';
6
- import { ScalarApiButton } from './ScalarApiButton';
7
- import { noReference } from './utils';
8
- /**
9
- * Display code samples to execute the operation.
10
- * It supports the Redocly custom syntax as well (https://redocly.com/docs/api-reference-docs/specification-extensions/x-code-samples/)
11
- */
12
- export function OpenAPICodeSample(props) {
13
- const { data, context } = props;
14
- const searchParams = new URLSearchParams();
15
- const headersObject = {};
16
- data.operation.parameters?.forEach((rawParam) => {
17
- const param = noReference(rawParam);
18
- if (!param) {
19
- return;
20
- }
21
- if (param.in === 'header' && param.required) {
22
- const example = param.schema
23
- ? generateSchemaExample(noReference(param.schema))
24
- : undefined;
25
- if (example !== undefined) {
26
- headersObject[param.name] =
27
- typeof example !== 'string' ? JSON.stringify(example) : example;
28
- }
29
- }
30
- else if (param.in === 'query' && param.required) {
31
- const example = param.schema
32
- ? generateSchemaExample(noReference(param.schema))
33
- : undefined;
34
- if (example !== undefined) {
35
- searchParams.append(param.name, String(Array.isArray(example) ? example[0] : example));
36
- }
37
- }
38
- });
39
- const requestBody = noReference(data.operation.requestBody);
40
- const requestBodyContent = requestBody ? Object.entries(requestBody.content)[0] : undefined;
41
- const input = {
42
- url: getServersURL(data.servers) +
43
- data.path +
44
- (searchParams.size ? `?${searchParams.toString()}` : ''),
45
- method: data.method,
46
- body: requestBodyContent
47
- ? generateMediaTypeExample(requestBodyContent[1], { onlyRequired: true })
48
- : undefined,
49
- headers: {
50
- ...getSecurityHeaders(data.securities),
51
- ...headersObject,
52
- ...(requestBodyContent
53
- ? {
54
- 'Content-Type': requestBodyContent[0],
55
- }
56
- : undefined),
57
- },
58
- };
59
- const autoCodeSamples = codeSampleGenerators.map((generator) => ({
60
- key: `default-${generator.id}`,
61
- label: generator.label,
62
- body: React.createElement(context.CodeBlock, { code: generator.generate(input), syntax: generator.syntax }),
63
- }));
64
- // Use custom samples if defined
65
- let customCodeSamples = null;
66
- ['x-custom-examples', 'x-code-samples', 'x-codeSamples'].forEach((key) => {
67
- const customSamples = data.operation[key];
68
- if (customSamples && Array.isArray(customSamples)) {
69
- customCodeSamples = customSamples
70
- .filter((sample) => {
71
- return (typeof sample.label === 'string' &&
72
- typeof sample.source === 'string' &&
73
- typeof sample.lang === 'string');
74
- })
75
- .map((sample) => ({
76
- key: `redocly-${sample.lang}`,
77
- label: sample.label,
78
- body: React.createElement(context.CodeBlock, { code: sample.source, syntax: sample.lang }),
79
- }));
80
- }
81
- });
82
- // Code samples can be disabled at the top-level or at the operation level
83
- // If code samples are defined at the operation level, it will override the top-level setting
84
- const codeSamplesDisabled = data['x-codeSamples'] === false || data.operation['x-codeSamples'] === false;
85
- const samples = customCodeSamples ?? (!codeSamplesDisabled ? autoCodeSamples : []);
86
- if (samples.length === 0) {
87
- return null;
88
- }
89
- return (React.createElement(InteractiveSection, { header: "Request", className: "openapi-codesample", tabs: samples, overlay: data['x-hideTryItPanel'] || data.operation['x-hideTryItPanel'] ? null : (React.createElement(ScalarApiButton, null)) }));
90
- }
91
- function getSecurityHeaders(securities) {
92
- const security = securities[0];
93
- if (!security) {
94
- return {};
95
- }
96
- switch (security[1].type) {
97
- case 'http': {
98
- let scheme = security[1].scheme;
99
- if (scheme === 'bearer') {
100
- scheme = 'Bearer';
101
- }
102
- return {
103
- Authorization: scheme + ' ' + (security[1].bearerFormat ?? '<token>'),
104
- };
105
- }
106
- default: {
107
- return {};
108
- }
109
- }
110
- }
@@ -1,38 +0,0 @@
1
- import * as React from 'react';
2
- import classNames from 'classnames';
3
- import { ApiClientModalProvider } from '@scalar/api-client-react';
4
- import { toJSON } from './fetchOpenAPIOperation';
5
- import { Markdown } from './Markdown';
6
- import { OpenAPICodeSample } from './OpenAPICodeSample';
7
- import { OpenAPIResponseExample } from './OpenAPIResponseExample';
8
- import { OpenAPIServerURL } from './OpenAPIServerURL';
9
- import { OpenAPISpec } from './OpenAPISpec';
10
- /**
11
- * Display an interactive OpenAPI operation.
12
- */
13
- export function OpenAPIOperation(props) {
14
- const { className, data, context } = props;
15
- const { operation, servers, method, path } = data;
16
- const clientContext = {
17
- defaultInteractiveOpened: context.defaultInteractiveOpened,
18
- icons: context.icons,
19
- blockKey: context.blockKey,
20
- };
21
- return (React.createElement(ApiClientModalProvider, { configuration: { spec: { url: context.specUrl } }, initialRequest: { path: data.path, method: data.method } },
22
- React.createElement("div", { className: classNames('openapi-operation', className) },
23
- React.createElement("div", { className: "openapi-intro" },
24
- React.createElement("h2", { className: "openapi-summary", id: context.id }, operation.summary),
25
- operation.description ? (React.createElement(Markdown, { className: "openapi-description", source: operation.description })) : null,
26
- React.createElement("div", { className: "openapi-target" },
27
- React.createElement("span", { className: classNames('openapi-method', `openapi-method-${method.toLowerCase()}`) }, method.toUpperCase()),
28
- React.createElement("span", { className: "openapi-url" },
29
- React.createElement(OpenAPIServerURL, { servers: servers }),
30
- path))),
31
- React.createElement("div", { className: classNames('openapi-columns') },
32
- React.createElement("div", { className: classNames('openapi-column-spec') },
33
- React.createElement(OpenAPISpec, { rawData: toJSON(data), context: clientContext })),
34
- React.createElement("div", { className: classNames('openapi-column-preview') },
35
- React.createElement("div", { className: classNames('openapi-column-preview-body') },
36
- React.createElement(OpenAPICodeSample, { ...props }),
37
- React.createElement(OpenAPIResponseExample, { ...props })))))));
38
- }
@@ -1,18 +0,0 @@
1
- import * as React from 'react';
2
- import { OpenAPIRootSchema } from './OpenAPISchema';
3
- import { noReference } from './utils';
4
- import { InteractiveSection } from './InteractiveSection';
5
- import { Markdown } from './Markdown';
6
- /**
7
- * Display an interactive request body.
8
- */
9
- export function OpenAPIRequestBody(props) {
10
- const { requestBody, context } = props;
11
- return (React.createElement(InteractiveSection, { header: "Body", className: "openapi-requestbody", tabs: Object.entries(requestBody.content ?? {}).map(([contentType, mediaTypeObject]) => {
12
- return {
13
- key: contentType,
14
- label: contentType,
15
- body: (React.createElement(OpenAPIRootSchema, { schema: noReference(mediaTypeObject.schema) ?? {}, context: context })),
16
- };
17
- }), defaultOpened: context.defaultInteractiveOpened }, requestBody.description ? (React.createElement(Markdown, { source: requestBody.description, className: "openapi-requestbody-description" })) : null));
18
- }
@@ -1,32 +0,0 @@
1
- import * as React from 'react';
2
- import classNames from 'classnames';
3
- import { OpenAPIRootSchema, OpenAPISchemaProperties } from './OpenAPISchema';
4
- import { noReference } from './utils';
5
- import { InteractiveSection } from './InteractiveSection';
6
- import { Markdown } from './Markdown';
7
- /**
8
- * Display an interactive response body.
9
- */
10
- export function OpenAPIResponse(props) {
11
- const { response, context } = props;
12
- const content = Object.entries(response.content ?? {});
13
- const headers = Object.entries(response.headers ?? {}).map(([name, header]) => [name, noReference(header) ?? {}]);
14
- if (content.length === 0 && !response.description && headers.length === 0) {
15
- return null;
16
- }
17
- return (React.createElement(React.Fragment, null,
18
- response.description ? (React.createElement(Markdown, { source: response.description, className: "openapi-response-description" })) : null,
19
- headers.length > 0 ? (React.createElement(InteractiveSection, { toggeable: true, defaultOpened: !!context.defaultInteractiveOpened, toggleCloseIcon: context.icons.chevronDown, toggleOpenIcon: context.icons.chevronRight, header: "Headers", className: classNames('openapi-responseheaders') },
20
- React.createElement(OpenAPISchemaProperties, { properties: headers.map(([name, header]) => ({
21
- propertyName: name,
22
- schema: noReference(header.schema) ?? {},
23
- required: header.required,
24
- })), context: context }))) : null,
25
- content.length > 0 ? (React.createElement(InteractiveSection, { header: "Body", className: classNames('openapi-responsebody'), tabs: content.map(([contentType, mediaType]) => {
26
- return {
27
- key: contentType,
28
- label: contentType,
29
- body: (React.createElement(OpenAPIRootSchema, { schema: noReference(mediaType.schema) ?? {}, context: context })),
30
- };
31
- }) })) : null));
32
- }
@@ -1,54 +0,0 @@
1
- import * as React from 'react';
2
- import { InteractiveSection } from './InteractiveSection';
3
- import { generateSchemaExample } from './generateSchemaExample';
4
- import { createStateKey, noReference } from './utils';
5
- /**
6
- * Display an example of the response content.
7
- */
8
- export function OpenAPIResponseExample(props) {
9
- const { data, context } = props;
10
- // if there are no responses defined for the operation
11
- if (!data.operation.responses) {
12
- return null;
13
- }
14
- const responses = Object.entries(data.operation.responses);
15
- // Sort response to get 200, and 2xx first
16
- responses.sort(([a], [b]) => {
17
- if (a === 'default') {
18
- return 1;
19
- }
20
- if (b === 'default') {
21
- return -1;
22
- }
23
- if (a === '200') {
24
- return -1;
25
- }
26
- if (b === '200') {
27
- return 1;
28
- }
29
- return Number(a) - Number(b);
30
- });
31
- const examples = responses
32
- .map((response) => {
33
- const responseObject = noReference(response[1]);
34
- const schema = noReference((responseObject.content?.['application/json'] ??
35
- responseObject.content?.[Object.keys(responseObject.content)[0]])?.schema);
36
- if (!schema) {
37
- return null;
38
- }
39
- const example = generateSchemaExample(schema);
40
- if (example === undefined) {
41
- return null;
42
- }
43
- return {
44
- key: `${response[0]}`,
45
- label: `${response[0]}`,
46
- body: (React.createElement(context.CodeBlock, { code: typeof example === 'string' ? example : JSON.stringify(example, null, 2), syntax: "json" })),
47
- };
48
- })
49
- .filter((val) => Boolean(val));
50
- if (examples.length === 0) {
51
- return null;
52
- }
53
- return (React.createElement(InteractiveSection, { stateKey: createStateKey('response', context.blockKey), header: "Response", className: "openapi-response-example", tabs: examples }));
54
- }
@@ -1,18 +0,0 @@
1
- import * as React from 'react';
2
- import classNames from 'classnames';
3
- import { createStateKey, noReference } from './utils';
4
- import { OpenAPIResponse } from './OpenAPIResponse';
5
- import { InteractiveSection } from './InteractiveSection';
6
- /**
7
- * Display an interactive response body.
8
- */
9
- export function OpenAPIResponses(props) {
10
- const { responses, context } = props;
11
- return (React.createElement(InteractiveSection, { stateKey: createStateKey('response', context.blockKey), header: "Response", className: classNames('openapi-responses'), tabs: Object.entries(responses).map(([statusCode, response]) => {
12
- return {
13
- key: statusCode,
14
- label: statusCode,
15
- body: React.createElement(OpenAPIResponse, { response: noReference(response), context: context }),
16
- };
17
- }) }));
18
- }
@@ -1,235 +0,0 @@
1
- import classNames from 'classnames';
2
- import React, { useId } from 'react';
3
- import { InteractiveSection } from './InteractiveSection';
4
- import { Markdown } from './Markdown';
5
- import { SYMBOL_REF_RESOLVED } from './resolveOpenAPIPath';
6
- import { noReference } from './utils';
7
- /**
8
- * Render a property of an OpenAPI schema.
9
- */
10
- export function OpenAPISchemaProperty(props) {
11
- const { propertyName, required, schema, circularRefs: parentCircularRefs = new Map(), context, className, } = props;
12
- const id = useId();
13
- const parentCircularRef = parentCircularRefs.get(schema);
14
- const circularRefs = new Map(parentCircularRefs).set(schema, id);
15
- // Avoid recursing infinitely, and instead render a link to the parent schema
16
- const properties = parentCircularRef ? null : getSchemaProperties(schema);
17
- const alternatives = parentCircularRef
18
- ? null
19
- : getSchemaAlternatives(schema, new Set(circularRefs.keys()));
20
- const shouldDisplayExample = (schema) => {
21
- return (typeof schema.example === 'string' ||
22
- typeof schema.example === 'number' ||
23
- typeof schema.example === 'boolean');
24
- };
25
- return (React.createElement(InteractiveSection, { id: id, className: classNames('openapi-schema', className), toggeable: !!properties || !!alternatives, defaultOpened: !!context.defaultInteractiveOpened, toggleOpenIcon: context.icons.chevronRight, toggleCloseIcon: context.icons.chevronDown, tabs: alternatives?.[0].map((alternative, index) => ({
26
- key: `${index}`,
27
- label: getSchemaTitle(alternative, alternatives[1]),
28
- body: circularRefs.has(alternative) ? (React.createElement(OpenAPISchemaCircularRef, { id: circularRefs.get(alternative), schema: alternative })) : (React.createElement(OpenAPISchemaAlternative, { schema: alternative, circularRefs: circularRefs, context: context })),
29
- })), header: React.createElement("div", { className: classNames('openapi-schema-presentation') },
30
- React.createElement("div", { className: classNames('openapi-schema-name') },
31
- propertyName ? (React.createElement("span", { className: classNames('openapi-schema-propertyname') }, propertyName)) : null,
32
- required ? (React.createElement("span", { className: classNames('openapi-schema-required') }, "*")) : null,
33
- React.createElement("span", { className: classNames('openapi-schema-type') }, getSchemaTitle(schema))),
34
- schema.description ? (React.createElement(Markdown, { source: schema.description, className: "openapi-schema-description" })) : null,
35
- shouldDisplayExample(schema) ? (React.createElement("span", { className: "openapi-schema-example" },
36
- "Example: ",
37
- React.createElement("code", null, JSON.stringify(schema.example)))) : null,
38
- schema.pattern ? (React.createElement("div", { className: "openapi-schema-pattern" },
39
- "Pattern: ",
40
- React.createElement("code", null, schema.pattern))) : null) }, (properties && properties.length > 0) ||
41
- (schema.enum && schema.enum.length > 0) ||
42
- parentCircularRef ? (React.createElement(React.Fragment, null,
43
- properties?.length ? (React.createElement(OpenAPISchemaProperties, { properties: properties, circularRefs: circularRefs, context: context })) : null,
44
- schema.enum && schema.enum.length > 0 ? (React.createElement(OpenAPISchemaEnum, { enumValues: schema.enum })) : null,
45
- parentCircularRef ? (React.createElement(OpenAPISchemaCircularRef, { id: parentCircularRef, schema: schema })) : null)) : null));
46
- }
47
- /**
48
- * Render a set of properties of an OpenAPI schema.
49
- */
50
- export function OpenAPISchemaProperties(props) {
51
- const { id, properties, circularRefs, context } = props;
52
- if (!properties.length) {
53
- return null;
54
- }
55
- return (React.createElement("div", { id: id, className: classNames('openapi-schema-properties') }, properties.map((property) => (React.createElement(OpenAPISchemaProperty, { key: property.propertyName, circularRefs: circularRefs, ...property, context: context })))));
56
- }
57
- /**
58
- * Render a root schema (such as the request body or response body).
59
- */
60
- export function OpenAPIRootSchema(props) {
61
- const { schema, context } = props;
62
- // Avoid recursing infinitely, and instead render a link to the parent schema
63
- const properties = getSchemaProperties(schema);
64
- if (properties && properties.length > 0) {
65
- return React.createElement(OpenAPISchemaProperties, { properties: properties, context: context });
66
- }
67
- return (React.createElement(OpenAPISchemaProperty, { schema: schema, context: context, className: "openapi-schema-root" }));
68
- }
69
- /**
70
- * Render a tab for an alternative schema.
71
- * It renders directly the properties if relevant;
72
- * for primitives, it renders the schema itself.
73
- */
74
- function OpenAPISchemaAlternative(props) {
75
- const { schema, circularRefs, context } = props;
76
- const id = useId();
77
- const subProperties = getSchemaProperties(schema);
78
- return (React.createElement(OpenAPISchemaProperties, { id: id, properties: subProperties ?? [{ schema }], circularRefs: subProperties ? new Map(circularRefs).set(schema, id) : circularRefs, context: context }));
79
- }
80
- /**
81
- * Render a circular reference to a schema.
82
- */
83
- function OpenAPISchemaCircularRef(props) {
84
- const { id, schema } = props;
85
- return (React.createElement("div", { className: "openapi-schema-circular" },
86
- "Circular reference to ",
87
- React.createElement("a", { href: `#${id}` }, getSchemaTitle(schema)),
88
- ' ',
89
- React.createElement("span", { className: "openapi-schema-circular-glyph" }, "\u21A9")));
90
- }
91
- /**
92
- * Render the enum value for a schema.
93
- */
94
- export function OpenAPISchemaEnum(props) {
95
- const { enumValues } = props;
96
- return (React.createElement("div", { className: "openapi-schema-enum" }, enumValues.map((value, index) => (React.createElement("span", { key: index, className: "openapi-schema-enum-value" }, `${value}`)))));
97
- }
98
- /**
99
- * Get the sub-properties of a schema.
100
- */
101
- function getSchemaProperties(schema) {
102
- if (schema.allOf) {
103
- return schema.allOf.reduce((acc, subSchema) => {
104
- const properties = getSchemaProperties(noReference(subSchema)) ?? [
105
- {
106
- schema: noReference(subSchema),
107
- },
108
- ];
109
- return [...acc, ...properties];
110
- }, []);
111
- }
112
- // check array AND schema.items as this is sometimes null despite what the type indicates
113
- if (schema.type === 'array' && !!schema.items) {
114
- const items = noReference(schema.items);
115
- const itemProperties = getSchemaProperties(items);
116
- if (itemProperties) {
117
- return itemProperties;
118
- }
119
- return [
120
- {
121
- propertyName: 'items',
122
- schema: items,
123
- },
124
- ];
125
- }
126
- if (schema.type === 'object' || schema.properties) {
127
- const result = [];
128
- if (schema.properties) {
129
- Object.entries(schema.properties).forEach(([propertyName, rawPropertySchema]) => {
130
- const propertySchema = noReference(rawPropertySchema);
131
- if (propertySchema.deprecated) {
132
- return;
133
- }
134
- result.push({
135
- propertyName,
136
- required: Array.isArray(schema.required)
137
- ? schema.required.includes(propertyName)
138
- : undefined,
139
- schema: propertySchema,
140
- });
141
- });
142
- }
143
- if (schema.additionalProperties) {
144
- const additionalProperties = noReference(schema.additionalProperties);
145
- result.push({
146
- propertyName: 'Other properties',
147
- schema: additionalProperties === true ? {} : additionalProperties,
148
- });
149
- }
150
- return result;
151
- }
152
- return null;
153
- }
154
- /**
155
- * Get the alternatives to display for a schema.
156
- */
157
- export function getSchemaAlternatives(schema, ancestors = new Set()) {
158
- const downAncestors = new Set(ancestors).add(schema);
159
- if (schema.anyOf) {
160
- return [
161
- flattenAlternatives('anyOf', schema.anyOf.map(noReference), downAncestors),
162
- noReference(schema.discriminator),
163
- ];
164
- }
165
- if (schema.oneOf) {
166
- return [
167
- flattenAlternatives('oneOf', schema.oneOf.map(noReference), downAncestors),
168
- noReference(schema.discriminator),
169
- ];
170
- }
171
- if (schema.allOf) {
172
- // allOf is managed in `getSchemaProperties`
173
- return null;
174
- }
175
- return null;
176
- }
177
- function flattenAlternatives(alternativeType, alternatives, ancestors) {
178
- return alternatives.reduce((acc, alternative) => {
179
- if (!!alternative[alternativeType] && !ancestors.has(alternative)) {
180
- return [...acc, ...(getSchemaAlternatives(alternative, ancestors)?.[0] || [])];
181
- }
182
- return [...acc, alternative];
183
- }, []);
184
- }
185
- function getSchemaTitle(schema,
186
- /** If the title is inferred in a oneOf with discriminator, we can use it to optimize the title */
187
- discriminator) {
188
- if (schema.title) {
189
- // If the schema has a title, use it
190
- return schema.title;
191
- }
192
- // Try using the discriminator
193
- if (discriminator && schema.properties) {
194
- const discriminatorProperty = noReference(schema.properties[discriminator.propertyName]);
195
- if (discriminatorProperty) {
196
- if (discriminatorProperty.enum) {
197
- return discriminatorProperty.enum.map((value) => value.toString()).join(' | ');
198
- }
199
- }
200
- }
201
- // Otherwise try to infer a nice title
202
- let type = 'any';
203
- if (schema.enum) {
204
- type = 'enum';
205
- // check array AND schema.items as this is sometimes null despite what the type indicates
206
- }
207
- else if (schema.type === 'array' && !!schema.items) {
208
- type = `array of ${getSchemaTitle(noReference(schema.items))}`;
209
- }
210
- else if (schema.type || schema.properties) {
211
- type = schema.type ?? 'object';
212
- if (schema.format) {
213
- type += ` (${schema.format})`;
214
- }
215
- }
216
- else if ('anyOf' in schema) {
217
- type = 'any of';
218
- }
219
- else if ('oneOf' in schema) {
220
- type = 'one of';
221
- }
222
- else if ('allOf' in schema) {
223
- type = 'all of';
224
- }
225
- else if ('not' in schema) {
226
- type = 'not';
227
- }
228
- if (SYMBOL_REF_RESOLVED in schema) {
229
- type = `${schema[SYMBOL_REF_RESOLVED]} (${type})`;
230
- }
231
- if (schema.nullable) {
232
- type = `nullable ${type}`;
233
- }
234
- return type;
235
- }
@@ -1 +0,0 @@
1
- export {};
@@ -1,91 +0,0 @@
1
- import { it, describe, expect } from 'bun:test';
2
- import { getSchemaAlternatives } from './OpenAPISchema';
3
- describe('getSchemaAlternatives', () => {
4
- it('should flatten oneOf', () => {
5
- expect(getSchemaAlternatives({
6
- oneOf: [
7
- {
8
- oneOf: [
9
- {
10
- type: 'number',
11
- },
12
- {
13
- type: 'boolean',
14
- },
15
- ],
16
- },
17
- {
18
- type: 'string',
19
- },
20
- ],
21
- })).toEqual([
22
- [
23
- {
24
- type: 'number',
25
- },
26
- {
27
- type: 'boolean',
28
- },
29
- {
30
- type: 'string',
31
- },
32
- ],
33
- undefined,
34
- ]);
35
- });
36
- it('should not flatten oneOf and allOf', () => {
37
- expect(getSchemaAlternatives({
38
- oneOf: [
39
- {
40
- allOf: [
41
- {
42
- type: 'number',
43
- },
44
- {
45
- type: 'boolean',
46
- },
47
- ],
48
- },
49
- {
50
- type: 'string',
51
- },
52
- ],
53
- })).toEqual([
54
- [
55
- {
56
- allOf: [
57
- {
58
- type: 'number',
59
- },
60
- {
61
- type: 'boolean',
62
- },
63
- ],
64
- },
65
- {
66
- type: 'string',
67
- },
68
- ],
69
- undefined,
70
- ]);
71
- });
72
- it('should stop at circular references', () => {
73
- const a = {
74
- anyOf: [
75
- {
76
- type: 'string',
77
- },
78
- ],
79
- };
80
- a.anyOf.push(a);
81
- expect(getSchemaAlternatives(a)).toEqual([
82
- [
83
- {
84
- type: 'string',
85
- },
86
- a,
87
- ],
88
- undefined,
89
- ]);
90
- });
91
- });
@@ -1,42 +0,0 @@
1
- import * as React from 'react';
2
- import { InteractiveSection } from './InteractiveSection';
3
- import { Markdown } from './Markdown';
4
- /**
5
- * Present securities authorization that can be used for this operation.
6
- */
7
- export function OpenAPISecurities(props) {
8
- const { securities, context } = props;
9
- if (securities.length === 0) {
10
- return null;
11
- }
12
- return (React.createElement(InteractiveSection, { header: "Authorization", className: "openapi-securities", toggeable: true, defaultOpened: false, toggleCloseIcon: context.icons.chevronDown, toggleOpenIcon: context.icons.chevronRight, tabs: securities.map(([key, security]) => {
13
- return {
14
- key: key,
15
- label: key,
16
- body: (React.createElement(React.Fragment, null,
17
- React.createElement("p", { className: "openapi-securities-label" }, getLabelForType(security)),
18
- security.description ? (React.createElement(Markdown, { source: security.description, className: "openapi-securities-description" })) : null)),
19
- };
20
- }) }));
21
- }
22
- function getLabelForType(security) {
23
- switch (security.type) {
24
- case 'apiKey':
25
- return 'API Key';
26
- case 'http':
27
- if (security.scheme === 'basic') {
28
- return 'Basic Auth';
29
- }
30
- if (security.scheme == 'bearer') {
31
- return `Bearer Token ${security.bearerFormat ? `(${security.bearerFormat})` : ''}`;
32
- }
33
- return 'HTTP';
34
- case 'oauth2':
35
- return 'OAuth2';
36
- case 'openIdConnect':
37
- return 'OpenID Connect';
38
- default:
39
- // @ts-ignore
40
- return security.type;
41
- }
42
- }