@gitbook/react-openapi 1.4.3 → 1.5.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.
Files changed (263) hide show
  1. package/CHANGELOG.md +36 -0
  2. package/dist/InteractiveSection.js +59 -0
  3. package/dist/Markdown.js +10 -0
  4. package/dist/OpenAPICodeSample.js +219 -0
  5. package/dist/OpenAPICodeSampleInteractive.js +66 -0
  6. package/dist/OpenAPICodeSampleSelector.js +45 -0
  7. package/dist/OpenAPICopyButton.js +39 -0
  8. package/dist/OpenAPIDisclosure.js +30 -0
  9. package/dist/OpenAPIDisclosureGroup.js +75 -0
  10. package/dist/OpenAPIExample.js +41 -0
  11. package/dist/OpenAPIMediaType.js +58 -0
  12. package/dist/OpenAPIOperation.d.ts +12 -7
  13. package/dist/OpenAPIOperation.js +30 -0
  14. package/dist/OpenAPIOperationContext.d.ts +10 -6
  15. package/dist/OpenAPIOperationContext.js +30 -0
  16. package/dist/OpenAPIPath.js +51 -0
  17. package/dist/OpenAPIPrefillContextProvider.d.ts +11 -7
  18. package/dist/OpenAPIPrefillContextProvider.js +25 -0
  19. package/dist/OpenAPIRequestBody.js +28 -0
  20. package/dist/OpenAPIRequestBodyHeaderType.js +23 -0
  21. package/dist/OpenAPIResponse.js +39 -0
  22. package/dist/OpenAPIResponseExample.js +75 -0
  23. package/dist/OpenAPIResponseExampleContent.js +61 -0
  24. package/dist/OpenAPIResponses.js +61 -0
  25. package/dist/OpenAPISchema.js +373 -0
  26. package/dist/OpenAPISchemaName.js +45 -0
  27. package/dist/OpenAPISchemaServer.js +13 -0
  28. package/dist/OpenAPISecurities.js +124 -0
  29. package/dist/OpenAPISelect.js +45 -0
  30. package/dist/OpenAPISpec.js +73 -0
  31. package/dist/OpenAPIWebhook.d.ts +12 -7
  32. package/dist/OpenAPIWebhook.js +28 -0
  33. package/dist/OpenAPIWebhookExample.js +40 -0
  34. package/dist/ScalarApiButton.js +87 -0
  35. package/dist/StaticSection.js +37 -0
  36. package/dist/code-samples.js +267 -419
  37. package/dist/common/OpenAPIColumnSpec.js +23 -0
  38. package/dist/common/OpenAPIOperationDescription.js +18 -0
  39. package/dist/common/OpenAPIStability.js +17 -0
  40. package/dist/common/OpenAPISummary.js +27 -0
  41. package/dist/contentTypeChecks.js +24 -20
  42. package/dist/context.d.ts +68 -72
  43. package/dist/context.js +25 -39
  44. package/dist/decycle.js +39 -68
  45. package/dist/dereference.js +20 -64
  46. package/dist/generateSchemaExample.js +188 -332
  47. package/dist/getDisclosureLabel.js +15 -16
  48. package/dist/getOrCreateStoreByKey.js +20 -17
  49. package/dist/index.d.ts +12 -10
  50. package/dist/index.js +11 -8
  51. package/dist/json2xml.js +10 -5
  52. package/dist/resolveOpenAPIOperation.d.ts +11 -7
  53. package/dist/resolveOpenAPIOperation.js +88 -159
  54. package/dist/resolveOpenAPIWebhook.d.ts +11 -7
  55. package/dist/resolveOpenAPIWebhook.js +41 -116
  56. package/dist/schemas/OpenAPISchemaItem.js +26 -0
  57. package/dist/schemas/OpenAPISchemas.d.ts +16 -11
  58. package/dist/schemas/OpenAPISchemas.js +57 -0
  59. package/dist/schemas/resolveOpenAPISchemas.d.ts +9 -4
  60. package/dist/schemas/resolveOpenAPISchemas.js +15 -59
  61. package/dist/stringifyOpenAPI.js +12 -13
  62. package/dist/translate.js +43 -0
  63. package/dist/translations/de.js +47 -42
  64. package/dist/translations/en.d.ts +46 -42
  65. package/dist/translations/en.js +47 -42
  66. package/dist/translations/es.js +47 -42
  67. package/dist/translations/fr.js +47 -42
  68. package/dist/translations/index.d.ts +404 -391
  69. package/dist/translations/index.js +28 -24
  70. package/dist/translations/ja.js +47 -42
  71. package/dist/translations/nl.js +47 -42
  72. package/dist/translations/no.js +47 -42
  73. package/dist/translations/pt-br.js +47 -42
  74. package/dist/translations/types.d.ts +7 -5
  75. package/dist/translations/zh.js +47 -42
  76. package/dist/types.d.ts +30 -24
  77. package/dist/util/example.js +84 -0
  78. package/dist/util/server.js +32 -38
  79. package/dist/util/tryit-prefill.js +135 -121
  80. package/dist/utils.js +135 -196
  81. package/package.json +18 -11
  82. package/dist/InteractiveSection.d.ts +0 -33
  83. package/dist/InteractiveSection.jsx +0 -61
  84. package/dist/Markdown.d.ts +0 -4
  85. package/dist/Markdown.jsx +0 -5
  86. package/dist/OpenAPICodeSample.d.ts +0 -19
  87. package/dist/OpenAPICodeSample.jsx +0 -230
  88. package/dist/OpenAPICodeSampleInteractive.d.ts +0 -14
  89. package/dist/OpenAPICodeSampleInteractive.jsx +0 -73
  90. package/dist/OpenAPICodeSampleSelector.d.ts +0 -14
  91. package/dist/OpenAPICodeSampleSelector.jsx +0 -44
  92. package/dist/OpenAPICopyButton.d.ts +0 -13
  93. package/dist/OpenAPICopyButton.jsx +0 -35
  94. package/dist/OpenAPIDisclosure.d.ts +0 -11
  95. package/dist/OpenAPIDisclosure.jsx +0 -30
  96. package/dist/OpenAPIDisclosureGroup.d.ts +0 -23
  97. package/dist/OpenAPIDisclosureGroup.jsx +0 -83
  98. package/dist/OpenAPIExample.d.ts +0 -16
  99. package/dist/OpenAPIExample.jsx +0 -36
  100. package/dist/OpenAPIMediaType.d.ts +0 -21
  101. package/dist/OpenAPIMediaType.jsx +0 -61
  102. package/dist/OpenAPIOperation.jsx +0 -25
  103. package/dist/OpenAPIOperationContext.jsx +0 -26
  104. package/dist/OpenAPIOperationDescription.d.ts +0 -9
  105. package/dist/OpenAPIOperationDescription.jsx +0 -22
  106. package/dist/OpenAPIOperationStability.d.ts +0 -9
  107. package/dist/OpenAPIOperationStability.jsx +0 -27
  108. package/dist/OpenAPIPath.d.ts +0 -18
  109. package/dist/OpenAPIPath.jsx +0 -55
  110. package/dist/OpenAPIPrefillContextProvider.jsx +0 -19
  111. package/dist/OpenAPIRequestBody.d.ts +0 -11
  112. package/dist/OpenAPIRequestBody.jsx +0 -28
  113. package/dist/OpenAPIRequestBodyHeaderType.d.ts +0 -8
  114. package/dist/OpenAPIRequestBodyHeaderType.jsx +0 -25
  115. package/dist/OpenAPIResponse.d.ts +0 -10
  116. package/dist/OpenAPIResponse.jsx +0 -57
  117. package/dist/OpenAPIResponseExample.d.ts +0 -9
  118. package/dist/OpenAPIResponseExample.jsx +0 -105
  119. package/dist/OpenAPIResponseExampleContent.d.ts +0 -22
  120. package/dist/OpenAPIResponseExampleContent.jsx +0 -60
  121. package/dist/OpenAPIResponses.d.ts +0 -9
  122. package/dist/OpenAPIResponses.jsx +0 -77
  123. package/dist/OpenAPISchema.d.ts +0 -27
  124. package/dist/OpenAPISchema.jsx +0 -400
  125. package/dist/OpenAPISchemaName.d.ts +0 -16
  126. package/dist/OpenAPISchemaName.jsx +0 -43
  127. package/dist/OpenAPISchemaServer.d.ts +0 -12
  128. package/dist/OpenAPISchemaServer.jsx +0 -8
  129. package/dist/OpenAPISecurities.d.ts +0 -9
  130. package/dist/OpenAPISecurities.jsx +0 -114
  131. package/dist/OpenAPISelect.d.ts +0 -22
  132. package/dist/OpenAPISelect.jsx +0 -44
  133. package/dist/OpenAPISpec.d.ts +0 -6
  134. package/dist/OpenAPISpec.jsx +0 -80
  135. package/dist/OpenAPITabs.d.ts +0 -26
  136. package/dist/OpenAPITabs.jsx +0 -109
  137. package/dist/OpenAPIWebhook.jsx +0 -23
  138. package/dist/OpenAPIWebhookExample.d.ts +0 -6
  139. package/dist/OpenAPIWebhookExample.jsx +0 -41
  140. package/dist/ScalarApiButton.d.ts +0 -14
  141. package/dist/ScalarApiButton.jsx +0 -81
  142. package/dist/StaticSection.d.ts +0 -13
  143. package/dist/StaticSection.jsx +0 -32
  144. package/dist/code-samples.d.ts +0 -17
  145. package/dist/common/OpenAPIColumnSpec.d.ts +0 -6
  146. package/dist/common/OpenAPIColumnSpec.jsx +0 -20
  147. package/dist/common/OpenAPIOperationDescription.d.ts +0 -6
  148. package/dist/common/OpenAPIOperationDescription.jsx +0 -19
  149. package/dist/common/OpenAPIStability.d.ts +0 -4
  150. package/dist/common/OpenAPIStability.jsx +0 -15
  151. package/dist/common/OpenAPISummary.d.ts +0 -6
  152. package/dist/common/OpenAPISummary.jsx +0 -30
  153. package/dist/contentTypeChecks.d.ts +0 -10
  154. package/dist/decycle.d.ts +0 -2
  155. package/dist/dereference.d.ts +0 -5
  156. package/dist/generateSchemaExample.d.ts +0 -45
  157. package/dist/getDisclosureLabel.d.ts +0 -7
  158. package/dist/getOrCreateStoreByKey.d.ts +0 -10
  159. package/dist/json2xml.d.ts +0 -4
  160. package/dist/schemas/OpenAPISchemaItem.d.ts +0 -7
  161. package/dist/schemas/OpenAPISchemaItem.jsx +0 -16
  162. package/dist/schemas/OpenAPISchemas.jsx +0 -59
  163. package/dist/schemas/index.d.ts +0 -2
  164. package/dist/schemas/index.js +0 -2
  165. package/dist/stringifyOpenAPI.d.ts +0 -4
  166. package/dist/translate.d.ts +0 -10
  167. package/dist/translate.jsx +0 -75
  168. package/dist/translations/de.d.ts +0 -43
  169. package/dist/translations/es.d.ts +0 -43
  170. package/dist/translations/fr.d.ts +0 -43
  171. package/dist/translations/ja.d.ts +0 -43
  172. package/dist/translations/nl.d.ts +0 -43
  173. package/dist/translations/no.d.ts +0 -43
  174. package/dist/translations/pt-br.d.ts +0 -43
  175. package/dist/translations/types.js +0 -1
  176. package/dist/translations/zh.d.ts +0 -43
  177. package/dist/tsconfig.build.tsbuildinfo +0 -1
  178. package/dist/types.js +0 -1
  179. package/dist/util/example.d.ts +0 -35
  180. package/dist/util/example.jsx +0 -103
  181. package/dist/util/server.d.ts +0 -9
  182. package/dist/util/tryit-prefill.d.ts +0 -20
  183. package/dist/utils.d.ts +0 -50
  184. package/src/InteractiveSection.tsx +0 -147
  185. package/src/Markdown.tsx +0 -12
  186. package/src/OpenAPICodeSample.tsx +0 -330
  187. package/src/OpenAPICodeSampleInteractive.tsx +0 -136
  188. package/src/OpenAPICodeSampleSelector.tsx +0 -94
  189. package/src/OpenAPICopyButton.tsx +0 -72
  190. package/src/OpenAPIDisclosure.tsx +0 -46
  191. package/src/OpenAPIDisclosureGroup.tsx +0 -158
  192. package/src/OpenAPIExample.tsx +0 -55
  193. package/src/OpenAPIMediaType.tsx +0 -139
  194. package/src/OpenAPIOperation.tsx +0 -35
  195. package/src/OpenAPIOperationContext.tsx +0 -45
  196. package/src/OpenAPIOperationDescription.tsx +0 -34
  197. package/src/OpenAPIOperationStability.tsx +0 -39
  198. package/src/OpenAPIPath.tsx +0 -90
  199. package/src/OpenAPIPrefillContextProvider.tsx +0 -40
  200. package/src/OpenAPIRequestBody.tsx +0 -54
  201. package/src/OpenAPIRequestBodyHeaderType.tsx +0 -36
  202. package/src/OpenAPIResponse.tsx +0 -82
  203. package/src/OpenAPIResponseExample.tsx +0 -151
  204. package/src/OpenAPIResponseExampleContent.tsx +0 -125
  205. package/src/OpenAPIResponses.tsx +0 -125
  206. package/src/OpenAPISchema.test.ts +0 -172
  207. package/src/OpenAPISchema.tsx +0 -654
  208. package/src/OpenAPISchemaName.tsx +0 -80
  209. package/src/OpenAPISchemaServer.tsx +0 -34
  210. package/src/OpenAPISecurities.tsx +0 -231
  211. package/src/OpenAPISelect.tsx +0 -96
  212. package/src/OpenAPISpec.tsx +0 -138
  213. package/src/OpenAPITabs.tsx +0 -147
  214. package/src/OpenAPIWebhook.tsx +0 -33
  215. package/src/OpenAPIWebhookExample.tsx +0 -60
  216. package/src/ScalarApiButton.tsx +0 -132
  217. package/src/StaticSection.tsx +0 -91
  218. package/src/__snapshots__/json2xml.test.ts.snap +0 -18
  219. package/src/code-samples.test.ts +0 -714
  220. package/src/code-samples.ts +0 -448
  221. package/src/common/OpenAPIColumnSpec.tsx +0 -31
  222. package/src/common/OpenAPIOperationDescription.tsx +0 -31
  223. package/src/common/OpenAPIStability.tsx +0 -23
  224. package/src/common/OpenAPISummary.tsx +0 -45
  225. package/src/contentTypeChecks.ts +0 -39
  226. package/src/context.ts +0 -99
  227. package/src/decycle.ts +0 -68
  228. package/src/dereference.ts +0 -29
  229. package/src/generateSchemaExample.test.ts +0 -1040
  230. package/src/generateSchemaExample.ts +0 -530
  231. package/src/getDisclosureLabel.ts +0 -25
  232. package/src/getOrCreateStoreByKey.ts +0 -33
  233. package/src/index.ts +0 -10
  234. package/src/json2xml.test.ts +0 -46
  235. package/src/json2xml.ts +0 -8
  236. package/src/resolveOpenAPIOperation.test.ts +0 -177
  237. package/src/resolveOpenAPIOperation.ts +0 -151
  238. package/src/resolveOpenAPIWebhook.ts +0 -99
  239. package/src/schemas/OpenAPISchemaItem.tsx +0 -34
  240. package/src/schemas/OpenAPISchemas.tsx +0 -98
  241. package/src/schemas/index.ts +0 -2
  242. package/src/schemas/resolveOpenAPISchemas.test.ts +0 -174
  243. package/src/schemas/resolveOpenAPISchemas.ts +0 -28
  244. package/src/stringifyOpenAPI.ts +0 -25
  245. package/src/translate.tsx +0 -80
  246. package/src/translations/de.ts +0 -43
  247. package/src/translations/en.ts +0 -43
  248. package/src/translations/es.ts +0 -43
  249. package/src/translations/fr.ts +0 -43
  250. package/src/translations/index.ts +0 -33
  251. package/src/translations/ja.ts +0 -43
  252. package/src/translations/nl.ts +0 -43
  253. package/src/translations/no.ts +0 -43
  254. package/src/translations/pt-br.ts +0 -43
  255. package/src/translations/types.ts +0 -7
  256. package/src/translations/zh.ts +0 -43
  257. package/src/types.ts +0 -46
  258. package/src/util/example.tsx +0 -129
  259. package/src/util/server.test.ts +0 -58
  260. package/src/util/server.ts +0 -47
  261. package/src/util/tryit-prefill.test.ts +0 -311
  262. package/src/util/tryit-prefill.ts +0 -160
  263. package/src/utils.ts +0 -255
