@gitbook/react-openapi 1.5.1 → 1.5.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +27 -0
- package/dist/InteractiveSection.js +59 -0
- package/dist/Markdown.js +10 -0
- package/dist/OpenAPICodeSample.js +219 -0
- package/dist/OpenAPICodeSampleInteractive.js +62 -0
- package/dist/OpenAPICodeSampleSelector.js +45 -0
- package/dist/OpenAPICopyButton.js +44 -0
- package/dist/OpenAPIDisclosure.js +28 -0
- package/dist/OpenAPIDisclosureGroup.js +89 -0
- package/dist/OpenAPIExample.js +41 -0
- package/dist/OpenAPIMediaType.js +58 -0
- package/dist/OpenAPIOperation.d.ts +15 -0
- package/dist/OpenAPIOperation.js +30 -0
- package/dist/OpenAPIOperationContext.d.ts +20 -0
- package/dist/OpenAPIOperationContext.js +30 -0
- package/dist/OpenAPIPath.js +25 -0
- package/dist/OpenAPIPathItem.js +22 -0
- package/dist/OpenAPIPathMultipleServers.js +43 -0
- package/dist/OpenAPIPrefillContextProvider.d.ts +26 -0
- package/dist/OpenAPIPrefillContextProvider.js +25 -0
- package/dist/OpenAPIRequestBody.js +28 -0
- package/dist/OpenAPIRequestBodyHeaderType.js +23 -0
- package/dist/OpenAPIRequiredScopes.js +67 -0
- package/dist/OpenAPIResponse.js +39 -0
- package/dist/OpenAPIResponseExample.js +75 -0
- package/dist/OpenAPIResponseExampleContent.js +61 -0
- package/dist/OpenAPIResponses.js +61 -0
- package/dist/OpenAPISchema.js +373 -0
- package/dist/OpenAPISchemaName.js +45 -0
- package/dist/OpenAPISchemaServer.js +13 -0
- package/dist/OpenAPISecurities.js +98 -0
- package/dist/OpenAPISelect.js +45 -0
- package/dist/OpenAPISpec.js +73 -0
- package/dist/OpenAPITooltip.js +23 -0
- package/dist/OpenAPIWebhook.d.ts +15 -0
- package/dist/OpenAPIWebhook.js +28 -0
- package/dist/OpenAPIWebhookExample.js +40 -0
- package/dist/ScalarApiButton.js +90 -0
- package/dist/StaticSection.js +37 -0
- package/dist/code-samples.js +305 -0
- package/dist/common/OpenAPIColumnSpec.js +23 -0
- package/dist/common/OpenAPIOperationDescription.js +18 -0
- package/dist/common/OpenAPIStability.js +17 -0
- package/dist/common/OpenAPISummary.js +27 -0
- package/dist/contentTypeChecks.js +34 -0
- package/dist/context.d.ts +74 -0
- package/dist/context.js +29 -0
- package/dist/decycle.js +41 -0
- package/dist/dereference.js +24 -0
- package/dist/formatPath.js +25 -0
- package/dist/generateSchemaExample.js +198 -0
- package/dist/getDisclosureLabel.js +17 -0
- package/dist/getOrCreateDisclosureStoreByKey.js +31 -0
- package/dist/getOrCreateStoreByKey.js +22 -0
- package/dist/index.d.ts +11 -662
- package/dist/index.js +9 -3871
- package/dist/json2xml.js +12 -0
- package/dist/resolveOpenAPIOperation.d.ts +15 -0
- package/dist/resolveOpenAPIOperation.js +105 -0
- package/dist/resolveOpenAPIWebhook.d.ts +15 -0
- package/dist/resolveOpenAPIWebhook.js +52 -0
- package/dist/schemas/OpenAPISchemaItem.js +26 -0
- package/dist/schemas/OpenAPISchemas.d.ts +19 -0
- package/dist/schemas/OpenAPISchemas.js +57 -0
- package/dist/schemas/resolveOpenAPISchemas.d.ts +15 -0
- package/dist/schemas/resolveOpenAPISchemas.js +17 -0
- package/dist/stringifyOpenAPI.js +14 -0
- package/dist/translate.js +43 -0
- package/dist/translations/de.js +50 -0
- package/dist/translations/en.d.ts +49 -0
- package/dist/translations/en.js +50 -0
- package/dist/translations/es.js +50 -0
- package/dist/translations/fr.js +50 -0
- package/dist/translations/index.d.ts +426 -0
- package/dist/translations/index.js +31 -0
- package/dist/translations/ja.js +50 -0
- package/dist/translations/nl.js +50 -0
- package/dist/translations/no.js +50 -0
- package/dist/translations/pt-br.js +50 -0
- package/dist/translations/types.d.ts +7 -0
- package/dist/translations/zh.js +50 -0
- package/dist/types.d.ts +38 -0
- package/dist/util/example.js +84 -0
- package/dist/util/server.js +38 -0
- package/dist/util/tryit-prefill.js +143 -0
- package/dist/utils.js +163 -0
- package/package.json +28 -12
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { OpenAPIContextInput } from "./context.js";
|
|
2
|
+
import { OpenAPIWebhookData } from "./types.js";
|
|
3
|
+
import * as react0 from "react";
|
|
4
|
+
|
|
5
|
+
//#region src/OpenAPIWebhook.d.ts
|
|
6
|
+
/**
|
|
7
|
+
* Display an interactive OpenAPI webhook.
|
|
8
|
+
*/
|
|
9
|
+
declare function OpenAPIWebhook(props: {
|
|
10
|
+
className?: string;
|
|
11
|
+
data: OpenAPIWebhookData;
|
|
12
|
+
context: OpenAPIContextInput;
|
|
13
|
+
}): react0.JSX.Element;
|
|
14
|
+
//#endregion
|
|
15
|
+
export { OpenAPIWebhook };
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { resolveOpenAPIContext } from "./context.js";
|
|
2
|
+
import { OpenAPIColumnSpec } from "./common/OpenAPIColumnSpec.js";
|
|
3
|
+
import { OpenAPISummary } from "./common/OpenAPISummary.js";
|
|
4
|
+
import { OpenAPIWebhookExample } from "./OpenAPIWebhookExample.js";
|
|
5
|
+
import clsx from "classnames";
|
|
6
|
+
|
|
7
|
+
//#region src/OpenAPIWebhook.tsx
|
|
8
|
+
/**
|
|
9
|
+
* Display an interactive OpenAPI webhook.
|
|
10
|
+
*/
|
|
11
|
+
function OpenAPIWebhook(props) {
|
|
12
|
+
const { className, data, context: contextInput } = props;
|
|
13
|
+
const context = resolveOpenAPIContext(contextInput);
|
|
14
|
+
return <div className={clsx("openapi-webhook", className)}>
|
|
15
|
+
<OpenAPISummary data={data} context={context} />
|
|
16
|
+
<div className="openapi-columns">
|
|
17
|
+
<OpenAPIColumnSpec data={data} context={context} />
|
|
18
|
+
<div className="openapi-column-preview">
|
|
19
|
+
<div className="openapi-column-preview-body">
|
|
20
|
+
<OpenAPIWebhookExample data={data} context={context} />
|
|
21
|
+
</div>
|
|
22
|
+
</div>
|
|
23
|
+
</div>
|
|
24
|
+
</div>;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
//#endregion
|
|
28
|
+
export { OpenAPIWebhook };
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { OpenAPIEmptyExample } from "./OpenAPIExample.js";
|
|
2
|
+
import { createStateKey } from "./utils.js";
|
|
3
|
+
import { getOpenAPIClientContext } from "./context.js";
|
|
4
|
+
import { getExamples } from "./util/example.js";
|
|
5
|
+
import { OpenAPIMediaTypeContent } from "./OpenAPIMediaType.js";
|
|
6
|
+
|
|
7
|
+
//#region src/OpenAPIWebhookExample.tsx
|
|
8
|
+
function OpenAPIWebhookExample(props) {
|
|
9
|
+
const { data, context } = props;
|
|
10
|
+
const { operation } = data;
|
|
11
|
+
const items = (() => {
|
|
12
|
+
if (!operation.requestBody) return [];
|
|
13
|
+
return Object.entries(operation.requestBody.content).map(([key, value]) => {
|
|
14
|
+
if (!value?.schema) return {
|
|
15
|
+
key,
|
|
16
|
+
label: key,
|
|
17
|
+
body: <OpenAPIEmptyExample context={context} />
|
|
18
|
+
};
|
|
19
|
+
return {
|
|
20
|
+
key,
|
|
21
|
+
label: key,
|
|
22
|
+
body: <></>,
|
|
23
|
+
examples: getExamples({
|
|
24
|
+
mediaTypeObject: value,
|
|
25
|
+
mediaType: key,
|
|
26
|
+
context
|
|
27
|
+
})
|
|
28
|
+
};
|
|
29
|
+
});
|
|
30
|
+
})();
|
|
31
|
+
return <div className="openapi-panel">
|
|
32
|
+
<h4 className="openapi-panel-heading">Payload</h4>
|
|
33
|
+
<div className="openapi-panel-body">
|
|
34
|
+
<OpenAPIMediaTypeContent selectIcon={context.icons.chevronDown} stateKey={createStateKey("request-body-media-type", context.blockKey)} items={items} context={getOpenAPIClientContext(context)} />
|
|
35
|
+
</div>
|
|
36
|
+
</div>;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
//#endregion
|
|
40
|
+
export { OpenAPIWebhookExample };
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
import { t } from "./translate.js";
|
|
5
|
+
import { useOpenAPIOperationContext } from "./OpenAPIOperationContext.js";
|
|
6
|
+
import { useOpenAPIPrefillContext } from "./OpenAPIPrefillContextProvider.js";
|
|
7
|
+
import { resolveTryItPrefillForOperation } from "./util/tryit-prefill.js";
|
|
8
|
+
import { Suspense, useEffect, useImperativeHandle, useMemo, useRef, useState } from "react";
|
|
9
|
+
import { ApiClientModalProvider, useApiClientModal } from "@scalar/api-client-react";
|
|
10
|
+
import { createPortal } from "react-dom";
|
|
11
|
+
|
|
12
|
+
//#region src/ScalarApiButton.tsx
|
|
13
|
+
/**
|
|
14
|
+
* Button which launches the Scalar API Client
|
|
15
|
+
*/
|
|
16
|
+
function ScalarApiButton(props) {
|
|
17
|
+
const { method, path, securities, servers, specUrl, context } = props;
|
|
18
|
+
const [isOpen, setIsOpen] = useState(false);
|
|
19
|
+
const controllerRef = useRef(null);
|
|
20
|
+
return <div className="scalar scalar-activate">
|
|
21
|
+
<button className="scalar-activate-button button" onClick={() => {
|
|
22
|
+
controllerRef.current?.openClient?.();
|
|
23
|
+
setIsOpen(true);
|
|
24
|
+
}}>
|
|
25
|
+
{t(context.translation, "test_it")}
|
|
26
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 10 12" fill="currentColor">
|
|
27
|
+
<path stroke="currentColor" strokeWidth="1.5" d="M1 10.05V1.43c0-.2.2-.31.37-.22l7.26 4.08c.17.1.17.33.01.43l-7.26 4.54a.25.25 0 0 1-.38-.21Z" />
|
|
28
|
+
</svg>
|
|
29
|
+
</button>
|
|
30
|
+
|
|
31
|
+
{isOpen && createPortal(<Suspense fallback={null}>
|
|
32
|
+
<ScalarModal controllerRef={controllerRef} method={method} path={path} securities={securities} servers={servers} specUrl={specUrl} />
|
|
33
|
+
</Suspense>, document.body)}
|
|
34
|
+
</div>;
|
|
35
|
+
}
|
|
36
|
+
function ScalarModal(props) {
|
|
37
|
+
const { method, path, securities, servers, specUrl, controllerRef } = props;
|
|
38
|
+
const prefillInputContext = useOpenAPIPrefillContext()();
|
|
39
|
+
const prefillConfig = resolveTryItPrefillForOperation({
|
|
40
|
+
operation: {
|
|
41
|
+
securities,
|
|
42
|
+
servers
|
|
43
|
+
},
|
|
44
|
+
prefillInputContext
|
|
45
|
+
});
|
|
46
|
+
return <ApiClientModalProvider configuration={{
|
|
47
|
+
url: specUrl,
|
|
48
|
+
...prefillConfig
|
|
49
|
+
}} initialRequest={{
|
|
50
|
+
method: toScalarHttpMethod(method),
|
|
51
|
+
path
|
|
52
|
+
}}>
|
|
53
|
+
<ScalarModalController method={method} path={path} controllerRef={controllerRef} />
|
|
54
|
+
</ApiClientModalProvider>;
|
|
55
|
+
}
|
|
56
|
+
function toScalarHttpMethod(method) {
|
|
57
|
+
return method.toUpperCase();
|
|
58
|
+
}
|
|
59
|
+
function ScalarModalController(props) {
|
|
60
|
+
const { method, path, controllerRef } = props;
|
|
61
|
+
const openScalarClient = useApiClientModal()?.open;
|
|
62
|
+
const { onOpenClient: trackClientOpening } = useOpenAPIOperationContext();
|
|
63
|
+
const openClient = useMemo(() => {
|
|
64
|
+
if (openScalarClient) return () => {
|
|
65
|
+
openScalarClient({
|
|
66
|
+
method: toScalarHttpMethod(method),
|
|
67
|
+
path,
|
|
68
|
+
_source: "gitbook"
|
|
69
|
+
});
|
|
70
|
+
trackClientOpening({
|
|
71
|
+
method,
|
|
72
|
+
path
|
|
73
|
+
});
|
|
74
|
+
};
|
|
75
|
+
return null;
|
|
76
|
+
}, [
|
|
77
|
+
openScalarClient,
|
|
78
|
+
method,
|
|
79
|
+
path,
|
|
80
|
+
trackClientOpening
|
|
81
|
+
]);
|
|
82
|
+
useImperativeHandle(controllerRef, () => ({ openClient: openClient ? () => openClient() : void 0 }), [openClient]);
|
|
83
|
+
useEffect(() => {
|
|
84
|
+
openClient?.();
|
|
85
|
+
}, [openClient]);
|
|
86
|
+
return null;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
//#endregion
|
|
90
|
+
export { ScalarApiButton };
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import clsx from "classnames";
|
|
2
|
+
import { forwardRef } from "react";
|
|
3
|
+
|
|
4
|
+
//#region src/StaticSection.tsx
|
|
5
|
+
function Section(props) {
|
|
6
|
+
return <div {...props} className={clsx("openapi-section", props.className)} />;
|
|
7
|
+
}
|
|
8
|
+
function SectionHeader(props) {
|
|
9
|
+
return <div {...props} className={clsx("openapi-section-header", props.className ? `${props.className}-header` : void 0)} />;
|
|
10
|
+
}
|
|
11
|
+
function SectionHeaderContent(props) {
|
|
12
|
+
return <div {...props} className={clsx("openapi-section-header-content", props.className && `${props.className}-header-content`)} />;
|
|
13
|
+
}
|
|
14
|
+
const SectionBody = forwardRef(function SectionBody$1(props, ref) {
|
|
15
|
+
return <div ref={ref} {...props} className={clsx("openapi-section-body", props.className && `${props.className}-body`)} />;
|
|
16
|
+
});
|
|
17
|
+
function SectionFooter(props) {
|
|
18
|
+
return <div {...props} className={clsx("openapi-section-footer", props.className && `${props.className}-footer`)} />;
|
|
19
|
+
}
|
|
20
|
+
function SectionFooterContent(props) {
|
|
21
|
+
return <div {...props} className={clsx("openapi-section-footer-content", props.className && `${props.className}-footer-content`)} />;
|
|
22
|
+
}
|
|
23
|
+
function StaticSection(props) {
|
|
24
|
+
const { className, header, children, footer } = props;
|
|
25
|
+
return <Section className={className}>
|
|
26
|
+
{header ? <SectionHeader className={className}>
|
|
27
|
+
<SectionHeaderContent className={className}>{header}</SectionHeaderContent>
|
|
28
|
+
</SectionHeader> : null}
|
|
29
|
+
<SectionBody className={className}>{children}</SectionBody>
|
|
30
|
+
{footer ? <SectionFooter className={className}>
|
|
31
|
+
<SectionFooterContent className={className}>{footer}</SectionFooterContent>
|
|
32
|
+
</SectionFooter> : null}
|
|
33
|
+
</Section>;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
//#endregion
|
|
37
|
+
export { Section, SectionBody, SectionHeader, SectionHeaderContent, StaticSection };
|
|
@@ -0,0 +1,305 @@
|
|
|
1
|
+
import { json2xml } from "./json2xml.js";
|
|
2
|
+
import { stringifyOpenAPI } from "./stringifyOpenAPI.js";
|
|
3
|
+
import { isCSV, isFormData, isFormUrlEncoded, isGraphQL, isJSON, isPDF, isPlainObject, isText, isXML, isYAML } from "./contentTypeChecks.js";
|
|
4
|
+
import yaml from "js-yaml";
|
|
5
|
+
|
|
6
|
+
//#region src/code-samples.ts
|
|
7
|
+
const codeSampleGenerators = [
|
|
8
|
+
{
|
|
9
|
+
id: "http",
|
|
10
|
+
label: "HTTP",
|
|
11
|
+
syntax: "http",
|
|
12
|
+
generate: ({ method, url: { origin, path }, headers = {}, body }) => {
|
|
13
|
+
if (body) {
|
|
14
|
+
const bodyContent = body ? stringifyOpenAPI(body) : "";
|
|
15
|
+
const encoder = new TextEncoder();
|
|
16
|
+
const bodyString$1 = BodyGenerators.getHTTPBody(body, headers);
|
|
17
|
+
if (bodyString$1) body = bodyString$1;
|
|
18
|
+
headers = {
|
|
19
|
+
...headers,
|
|
20
|
+
"Content-Length": encoder.encode(bodyContent).length.toString()
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
if (!headers.hasOwnProperty("Accept")) headers.Accept = "*/*";
|
|
24
|
+
const headerString = headers ? `${Object.entries(headers).map(([key, value]) => key.toLowerCase() !== "host" ? `${key}: ${value}` : "").join("\n")}\n` : "";
|
|
25
|
+
const bodyString = body ? `\n${body}` : "";
|
|
26
|
+
return `${method.toUpperCase()} ${decodeURI(path)} HTTP/1.1
|
|
27
|
+
Host: ${origin.replaceAll(/https*:\/\//g, "")}
|
|
28
|
+
${headerString}${bodyString}`;
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
id: "curl",
|
|
33
|
+
label: "cURL",
|
|
34
|
+
syntax: "bash",
|
|
35
|
+
generate: ({ method, url: { origin, path }, headers, body }) => {
|
|
36
|
+
const lines = ["curl -L"];
|
|
37
|
+
if (method.toUpperCase() !== "GET") lines.push(`--request ${method.toUpperCase()}`);
|
|
38
|
+
lines.push(`--url '${origin}${path}'`);
|
|
39
|
+
if (body) {
|
|
40
|
+
const bodyContent = BodyGenerators.getCurlBody(body, headers);
|
|
41
|
+
if (bodyContent) {
|
|
42
|
+
body = bodyContent.body;
|
|
43
|
+
headers = bodyContent.headers;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
if (headers && Object.keys(headers).length > 0) Object.entries(headers).forEach(([key, value]) => {
|
|
47
|
+
lines.push(`--header '${key}: ${value}'`);
|
|
48
|
+
});
|
|
49
|
+
if (body) if (Array.isArray(body)) lines.push(...body);
|
|
50
|
+
else lines.push(body);
|
|
51
|
+
return buildHeredoc(lines);
|
|
52
|
+
}
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
id: "javascript",
|
|
56
|
+
label: "JavaScript",
|
|
57
|
+
syntax: "javascript",
|
|
58
|
+
generate: ({ method, url: { origin, path }, headers, body }) => {
|
|
59
|
+
let code = "";
|
|
60
|
+
if (body) {
|
|
61
|
+
const lines = BodyGenerators.getJavaScriptBody(body, headers);
|
|
62
|
+
if (lines) {
|
|
63
|
+
code += lines.code;
|
|
64
|
+
body = lines.body;
|
|
65
|
+
headers = lines.headers;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
code += `const response = await fetch('${origin}${path}', {
|
|
69
|
+
method: '${method.toUpperCase()}',\n`;
|
|
70
|
+
if (headers && Object.keys(headers).length > 0) code += indent(`headers: ${stringifyOpenAPI(headers, null, 2)},\n`, 4);
|
|
71
|
+
if (body) code += indent(`body: ${body}\n`, 4);
|
|
72
|
+
code += "});\n\n";
|
|
73
|
+
code += "const data = await response.json();";
|
|
74
|
+
return code;
|
|
75
|
+
}
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
id: "python",
|
|
79
|
+
label: "Python",
|
|
80
|
+
syntax: "python",
|
|
81
|
+
generate: ({ method, url: { origin, path }, headers, body }) => {
|
|
82
|
+
const contentType = headers?.["Content-Type"];
|
|
83
|
+
let code = `${isJSON(contentType) ? "import json\n" : ""}import requests\n\n`;
|
|
84
|
+
if (body) {
|
|
85
|
+
const lines = BodyGenerators.getPythonBody(body, headers);
|
|
86
|
+
if (lines) {
|
|
87
|
+
code += lines.code;
|
|
88
|
+
body = lines.body;
|
|
89
|
+
headers = lines.headers;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
code += `response = requests.${method.toLowerCase()}(\n`;
|
|
93
|
+
code += indent(`"${origin}${path}",\n`, 4);
|
|
94
|
+
if (headers && Object.keys(headers).length > 0) code += indent(`headers=${stringifyOpenAPI(headers)},\n`, 4);
|
|
95
|
+
if (body) if (body === "files") code += indent(`files=${body}\n`, 4);
|
|
96
|
+
else if (isJSON(contentType)) code += indent(`data=json.dumps(${body})\n`, 4);
|
|
97
|
+
else code += indent(`data=${body}\n`, 4);
|
|
98
|
+
code += ")\n\n";
|
|
99
|
+
code += "data = response.json()";
|
|
100
|
+
return code;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
];
|
|
104
|
+
function indent(code, spaces) {
|
|
105
|
+
const indent$1 = " ".repeat(spaces);
|
|
106
|
+
return code.split("\n").map((line) => line ? indent$1 + line : "").join("\n");
|
|
107
|
+
}
|
|
108
|
+
function parseHostAndPath(url) {
|
|
109
|
+
try {
|
|
110
|
+
const urlObj = new URL(url);
|
|
111
|
+
const path = urlObj.pathname || "/";
|
|
112
|
+
return {
|
|
113
|
+
host: urlObj.host,
|
|
114
|
+
path
|
|
115
|
+
};
|
|
116
|
+
} catch (_e) {
|
|
117
|
+
const splitted = url.split("//");
|
|
118
|
+
const parts = (splitted[1] ? splitted[1] : url).split("/");
|
|
119
|
+
return {
|
|
120
|
+
host: parts.shift(),
|
|
121
|
+
path: `/${parts.join("/")}`
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
const BodyGenerators = {
|
|
126
|
+
getCurlBody(body, headers) {
|
|
127
|
+
if (!body || !headers) return void 0;
|
|
128
|
+
const headersCopy = { ...headers };
|
|
129
|
+
const contentType = headersCopy["Content-Type"] || "";
|
|
130
|
+
if (isFormData(contentType)) body = isPlainObject(body) ? Object.entries(body).map(([key, value]) => `--form '${key}=${String(value)}'`) : `--form 'file=@${body}'`;
|
|
131
|
+
else if (isFormUrlEncoded(contentType)) body = isPlainObject(body) ? `--data '${Object.entries(body).map(([key, value]) => `${key}=${String(value)}`).join("&")}'` : String(body);
|
|
132
|
+
else if (isText(contentType)) body = `--data '${String(body).replace(/"/g, "")}'`;
|
|
133
|
+
else if (isXML(contentType)) body = `--data-binary $'${convertBodyToXML(body)}'`;
|
|
134
|
+
else if (isCSV(contentType)) body = `--data-binary $'${stringifyOpenAPI(body).replace(/"/g, "").replace(/\\n/g, "\n")}'`;
|
|
135
|
+
else if (isGraphQL(contentType)) {
|
|
136
|
+
body = `--data '${stringifyOpenAPI(body)}'`;
|
|
137
|
+
headersCopy["Content-Type"] = "application/json";
|
|
138
|
+
} else if (isPDF(contentType)) body = `--data-binary '@${String(body)}'`;
|
|
139
|
+
else if (isYAML(contentType)) body = `--data-binary $'${yaml.dump(body).replace(/'/g, "").replace(/\\n/g, "\n")}'`;
|
|
140
|
+
else {
|
|
141
|
+
const jsonString = stringifyOpenAPI(body, null, 2).replace(/\\n/g, "\n");
|
|
142
|
+
if (jsonString.includes("'")) body = [
|
|
143
|
+
"--data @- <<'EOF'",
|
|
144
|
+
...jsonString.split("\n"),
|
|
145
|
+
"EOF"
|
|
146
|
+
];
|
|
147
|
+
else body = `--data '${jsonString}'`;
|
|
148
|
+
}
|
|
149
|
+
return {
|
|
150
|
+
body,
|
|
151
|
+
headers: headersCopy
|
|
152
|
+
};
|
|
153
|
+
},
|
|
154
|
+
getJavaScriptBody: (body, headers) => {
|
|
155
|
+
if (!body || !headers) return;
|
|
156
|
+
let code = "";
|
|
157
|
+
const headersCopy = { ...headers };
|
|
158
|
+
const contentType = headersCopy["Content-Type"] || "";
|
|
159
|
+
if (isFormData(contentType)) {
|
|
160
|
+
code += "const formData = new FormData();\n\n";
|
|
161
|
+
if (isPlainObject(body)) Object.entries(body).forEach(([key, value]) => {
|
|
162
|
+
code += `formData.append("${key}", "${String(value)}");\n`;
|
|
163
|
+
});
|
|
164
|
+
else if (typeof body === "string") code += `formData.append("file", "${body}");\n`;
|
|
165
|
+
code += "\n";
|
|
166
|
+
body = "formData";
|
|
167
|
+
} else if (isFormUrlEncoded(contentType)) {
|
|
168
|
+
code += "const params = new URLSearchParams();\n\n";
|
|
169
|
+
if (isPlainObject(body)) Object.entries(body).forEach(([key, value]) => {
|
|
170
|
+
code += `params.append("${key}", "${String(value)}");\n`;
|
|
171
|
+
});
|
|
172
|
+
code += "\n";
|
|
173
|
+
body = "params.toString()";
|
|
174
|
+
} else if (isGraphQL(contentType)) if (isPlainObject(body)) {
|
|
175
|
+
Object.entries(body).forEach(([key, value]) => {
|
|
176
|
+
code += `const ${key} = \`\n${indent(String(value), 4)}\`;\n\n`;
|
|
177
|
+
});
|
|
178
|
+
body = `JSON.stringify({ ${Object.keys(body).join(", ")} })`;
|
|
179
|
+
headersCopy["Content-Type"] = "application/json";
|
|
180
|
+
} else {
|
|
181
|
+
code += `const query = \`\n${indent(String(body), 4)}\`;\n\n`;
|
|
182
|
+
body = "JSON.stringify(query)";
|
|
183
|
+
}
|
|
184
|
+
else if (isCSV(contentType)) {
|
|
185
|
+
code += "const csv = `\n";
|
|
186
|
+
code += indent(String(body), 4);
|
|
187
|
+
code += "`;\n\n";
|
|
188
|
+
body = "csv";
|
|
189
|
+
} else if (isPDF(contentType)) {
|
|
190
|
+
code += "const formData = new FormData();\n\n";
|
|
191
|
+
code += `formData.append("file", "${body}");\n\n`;
|
|
192
|
+
body = "formData";
|
|
193
|
+
} else if (isXML(contentType)) {
|
|
194
|
+
code += "const xml = `\n";
|
|
195
|
+
code += indent(convertBodyToXML(body), 4);
|
|
196
|
+
code += "`;\n\n";
|
|
197
|
+
body = "xml";
|
|
198
|
+
} else if (isYAML(contentType)) {
|
|
199
|
+
code += `const yamlBody = \`\n${indent(yaml.dump(body), 4)}\`;\n\n`;
|
|
200
|
+
body = "yamlBody";
|
|
201
|
+
} else if (isText(contentType)) body = stringifyOpenAPI(body, null, 2);
|
|
202
|
+
else body = `JSON.stringify(${stringifyOpenAPI(body, null, 2)})`;
|
|
203
|
+
return {
|
|
204
|
+
body,
|
|
205
|
+
code,
|
|
206
|
+
headers: headersCopy
|
|
207
|
+
};
|
|
208
|
+
},
|
|
209
|
+
getPythonBody: (body, headers) => {
|
|
210
|
+
if (!body || !headers) return;
|
|
211
|
+
let code = "";
|
|
212
|
+
const contentType = headers["Content-Type"] || "";
|
|
213
|
+
if (isFormData(contentType)) {
|
|
214
|
+
code += "files = {\n";
|
|
215
|
+
if (isPlainObject(body)) Object.entries(body).forEach(([key, value]) => {
|
|
216
|
+
code += `${indent(`"${key}": "${String(value)}",`, 4)}\n`;
|
|
217
|
+
});
|
|
218
|
+
code += "}\n\n";
|
|
219
|
+
body = "files";
|
|
220
|
+
} else if (isPDF(contentType)) {
|
|
221
|
+
code += "files = {\n";
|
|
222
|
+
code += `${indent(`"file": "${body}",`, 4)}\n`;
|
|
223
|
+
code += "}\n\n";
|
|
224
|
+
body = "files";
|
|
225
|
+
} else if (isXML(contentType)) body = JSON.stringify(convertBodyToXML(body));
|
|
226
|
+
else if (isYAML(contentType)) {
|
|
227
|
+
code += `yamlBody = \"\"\"\n${indent(yaml.dump(body), 4)}\"\"\"\n\n`;
|
|
228
|
+
body = "yamlBody";
|
|
229
|
+
} else body = stringifyOpenAPI(body, (_key, value) => {
|
|
230
|
+
switch (value) {
|
|
231
|
+
case true: return "$$__TRUE__$$";
|
|
232
|
+
case false: return "$$__FALSE__$$";
|
|
233
|
+
case null: return "$$__NULL__$$";
|
|
234
|
+
default: return value;
|
|
235
|
+
}
|
|
236
|
+
}, 2).replaceAll("\"$$__TRUE__$$\"", "True").replaceAll("\"$$__FALSE__$$\"", "False").replaceAll("\"$$__NULL__$$\"", "None");
|
|
237
|
+
return {
|
|
238
|
+
body,
|
|
239
|
+
code,
|
|
240
|
+
headers
|
|
241
|
+
};
|
|
242
|
+
},
|
|
243
|
+
getHTTPBody: (body, headers) => {
|
|
244
|
+
if (!body || !headers) return void 0;
|
|
245
|
+
const contentType = headers["Content-Type"] || "";
|
|
246
|
+
const typeHandlers = {
|
|
247
|
+
pdf: () => `${stringifyOpenAPI(body, null, 2)}`,
|
|
248
|
+
formUrlEncoded: () => {
|
|
249
|
+
return `"${(isPlainObject(body) ? Object.entries(body).map(([key, value]) => `${key}=${stringifyOpenAPI(value)}`).join("&") : stringifyOpenAPI(body)).replace(/"/g, "'")}"`;
|
|
250
|
+
},
|
|
251
|
+
text: () => `"${String(body)}"`,
|
|
252
|
+
xml: () => {
|
|
253
|
+
return `"${convertBodyToXML(body)}"`;
|
|
254
|
+
},
|
|
255
|
+
yaml: () => `"${yaml.dump(body).replace(/"/g, "\\\"")}"`,
|
|
256
|
+
csv: () => `"${stringifyOpenAPI(body).replace(/"/g, "")}"`,
|
|
257
|
+
default: () => `${stringifyOpenAPI(body, null, 2)}`
|
|
258
|
+
};
|
|
259
|
+
if (isPDF(contentType)) return typeHandlers.pdf();
|
|
260
|
+
if (isFormUrlEncoded(contentType)) return typeHandlers.formUrlEncoded();
|
|
261
|
+
if (isText(contentType)) return typeHandlers.text();
|
|
262
|
+
if (isXML(contentType)) return typeHandlers.xml();
|
|
263
|
+
if (isYAML(contentType)) return typeHandlers.yaml();
|
|
264
|
+
if (isCSV(contentType)) return typeHandlers.csv();
|
|
265
|
+
return typeHandlers.default();
|
|
266
|
+
}
|
|
267
|
+
};
|
|
268
|
+
/**
|
|
269
|
+
* Converts a body to XML format
|
|
270
|
+
*/
|
|
271
|
+
function convertBodyToXML(body) {
|
|
272
|
+
if (typeof body === "string" && body.trim().startsWith("<")) return body;
|
|
273
|
+
if (typeof body !== "object" || body === null) try {
|
|
274
|
+
body = JSON.parse(body);
|
|
275
|
+
} catch {
|
|
276
|
+
return body;
|
|
277
|
+
}
|
|
278
|
+
return json2xml(body).replace(/"/g, "").replace(/\\n/g, "\n").replace(/\\t/g, " ");
|
|
279
|
+
}
|
|
280
|
+
/**
|
|
281
|
+
* Builds a heredoc string from an array of lines
|
|
282
|
+
*/
|
|
283
|
+
function buildHeredoc(lines) {
|
|
284
|
+
const separator = " \\\n";
|
|
285
|
+
let result = "";
|
|
286
|
+
let inHeredoc = false;
|
|
287
|
+
for (let i = 0; i < lines.length; i++) {
|
|
288
|
+
const line = lines[i];
|
|
289
|
+
if (!line) continue;
|
|
290
|
+
const isHeredocStart = line.includes("<<'EOF'");
|
|
291
|
+
const isHeredocEnd = inHeredoc && line === "EOF";
|
|
292
|
+
if (isHeredocStart) {
|
|
293
|
+
inHeredoc = true;
|
|
294
|
+
result += `${i > 0 ? indent(line, 2) : line}\n`;
|
|
295
|
+
} else if (isHeredocEnd) {
|
|
296
|
+
inHeredoc = false;
|
|
297
|
+
result += line;
|
|
298
|
+
} else if (inHeredoc) result += `${indent(line, 2)}\n`;
|
|
299
|
+
else result += `${i > 0 ? indent(line, 2) : line}${i < lines.length - 1 ? separator : ""}`;
|
|
300
|
+
}
|
|
301
|
+
return result;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
//#endregion
|
|
305
|
+
export { codeSampleGenerators, parseHostAndPath };
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { t } from "../translate.js";
|
|
2
|
+
import { getOpenAPIClientContext } from "../context.js";
|
|
3
|
+
import { OpenAPISpec } from "../OpenAPISpec.js";
|
|
4
|
+
import { OpenAPIOperationDescription } from "./OpenAPIOperationDescription.js";
|
|
5
|
+
|
|
6
|
+
//#region src/common/OpenAPIColumnSpec.tsx
|
|
7
|
+
function OpenAPIColumnSpec(props) {
|
|
8
|
+
const { data, context } = props;
|
|
9
|
+
const { operation } = data;
|
|
10
|
+
const clientContext = getOpenAPIClientContext(context);
|
|
11
|
+
return <div className="openapi-column-spec">
|
|
12
|
+
{operation["x-deprecated-sunset"] ? <div className="openapi-deprecated-sunset openapi-description openapi-markdown">
|
|
13
|
+
{t(context.translation, "deprecated_and_sunset_on", [<span key="date" className="openapi-deprecated-sunset-date">
|
|
14
|
+
{operation["x-deprecated-sunset"]}
|
|
15
|
+
</span>])}
|
|
16
|
+
</div> : null}
|
|
17
|
+
<OpenAPIOperationDescription operation={operation} context={context} />
|
|
18
|
+
<OpenAPISpec data={data} context={clientContext} />
|
|
19
|
+
</div>;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
//#endregion
|
|
23
|
+
export { OpenAPIColumnSpec };
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { Markdown } from "../Markdown.js";
|
|
2
|
+
import { resolveDescription } from "../utils.js";
|
|
3
|
+
|
|
4
|
+
//#region src/common/OpenAPIOperationDescription.tsx
|
|
5
|
+
function OpenAPIOperationDescription(props) {
|
|
6
|
+
const { operation } = props;
|
|
7
|
+
if (operation["x-gitbook-description-document"]) return <div className="openapi-intro">
|
|
8
|
+
{props.context.renderDocument({ document: operation["x-gitbook-description-document"] })}
|
|
9
|
+
</div>;
|
|
10
|
+
const description = resolveDescription(operation);
|
|
11
|
+
if (!description) return null;
|
|
12
|
+
return <div className="openapi-intro">
|
|
13
|
+
<Markdown className="openapi-description" source={description} />
|
|
14
|
+
</div>;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
//#endregion
|
|
18
|
+
export { OpenAPIOperationDescription };
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
//#region src/common/OpenAPIStability.tsx
|
|
2
|
+
const stabilityEnum = {
|
|
3
|
+
experimental: "Experimental",
|
|
4
|
+
alpha: "Alpha",
|
|
5
|
+
beta: "Beta"
|
|
6
|
+
};
|
|
7
|
+
function OpenAPIStability(props) {
|
|
8
|
+
const { stability } = props;
|
|
9
|
+
const foundStability = stabilityEnum[stability];
|
|
10
|
+
if (!foundStability) return null;
|
|
11
|
+
return <div className={`openapi-stability openapi-stability-${foundStability.toLowerCase()}`}>
|
|
12
|
+
{foundStability}
|
|
13
|
+
</div>;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
//#endregion
|
|
17
|
+
export { OpenAPIStability };
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { OpenAPIPath } from "../OpenAPIPath.js";
|
|
2
|
+
import { OpenAPIStability } from "./OpenAPIStability.js";
|
|
3
|
+
|
|
4
|
+
//#region src/common/OpenAPISummary.tsx
|
|
5
|
+
function OpenAPISummary(props) {
|
|
6
|
+
const { data, context } = props;
|
|
7
|
+
const { operation } = data;
|
|
8
|
+
const title = (() => {
|
|
9
|
+
if (operation.summary) return operation.summary;
|
|
10
|
+
if ("name" in data) return data.name;
|
|
11
|
+
})();
|
|
12
|
+
return <div className="openapi-summary" id={operation.summary ? void 0 : context.id}>
|
|
13
|
+
{(operation.deprecated || operation["x-stability"]) && <div className="openapi-summary-tags">
|
|
14
|
+
{operation.deprecated && <div className="openapi-deprecated">Deprecated</div>}
|
|
15
|
+
{operation["x-stability"] && <OpenAPIStability stability={operation["x-stability"]} />}
|
|
16
|
+
</div>}
|
|
17
|
+
{title ? context.renderHeading({
|
|
18
|
+
deprecated: operation.deprecated ?? false,
|
|
19
|
+
stability: operation["x-stability"],
|
|
20
|
+
title
|
|
21
|
+
}) : null}
|
|
22
|
+
{"path" in data ? <OpenAPIPath data={data} context={context} /> : null}
|
|
23
|
+
</div>;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
//#endregion
|
|
27
|
+
export { OpenAPISummary };
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
//#region src/contentTypeChecks.ts
|
|
2
|
+
function isJSON(contentType) {
|
|
3
|
+
return contentType?.toLowerCase().includes("application/json") || false;
|
|
4
|
+
}
|
|
5
|
+
function isXML(contentType) {
|
|
6
|
+
return contentType?.toLowerCase().includes("application/xml") || false;
|
|
7
|
+
}
|
|
8
|
+
function isYAML(contentType) {
|
|
9
|
+
return contentType?.toLowerCase().includes("application/yaml") || false;
|
|
10
|
+
}
|
|
11
|
+
function isGraphQL(contentType) {
|
|
12
|
+
return contentType?.toLowerCase().includes("application/graphql") || false;
|
|
13
|
+
}
|
|
14
|
+
function isCSV(contentType) {
|
|
15
|
+
return contentType?.toLowerCase().includes("text/csv") || false;
|
|
16
|
+
}
|
|
17
|
+
function isPDF(contentType) {
|
|
18
|
+
return contentType?.toLowerCase().includes("application/pdf") || false;
|
|
19
|
+
}
|
|
20
|
+
function isText(contentType) {
|
|
21
|
+
return contentType?.toLowerCase().includes("text/plain") || false;
|
|
22
|
+
}
|
|
23
|
+
function isFormUrlEncoded(contentType) {
|
|
24
|
+
return contentType?.toLowerCase().includes("application/x-www-form-urlencoded") || false;
|
|
25
|
+
}
|
|
26
|
+
function isFormData(contentType) {
|
|
27
|
+
return !!contentType && contentType.toLowerCase().includes("multipart/form-data");
|
|
28
|
+
}
|
|
29
|
+
function isPlainObject(value) {
|
|
30
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
//#endregion
|
|
34
|
+
export { isCSV, isFormData, isFormUrlEncoded, isGraphQL, isJSON, isPDF, isPlainObject, isText, isXML, isYAML };
|