@gitbook/react-openapi 1.5.2 → 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 +18 -0
- package/dist/InteractiveSection.js +2 -2
- package/dist/OpenAPICodeSample.js +2 -2
- package/dist/OpenAPICodeSampleInteractive.js +1 -5
- package/dist/OpenAPICopyButton.js +12 -7
- package/dist/OpenAPIDisclosure.js +4 -6
- package/dist/OpenAPIDisclosureGroup.js +21 -7
- package/dist/OpenAPIPath.js +12 -38
- package/dist/OpenAPIPathItem.js +22 -0
- package/dist/OpenAPIPathMultipleServers.js +43 -0
- package/dist/OpenAPIRequiredScopes.js +67 -0
- package/dist/OpenAPISecurities.js +17 -43
- package/dist/OpenAPISelect.js +6 -6
- package/dist/OpenAPISpec.js +1 -1
- package/dist/OpenAPITooltip.js +23 -0
- package/dist/ScalarApiButton.js +5 -2
- package/dist/code-samples.js +33 -3
- package/dist/context.d.ts +3 -0
- package/dist/formatPath.js +25 -0
- package/dist/getOrCreateDisclosureStoreByKey.js +31 -0
- package/dist/resolveOpenAPIOperation.js +5 -2
- package/dist/translate.js +2 -2
- package/dist/translations/de.js +2 -0
- package/dist/translations/en.d.ts +2 -0
- package/dist/translations/en.js +2 -0
- package/dist/translations/es.js +2 -0
- package/dist/translations/fr.js +2 -0
- package/dist/translations/index.d.ts +18 -0
- package/dist/translations/ja.js +2 -0
- package/dist/translations/nl.js +2 -0
- package/dist/translations/no.js +2 -0
- package/dist/translations/pt-br.js +2 -0
- package/dist/translations/zh.js +2 -0
- package/dist/types.d.ts +1 -0
- package/package.json +21 -8
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,23 @@
|
|
|
1
1
|
# @gitbook/react-openapi
|
|
2
2
|
|
|
3
|
+
## 1.5.3
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- b4a021a: Add heredoc support for cURL JSON body
|
|
8
|
+
- a512c90: Re-arrange OpenAPI Scopes for OAuth2
|
|
9
|
+
- df1966d: Bump Scalar
|
|
10
|
+
- b45feaf: Disable OpenAPI "Try it" when no servers are defined
|
|
11
|
+
- 10995e0: Use NPM Trusted publishing for publishing the package.
|
|
12
|
+
- f9f8011: Add alt text support to card covers
|
|
13
|
+
- 8ce7322: Add OpenAPI servers selection
|
|
14
|
+
- 2c3066e: Improve OAuth2 scopes handling in OpenAPI
|
|
15
|
+
- Updated dependencies [df1966d]
|
|
16
|
+
- Updated dependencies [10995e0]
|
|
17
|
+
- Updated dependencies [10995e0]
|
|
18
|
+
- @gitbook/openapi-parser@3.0.5
|
|
19
|
+
- @gitbook/expr@1.2.4
|
|
20
|
+
|
|
3
21
|
## 1.5.2
|
|
4
22
|
|
|
5
23
|
### Patch Changes
|
|
@@ -3,10 +3,10 @@
|
|
|
3
3
|
|
|
4
4
|
import { Section, SectionBody, SectionHeader, SectionHeaderContent } from "./StaticSection.js";
|
|
5
5
|
import { OpenAPISelect, OpenAPISelectItem, useSelectState } from "./OpenAPISelect.js";
|
|
6
|
-
import { useDisclosureState } from "./node_modules/react-stately/dist/import.js";
|
|
7
6
|
import clsx from "classnames";
|
|
8
7
|
import { useRef } from "react";
|
|
9
8
|
import { mergeProps, useButton, useDisclosure, useFocusRing } from "react-aria";
|
|
9
|
+
import { useDisclosureState } from "react-stately";
|
|
10
10
|
|
|
11
11
|
//#region src/InteractiveSection.tsx
|
|
12
12
|
/**
|
|
@@ -37,7 +37,7 @@ function InteractiveSection(props) {
|
|
|
37
37
|
<div className={clsx("openapi-section-header-controls", `${className}-header-controls`)} onClick={(event) => {
|
|
38
38
|
event.stopPropagation();
|
|
39
39
|
}}>
|
|
40
|
-
{tabs.length > 0 ? <OpenAPISelect stateKey={stateKey} items={tabs}
|
|
40
|
+
{tabs.length > 0 ? <OpenAPISelect stateKey={stateKey} items={tabs} onChange={() => {
|
|
41
41
|
state.expand();
|
|
42
42
|
}} icon={selectIcon} placement="bottom end">
|
|
43
43
|
{tabs.map((tab) => <OpenAPISelectItem key={tab.key} id={tab.key} value={tab}>
|
|
@@ -132,10 +132,10 @@ function OpenAPICodeSampleFooter(props) {
|
|
|
132
132
|
const hideTryItPanel = data["x-hideTryItPanel"] || data.operation["x-hideTryItPanel"];
|
|
133
133
|
const hasMultipleMediaTypes = renderers.length > 1 || renderers.some((renderer) => renderer.examples.length > 0);
|
|
134
134
|
if (hideTryItPanel && !hasMultipleMediaTypes) return null;
|
|
135
|
-
if (!validateHttpMethod(method)) return null;
|
|
135
|
+
if (!validateHttpMethod(method) || !hasMultipleMediaTypes && servers.length === 0) return null;
|
|
136
136
|
return <div className="openapi-codesample-footer">
|
|
137
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} />}
|
|
138
|
+
{!hideTryItPanel && servers.length > 0 && <ScalarApiButton context={getOpenAPIClientContext(context)} method={method} path={path} securities={securities} servers={servers} specUrl={specUrl} />}
|
|
139
139
|
</div>;
|
|
140
140
|
}
|
|
141
141
|
/**
|
|
@@ -3,7 +3,6 @@
|
|
|
3
3
|
|
|
4
4
|
import { createStateKey } from "./utils.js";
|
|
5
5
|
import { OpenAPISelect, OpenAPISelectItem, useSelectState } from "./OpenAPISelect.js";
|
|
6
|
-
import clsx from "classnames";
|
|
7
6
|
|
|
8
7
|
//#region src/OpenAPICodeSampleInteractive.tsx
|
|
9
8
|
function OpenAPIMediaTypeExamplesSelector(props) {
|
|
@@ -24,10 +23,7 @@ function MediaTypeSelector(props) {
|
|
|
24
23
|
key: renderer.mediaType,
|
|
25
24
|
label: renderer.mediaType
|
|
26
25
|
}));
|
|
27
|
-
return <OpenAPISelect
|
|
28
|
-
key: renderer.mediaType,
|
|
29
|
-
label: renderer.mediaType
|
|
30
|
-
}))} icon={selectIcon} stateKey={stateKey} placement="bottom start">
|
|
26
|
+
return <OpenAPISelect items={items} icon={selectIcon} stateKey={stateKey} placement="bottom start">
|
|
31
27
|
{items.map((item) => <OpenAPISelectItem key={item.key} id={item.key} value={item}>
|
|
32
28
|
{item.label}
|
|
33
29
|
</OpenAPISelectItem>)}
|
|
@@ -2,8 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
|
|
4
4
|
import { t } from "./translate.js";
|
|
5
|
+
import { OpenAPITooltip } from "./OpenAPITooltip.js";
|
|
6
|
+
import clsx from "classnames";
|
|
5
7
|
import { useState } from "react";
|
|
6
|
-
import { Button
|
|
8
|
+
import { Button } from "react-aria-components";
|
|
7
9
|
|
|
8
10
|
//#region src/OpenAPICopyButton.tsx
|
|
9
11
|
function OpenAPICopyButton(props) {
|
|
@@ -21,18 +23,21 @@ function OpenAPICopyButton(props) {
|
|
|
21
23
|
}, 2e3);
|
|
22
24
|
});
|
|
23
25
|
};
|
|
24
|
-
return <
|
|
26
|
+
return <OpenAPITooltip isDisabled={!withTooltip} isOpen={isOpen} onOpenChange={setIsOpen}>
|
|
25
27
|
<Button type="button" preventFocusOnPress onPress={(e) => {
|
|
26
28
|
handleCopy();
|
|
27
29
|
onPress?.(e);
|
|
28
|
-
}} className={
|
|
30
|
+
}} className={clsx("openapi-copy-button", className)} {...props}>
|
|
29
31
|
{children}
|
|
30
32
|
</Button>
|
|
31
33
|
|
|
32
|
-
<
|
|
33
|
-
{copied ?
|
|
34
|
-
|
|
35
|
-
|
|
34
|
+
<OpenAPITooltip.Content isOpen={isOpen} onOpenChange={setIsOpen}>
|
|
35
|
+
{copied ? <>
|
|
36
|
+
{context.icons.check}
|
|
37
|
+
{t(context.translation, "copied")}
|
|
38
|
+
</> : label || t(context.translation, "copy_to_clipboard")}
|
|
39
|
+
</OpenAPITooltip.Content>
|
|
40
|
+
</OpenAPITooltip>;
|
|
36
41
|
}
|
|
37
42
|
|
|
38
43
|
//#endregion
|
|
@@ -10,19 +10,17 @@ import { Button, Disclosure, DisclosurePanel } from "react-aria-components";
|
|
|
10
10
|
* Display an interactive OpenAPI disclosure.
|
|
11
11
|
*/
|
|
12
12
|
function OpenAPIDisclosure(props) {
|
|
13
|
-
const { icon, header, label, children, className } = props;
|
|
14
|
-
const [isExpanded, setIsExpanded] = useState(
|
|
13
|
+
const { icon, header, label, children, className, defaultExpanded = false } = props;
|
|
14
|
+
const [isExpanded, setIsExpanded] = useState(defaultExpanded);
|
|
15
15
|
return <Disclosure className={clsx("openapi-disclosure", className)} isExpanded={isExpanded} onExpandedChange={setIsExpanded}>
|
|
16
16
|
<Button slot="trigger" className="openapi-disclosure-trigger" style={({ isFocusVisible }) => ({ outline: isFocusVisible ? "2px solid rgb(var(--primary-color-500) / 0.4)" : "none" })}>
|
|
17
17
|
{header}
|
|
18
18
|
<div className="openapi-disclosure-trigger-label">
|
|
19
|
-
<span>{typeof label === "function" ? label(isExpanded) : label}</span>
|
|
19
|
+
{label ? <span>{typeof label === "function" ? label(isExpanded) : label}</span> : null}
|
|
20
20
|
{icon}
|
|
21
21
|
</div>
|
|
22
22
|
</Button>
|
|
23
|
-
<DisclosurePanel className="openapi-disclosure-panel">
|
|
24
|
-
{isExpanded ? children : null}
|
|
25
|
-
</DisclosurePanel>
|
|
23
|
+
{isExpanded ? <DisclosurePanel className="openapi-disclosure-panel">{children}</DisclosurePanel> : null}
|
|
26
24
|
</Disclosure>;
|
|
27
25
|
}
|
|
28
26
|
|
|
@@ -2,24 +2,38 @@
|
|
|
2
2
|
|
|
3
3
|
|
|
4
4
|
import { OpenAPISelect, OpenAPISelectItem, useSelectState } from "./OpenAPISelect.js";
|
|
5
|
-
import {
|
|
5
|
+
import { getOrCreateDisclosureStoreByKey } from "./getOrCreateDisclosureStoreByKey.js";
|
|
6
|
+
import clsx from "classnames";
|
|
6
7
|
import { createContext, useContext, useRef } from "react";
|
|
8
|
+
import { useStore } from "zustand";
|
|
7
9
|
import { mergeProps, useButton, useDisclosure, useFocusRing, useId as useId$1 } from "react-aria";
|
|
10
|
+
import { useDisclosureGroupState, useDisclosureState } from "react-stately";
|
|
8
11
|
|
|
9
12
|
//#region src/OpenAPIDisclosureGroup.tsx
|
|
10
13
|
const DisclosureGroupStateContext = createContext(null);
|
|
14
|
+
function useDisclosureGroupStore(stateKey = "disclosure-group", initialKeys) {
|
|
15
|
+
return useStore(getOrCreateDisclosureStoreByKey(stateKey, initialKeys));
|
|
16
|
+
}
|
|
11
17
|
/**
|
|
12
18
|
* Display an interactive OpenAPI disclosure group.
|
|
13
19
|
*/
|
|
14
20
|
function OpenAPIDisclosureGroup(props) {
|
|
15
|
-
const { icon, groups, selectStateKey, selectIcon } = props;
|
|
16
|
-
const
|
|
21
|
+
const { icon, groups, selectStateKey, stateKey, selectIcon, className, expandedKeys, defaultExpandedKeys, onExpandedChange } = props;
|
|
22
|
+
const { expandedKeys: storeExpandedKeys, setExpandedKeys } = useDisclosureGroupStore(stateKey, expandedKeys || defaultExpandedKeys ? new Set(expandedKeys || defaultExpandedKeys) : void 0);
|
|
23
|
+
const state = useDisclosureGroupState({
|
|
24
|
+
...props,
|
|
25
|
+
expandedKeys: storeExpandedKeys,
|
|
26
|
+
onExpandedChange: (keys) => {
|
|
27
|
+
setExpandedKeys(keys);
|
|
28
|
+
onExpandedChange?.(keys);
|
|
29
|
+
}
|
|
30
|
+
});
|
|
17
31
|
return <DisclosureGroupStateContext.Provider value={state}>
|
|
18
|
-
{groups.map((group) => <DisclosureItem selectStateKey={selectStateKey} selectIcon={selectIcon} icon={icon} key={group.key} group={group} />)}
|
|
32
|
+
{groups.map((group) => <DisclosureItem className={className} selectStateKey={selectStateKey} selectIcon={selectIcon} icon={icon} key={group.key} group={group} />)}
|
|
19
33
|
</DisclosureGroupStateContext.Provider>;
|
|
20
34
|
}
|
|
21
35
|
function DisclosureItem(props) {
|
|
22
|
-
const { icon, group, selectStateKey, selectIcon } = props;
|
|
36
|
+
const { icon, group, selectStateKey, selectIcon, className } = props;
|
|
23
37
|
const defaultId = useId$1();
|
|
24
38
|
const id = group.key || defaultId;
|
|
25
39
|
const groupState = useContext(DisclosureGroupStateContext);
|
|
@@ -42,7 +56,7 @@ function DisclosureItem(props) {
|
|
|
42
56
|
const { isFocusVisible, focusProps } = useFocusRing();
|
|
43
57
|
const store = useSelectState(selectStateKey, group.tabs?.[0]?.key || "");
|
|
44
58
|
const selectedTab = group.tabs?.find((tab) => tab.key === store.key) || group.tabs?.[0];
|
|
45
|
-
return <div className="openapi-disclosure-group" aria-expanded={state.isExpanded}>
|
|
59
|
+
return <div className={clsx("openapi-disclosure-group", className)} aria-expanded={state.isExpanded}>
|
|
46
60
|
<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
61
|
<div className="openapi-disclosure-group-icon">
|
|
48
62
|
{icon || <svg viewBox="0 0 24 24" className="openapi-disclosure-group-icon">
|
|
@@ -54,7 +68,7 @@ function DisclosureItem(props) {
|
|
|
54
68
|
{group.label}
|
|
55
69
|
|
|
56
70
|
{group.tabs ? <div className="openapi-disclosure-group-mediatype" onClick={(e) => e.stopPropagation()}>
|
|
57
|
-
{group.tabs?.length > 1 ? <OpenAPISelect icon={selectIcon} stateKey={selectStateKey}
|
|
71
|
+
{group.tabs?.length > 1 ? <OpenAPISelect icon={selectIcon} stateKey={selectStateKey} onChange={() => {
|
|
58
72
|
state.expand();
|
|
59
73
|
}} items={group.tabs} placement="bottom end">
|
|
60
74
|
{group.tabs.map((tab) => <OpenAPISelectItem key={tab.key} id={tab.key} value={tab}>
|
package/dist/OpenAPIPath.js
CHANGED
|
@@ -1,50 +1,24 @@
|
|
|
1
|
-
import { OpenAPICopyButton } from "./OpenAPICopyButton.js";
|
|
2
1
|
import { getOpenAPIClientContext } from "./context.js";
|
|
2
|
+
import { OpenAPIPathItem } from "./OpenAPIPathItem.js";
|
|
3
|
+
import { formatPath } from "./formatPath.js";
|
|
3
4
|
import { getDefaultServerURL } from "./util/server.js";
|
|
5
|
+
import { OpenAPIPathMultipleServers } from "./OpenAPIPathMultipleServers.js";
|
|
4
6
|
|
|
5
7
|
//#region src/OpenAPIPath.tsx
|
|
6
8
|
/**
|
|
7
9
|
* Display the path of an operation.
|
|
8
10
|
*/
|
|
9
11
|
function OpenAPIPath(props) {
|
|
10
|
-
const { data,
|
|
11
|
-
const {
|
|
12
|
-
const
|
|
12
|
+
const { data, withServer = true, context } = props;
|
|
13
|
+
const { path } = data;
|
|
14
|
+
const clientContext = getOpenAPIClientContext(context);
|
|
15
|
+
if (withServer && data.servers.length > 1) return <OpenAPIPathMultipleServers {...props} context={clientContext} />;
|
|
13
16
|
const formattedPath = formatPath(path);
|
|
14
|
-
const
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
})();
|
|
20
|
-
return <div className="openapi-path">
|
|
21
|
-
<div className={`openapi-method openapi-method-${method}`}>{method}</div>
|
|
22
|
-
|
|
23
|
-
<OpenAPICopyButton value={`${withServer ? server : ""}${path}`} className="openapi-path-title" data-deprecated={operation.deprecated} isDisabled={!canCopy} context={getOpenAPIClientContext(context)}>
|
|
24
|
-
{element}
|
|
25
|
-
</OpenAPICopyButton>
|
|
26
|
-
</div>;
|
|
27
|
-
}
|
|
28
|
-
/**
|
|
29
|
-
* Format the path by wrapping placeholders in <span> tags.
|
|
30
|
-
*/
|
|
31
|
-
function formatPath(path) {
|
|
32
|
-
const regex = /\{\s*(\w+)\s*\}|:\w+/g;
|
|
33
|
-
const parts = [];
|
|
34
|
-
let lastIndex = 0;
|
|
35
|
-
path.replace(regex, (match, _, offset) => {
|
|
36
|
-
if (offset > lastIndex) parts.push(path.slice(lastIndex, offset));
|
|
37
|
-
parts.push(<span key={`offset-${offset}`} className="openapi-path-variable">
|
|
38
|
-
{match}
|
|
39
|
-
</span>);
|
|
40
|
-
lastIndex = offset + match.length;
|
|
41
|
-
return match;
|
|
42
|
-
});
|
|
43
|
-
if (lastIndex < path.length) parts.push(path.slice(lastIndex));
|
|
44
|
-
return parts.map((part, index) => {
|
|
45
|
-
if (typeof part === "string") return <span key={`part-${index}`}>{part}</span>;
|
|
46
|
-
return part;
|
|
47
|
-
});
|
|
17
|
+
const defaultServer = getDefaultServerURL(data.servers);
|
|
18
|
+
return <OpenAPIPathItem {...props} value={`${defaultServer}${path}`} context={clientContext}>
|
|
19
|
+
{withServer ? <span className="openapi-path-server">{defaultServer}</span> : null}
|
|
20
|
+
{formattedPath}
|
|
21
|
+
</OpenAPIPathItem>;
|
|
48
22
|
}
|
|
49
23
|
|
|
50
24
|
//#endregion
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { OpenAPICopyButton } from "./OpenAPICopyButton.js";
|
|
2
|
+
|
|
3
|
+
//#region src/OpenAPIPathItem.tsx
|
|
4
|
+
function OpenAPIPathItem(props) {
|
|
5
|
+
const { value, canCopy = true, context, children, data, copyType = "children" } = props;
|
|
6
|
+
const { operation, method } = data;
|
|
7
|
+
const title = <span className="openapi-path-title">{children}</span>;
|
|
8
|
+
return <div className="openapi-path">
|
|
9
|
+
<div className={`openapi-method openapi-method-${method}`}>{method}</div>
|
|
10
|
+
{canCopy && value ? copyType === "children" ? <OpenAPICopyButton value={value} data-deprecated={operation.deprecated} isDisabled={!canCopy} context={context} className="openapi-path-copy-button">
|
|
11
|
+
{title}
|
|
12
|
+
</OpenAPICopyButton> : <>
|
|
13
|
+
{title}
|
|
14
|
+
<OpenAPICopyButton value={value} data-deprecated={operation.deprecated} isDisabled={!canCopy} context={context} className="openapi-path-copy-button openapi-path-copy-button-icon">
|
|
15
|
+
{context.icons.copy}
|
|
16
|
+
</OpenAPICopyButton>
|
|
17
|
+
</> : title}
|
|
18
|
+
</div>;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
//#endregion
|
|
22
|
+
export { OpenAPIPathItem };
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
import { OpenAPITooltip } from "./OpenAPITooltip.js";
|
|
5
|
+
import { createStateKey } from "./utils.js";
|
|
6
|
+
import { OpenAPISelect, OpenAPISelectItem, useSelectState } from "./OpenAPISelect.js";
|
|
7
|
+
import { OpenAPIPathItem } from "./OpenAPIPathItem.js";
|
|
8
|
+
import { formatPath } from "./formatPath.js";
|
|
9
|
+
import { getDefaultServerURL } from "./util/server.js";
|
|
10
|
+
import { Text } from "react-aria-components";
|
|
11
|
+
|
|
12
|
+
//#region src/OpenAPIPathMultipleServers.tsx
|
|
13
|
+
const serversStateKey = createStateKey("servers");
|
|
14
|
+
/**
|
|
15
|
+
* Display the path of an operation.
|
|
16
|
+
*/
|
|
17
|
+
function OpenAPIPathMultipleServers(props) {
|
|
18
|
+
const { data, withServer = true, context } = props;
|
|
19
|
+
const { path, servers } = data;
|
|
20
|
+
const defaultServer = getDefaultServerURL(servers);
|
|
21
|
+
const { key, setKey } = useSelectState(serversStateKey, defaultServer);
|
|
22
|
+
const formattedPath = formatPath(path);
|
|
23
|
+
const items = servers.filter((server) => !!server.url).map((server) => ({
|
|
24
|
+
key: server.url,
|
|
25
|
+
label: server.url,
|
|
26
|
+
description: server.description
|
|
27
|
+
}));
|
|
28
|
+
return <OpenAPIPathItem copyType="button" {...props} value={`${withServer ? key : ""}${path}`} context={context}>
|
|
29
|
+
{withServer ? <OpenAPITooltip>
|
|
30
|
+
<OpenAPISelect className="openapi-select openapi-select-unstyled" items={items} stateKey={serversStateKey} placement="bottom start" icon={context.icons.chevronDown} defaultValue={defaultServer} onChange={setKey}>
|
|
31
|
+
{items.map((item) => <OpenAPISelectItem textValue={item.label} key={item.key} id={item.key} value={item} className="openapi-select-item-column">
|
|
32
|
+
<Text slot="label">{item.label}</Text>
|
|
33
|
+
{item.description ? <Text slot="description">{item.description}</Text> : null}
|
|
34
|
+
</OpenAPISelectItem>)}
|
|
35
|
+
</OpenAPISelect>
|
|
36
|
+
<OpenAPITooltip.Content>Click to select a server</OpenAPITooltip.Content>
|
|
37
|
+
</OpenAPITooltip> : null}
|
|
38
|
+
{formattedPath}
|
|
39
|
+
</OpenAPIPathItem>;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
//#endregion
|
|
43
|
+
export { OpenAPIPathMultipleServers };
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
import { t } from "./translate.js";
|
|
5
|
+
import { OpenAPICopyButton } from "./OpenAPICopyButton.js";
|
|
6
|
+
import { useSelectState } from "./OpenAPISelect.js";
|
|
7
|
+
import { OpenAPIDisclosureGroup } from "./OpenAPIDisclosureGroup.js";
|
|
8
|
+
|
|
9
|
+
//#region src/OpenAPIRequiredScopes.tsx
|
|
10
|
+
/**
|
|
11
|
+
* Present securities authorization that can be used for this operation.
|
|
12
|
+
*/
|
|
13
|
+
function OpenAPIRequiredScopes(props) {
|
|
14
|
+
const { securities, stateKey, context } = props;
|
|
15
|
+
const { key: selectedKey } = useSelectState(stateKey, securities[0]?.key);
|
|
16
|
+
const selectedSecurity = securities.find((security) => security.key === selectedKey);
|
|
17
|
+
if (!selectedSecurity) return null;
|
|
18
|
+
const scopes = selectedSecurity.schemes.flatMap((scheme) => {
|
|
19
|
+
return scheme.scopes ?? [];
|
|
20
|
+
});
|
|
21
|
+
if (!scopes.length) return null;
|
|
22
|
+
return <OpenAPIDisclosureGroup className="openapi-required-scopes" icon={context.icons.chevronRight} stateKey="required-scopes" defaultExpandedKeys={["required-scopes"]} groups={[{
|
|
23
|
+
key: "required-scopes",
|
|
24
|
+
label: <div className="openapi-required-scopes-header">
|
|
25
|
+
{context.icons.lock}
|
|
26
|
+
<span>{t(context.translation, "required_scopes")}</span>
|
|
27
|
+
</div>,
|
|
28
|
+
tabs: [{
|
|
29
|
+
key: "scopes",
|
|
30
|
+
label: "",
|
|
31
|
+
body: <OpenAPISchemaScopes scopes={scopes} context={context} />
|
|
32
|
+
}]
|
|
33
|
+
}]} />;
|
|
34
|
+
}
|
|
35
|
+
function OpenAPISchemaScopes(props) {
|
|
36
|
+
const { scopes, context, isOAuth2 } = props;
|
|
37
|
+
return <div className="openapi-securities-scopes openapi-markdown">
|
|
38
|
+
<div className="openapi-required-scopes-description">
|
|
39
|
+
{t(context.translation, isOAuth2 ? "available_scopes" : "required_scopes_description")}
|
|
40
|
+
</div>
|
|
41
|
+
<ul>
|
|
42
|
+
{scopes.map((scope) => <OpenAPIScopeItem key={scope[0]} scope={scope} context={context} />)}
|
|
43
|
+
</ul>
|
|
44
|
+
</div>;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Display a scope item. Either a key-value pair or a single string.
|
|
48
|
+
*/
|
|
49
|
+
function OpenAPIScopeItem(props) {
|
|
50
|
+
const { scope, context } = props;
|
|
51
|
+
return <li>
|
|
52
|
+
<OpenAPIScopeItemKey name={scope[0]} context={context} />
|
|
53
|
+
{scope[1] ? <span>: {scope[1]}</span> : null}
|
|
54
|
+
</li>;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Displays the scope name within a copyable button.
|
|
58
|
+
*/
|
|
59
|
+
function OpenAPIScopeItemKey(props) {
|
|
60
|
+
const { name, context } = props;
|
|
61
|
+
return <OpenAPICopyButton value={name} context={context} withTooltip>
|
|
62
|
+
<code>{name}</code>
|
|
63
|
+
</OpenAPICopyButton>;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
//#endregion
|
|
67
|
+
export { OpenAPIRequiredScopes, OpenAPISchemaScopes };
|
|
@@ -4,6 +4,7 @@ import { OpenAPICopyButton } from "./OpenAPICopyButton.js";
|
|
|
4
4
|
import { OpenAPISchemaName } from "./OpenAPISchemaName.js";
|
|
5
5
|
import { createStateKey, extractOperationSecurityInfo, resolveDescription } from "./utils.js";
|
|
6
6
|
import { InteractiveSection } from "./InteractiveSection.js";
|
|
7
|
+
import { OpenAPIRequiredScopes, OpenAPISchemaScopes } from "./OpenAPIRequiredScopes.js";
|
|
7
8
|
import { Fragment } from "react";
|
|
8
9
|
|
|
9
10
|
//#region src/OpenAPISecurities.tsx
|
|
@@ -17,20 +18,23 @@ function OpenAPISecurities(props) {
|
|
|
17
18
|
securityRequirement,
|
|
18
19
|
securities
|
|
19
20
|
});
|
|
20
|
-
|
|
21
|
+
const stateKey = createStateKey("securities", context.blockKey);
|
|
22
|
+
return <>
|
|
23
|
+
<OpenAPIRequiredScopes context={context} stateKey={stateKey} securities={tabsData} />
|
|
24
|
+
<InteractiveSection header={t(context.translation, "authorizations")} stateKey={stateKey} toggleIcon={context.icons.chevronRight} selectIcon={context.icons.chevronDown} className="openapi-securities" tabs={tabsData.map(({ key, label, schemes }) => ({
|
|
21
25
|
key,
|
|
22
26
|
label,
|
|
23
27
|
body: <div className="openapi-schema">
|
|
24
|
-
|
|
25
|
-
const description = resolveDescription(security);
|
|
28
|
+
{schemes.map((security, index) => {
|
|
29
|
+
const description = security.type !== "oauth2" ? resolveDescription(security) : void 0;
|
|
26
30
|
return <div key={`${key}-${index}`} className="openapi-schema-presentation">
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
</div>;
|
|
31
|
+
{getLabelForType(security, context)}
|
|
32
|
+
{description ? <Markdown source={description} className="openapi-securities-description" /> : null}
|
|
33
|
+
</div>;
|
|
31
34
|
})}
|
|
32
|
-
|
|
33
|
-
}))}
|
|
35
|
+
</div>
|
|
36
|
+
}))} />
|
|
37
|
+
</>;
|
|
34
38
|
}
|
|
35
39
|
function getLabelForType(security, context) {
|
|
36
40
|
switch (security.type) {
|
|
@@ -61,11 +65,12 @@ function OpenAPISchemaOAuth2Flows(props) {
|
|
|
61
65
|
function OpenAPISchemaOAuth2Item(props) {
|
|
62
66
|
const { flow, context, security, name } = props;
|
|
63
67
|
if (!flow) return null;
|
|
64
|
-
const scopes = flow.scopes ? Object.entries(flow.scopes) : [];
|
|
68
|
+
const scopes = !security.scopes?.length && flow.scopes ? Object.entries(flow.scopes) : [];
|
|
69
|
+
const description = resolveDescription(security);
|
|
65
70
|
return <div>
|
|
66
71
|
<OpenAPISchemaName context={context} propertyName="OAuth2" type={name} required={security.required} />
|
|
67
72
|
<div className="openapi-securities-oauth-content openapi-markdown">
|
|
68
|
-
{
|
|
73
|
+
{description ? <Markdown source={description} className="openapi-securities-description" /> : null}
|
|
69
74
|
{"authorizationUrl" in flow && flow.authorizationUrl ? <span>
|
|
70
75
|
Authorization URL:{" "}
|
|
71
76
|
<OpenAPICopyButton value={flow.authorizationUrl} context={context} className="openapi-securities-url" withTooltip>
|
|
@@ -84,41 +89,10 @@ function OpenAPISchemaOAuth2Item(props) {
|
|
|
84
89
|
{flow.refreshUrl}
|
|
85
90
|
</OpenAPICopyButton>
|
|
86
91
|
</span> : null}
|
|
87
|
-
{scopes.length ? <OpenAPISchemaScopes scopes={scopes} context={context} /> : null}
|
|
92
|
+
{scopes.length ? <OpenAPISchemaScopes scopes={scopes} context={context} isOAuth2 /> : null}
|
|
88
93
|
</div>
|
|
89
94
|
</div>;
|
|
90
95
|
}
|
|
91
|
-
/**
|
|
92
|
-
* Render a list of available scopes.
|
|
93
|
-
*/
|
|
94
|
-
function OpenAPISchemaScopes(props) {
|
|
95
|
-
const { scopes, context } = props;
|
|
96
|
-
return <div className="openapi-securities-scopes openapi-markdown">
|
|
97
|
-
<span>{t(context.translation, "required_scopes")}: </span>
|
|
98
|
-
<ul>
|
|
99
|
-
{scopes.map((scope) => <OpenAPIScopeItem key={scope[0]} scope={scope} context={context} />)}
|
|
100
|
-
</ul>
|
|
101
|
-
</div>;
|
|
102
|
-
}
|
|
103
|
-
/**
|
|
104
|
-
* Display a scope item. Either a key-value pair or a single string.
|
|
105
|
-
*/
|
|
106
|
-
function OpenAPIScopeItem(props) {
|
|
107
|
-
const { scope, context } = props;
|
|
108
|
-
return <li>
|
|
109
|
-
<OpenAPIScopeItemKey name={scope[0]} context={context} />
|
|
110
|
-
{scope[1] ? `: ${scope[1]}` : null}
|
|
111
|
-
</li>;
|
|
112
|
-
}
|
|
113
|
-
/**
|
|
114
|
-
* Displays the scope name within a copyable button.
|
|
115
|
-
*/
|
|
116
|
-
function OpenAPIScopeItemKey(props) {
|
|
117
|
-
const { name, context } = props;
|
|
118
|
-
return <OpenAPICopyButton value={name} context={context} withTooltip>
|
|
119
|
-
<code>{name}</code>
|
|
120
|
-
</OpenAPICopyButton>;
|
|
121
|
-
}
|
|
122
96
|
|
|
123
97
|
//#endregion
|
|
124
98
|
export { OpenAPISecurities };
|
package/dist/OpenAPISelect.js
CHANGED
|
@@ -16,16 +16,16 @@ function useSelectState(stateKey = "select-state", initialKey = "default") {
|
|
|
16
16
|
};
|
|
17
17
|
}
|
|
18
18
|
function OpenAPISelect(props) {
|
|
19
|
-
const { icon
|
|
20
|
-
const state = useSelectState(stateKey, items[0]?.key);
|
|
19
|
+
const { icon, items, children, className, placement, stateKey, value, onChange, defaultValue } = props;
|
|
20
|
+
const state = useSelectState(stateKey, defaultValue ?? items[0]?.key);
|
|
21
21
|
const selected = items.find((item) => item.key === state.key) || items[0];
|
|
22
|
-
return <Select aria-label="OpenAPI Select" {...props} value={
|
|
23
|
-
|
|
22
|
+
return <Select aria-label="OpenAPI Select" {...props} value={value ?? selected?.key} onChange={(key) => {
|
|
23
|
+
onChange?.(key);
|
|
24
24
|
state.setKey(key);
|
|
25
25
|
}} className={clsx("openapi-select", className)}>
|
|
26
26
|
<Button>
|
|
27
27
|
<SelectValue />
|
|
28
|
-
{icon}
|
|
28
|
+
{icon !== null ? icon || "▼" : null}
|
|
29
29
|
</Button>
|
|
30
30
|
<Popover placement={placement} className="openapi-select-popover">
|
|
31
31
|
<ListBox className="openapi-select-listbox" items={items}>
|
|
@@ -38,7 +38,7 @@ function OpenAPISelectItem(props) {
|
|
|
38
38
|
return <ListBoxItem {...props} className={({ isFocused, isSelected }) => clsx("openapi-select-item", {
|
|
39
39
|
"openapi-select-item-focused": isFocused,
|
|
40
40
|
"openapi-select-item-selected": isSelected
|
|
41
|
-
})} />;
|
|
41
|
+
}, props.className)} />;
|
|
42
42
|
}
|
|
43
43
|
|
|
44
44
|
//#endregion
|
package/dist/OpenAPISpec.js
CHANGED
|
@@ -36,7 +36,7 @@ function groupParameters(parameters, context) {
|
|
|
36
36
|
const key = parameter.in;
|
|
37
37
|
const label = getParameterGroupName(parameter.in, context);
|
|
38
38
|
const group = groups.find((group$1) => group$1.key === key);
|
|
39
|
-
if (group) group.parameters.
|
|
39
|
+
if (group) group.parameters = [...group.parameters, parameter];
|
|
40
40
|
else groups.push({
|
|
41
41
|
key,
|
|
42
42
|
label,
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
import clsx from "classnames";
|
|
5
|
+
import { Tooltip, TooltipTrigger } from "react-aria-components";
|
|
6
|
+
|
|
7
|
+
//#region src/OpenAPITooltip.tsx
|
|
8
|
+
function OpenAPITooltip(props) {
|
|
9
|
+
const { children,...rest } = props;
|
|
10
|
+
return <TooltipTrigger {...rest} closeDelay={200} delay={200}>
|
|
11
|
+
{children}
|
|
12
|
+
</TooltipTrigger>;
|
|
13
|
+
}
|
|
14
|
+
function OpenAPITooltipContent(props) {
|
|
15
|
+
const { children, placement = "top", offset = 4, className,...rest } = props;
|
|
16
|
+
return <Tooltip {...rest} placement={placement} offset={offset} className={clsx("openapi-tooltip", className)}>
|
|
17
|
+
{children}
|
|
18
|
+
</Tooltip>;
|
|
19
|
+
}
|
|
20
|
+
OpenAPITooltip.Content = OpenAPITooltipContent;
|
|
21
|
+
|
|
22
|
+
//#endregion
|
|
23
|
+
export { OpenAPITooltip };
|
package/dist/ScalarApiButton.js
CHANGED
|
@@ -47,12 +47,15 @@ function ScalarModal(props) {
|
|
|
47
47
|
url: specUrl,
|
|
48
48
|
...prefillConfig
|
|
49
49
|
}} initialRequest={{
|
|
50
|
-
method,
|
|
50
|
+
method: toScalarHttpMethod(method),
|
|
51
51
|
path
|
|
52
52
|
}}>
|
|
53
53
|
<ScalarModalController method={method} path={path} controllerRef={controllerRef} />
|
|
54
54
|
</ApiClientModalProvider>;
|
|
55
55
|
}
|
|
56
|
+
function toScalarHttpMethod(method) {
|
|
57
|
+
return method.toUpperCase();
|
|
58
|
+
}
|
|
56
59
|
function ScalarModalController(props) {
|
|
57
60
|
const { method, path, controllerRef } = props;
|
|
58
61
|
const openScalarClient = useApiClientModal()?.open;
|
|
@@ -60,7 +63,7 @@ function ScalarModalController(props) {
|
|
|
60
63
|
const openClient = useMemo(() => {
|
|
61
64
|
if (openScalarClient) return () => {
|
|
62
65
|
openScalarClient({
|
|
63
|
-
method,
|
|
66
|
+
method: toScalarHttpMethod(method),
|
|
64
67
|
path,
|
|
65
68
|
_source: "gitbook"
|
|
66
69
|
});
|
package/dist/code-samples.js
CHANGED
|
@@ -33,7 +33,6 @@ ${headerString}${bodyString}`;
|
|
|
33
33
|
label: "cURL",
|
|
34
34
|
syntax: "bash",
|
|
35
35
|
generate: ({ method, url: { origin, path }, headers, body }) => {
|
|
36
|
-
const separator = " \\\n";
|
|
37
36
|
const lines = ["curl -L"];
|
|
38
37
|
if (method.toUpperCase() !== "GET") lines.push(`--request ${method.toUpperCase()}`);
|
|
39
38
|
lines.push(`--url '${origin}${path}'`);
|
|
@@ -49,7 +48,7 @@ ${headerString}${bodyString}`;
|
|
|
49
48
|
});
|
|
50
49
|
if (body) if (Array.isArray(body)) lines.push(...body);
|
|
51
50
|
else lines.push(body);
|
|
52
|
-
return lines
|
|
51
|
+
return buildHeredoc(lines);
|
|
53
52
|
}
|
|
54
53
|
},
|
|
55
54
|
{
|
|
@@ -138,7 +137,15 @@ const BodyGenerators = {
|
|
|
138
137
|
headersCopy["Content-Type"] = "application/json";
|
|
139
138
|
} else if (isPDF(contentType)) body = `--data-binary '@${String(body)}'`;
|
|
140
139
|
else if (isYAML(contentType)) body = `--data-binary $'${yaml.dump(body).replace(/'/g, "").replace(/\\n/g, "\n")}'`;
|
|
141
|
-
else
|
|
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
|
+
}
|
|
142
149
|
return {
|
|
143
150
|
body,
|
|
144
151
|
headers: headersCopy
|
|
@@ -270,6 +277,29 @@ function convertBodyToXML(body) {
|
|
|
270
277
|
}
|
|
271
278
|
return json2xml(body).replace(/"/g, "").replace(/\\n/g, "\n").replace(/\\t/g, " ");
|
|
272
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
|
+
}
|
|
273
303
|
|
|
274
304
|
//#endregion
|
|
275
305
|
export { codeSampleGenerators, parseHostAndPath };
|
package/dist/context.d.ts
CHANGED
|
@@ -14,6 +14,9 @@ interface OpenAPIClientContext {
|
|
|
14
14
|
chevronDown: React.ReactNode;
|
|
15
15
|
chevronRight: React.ReactNode;
|
|
16
16
|
plus: React.ReactNode;
|
|
17
|
+
copy: React.ReactNode;
|
|
18
|
+
check: React.ReactNode;
|
|
19
|
+
lock: React.ReactNode;
|
|
17
20
|
};
|
|
18
21
|
/**
|
|
19
22
|
* Force all sections to be opened by default.
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
//#region src/formatPath.tsx
|
|
2
|
+
/**
|
|
3
|
+
* Format the path by wrapping placeholders in <span> tags.
|
|
4
|
+
*/
|
|
5
|
+
function formatPath(path) {
|
|
6
|
+
const regex = /\{\s*(\w+)\s*\}|:\w+/g;
|
|
7
|
+
const parts = [];
|
|
8
|
+
let lastIndex = 0;
|
|
9
|
+
path.replace(regex, (match, _, offset) => {
|
|
10
|
+
if (offset > lastIndex) parts.push(path.slice(lastIndex, offset));
|
|
11
|
+
parts.push(<span key={`offset-${offset}`} className="openapi-path-variable">
|
|
12
|
+
{match}
|
|
13
|
+
</span>);
|
|
14
|
+
lastIndex = offset + match.length;
|
|
15
|
+
return match;
|
|
16
|
+
});
|
|
17
|
+
if (lastIndex < path.length) parts.push(path.slice(lastIndex));
|
|
18
|
+
return parts.map((part, index) => {
|
|
19
|
+
if (typeof part === "string") return <span key={`part-${index}`}>{part}</span>;
|
|
20
|
+
return part;
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
//#endregion
|
|
25
|
+
export { formatPath };
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { createStore } from "zustand";
|
|
2
|
+
|
|
3
|
+
//#region src/getOrCreateDisclosureStoreByKey.ts
|
|
4
|
+
const createDisclosureStore = (initialKeys) => {
|
|
5
|
+
return createStore()((set) => ({
|
|
6
|
+
expandedKeys: initialKeys ? new Set(initialKeys) : /* @__PURE__ */ new Set(),
|
|
7
|
+
setExpandedKeys: (keys) => {
|
|
8
|
+
set(() => ({ expandedKeys: keys }));
|
|
9
|
+
},
|
|
10
|
+
toggleKey: (key) => {
|
|
11
|
+
set((state) => {
|
|
12
|
+
const newKeys = new Set(state.expandedKeys);
|
|
13
|
+
if (newKeys.has(key)) newKeys.delete(key);
|
|
14
|
+
else newKeys.add(key);
|
|
15
|
+
return { expandedKeys: newKeys };
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
}));
|
|
19
|
+
};
|
|
20
|
+
const defaultDisclosureStores = /* @__PURE__ */ new Map();
|
|
21
|
+
const createDisclosureStoreFactory = (stores) => {
|
|
22
|
+
return (storeKey, initialKeys) => {
|
|
23
|
+
if (!stores.has(storeKey)) stores.set(storeKey, createDisclosureStore(initialKeys));
|
|
24
|
+
if (!stores.get(storeKey)) throw new Error(`Failed to get or create store for key: ${storeKey}`);
|
|
25
|
+
return stores.get(storeKey);
|
|
26
|
+
};
|
|
27
|
+
};
|
|
28
|
+
const getOrCreateDisclosureStoreByKey = createDisclosureStoreFactory(defaultDisclosureStores);
|
|
29
|
+
|
|
30
|
+
//#endregion
|
|
31
|
+
export { getOrCreateDisclosureStoreByKey };
|
|
@@ -88,8 +88,11 @@ function flattenSecurities(security) {
|
|
|
88
88
|
* Resolve the scopes for a security scheme.
|
|
89
89
|
*/
|
|
90
90
|
function resolveSecurityScopes({ securityScheme, operationScopes }) {
|
|
91
|
-
if (!
|
|
92
|
-
return
|
|
91
|
+
if (!operationScopes?.length || !securityScheme || checkIsReference(securityScheme)) return null;
|
|
92
|
+
if (isOAuthSecurityScheme(securityScheme)) return (securityScheme.flows ? Object.entries(securityScheme.flows) : []).flatMap(([_, flow]) => {
|
|
93
|
+
return Object.entries(flow.scopes ?? {}).filter(([scope]) => operationScopes.includes(scope));
|
|
94
|
+
});
|
|
95
|
+
return operationScopes.map((scope) => [scope, void 0]);
|
|
93
96
|
}
|
|
94
97
|
/**
|
|
95
98
|
* Check if a security scheme is an OAuth or OpenID Connect security scheme.
|
package/dist/translate.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React from "react";
|
|
1
|
+
import React, { isValidElement } from "react";
|
|
2
2
|
|
|
3
3
|
//#region src/translate.tsx
|
|
4
4
|
/**
|
|
@@ -35,7 +35,7 @@ function reactToString(el) {
|
|
|
35
35
|
if (typeof el === "string" || typeof el === "number" || typeof el === "boolean") return `${el}`;
|
|
36
36
|
if (el === null || el === void 0) return "";
|
|
37
37
|
if (Array.isArray(el)) return el.map(reactToString).join("");
|
|
38
|
-
if (
|
|
38
|
+
if (isValidElement(el)) return el.props.children.map(reactToString).join("");
|
|
39
39
|
throw new Error(`Unsupported type ${typeof el}`);
|
|
40
40
|
}
|
|
41
41
|
|
package/dist/translations/de.js
CHANGED
|
@@ -38,6 +38,8 @@ const de = {
|
|
|
38
38
|
hide: "Verstecke ${1}",
|
|
39
39
|
available_items: "Verfügbare Elemente",
|
|
40
40
|
required_scopes: "Erforderliche Scopes",
|
|
41
|
+
required_scopes_description: "Dieser Endpunkt erfordert die folgenden Scopes:",
|
|
42
|
+
available_scopes: "Verfügbare Scopes:",
|
|
41
43
|
properties: "Eigenschaften",
|
|
42
44
|
or: "oder",
|
|
43
45
|
and: "und",
|
package/dist/translations/en.js
CHANGED
|
@@ -38,6 +38,8 @@ const en = {
|
|
|
38
38
|
hide: "Hide ${1}",
|
|
39
39
|
available_items: "Available items",
|
|
40
40
|
required_scopes: "Required scopes",
|
|
41
|
+
required_scopes_description: "This endpoint requires the following scopes:",
|
|
42
|
+
available_scopes: "Available scopes:",
|
|
41
43
|
possible_values: "Possible values",
|
|
42
44
|
properties: "Properties",
|
|
43
45
|
or: "or",
|
package/dist/translations/es.js
CHANGED
|
@@ -38,6 +38,8 @@ const es = {
|
|
|
38
38
|
hide: "Ocultar ${1}",
|
|
39
39
|
available_items: "Elementos disponibles",
|
|
40
40
|
required_scopes: "Scopes requeridos",
|
|
41
|
+
required_scopes_description: "Este endpoint requiere los siguientes scopes:",
|
|
42
|
+
available_scopes: "Scopes disponibles:",
|
|
41
43
|
properties: "Propiedades",
|
|
42
44
|
or: "o",
|
|
43
45
|
and: "y",
|
package/dist/translations/fr.js
CHANGED
|
@@ -38,6 +38,8 @@ const fr = {
|
|
|
38
38
|
hide: "Masquer ${1}",
|
|
39
39
|
available_items: "Éléments disponibles",
|
|
40
40
|
required_scopes: "Scopes requis",
|
|
41
|
+
required_scopes_description: "Cet endpoint nécessite les scopes suivants:",
|
|
42
|
+
available_scopes: "Scopes disponibles:",
|
|
41
43
|
properties: "Propriétés",
|
|
42
44
|
or: "ou",
|
|
43
45
|
and: "et",
|
|
@@ -41,6 +41,8 @@ declare const translations: {
|
|
|
41
41
|
hide: string;
|
|
42
42
|
available_items: string;
|
|
43
43
|
required_scopes: string;
|
|
44
|
+
required_scopes_description: string;
|
|
45
|
+
available_scopes: string;
|
|
44
46
|
possible_values: string;
|
|
45
47
|
properties: string;
|
|
46
48
|
or: string;
|
|
@@ -85,6 +87,8 @@ declare const translations: {
|
|
|
85
87
|
hide: string;
|
|
86
88
|
available_items: string;
|
|
87
89
|
required_scopes: string;
|
|
90
|
+
required_scopes_description: string;
|
|
91
|
+
available_scopes: string;
|
|
88
92
|
properties: string;
|
|
89
93
|
or: string;
|
|
90
94
|
and: string;
|
|
@@ -129,6 +133,8 @@ declare const translations: {
|
|
|
129
133
|
hide: string;
|
|
130
134
|
available_items: string;
|
|
131
135
|
required_scopes: string;
|
|
136
|
+
required_scopes_description: string;
|
|
137
|
+
available_scopes: string;
|
|
132
138
|
properties: string;
|
|
133
139
|
or: string;
|
|
134
140
|
and: string;
|
|
@@ -173,6 +179,8 @@ declare const translations: {
|
|
|
173
179
|
hide: string;
|
|
174
180
|
available_items: string;
|
|
175
181
|
required_scopes: string;
|
|
182
|
+
required_scopes_description: string;
|
|
183
|
+
available_scopes: string;
|
|
176
184
|
properties: string;
|
|
177
185
|
or: string;
|
|
178
186
|
and: string;
|
|
@@ -217,6 +225,8 @@ declare const translations: {
|
|
|
217
225
|
hide: string;
|
|
218
226
|
available_items: string;
|
|
219
227
|
required_scopes: string;
|
|
228
|
+
required_scopes_description: string;
|
|
229
|
+
available_scopes: string;
|
|
220
230
|
properties: string;
|
|
221
231
|
or: string;
|
|
222
232
|
and: string;
|
|
@@ -261,6 +271,8 @@ declare const translations: {
|
|
|
261
271
|
hide: string;
|
|
262
272
|
available_items: string;
|
|
263
273
|
required_scopes: string;
|
|
274
|
+
required_scopes_description: string;
|
|
275
|
+
available_scopes: string;
|
|
264
276
|
properties: string;
|
|
265
277
|
or: string;
|
|
266
278
|
and: string;
|
|
@@ -305,6 +317,8 @@ declare const translations: {
|
|
|
305
317
|
hide: string;
|
|
306
318
|
available_items: string;
|
|
307
319
|
required_scopes: string;
|
|
320
|
+
required_scopes_description: string;
|
|
321
|
+
available_scopes: string;
|
|
308
322
|
properties: string;
|
|
309
323
|
or: string;
|
|
310
324
|
and: string;
|
|
@@ -349,6 +363,8 @@ declare const translations: {
|
|
|
349
363
|
hide: string;
|
|
350
364
|
available_items: string;
|
|
351
365
|
required_scopes: string;
|
|
366
|
+
required_scopes_description: string;
|
|
367
|
+
available_scopes: string;
|
|
352
368
|
properties: string;
|
|
353
369
|
or: string;
|
|
354
370
|
and: string;
|
|
@@ -393,6 +409,8 @@ declare const translations: {
|
|
|
393
409
|
hide: string;
|
|
394
410
|
available_items: string;
|
|
395
411
|
required_scopes: string;
|
|
412
|
+
required_scopes_description: string;
|
|
413
|
+
available_scopes: string;
|
|
396
414
|
properties: string;
|
|
397
415
|
or: string;
|
|
398
416
|
and: string;
|
package/dist/translations/ja.js
CHANGED
package/dist/translations/nl.js
CHANGED
|
@@ -38,6 +38,8 @@ const nl = {
|
|
|
38
38
|
hide: "Verberg ${1}",
|
|
39
39
|
available_items: "Beschikbare items",
|
|
40
40
|
required_scopes: "Vereiste scopes",
|
|
41
|
+
required_scopes_description: "Dit endpoint vereist de volgende scopes:",
|
|
42
|
+
available_scopes: "Beschikbare scopes:",
|
|
41
43
|
properties: "Eigenschappen",
|
|
42
44
|
or: "of",
|
|
43
45
|
and: "en",
|
package/dist/translations/no.js
CHANGED
|
@@ -38,6 +38,8 @@ const no = {
|
|
|
38
38
|
hide: "Skjul ${1}",
|
|
39
39
|
available_items: "Tilgjengelige elementer",
|
|
40
40
|
required_scopes: "Påkrevde scopes",
|
|
41
|
+
required_scopes_description: "Dette endepunktet krever følgende scopes:",
|
|
42
|
+
available_scopes: "Tilgjengelige scopes:",
|
|
41
43
|
properties: "Egenskaper",
|
|
42
44
|
or: "eller",
|
|
43
45
|
and: "og",
|
|
@@ -38,6 +38,8 @@ const pt_br = {
|
|
|
38
38
|
hide: "Ocultar ${1}",
|
|
39
39
|
available_items: "Itens disponíveis",
|
|
40
40
|
required_scopes: "Scopes obrigatórios",
|
|
41
|
+
required_scopes_description: "Este endpoint requer os seguintes scopes:",
|
|
42
|
+
available_scopes: "Scopes disponíveis:",
|
|
41
43
|
properties: "Propriedades",
|
|
42
44
|
or: "ou",
|
|
43
45
|
and: "e",
|
package/dist/translations/zh.js
CHANGED
package/dist/types.d.ts
CHANGED
|
@@ -6,6 +6,7 @@ type OpenAPIServerVariableWithCustomProperties = OpenAPIV3.ServerVariableObject
|
|
|
6
6
|
* OpenAPI ServerObject type extended to provide x-gitbook prefill custom properties at the variable level.
|
|
7
7
|
*/
|
|
8
8
|
type OpenAPIServerWithCustomProperties = Omit<OpenAPIV3.ServerObject, 'variables'> & {
|
|
9
|
+
name?: string;
|
|
9
10
|
variables?: {
|
|
10
11
|
[variable: string]: OpenAPIServerVariableWithCustomProperties;
|
|
11
12
|
};
|
package/package.json
CHANGED
|
@@ -7,31 +7,40 @@
|
|
|
7
7
|
"default": "./dist/index.js"
|
|
8
8
|
}
|
|
9
9
|
},
|
|
10
|
-
"version": "1.5.
|
|
10
|
+
"version": "1.5.3",
|
|
11
11
|
"sideEffects": false,
|
|
12
12
|
"dependencies": {
|
|
13
|
-
"@gitbook/expr": "1.2.
|
|
14
|
-
"@gitbook/openapi-parser": "3.0.
|
|
15
|
-
"@scalar/api-client-react": "^1.3.
|
|
16
|
-
"@scalar/oas-utils": "^0.
|
|
17
|
-
"@scalar/types": "^0.
|
|
13
|
+
"@gitbook/expr": "1.2.4",
|
|
14
|
+
"@gitbook/openapi-parser": "3.0.5",
|
|
15
|
+
"@scalar/api-client-react": "^1.3.46",
|
|
16
|
+
"@scalar/oas-utils": "^0.6.3",
|
|
17
|
+
"@scalar/types": "^0.4.0",
|
|
18
18
|
"classnames": "^2.5.1",
|
|
19
19
|
"flatted": "^3.2.9",
|
|
20
20
|
"json-xml-parse": "^1.3.0",
|
|
21
21
|
"react-aria-components": "^1.13.0",
|
|
22
22
|
"react-aria": "^3.44.0",
|
|
23
|
-
"
|
|
23
|
+
"react-stately": "^3.42.0",
|
|
24
|
+
"usehooks-ts": "^3.1.1",
|
|
24
25
|
"zustand": "^5.0.3",
|
|
25
26
|
"js-yaml": "^4.1.0"
|
|
26
27
|
},
|
|
27
28
|
"devDependencies": {
|
|
28
29
|
"@types/js-yaml": "^4.0.9",
|
|
30
|
+
"@types/react": "^19.0.0",
|
|
31
|
+
"@types/react-dom": "^19.0.0",
|
|
29
32
|
"bun-types": "^1.1.20",
|
|
30
33
|
"react": "^19.0.0",
|
|
31
34
|
"react-dom": "^19.0.0",
|
|
32
35
|
"tsdown": "^0.15.6",
|
|
33
36
|
"typescript": "^5.5.3"
|
|
34
37
|
},
|
|
38
|
+
"overrides": {
|
|
39
|
+
"@types/react": "catalog:",
|
|
40
|
+
"@types/react-dom": "catalog:",
|
|
41
|
+
"react": "catalog:",
|
|
42
|
+
"react-dom": "catalog:"
|
|
43
|
+
},
|
|
35
44
|
"peerDependencies": {
|
|
36
45
|
"react": "*",
|
|
37
46
|
"react-dom": "*"
|
|
@@ -41,11 +50,15 @@
|
|
|
41
50
|
"typecheck": "tsc --noEmit",
|
|
42
51
|
"unit": "bun test",
|
|
43
52
|
"dev": "bun run build -- --watch ./src",
|
|
44
|
-
"clean": "rm -rf ./dist"
|
|
53
|
+
"clean": "rm -rf ./dist",
|
|
54
|
+
"publish-to-npm": "../../scripts/publish-if-new.sh"
|
|
45
55
|
},
|
|
46
56
|
"files": ["dist", "README.md", "CHANGELOG.md"],
|
|
47
57
|
"publishConfig": {
|
|
48
58
|
"access": "public",
|
|
49
59
|
"registry": "https://registry.npmjs.org/"
|
|
60
|
+
},
|
|
61
|
+
"repository": {
|
|
62
|
+
"url": "https://github.com/GitbookIO/gitbook"
|
|
50
63
|
}
|
|
51
64
|
}
|