package/CHANGELOG.md CHANGED
@@ -1,5 +1,41 @@
1
1
  # @gitbook/react-openapi
2
2
 
3
+ ## 1.5.2
4
+
5
+ ### Patch Changes
6
+
7
+ - 6142d6b: Mark as sideEffects, fix all package bundles
8
+ - Updated dependencies [6142d6b]
9
+ - @gitbook/openapi-parser@3.0.4
10
+ - @gitbook/expr@1.2.3
11
+
12
+ ## 1.5.1
13
+
14
+ ### Patch Changes
15
+
16
+ - 295f03d: Republish packages
17
+ - Updated dependencies [295f03d]
18
+ - @gitbook/expr@1.2.2
19
+ - @gitbook/openapi-parser@3.0.3
20
+
21
+ ## 1.5.0
22
+
23
+ ### Minor Changes
24
+
25
+ - 529f940: Fix OpenAPISecurities and code sample not using operation security requirements
26
+
27
+ ### Patch Changes
28
+
29
+ - eea8f1e: Enhance OpenAPI security scopes handling
30
+ - 8e99871: Highlight discriminator properties in oneOf, allOf, anyOf objects
31
+ - f3e4041: Adapt OpenAPI code samples to prefill API key using visitor data
32
+ - 319a1e5: Ensure operation security requirements inherits from spec-level when not defined
33
+ - 754cc11: Fix merge logic for allOf alternatives
34
+ - d7948e3: Fix OpenAPI response showing as JSON instead of YAML when it should
35
+ - a4c3399: Fix OpenAPI alternatives not showing
36
+ - Updated dependencies [a629900]
37
+ - @gitbook/expr@1.2.1
38
+
3
39
  ## 1.4.3
