zudoku 0.23.4 → 0.23.6
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/dist/config/validators/common.d.ts +37 -37
- package/dist/config/validators/common.js +4 -1
- package/dist/config/validators/common.js.map +1 -1
- package/dist/config/validators/validate.d.ts +14 -14
- package/dist/lib/components/navigation/SidebarBadge.d.ts +0 -9
- package/dist/lib/components/navigation/SidebarBadge.js +0 -9
- package/dist/lib/components/navigation/SidebarBadge.js.map +1 -1
- package/dist/lib/plugins/openapi/OperationList.js +10 -34
- package/dist/lib/plugins/openapi/OperationList.js.map +1 -1
- package/dist/lib/plugins/openapi/OperationListItem.d.ts +2 -1
- package/dist/lib/plugins/openapi/OperationListItem.js +14 -4
- package/dist/lib/plugins/openapi/OperationListItem.js.map +1 -1
- package/dist/lib/plugins/openapi/Route.d.ts +4 -2
- package/dist/lib/plugins/openapi/Route.js +25 -2
- package/dist/lib/plugins/openapi/Route.js.map +1 -1
- package/dist/lib/plugins/openapi/Sidecar.js +2 -12
- package/dist/lib/plugins/openapi/Sidecar.js.map +1 -1
- package/dist/lib/plugins/openapi/context.d.ts +3 -3
- package/dist/lib/plugins/openapi/index.js +12 -12
- package/dist/lib/plugins/openapi/index.js.map +1 -1
- package/dist/lib/plugins/openapi/interfaces.d.ts +19 -0
- package/dist/lib/plugins/openapi/util/methodToColor.d.ts +20 -0
- package/dist/lib/plugins/openapi/util/methodToColor.js +24 -0
- package/dist/lib/plugins/openapi/util/methodToColor.js.map +1 -0
- package/dist/lib/plugins/openapi/util/sanitizeMarkdownForMetatag.d.ts +1 -0
- package/dist/lib/plugins/openapi/util/sanitizeMarkdownForMetatag.js +27 -0
- package/dist/lib/plugins/openapi/util/sanitizeMarkdownForMetatag.js.map +1 -0
- package/dist/vite/config.js +2 -1
- package/dist/vite/config.js.map +1 -1
- package/dist/vite/plugin-api.js +39 -15
- package/dist/vite/plugin-api.js.map +1 -1
- package/lib/{OperationList-C7ac3kR5.js → OperationList-n4U_BHmO.js} +1886 -1838
- package/lib/OperationList-n4U_BHmO.js.map +1 -0
- package/lib/Route-C8nwd9A2.js +37 -0
- package/lib/Route-C8nwd9A2.js.map +1 -0
- package/lib/StaggeredRender-DgsamH_G.js +17 -0
- package/lib/StaggeredRender-DgsamH_G.js.map +1 -0
- package/lib/context-h_UkBLvr.js.map +1 -1
- package/lib/{index-C8ubT49C.js → index-DStSNvP-.js} +442 -437
- package/lib/{index-C8ubT49C.js.map → index-DStSNvP-.js.map} +1 -1
- package/lib/zudoku.components.js +385 -363
- package/lib/zudoku.components.js.map +1 -1
- package/lib/zudoku.plugin-openapi.js +1 -1
- package/package.json +1 -1
- package/src/lib/components/navigation/SidebarBadge.tsx +0 -10
- package/src/lib/plugins/openapi/OperationList.tsx +45 -50
- package/src/lib/plugins/openapi/OperationListItem.tsx +31 -2
- package/src/lib/plugins/openapi/Route.tsx +45 -9
- package/src/lib/plugins/openapi/Sidecar.tsx +2 -16
- package/src/lib/plugins/openapi/context.tsx +2 -2
- package/src/lib/plugins/openapi/index.tsx +35 -28
- package/src/lib/plugins/openapi/interfaces.ts +22 -1
- package/src/lib/plugins/openapi/util/methodToColor.ts +27 -0
- package/src/lib/plugins/openapi/util/sanitizeMarkdownForMetatag.tsx +32 -0
- package/lib/OperationList-C7ac3kR5.js.map +0 -1
- package/lib/Route-C9cYcP-j.js +0 -11
- package/lib/Route-C9cYcP-j.js.map +0 -1
- package/lib/SidebarBadge-Bm793GDY.js +0 -51
- package/lib/SidebarBadge-Bm793GDY.js.map +0 -1
package/package.json
CHANGED
|
@@ -1,15 +1,5 @@
|
|
|
1
1
|
import { cn } from "../../util/cn.js";
|
|
2
2
|
|
|
3
|
-
export const TextColorMap = {
|
|
4
|
-
green: "text-green-600",
|
|
5
|
-
blue: "text-sky-600",
|
|
6
|
-
yellow: "text-yellow-600",
|
|
7
|
-
red: "text-red-600",
|
|
8
|
-
purple: "text-purple-600",
|
|
9
|
-
indigo: "text-indigo-600",
|
|
10
|
-
gray: "text-gray-600",
|
|
11
|
-
};
|
|
12
|
-
|
|
13
3
|
export const ColorMap = {
|
|
14
4
|
green: "bg-green-400 dark:bg-green-800",
|
|
15
5
|
blue: "bg-sky-400 dark:bg-sky-800",
|
|
@@ -1,6 +1,15 @@
|
|
|
1
1
|
import { ResultOf } from "@graphql-typed-document-node/core";
|
|
2
2
|
import { useSuspenseQuery } from "@tanstack/react-query";
|
|
3
3
|
import { Helmet } from "@zudoku/react-helmet-async";
|
|
4
|
+
import { useNavigate } from "react-router";
|
|
5
|
+
import {
|
|
6
|
+
Select,
|
|
7
|
+
SelectContent,
|
|
8
|
+
SelectItem,
|
|
9
|
+
SelectTrigger,
|
|
10
|
+
SelectValue,
|
|
11
|
+
} from "zudoku/ui/Select.js";
|
|
12
|
+
import { useSelectedServerStore } from "../../authentication/state.js";
|
|
4
13
|
import { CategoryHeading } from "../../components/CategoryHeading.js";
|
|
5
14
|
import { Heading } from "../../components/Heading.js";
|
|
6
15
|
import { Markdown, ProseClasses } from "../../components/Markdown.js";
|
|
@@ -11,6 +20,7 @@ import StaggeredRender from "./StaggeredRender.js";
|
|
|
11
20
|
import { useCreateQuery } from "./client/useCreateQuery.js";
|
|
12
21
|
import { useOasConfig } from "./context.js";
|
|
13
22
|
import { graphql } from "./graphql/index.js";
|
|
23
|
+
import { sanitizeMarkdownForMetatag } from "./util/sanitizeMarkdownForMetatag.js";
|
|
14
24
|
|
|
15
25
|
export const OperationsFragment = graphql(/* GraphQL */ `
|
|
16
26
|
fragment OperationsFragment on OperationItem {
|
|
@@ -98,63 +108,25 @@ const AllOperationsQuery = graphql(/* GraphQL */ `
|
|
|
98
108
|
}
|
|
99
109
|
`);
|
|
100
110
|
|
|
101
|
-
/**
|
|
102
|
-
* @description Clean up a commonmark formatted description for use in the meta
|
|
103
|
-
* description.
|
|
104
|
-
*/
|
|
105
|
-
function cleanDescription(
|
|
106
|
-
description: string,
|
|
107
|
-
maxLength: number = 160,
|
|
108
|
-
): string {
|
|
109
|
-
if (!description) {
|
|
110
|
-
return "";
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
// Replace Markdown links [text](url) with just "text"
|
|
114
|
-
description = description.replace(/\[([^\]]+)\]\([^)]+\)/g, "$1");
|
|
115
|
-
|
|
116
|
-
// Remove Markdown image syntax: 
|
|
117
|
-
description = description.replace(/!\[.*?\]\(.*?\)/g, "");
|
|
118
|
-
|
|
119
|
-
// Remove other Markdown syntax (e.g., **bold**, _italic_, `code`)
|
|
120
|
-
description = description.replace(/[_*`~]/g, "");
|
|
121
|
-
|
|
122
|
-
// Remove headings (# Heading), blockquotes (> Quote), and horizontal rules (--- or ***)
|
|
123
|
-
description = description.replace(/^(?:>|\s*#+|-{3,}|\*{3,})/gm, "");
|
|
124
|
-
|
|
125
|
-
// Remove any remaining formatting characters
|
|
126
|
-
description = description.replace(/[|>{}[\]]/g, "");
|
|
127
|
-
|
|
128
|
-
// Collapse multiple spaces and trim the text
|
|
129
|
-
description = description.replace(/\s+/g, " ").trim();
|
|
130
|
-
|
|
131
|
-
// Limit to the specified maximum length
|
|
132
|
-
description = description.substring(0, maxLength);
|
|
133
|
-
|
|
134
|
-
// Escape for HTML safety
|
|
135
|
-
return description
|
|
136
|
-
.replace(/&/g, "&")
|
|
137
|
-
.replace(/</g, "<")
|
|
138
|
-
.replace(/>/g, ">")
|
|
139
|
-
.replace(/"/g, """)
|
|
140
|
-
.replace(/'/g, "'");
|
|
141
|
-
}
|
|
142
|
-
|
|
143
111
|
export const OperationList = () => {
|
|
144
|
-
const { input, type } = useOasConfig();
|
|
112
|
+
const { input, type, versions, version } = useOasConfig();
|
|
145
113
|
const query = useCreateQuery(AllOperationsQuery, { input, type });
|
|
114
|
+
const { selectedServer } = useSelectedServerStore();
|
|
146
115
|
const result = useSuspenseQuery(query);
|
|
147
116
|
const title = result.data.schema.title;
|
|
148
117
|
const summary = result.data.schema.summary;
|
|
149
118
|
const description = result.data.schema.description;
|
|
119
|
+
const navigate = useNavigate();
|
|
120
|
+
|
|
150
121
|
// The summary property is preferable here as it is a short description of
|
|
151
122
|
// the API, whereas the description property is typically longer and supports
|
|
152
123
|
// commonmark formatting, making it ill-suited for use in the meta description
|
|
153
124
|
const metaDescription = summary
|
|
154
125
|
? summary
|
|
155
126
|
: description
|
|
156
|
-
?
|
|
127
|
+
? sanitizeMarkdownForMetatag(description)
|
|
157
128
|
: undefined;
|
|
129
|
+
|
|
158
130
|
return (
|
|
159
131
|
<div className="pt-[--padding-content-top]">
|
|
160
132
|
<Helmet>
|
|
@@ -166,17 +138,39 @@ export const OperationList = () => {
|
|
|
166
138
|
<div
|
|
167
139
|
className={cn(ProseClasses, "mb-16 max-w-full prose-img:max-w-prose")}
|
|
168
140
|
>
|
|
169
|
-
<
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
141
|
+
<div className="flex">
|
|
142
|
+
<div className="flex-1">
|
|
143
|
+
<CategoryHeading>Overview</CategoryHeading>
|
|
144
|
+
<Heading level={1} id="description" registerSidebarAnchor>
|
|
145
|
+
{title}
|
|
146
|
+
</Heading>
|
|
147
|
+
</div>
|
|
148
|
+
<div>
|
|
149
|
+
{Object.entries(versions).length > 1 && (
|
|
150
|
+
<Select
|
|
151
|
+
onValueChange={(version) => navigate(versions[version]!)}
|
|
152
|
+
defaultValue={version}
|
|
153
|
+
>
|
|
154
|
+
<SelectTrigger className="w-[180px]">
|
|
155
|
+
<SelectValue placeholder="Select version" />
|
|
156
|
+
</SelectTrigger>
|
|
157
|
+
<SelectContent>
|
|
158
|
+
{Object.entries(versions).map(([version]) => (
|
|
159
|
+
<SelectItem key={version} value={version}>
|
|
160
|
+
{version}
|
|
161
|
+
</SelectItem>
|
|
162
|
+
))}
|
|
163
|
+
</SelectContent>
|
|
164
|
+
</Select>
|
|
165
|
+
)}
|
|
166
|
+
</div>
|
|
167
|
+
</div>
|
|
173
168
|
<Markdown content={result.data.schema.description ?? ""} />
|
|
174
169
|
</div>
|
|
175
170
|
<hr />
|
|
176
|
-
<div className="my-4 flex justify-end">
|
|
171
|
+
<div className="my-4 flex items-center justify-end gap-4">
|
|
177
172
|
<Endpoint />
|
|
178
173
|
</div>
|
|
179
|
-
|
|
180
174
|
{result.data.schema.tags
|
|
181
175
|
.filter((tag) => tag.operations.length > 0)
|
|
182
176
|
.map((tag) => (
|
|
@@ -193,6 +187,7 @@ export const OperationList = () => {
|
|
|
193
187
|
<StaggeredRender>
|
|
194
188
|
{tag.operations.map((fragment) => (
|
|
195
189
|
<OperationListItem
|
|
190
|
+
serverUrl={selectedServer ?? result.data.schema.url}
|
|
196
191
|
key={fragment.slug}
|
|
197
192
|
operationFragment={fragment}
|
|
198
193
|
/>
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { useState } from "react";
|
|
1
|
+
import { useRef, useState } from "react";
|
|
2
2
|
import { Heading } from "../../components/Heading.js";
|
|
3
3
|
import { Markdown, ProseClasses } from "../../components/Markdown.js";
|
|
4
4
|
import { Tabs, TabsContent, TabsList, TabsTrigger } from "../../ui/Tabs.js";
|
|
@@ -9,20 +9,24 @@ import { ParameterList } from "./ParameterList.js";
|
|
|
9
9
|
import { Sidecar } from "./Sidecar.js";
|
|
10
10
|
import { FragmentType, useFragment } from "./graphql/index.js";
|
|
11
11
|
import { SchemaView } from "./schema/SchemaView.js";
|
|
12
|
+
import { methodForColor } from "./util/methodToColor.js";
|
|
12
13
|
|
|
13
14
|
export const PARAM_GROUPS = ["path", "query", "header", "cookie"] as const;
|
|
14
15
|
export type ParameterGroup = (typeof PARAM_GROUPS)[number];
|
|
15
16
|
|
|
16
17
|
export const OperationListItem = ({
|
|
17
18
|
operationFragment,
|
|
19
|
+
serverUrl,
|
|
18
20
|
}: {
|
|
19
21
|
operationFragment: FragmentType<typeof OperationsFragment>;
|
|
22
|
+
serverUrl?: string;
|
|
20
23
|
}) => {
|
|
21
24
|
const operation = useFragment(OperationsFragment, operationFragment);
|
|
22
25
|
const groupedParameters = groupBy(
|
|
23
26
|
operation.parameters ?? [],
|
|
24
27
|
(param) => param.in,
|
|
25
28
|
);
|
|
29
|
+
const parentRef = useRef<HTMLDivElement>(null);
|
|
26
30
|
|
|
27
31
|
const first = operation.responses.at(0);
|
|
28
32
|
const [selectedResponse, setSelectedResponse] = useState(first?.statusCode);
|
|
@@ -30,12 +34,37 @@ export const OperationListItem = ({
|
|
|
30
34
|
return (
|
|
31
35
|
<div
|
|
32
36
|
key={operation.operationId}
|
|
33
|
-
className="grid grid-cols-1 lg:grid-cols-[
|
|
37
|
+
className="grid grid-cols-1 lg:grid-cols-[minmax(0,4fr)_minmax(0,3fr)] gap-8 items-start border-b-2 mb-16 pb-16"
|
|
34
38
|
>
|
|
35
39
|
<div className="flex flex-col gap-4">
|
|
36
40
|
<Heading level={2} id={operation.slug} registerSidebarAnchor>
|
|
37
41
|
{operation.summary}
|
|
38
42
|
</Heading>
|
|
43
|
+
<div className="text-sm flex gap-2 font-mono">
|
|
44
|
+
<span className={methodForColor(operation.method)}>
|
|
45
|
+
{operation.method.toUpperCase()}
|
|
46
|
+
</span>
|
|
47
|
+
<div
|
|
48
|
+
ref={parentRef}
|
|
49
|
+
className="max-w-full truncate flex cursor-pointer"
|
|
50
|
+
onClick={() => {
|
|
51
|
+
if (parentRef.current) {
|
|
52
|
+
const range = document.createRange();
|
|
53
|
+
range.selectNodeContents(parentRef.current);
|
|
54
|
+
const selection = window.getSelection();
|
|
55
|
+
selection?.removeAllRanges();
|
|
56
|
+
selection?.addRange(range);
|
|
57
|
+
}
|
|
58
|
+
}}
|
|
59
|
+
>
|
|
60
|
+
<div className="text-neutral-400 dark:text-neutral-500 truncate">
|
|
61
|
+
{serverUrl}
|
|
62
|
+
</div>
|
|
63
|
+
<div className="text-neutral-900 dark:text-neutral-200">
|
|
64
|
+
{operation.path}
|
|
65
|
+
</div>
|
|
66
|
+
</div>
|
|
67
|
+
</div>
|
|
39
68
|
{operation.description && (
|
|
40
69
|
<Markdown
|
|
41
70
|
className={`${ProseClasses} max-w-full prose-img:max-w-prose`}
|
|
@@ -1,19 +1,55 @@
|
|
|
1
|
-
import { Outlet } from "react-router";
|
|
1
|
+
import { Outlet, useParams } from "react-router";
|
|
2
|
+
import { joinPath } from "../../util/joinPath.js";
|
|
2
3
|
import type { GraphQLClient } from "./client/GraphQLClient.js";
|
|
3
4
|
import { GraphQLProvider } from "./client/GraphQLContext.js";
|
|
4
5
|
import { OasConfigProvider } from "./context.js";
|
|
5
|
-
import { OasPluginConfig } from "./interfaces.js";
|
|
6
|
+
import { type OasPluginConfig } from "./interfaces.js";
|
|
6
7
|
|
|
7
8
|
export const OpenApiRoute = ({
|
|
9
|
+
basePath,
|
|
10
|
+
versions,
|
|
8
11
|
config,
|
|
9
12
|
client,
|
|
10
13
|
}: {
|
|
14
|
+
basePath: string;
|
|
15
|
+
versions: string[];
|
|
11
16
|
config: OasPluginConfig;
|
|
12
17
|
client: GraphQLClient;
|
|
13
|
-
}) =>
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
18
|
+
}) => {
|
|
19
|
+
const { version } = useParams<"version">();
|
|
20
|
+
|
|
21
|
+
const input =
|
|
22
|
+
config.type === "file"
|
|
23
|
+
? {
|
|
24
|
+
type: config.type,
|
|
25
|
+
input: version
|
|
26
|
+
? config.input[version]!
|
|
27
|
+
: Object.values(config.input).at(0)!,
|
|
28
|
+
}
|
|
29
|
+
: { type: config.type, input: config.input };
|
|
30
|
+
|
|
31
|
+
const currentVersion = version ?? versions.at(0);
|
|
32
|
+
|
|
33
|
+
if (!currentVersion) {
|
|
34
|
+
throw new Error("No version found");
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
return (
|
|
38
|
+
<OasConfigProvider
|
|
39
|
+
value={{
|
|
40
|
+
config: {
|
|
41
|
+
...config,
|
|
42
|
+
version: currentVersion,
|
|
43
|
+
versions: Object.fromEntries(
|
|
44
|
+
versions.map((version) => [version, joinPath(basePath, version)]),
|
|
45
|
+
),
|
|
46
|
+
...input,
|
|
47
|
+
},
|
|
48
|
+
}}
|
|
49
|
+
>
|
|
50
|
+
<GraphQLProvider client={client}>
|
|
51
|
+
<Outlet />
|
|
52
|
+
</GraphQLProvider>
|
|
53
|
+
</OasConfigProvider>
|
|
54
|
+
);
|
|
55
|
+
};
|
|
@@ -3,7 +3,6 @@ import { HTTPSnippet } from "@zudoku/httpsnippet";
|
|
|
3
3
|
import { Fragment, useMemo, useTransition } from "react";
|
|
4
4
|
import { useSearchParams } from "react-router";
|
|
5
5
|
import { useSelectedServerStore } from "../../authentication/state.js";
|
|
6
|
-
import { TextColorMap } from "../../components/navigation/SidebarBadge.js";
|
|
7
6
|
import { SyntaxHighlight } from "../../components/SyntaxHighlight.js";
|
|
8
7
|
import type { SchemaObject } from "../../oas/parser/index.js";
|
|
9
8
|
import { cn } from "../../util/cn.js";
|
|
@@ -20,6 +19,7 @@ import { ResponsesSidecarBox } from "./ResponsesSidecarBox.js";
|
|
|
20
19
|
import * as SidecarBox from "./SidecarBox.js";
|
|
21
20
|
import { SimpleSelect } from "./SimpleSelect.js";
|
|
22
21
|
import { generateSchemaExample } from "./util/generateSchemaExample.js";
|
|
22
|
+
import { methodForColor } from "./util/methodToColor.js";
|
|
23
23
|
|
|
24
24
|
const getConverted = (snippet: HTTPSnippet, option: string) => {
|
|
25
25
|
let converted;
|
|
@@ -76,17 +76,6 @@ export const GetServerQuery = graphql(/* GraphQL */ `
|
|
|
76
76
|
}
|
|
77
77
|
`);
|
|
78
78
|
|
|
79
|
-
const methodToColor = {
|
|
80
|
-
get: TextColorMap.green,
|
|
81
|
-
post: TextColorMap.blue,
|
|
82
|
-
put: TextColorMap.yellow,
|
|
83
|
-
delete: TextColorMap.red,
|
|
84
|
-
patch: TextColorMap.purple,
|
|
85
|
-
options: TextColorMap.indigo,
|
|
86
|
-
head: TextColorMap.gray,
|
|
87
|
-
trace: TextColorMap.gray,
|
|
88
|
-
};
|
|
89
|
-
|
|
90
79
|
const EXAMPLE_LANGUAGES = [
|
|
91
80
|
{ value: "shell", label: "cURL" },
|
|
92
81
|
{ value: "js", label: "JavaScript" },
|
|
@@ -114,10 +103,7 @@ export const Sidecar = ({
|
|
|
114
103
|
const query = useCreateQuery(GetServerQuery, { input, type });
|
|
115
104
|
const result = useSuspenseQuery(query);
|
|
116
105
|
|
|
117
|
-
const methodTextColor =
|
|
118
|
-
methodToColor[
|
|
119
|
-
operation.method.toLocaleLowerCase() as keyof typeof methodToColor
|
|
120
|
-
] ?? TextColorMap.gray;
|
|
106
|
+
const methodTextColor = methodForColor(operation.method);
|
|
121
107
|
|
|
122
108
|
const [searchParams, setSearchParams] = useSearchParams();
|
|
123
109
|
const [, startTransition] = useTransition();
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { createContext, useContext } from "react";
|
|
2
|
-
import {
|
|
2
|
+
import { OasPluginContext } from "./interfaces.js";
|
|
3
3
|
|
|
4
|
-
const OasContext = createContext<{ config:
|
|
4
|
+
const OasContext = createContext<{ config: OasPluginContext } | undefined>(
|
|
5
5
|
undefined,
|
|
6
6
|
);
|
|
7
7
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { matchPath
|
|
1
|
+
import { matchPath } from "react-router";
|
|
2
2
|
import { type ZudokuPlugin } from "../../core/plugins.js";
|
|
3
3
|
import { graphql } from "./graphql/index.js";
|
|
4
4
|
|
|
@@ -52,6 +52,8 @@ export type OpenApiPluginOptions = OasPluginConfig & InternalOasPluginConfig;
|
|
|
52
52
|
export const openApiPlugin = (config: OpenApiPluginOptions): ZudokuPlugin => {
|
|
53
53
|
const basePath = joinPath(config.navigationId ?? "/reference");
|
|
54
54
|
|
|
55
|
+
const versions = config.type === "file" ? Object.keys(config.input) : [];
|
|
56
|
+
|
|
55
57
|
const client = new GraphQLClient(config);
|
|
56
58
|
|
|
57
59
|
return {
|
|
@@ -125,9 +127,14 @@ export const openApiPlugin = (config: OpenApiPluginOptions): ZudokuPlugin => {
|
|
|
125
127
|
}
|
|
126
128
|
|
|
127
129
|
try {
|
|
130
|
+
const version =
|
|
131
|
+
versions.find((v) => path === joinPath(basePath, v)) ??
|
|
132
|
+
Object.keys(config.input).at(0);
|
|
133
|
+
|
|
128
134
|
const data = await client.fetch(GetCategoriesQuery, {
|
|
129
135
|
type: config.type,
|
|
130
|
-
input: config.input,
|
|
136
|
+
input: config.type === "file" ? config.input[version!] : config.input,
|
|
137
|
+
version,
|
|
131
138
|
});
|
|
132
139
|
|
|
133
140
|
const categories = data.schema.tags
|
|
@@ -159,32 +166,32 @@ export const openApiPlugin = (config: OpenApiPluginOptions): ZudokuPlugin => {
|
|
|
159
166
|
return [];
|
|
160
167
|
}
|
|
161
168
|
},
|
|
162
|
-
getRoutes: () =>
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
async lazy() {
|
|
178
|
-
const { OperationList } = await import(
|
|
179
|
-
"./OperationList.js"
|
|
180
|
-
);
|
|
181
|
-
return { element: <OperationList /> };
|
|
182
|
-
},
|
|
183
|
-
},
|
|
184
|
-
],
|
|
185
|
-
},
|
|
186
|
-
],
|
|
169
|
+
getRoutes: () => [
|
|
170
|
+
{
|
|
171
|
+
path: basePath + "/:version?",
|
|
172
|
+
async lazy() {
|
|
173
|
+
const { OpenApiRoute } = await import("./Route.js");
|
|
174
|
+
return {
|
|
175
|
+
element: (
|
|
176
|
+
<OpenApiRoute
|
|
177
|
+
basePath={basePath}
|
|
178
|
+
versions={versions}
|
|
179
|
+
client={client}
|
|
180
|
+
config={config}
|
|
181
|
+
/>
|
|
182
|
+
),
|
|
183
|
+
};
|
|
187
184
|
},
|
|
188
|
-
|
|
185
|
+
children: [
|
|
186
|
+
{
|
|
187
|
+
index: true,
|
|
188
|
+
async lazy() {
|
|
189
|
+
const { OperationList } = await import("./OperationList.js");
|
|
190
|
+
return { element: <OperationList /> };
|
|
191
|
+
},
|
|
192
|
+
},
|
|
193
|
+
],
|
|
194
|
+
},
|
|
195
|
+
],
|
|
189
196
|
};
|
|
190
197
|
};
|
|
@@ -1,6 +1,19 @@
|
|
|
1
1
|
type OasSource =
|
|
2
2
|
| { type: "url"; input: string }
|
|
3
|
-
| {
|
|
3
|
+
| {
|
|
4
|
+
type: "file";
|
|
5
|
+
input: {
|
|
6
|
+
[version: string]: () => Promise<unknown>;
|
|
7
|
+
};
|
|
8
|
+
}
|
|
9
|
+
| { type: "raw"; input: string };
|
|
10
|
+
|
|
11
|
+
export type ContextOasSource =
|
|
12
|
+
| { type: "url"; input: string }
|
|
13
|
+
| {
|
|
14
|
+
type: "file";
|
|
15
|
+
input: () => Promise<unknown>;
|
|
16
|
+
}
|
|
4
17
|
| { type: "raw"; input: string };
|
|
5
18
|
|
|
6
19
|
export type OasPluginConfig = {
|
|
@@ -8,3 +21,11 @@ export type OasPluginConfig = {
|
|
|
8
21
|
navigationId?: string;
|
|
9
22
|
skipPreload?: boolean;
|
|
10
23
|
} & OasSource;
|
|
24
|
+
|
|
25
|
+
export type OasPluginContext = {
|
|
26
|
+
server?: string;
|
|
27
|
+
navigationId?: string;
|
|
28
|
+
skipPreload?: boolean;
|
|
29
|
+
version: string;
|
|
30
|
+
versions: Record<string, string>;
|
|
31
|
+
} & ContextOasSource;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export const TextColorMap = {
|
|
2
|
+
green: "text-green-600",
|
|
3
|
+
blue: "text-sky-600",
|
|
4
|
+
yellow: "text-yellow-600",
|
|
5
|
+
red: "text-red-600",
|
|
6
|
+
purple: "text-purple-600",
|
|
7
|
+
indigo: "text-indigo-600",
|
|
8
|
+
gray: "text-gray-600",
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export const methodToColor = {
|
|
12
|
+
get: TextColorMap.green,
|
|
13
|
+
post: TextColorMap.blue,
|
|
14
|
+
put: TextColorMap.yellow,
|
|
15
|
+
delete: TextColorMap.red,
|
|
16
|
+
patch: TextColorMap.purple,
|
|
17
|
+
options: TextColorMap.indigo,
|
|
18
|
+
head: TextColorMap.gray,
|
|
19
|
+
trace: TextColorMap.gray,
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
export const methodForColor = (method: string) => {
|
|
23
|
+
return (
|
|
24
|
+
methodToColor[method.toLocaleLowerCase() as keyof typeof methodToColor] ??
|
|
25
|
+
TextColorMap.gray
|
|
26
|
+
);
|
|
27
|
+
};
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
export function sanitizeMarkdownForMetatag(
|
|
2
|
+
description: string,
|
|
3
|
+
maxLength: number = 160,
|
|
4
|
+
): string {
|
|
5
|
+
if (!description) {
|
|
6
|
+
return "";
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
return (
|
|
10
|
+
description
|
|
11
|
+
// Replace Markdown links [text](url) with just "text"
|
|
12
|
+
.replace(/\[([^\]]+)\]\([^)]+\)/g, "$1")
|
|
13
|
+
// Remove Markdown image syntax: 
|
|
14
|
+
.replace(/!\[.*?\]\(.*?\)/g, "")
|
|
15
|
+
// Remove other Markdown syntax (e.g., **bold**, _italic_, `code`)
|
|
16
|
+
.replace(/[_*`~]/g, "")
|
|
17
|
+
// Remove headings (# Heading), blockquotes (> Quote), and horizontal rules (--- or ***)
|
|
18
|
+
.replace(/^(?:>|\s*#+|-{3,}|\*{3,})/gm, "")
|
|
19
|
+
// Remove any remaining formatting characters
|
|
20
|
+
.replace(/[|>{}[\]]/g, "")
|
|
21
|
+
// Collapse multiple spaces and trim the text
|
|
22
|
+
.replace(/\s+/g, " ")
|
|
23
|
+
.trim()
|
|
24
|
+
// Limit to the specified maximum length
|
|
25
|
+
.substring(0, maxLength)
|
|
26
|
+
.replace(/&/g, "&")
|
|
27
|
+
.replace(/</g, "<")
|
|
28
|
+
.replace(/>/g, ">")
|
|
29
|
+
.replace(/"/g, """)
|
|
30
|
+
.replace(/'/g, "'")
|
|
31
|
+
);
|
|
32
|
+
}
|