4
40
 
5
41
  ### Patch Changes
@@ -0,0 +1,59 @@
1
+ 'use client';
2
+
3
+
4
+ import { Section, SectionBody, SectionHeader, SectionHeaderContent } from "./StaticSection.js";
5
+ import { OpenAPISelect, OpenAPISelectItem, useSelectState } from "./OpenAPISelect.js";
6
+ import { useDisclosureState } from "./node_modules/react-stately/dist/import.js";
7
+ import clsx from "classnames";
8
+ import { useRef } from "react";
9
+ import { mergeProps, useButton, useDisclosure, useFocusRing } from "react-aria";
10
+
11
+ //#region src/InteractiveSection.tsx
12
+ /**
13
+ * To optimize rendering, most of the components are server-components,
14
+ * and the interactiveness is mainly handled by a few key components like this one.
15
+ */
16
+ function InteractiveSection(props) {
17
+ const { id, className, toggeable = false, defaultOpened = true, tabs = [], defaultTab = tabs[0]?.key, header, overlay, toggleIcon = "▶", selectIcon, stateKey = "interactive-section" } = props;
18
+ const state = useDisclosureState({ defaultExpanded: defaultOpened });
19
+ const panelRef = useRef(null);
20
+ const triggerRef = useRef(null);
21
+ const { buttonProps: triggerProps, panelProps } = useDisclosure({}, state, panelRef);
22
+ const { buttonProps } = useButton(triggerProps, triggerRef);
23
+ const { isFocusVisible, focusProps } = useFocusRing();
24
+ const store = useSelectState(stateKey, defaultTab);
25
+ const selectedTab = tabs.find((tab) => tab.key === store.key) ?? tabs[0];
26
+ return <Section id={id} className={clsx("openapi-section", toggeable ? "openapi-section-toggeable" : null, className, toggeable ? `${className}-${state.isExpanded ? "opened" : "closed"}` : null)}>
27
+ {header ? <SectionHeader onClick={() => {
28
+ if (toggeable) state.toggle();
29
+ }} className={className}>
30
+ <SectionHeaderContent className={className}>
31
+ {selectedTab?.body && toggeable ? <button {...mergeProps(buttonProps, focusProps)} ref={triggerRef} className={clsx("openapi-section-toggle", `${className}-toggle`)} style={{ outline: isFocusVisible ? "2px solid rgb(var(--primary-color-500) / 0.4)" : "none" }}>
32
+ {toggleIcon}
33
+ </button> : null}
34
+ {header}
35
+ </SectionHeaderContent>
36
+ {}
37
+ <div className={clsx("openapi-section-header-controls", `${className}-header-controls`)} onClick={(event) => {
38
+ event.stopPropagation();
39
+ }}>
40
+ {tabs.length > 0 ? <OpenAPISelect stateKey={stateKey} items={tabs} onSelectionChange={() => {
41
+ state.expand();
42
+ }} icon={selectIcon} placement="bottom end">
43
+ {tabs.map((tab) => <OpenAPISelectItem key={tab.key} id={tab.key} value={tab}>
44
+ {tab.label}
45
+ </OpenAPISelectItem>)}
46
+ </OpenAPISelect> : null}
47
+ </div>
48
+ </SectionHeader> : null}
49
+ {(!toggeable || state.isExpanded) && selectedTab?.body ? <SectionBody ref={panelRef} {...panelProps} className={className}>
50
+ {selectedTab?.body}
51
+ </SectionBody> : null}
52
+ {overlay ? <div className={clsx("openapi-section-overlay", `${className}-overlay`)}>
53
+ {overlay}
54
+ </div> : null}
55
+ </Section>;
56
+ }
57
+
58
+ //#endregion
59
+ export { InteractiveSection };
@@ -0,0 +1,10 @@
1
+ import clsx from "classnames";
2
+
3
+ //#region src/Markdown.tsx
4
+ function Markdown(props) {
5
+ const { source, className } = props;
6
+ return <div className={clsx("openapi-markdown", className)} dangerouslySetInnerHTML={{ __html: source }} />;
7
+ }
8
+
9
+ //#endregion
10
+ export { Markdown };
@@ -0,0 +1,219 @@
1
+ import { stringifyOpenAPI } from "./stringifyOpenAPI.js";
2
+ import { checkIsReference, extractOperationSecurityInfo } from "./utils.js";
3
+ import { getOpenAPIClientContext } from "./context.js";
4
+ import { generateMediaTypeExamples, generateSchemaExample } from "./generateSchemaExample.js";
5
+ import { OpenAPIMediaTypeExamplesBody, OpenAPIMediaTypeExamplesSelector } from "./OpenAPICodeSampleInteractive.js";
6
+ import { getDefaultServerURL } from "./util/server.js";
7
+ import { OpenAPICodeSampleBody } from "./OpenAPICodeSampleSelector.js";
8
+ import { resolvePrefillCodePlaceholderFromSecurityScheme, resolveURLWithPrefillCodePlaceholdersFromServer } from "./util/tryit-prefill.js";
9
+ import { ScalarApiButton } from "./ScalarApiButton.js";
10
+ import { codeSampleGenerators, parseHostAndPath } from "./code-samples.js";
11
+
12
+ //#region src/OpenAPICodeSample.tsx
13
+ const CUSTOM_CODE_SAMPLES_KEYS = [
14
+ "x-custom-examples",
15
+ "x-code-samples",
16
+ "x-codeSamples"
17
+ ];
18
+ /**
19
+ * Display code samples to execute the operation.
20
+ * It supports the Redocly custom syntax as well (https://redocly.com/docs/api-reference-docs/specification-extensions/x-code-samples/)
21
+ */
22
+ function OpenAPICodeSample(props) {
23
+ const { data, context } = props;
24
+ if (data.operation["x-codeSamples"] === false) return null;
25
+ const customCodeSamples = getCustomCodeSamples(props);
26
+ if (data["x-codeSamples"] === false && !customCodeSamples) return null;
27
+ const samples = customCodeSamples ?? generateCodeSamples(props);
28
+ if (samples.length === 0) return null;
29
+ return <OpenAPICodeSampleBody context={getOpenAPIClientContext(context)} data={data} items={samples} selectIcon={context.icons.chevronDown} />;
30
+ }
31
+ /**
32
+ * Generate code samples for the operation.
33
+ */
34
+ function generateCodeSamples(props) {
35
+ const { data, context } = props;
36
+ const searchParams = new URLSearchParams();
37
+ const headersObject = {};
38
+ (Array.isArray(data.operation.parameters) ? data.operation.parameters : []).forEach((param) => {
39
+ if (!param) return;
40
+ if (param.in === "header" && param.required) {
41
+ const example = param.schema ? generateSchemaExample(param.schema, { mode: "write" }) : void 0;
42
+ if (example !== void 0 && param.name) headersObject[param.name] = typeof example !== "string" ? stringifyOpenAPI(example) : example;
43
+ } else if (param.in === "query" && param.required) {
44
+ const example = param.schema ? generateSchemaExample(param.schema, { mode: "write" }) : void 0;
45
+ if (example !== void 0 && param.name) searchParams.append(param.name, String(Array.isArray(example) ? example[0] : example));
46
+ }
47
+ });
48
+ const requestBody = !checkIsReference(data.operation.requestBody) ? data.operation.requestBody : void 0;
49
+ const defaultServerUrl = getDefaultServerURL(data.servers);
50
+ let serverUrlPath = defaultServerUrl ? parseHostAndPath(defaultServerUrl).path : "";
51
+ serverUrlPath = serverUrlPath === "/" ? "" : serverUrlPath;
52
+ const serverUrlOrigin = (data.servers[0] ? resolveURLWithPrefillCodePlaceholdersFromServer(data.servers[0], defaultServerUrl) : defaultServerUrl).replaceAll(serverUrlPath, "");
53
+ const path = serverUrlPath + data.path + (searchParams.size ? `?${searchParams.toString()}` : "");
54
+ const genericHeaders = {
55
+ ...getSecurityHeaders({
56
+ securityRequirement: data.operation.security,
57
+ securities: data.securities
58
+ }),
59
+ ...headersObject
60
+ };
61
+ const mediaTypeRendererFactories = Object.entries(requestBody?.content ?? {}).map(([mediaType, mediaTypeObject]) => {
62
+ return (generator) => {
63
+ const mediaTypeHeaders = {
64
+ ...genericHeaders,
65
+ "Content-Type": mediaType
66
+ };
67
+ return {
68
+ mediaType,
69
+ element: context.renderCodeBlock({
70
+ code: generator.generate({
71
+ url: {
72
+ origin: serverUrlOrigin,
73
+ path
74
+ },
75
+ method: data.method,
76
+ body: void 0,
77
+ headers: mediaTypeHeaders
78
+ }),
79
+ syntax: generator.syntax
80
+ }),
81
+ examples: generateMediaTypeExamples(mediaTypeObject, { mode: "write" }).map((example) => ({
82
+ example,
83
+ element: context.renderCodeBlock({
84
+ code: generator.generate({
85
+ url: {
86
+ origin: serverUrlOrigin,
87
+ path
88
+ },
89
+ method: data.method,
90
+ body: example.value,
91
+ headers: mediaTypeHeaders
92
+ }),
93
+ syntax: generator.syntax
94
+ })
95
+ }))
96
+ };
97
+ };
98
+ });
99
+ return codeSampleGenerators.map((generator) => {
100
+ if (mediaTypeRendererFactories.length > 0) {
101
+ const renderers = mediaTypeRendererFactories.map((generate) => generate(generator));
102
+ return {
103
+ key: `default-${generator.id}`,
104
+ label: generator.label,
105
+ body: <OpenAPIMediaTypeExamplesBody method={data.method} path={data.path} renderers={renderers} blockKey={context.blockKey} />,
106
+ footer: <OpenAPICodeSampleFooter renderers={renderers} data={data} context={context} />
107
+ };
108
+ }
109
+ return {
110
+ key: `default-${generator.id}`,
111
+ label: generator.label,
112
+ body: context.renderCodeBlock({
113
+ code: generator.generate({
114
+ url: {
115
+ origin: serverUrlOrigin,
116
+ path
117
+ },
118
+ method: data.method,
119
+ body: void 0,
120
+ headers: genericHeaders
121
+ }),
122
+ syntax: generator.syntax
123
+ }),
124
+ footer: <OpenAPICodeSampleFooter data={data} renderers={[]} context={context} />
125
+ };
126
+ });
127
+ }
128
+ function OpenAPICodeSampleFooter(props) {
129
+ const { data, context, renderers } = props;
130
+ const { method, path, securities, servers } = data;
131
+ const { specUrl } = context;
132
+ const hideTryItPanel = data["x-hideTryItPanel"] || data.operation["x-hideTryItPanel"];
133
+ const hasMultipleMediaTypes = renderers.length > 1 || renderers.some((renderer) => renderer.examples.length > 0);
134
+ if (hideTryItPanel && !hasMultipleMediaTypes) return null;
135
+ if (!validateHttpMethod(method)) return null;
136
+ return <div className="openapi-codesample-footer">
137
+ {hasMultipleMediaTypes ? <OpenAPIMediaTypeExamplesSelector method={data.method} path={data.path} renderers={renderers} selectIcon={context.icons.chevronDown} blockKey={context.blockKey} /> : <span />}
138
+ {!hideTryItPanel && <ScalarApiButton context={getOpenAPIClientContext(context)} method={method} path={path} securities={securities} servers={servers} specUrl={specUrl} />}
139
+ </div>;
140
+ }
141
+ /**
142
+ * Get custom code samples for the operation.
143
+ */
144
+ function getCustomCodeSamples(props) {
145
+ const { data, context } = props;
146
+ let customCodeSamples = null;
147
+ CUSTOM_CODE_SAMPLES_KEYS.forEach((key) => {
148
+ const customSamples = data.operation[key];
149
+ if (customSamples && Array.isArray(customSamples)) customCodeSamples = customSamples.filter((sample) => {
150
+ return typeof sample.source === "string" && typeof sample.lang === "string";
151
+ }).map((sample, index) => ({
152
+ key: `custom-sample-${sample.lang}-${index}`,
153
+ label: sample.label || sample.lang,
154
+ body: context.renderCodeBlock({
155
+ code: sample.source,
156
+ syntax: sample.lang
157
+ }),
158
+ footer: <OpenAPICodeSampleFooter renderers={[]} data={data} context={context} />
159
+ }));
160
+ });
161
+ return customCodeSamples;
162
+ }
163
+ function getSecurityHeaders(args) {
164
+ const { securityRequirement, securities } = args;
165
+ const operationSecurityInfo = extractOperationSecurityInfo({
166
+ securityRequirement,
167
+ securities
168
+ });
169
+ if (operationSecurityInfo.length === 0) return {};
170
+ const selectedSecurity = operationSecurityInfo.at(0);
171
+ if (!selectedSecurity) return {};
172
+ const headers = {};
173
+ for (const security of selectedSecurity.schemes) switch (security.type) {
174
+ case "http": {
175
+ let scheme = security.scheme;
176
+ const format = resolvePrefillCodePlaceholderFromSecurityScheme({
177
+ security,
178
+ defaultPlaceholderValue: scheme?.includes("basic") ? "username:password" : "YOUR_SECRET_TOKEN"
179
+ });
180
+ if (scheme?.includes("bearer")) scheme = "Bearer";
181
+ else if (scheme?.includes("basic")) scheme = "Basic";
182
+ else if (scheme?.includes("token")) scheme = "Token";
183
+ headers.Authorization = `${scheme} ${format}`;
184
+ break;
185
+ }
186
+ case "apiKey": {
187
+ if (security.in !== "header") break;
188
+ const name = security.name ?? "Authorization";
189
+ headers[name] = resolvePrefillCodePlaceholderFromSecurityScheme({
190
+ security,
191
+ defaultPlaceholderValue: "YOUR_API_KEY"
192
+ });
193
+ break;
194
+ }
195
+ case "oauth2":
196
+ headers.Authorization = `Bearer ${resolvePrefillCodePlaceholderFromSecurityScheme({
197
+ security,
198
+ defaultPlaceholderValue: "YOUR_OAUTH2_TOKEN"
199
+ })}`;
200
+ break;
201
+ default: break;
202
+ }
203
+ return headers;
204
+ }
205
+ function validateHttpMethod(method) {
206
+ return [
207
+ "get",
208
+ "post",
209
+ "put",
210
+ "delete",
211
+ "patch",
212
+ "head",
213
+ "options",
214
+ "trace"
215
+ ].includes(method);
216
+ }
217
+
218
+ //#endregion
219
+ export { OpenAPICodeSample };
@@ -0,0 +1,66 @@
1
+ 'use client';
2
+
3
+
4
+ import { createStateKey } from "./utils.js";
5
+ import { OpenAPISelect, OpenAPISelectItem, useSelectState } from "./OpenAPISelect.js";
6
+ import clsx from "classnames";
7
+
8
+ //#region src/OpenAPICodeSampleInteractive.tsx
9
+ function OpenAPIMediaTypeExamplesSelector(props) {
10
+ const { method, path, renderers, selectIcon, blockKey } = props;
11
+ if (!renderers[0]) throw new Error("No renderers provided");
12
+ const stateKey = createStateKey("request-body-media-type", blockKey);
13
+ const state = useSelectState(stateKey, renderers[0].mediaType);
14
+ const selected = renderers.find((r) => r.mediaType === state.key) || renderers[0];
15
+ return <div className="openapi-codesample-selectors">
16
+ <MediaTypeSelector selectIcon={selectIcon} stateKey={stateKey} renderers={renderers} />
17
+ <ExamplesSelector selectIcon={selectIcon} method={method} path={path} renderer={selected} />
18
+ </div>;
19
+ }
20
+ function MediaTypeSelector(props) {
21
+ const { renderers, stateKey, selectIcon } = props;
22
+ if (renderers.length < 2) return null;
23
+ const items = renderers.map((renderer) => ({
24
+ key: renderer.mediaType,
25
+ label: renderer.mediaType
26
+ }));
27
+ return <OpenAPISelect className={clsx("openapi-select")} items={renderers.map((renderer) => ({
28
+ key: renderer.mediaType,
29
+ label: renderer.mediaType
30
+ }))} icon={selectIcon} stateKey={stateKey} placement="bottom start">
31
+ {items.map((item) => <OpenAPISelectItem key={item.key} id={item.key} value={item}>
32
+ {item.label}
33
+ </OpenAPISelectItem>)}
34
+ </OpenAPISelect>;
35
+ }
36
+ function ExamplesSelector(props) {
37
+ const { method, path, renderer, selectIcon } = props;
38
+ if (renderer.examples.length < 2) return null;
39
+ const items = renderer.examples.map((example, index) => ({
40
+ key: index,
41
+ label: example.example.summary || `Example ${index + 1}`
42
+ }));
43
+ return <OpenAPISelect items={items} icon={selectIcon} stateKey={`media-type-sample-${renderer.mediaType}-${method}-${path}`} placement="bottom start">
44
+ {items.map((item) => <OpenAPISelectItem key={item.key} id={item.key} value={item}>
45
+ {item.label}
46
+ </OpenAPISelectItem>)}
47
+ </OpenAPISelect>;
48
+ }
49
+ function OpenAPIMediaTypeExamplesBody(props) {
50
+ const { renderers, method, path, blockKey } = props;
51
+ if (!renderers[0]) throw new Error("No renderers provided");
52
+ const mediaTypeState = useSelectState(createStateKey("request-body-media-type", blockKey), renderers[0].mediaType);
53
+ const selected = renderers.find((r) => r.mediaType === mediaTypeState.key) ?? renderers[0];
54
+ if (selected.examples.length === 0) return selected.element;
55
+ return <ExamplesBody method={method} path={path} renderer={selected} />;
56
+ }
57
+ function ExamplesBody(props) {
58
+ const { method, path, renderer } = props;
59
+ const exampleState = useSelectState(`media-type-sample-${renderer.mediaType}-${method}-${path}`, renderer.mediaType);
60
+ const example = renderer.examples[Number(exampleState.key)] ?? renderer.examples[0];
61
+ if (!example) throw new Error(`No example found for key ${exampleState.key}`);
62
+ return example.element;
63
+ }
64
+
65
+ //#endregion
66
+ export { OpenAPIMediaTypeExamplesBody, OpenAPIMediaTypeExamplesSelector };
@@ -0,0 +1,45 @@
1
+ 'use client';
2
+
3
+
4
+ import { StaticSection } from "./StaticSection.js";
5
+ import { getOrCreateStoreByKey } from "./getOrCreateStoreByKey.js";
6
+ import { OpenAPISelect, OpenAPISelectItem } from "./OpenAPISelect.js";
7
+ import { OpenAPIPath } from "./OpenAPIPath.js";
8
+ import { useCallback } from "react";
9
+ import { useStore } from "zustand";
10
+
11
+ //#region src/OpenAPICodeSampleSelector.tsx
12
+ function useCodeSampleState(initialKey = "default") {
13
+ const store = useStore(getOrCreateStoreByKey("codesample", initialKey));
14
+ return {
15
+ key: store.key,
16
+ setKey: useCallback((key) => store.setKey(key), [store.setKey])
17
+ };
18
+ }
19
+ function OpenAPICodeSampleHeader(props) {
20
+ const { data, items, selectIcon, context } = props;
21
+ return <>
22
+ <OpenAPIPath context={context} canCopy={false} withServer={false} data={data} />
23
+ {items.length > 1 ? <OpenAPISelect icon={selectIcon} items={items} stateKey="codesample" placement="bottom end">
24
+ {items.map((item) => <OpenAPISelectItem key={item.key} id={item.key} value={item}>
25
+ {item.label}
26
+ </OpenAPISelectItem>)}
27
+ </OpenAPISelect> : items[0] ? <span className="openapi-codesample-label">{items[0].label}</span> : null}
28
+ </>;
29
+ }
30
+ function OpenAPICodeSampleBody(props) {
31
+ const { items, data, selectIcon, context } = props;
32
+ if (!items[0]) throw new Error("No items provided");
33
+ const state = useCodeSampleState(items[0]?.key);
34
+ const selected = items.find((item) => item.key === state.key) || items[0];
35
+ if (!selected) return null;
36
+ return <StaticSection header={<OpenAPICodeSampleHeader context={context} selectIcon={selectIcon} data={data} items={items} />} className="openapi-codesample">
37
+ <div id={selected.key} className="openapi-codesample-panel">
38
+ {selected.body ? selected.body : null}
39
+ {selected.footer ? selected.footer : null}
40
+ </div>
41
+ </StaticSection>;
42
+ }
43
+
44
+ //#endregion
45
+ export { OpenAPICodeSampleBody };
@@ -0,0 +1,39 @@
1
+ 'use client';
2
+
3
+
4
+ import { t } from "./translate.js";
5
+ import { useState } from "react";
6
+ import { Button, Tooltip, TooltipTrigger } from "react-aria-components";
7
+
8
+ //#region src/OpenAPICopyButton.tsx
9
+ function OpenAPICopyButton(props) {
10
+ const { value, label, children, onPress, className, context, withTooltip = true } = props;
11
+ const [copied, setCopied] = useState(false);
12
+ const [isOpen, setIsOpen] = useState(false);
13
+ const handleCopy = () => {
14
+ if (!value) return;
15
+ navigator.clipboard.writeText(value).then(() => {
16
+ setIsOpen(true);
17
+ setCopied(true);
18
+ setTimeout(() => {
19
+ setCopied(false);
20
+ setIsOpen(false);
21
+ }, 2e3);
22
+ });
23
+ };
24
+ return <TooltipTrigger isOpen={isOpen} onOpenChange={setIsOpen} isDisabled={!withTooltip} closeDelay={200} delay={200}>
25
+ <Button type="button" preventFocusOnPress onPress={(e) => {
26
+ handleCopy();
27
+ onPress?.(e);
28
+ }} className={`openapi-copy-button ${className}`} {...props}>
29
+ {children}
30
+ </Button>
31
+
32
+ <Tooltip isOpen={isOpen} onOpenChange={setIsOpen} placement="top" offset={4} className="openapi-tooltip">
33
+ {copied ? t(context.translation, "copied") : label || t(context.translation, "copy_to_clipboard")}
34
+ </Tooltip>
35
+ </TooltipTrigger>;
36
+ }
37
+
38
+ //#endregion
39
+ export { OpenAPICopyButton };
@@ -0,0 +1,30 @@
1
+ 'use client';
2
+
3
+
4
+ import clsx from "classnames";
5
+ import { useState } from "react";
6
+ import { Button, Disclosure, DisclosurePanel } from "react-aria-components";
7
+
8
+ //#region src/OpenAPIDisclosure.tsx
9
+ /**
10
+ * Display an interactive OpenAPI disclosure.
11
+ */
12
+ function OpenAPIDisclosure(props) {
13
+ const { icon, header, label, children, className } = props;
14
+ const [isExpanded, setIsExpanded] = useState(false);
15
+ return <Disclosure className={clsx("openapi-disclosure", className)} isExpanded={isExpanded} onExpandedChange={setIsExpanded}>
16
+ <Button slot="trigger" className="openapi-disclosure-trigger" style={({ isFocusVisible }) => ({ outline: isFocusVisible ? "2px solid rgb(var(--primary-color-500) / 0.4)" : "none" })}>
17
+ {header}
18
+ <div className="openapi-disclosure-trigger-label">
19
+ <span>{typeof label === "function" ? label(isExpanded) : label}</span>
20
+ {icon}
21
+ </div>
22
+ </Button>
23
+ <DisclosurePanel className="openapi-disclosure-panel">
24
+ {isExpanded ? children : null}
25
+ </DisclosurePanel>
26
+ </Disclosure>;
27
+ }
28
+
29
+ //#endregion
30
+ export { OpenAPIDisclosure };
@@ -0,0 +1,75 @@
1
+ 'use client';
2
+
3
+
4
+ import { OpenAPISelect, OpenAPISelectItem, useSelectState } from "./OpenAPISelect.js";
5
+ import { useDisclosureGroupState, useDisclosureState } from "./node_modules/react-stately/dist/import.js";
6
+ import { createContext, useContext, useRef } from "react";
7
+ import { mergeProps, useButton, useDisclosure, useFocusRing, useId as useId$1 } from "react-aria";
8
+
9
+ //#region src/OpenAPIDisclosureGroup.tsx
10
+ const DisclosureGroupStateContext = createContext(null);
11
+ /**
12
+ * Display an interactive OpenAPI disclosure group.
13
+ */
14
+ function OpenAPIDisclosureGroup(props) {
15
+ const { icon, groups, selectStateKey, selectIcon } = props;
16
+ const state = useDisclosureGroupState(props);
17
+ return <DisclosureGroupStateContext.Provider value={state}>
18
+ {groups.map((group) => <DisclosureItem selectStateKey={selectStateKey} selectIcon={selectIcon} icon={icon} key={group.key} group={group} />)}
19
+ </DisclosureGroupStateContext.Provider>;
20
+ }
21
+ function DisclosureItem(props) {
22
+ const { icon, group, selectStateKey, selectIcon } = props;
23
+ const defaultId = useId$1();
24
+ const id = group.key || defaultId;
25
+ const groupState = useContext(DisclosureGroupStateContext);
26
+ const isExpanded = groupState?.expandedKeys.has(id) || false;
27
+ const state = useDisclosureState({
28
+ isExpanded,
29
+ onExpandedChange() {
30
+ if (groupState) groupState.toggleKey(id);
31
+ }
32
+ });
33
+ const panelRef = useRef(null);
34
+ const triggerRef = useRef(null);
35
+ const isDisabled = groupState?.isDisabled || !group.tabs?.length || false;
36
+ const { buttonProps: triggerProps, panelProps } = useDisclosure({
37
+ ...props,
38
+ isExpanded,
39
+ isDisabled
40
+ }, state, panelRef);
41
+ const { buttonProps } = useButton(triggerProps, triggerRef);
42
+ const { isFocusVisible, focusProps } = useFocusRing();
43
+ const store = useSelectState(selectStateKey, group.tabs?.[0]?.key || "");
44
+ const selectedTab = group.tabs?.find((tab) => tab.key === store.key) || group.tabs?.[0];
45
+ return <div className="openapi-disclosure-group" aria-expanded={state.isExpanded}>
46
+ <div slot="trigger" ref={triggerRef} {...mergeProps(buttonProps, focusProps)} aria-disabled={isDisabled} style={{ outline: isFocusVisible ? "2px solid rgb(var(--primary-color-500)/0.4)" : "none" }} className="openapi-disclosure-group-trigger">
47
+ <div className="openapi-disclosure-group-icon">
48
+ {icon || <svg viewBox="0 0 24 24" className="openapi-disclosure-group-icon">
49
+ <path d="m8.25 4.5 7.5 7.5-7.5 7.5" />
50
+ </svg>}
51
+ </div>
52
+
53
+ <div className="openapi-disclosure-group-label">
54
+ {group.label}
55
+
56
+ {group.tabs ? <div className="openapi-disclosure-group-mediatype" onClick={(e) => e.stopPropagation()}>
57
+ {group.tabs?.length > 1 ? <OpenAPISelect icon={selectIcon} stateKey={selectStateKey} onSelectionChange={() => {
58
+ state.expand();
59
+ }} items={group.tabs} placement="bottom end">
60
+ {group.tabs.map((tab) => <OpenAPISelectItem key={tab.key} id={tab.key} value={tab}>
61
+ {tab.label}
62
+ </OpenAPISelectItem>)}
63
+ </OpenAPISelect> : group.tabs[0]?.label ? <span>{group.tabs[0].label}</span> : null}
64
+ </div> : null}
65
+ </div>
66
+ </div>
67
+
68
+ {state.isExpanded && selectedTab && <div className="openapi-disclosure-group-panel" ref={panelRef} {...panelProps}>
69
+ {selectedTab.body}
70
+ </div>}
71
+ </div>;
72
+ }
73
+
74
+ //#endregion
75
+ export { OpenAPIDisclosureGroup };
@@ -0,0 +1,41 @@
1
+ import { json2xml } from "./json2xml.js";
2
+ import { stringifyOpenAPI } from "./stringifyOpenAPI.js";
3
+ import { t } from "./translate.js";
4
+ import yaml from "js-yaml";
5
+
6
+ //#region src/OpenAPIExample.tsx
7
+ /**
8
+ * Display an example.
9
+ */
10
+ function OpenAPIExample(props) {
11
+ const { example, context, syntax } = props;
12
+ const code = stringifyExample({
13
+ example,
14
+ syntax
15
+ });
16
+ if (code === null) return <OpenAPIEmptyExample context={context} />;
17
+ return context.renderCodeBlock({
18
+ code,
19
+ syntax
20
+ });
21
+ }
22
+ function stringifyExample(args) {
23
+ const { example, syntax } = args;
24
+ if (!example.value) return null;
25
+ if (typeof example.value === "string") return example.value;
26
+ if (syntax === "xml") return json2xml(example.value);
27
+ if (syntax === "yaml") return yaml.dump(example.value).replace(/'/g, "").replace(/\\n/g, "\n");
28
+ return stringifyOpenAPI(example.value, null, 2);
29
+ }
30
+ /**
31
+ * Empty response example.
32
+ */
33
+ function OpenAPIEmptyExample(props) {
34
+ const { context } = props;
35
+ return <pre className="openapi-example-empty">
36
+ <p>{t(context.translation, "no_content")}</p>
37
+ </pre>;
38
+ }
39
+
40
+ //#endregion
41
+ export { OpenAPIEmptyExample, OpenAPIExample };