fumadocs-openapi 10.3.12 → 10.3.13
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/css/generated/shared.css +24 -4
- package/dist/requests/generators/all.d.ts +6 -0
- package/dist/requests/generators/all.js +19 -0
- package/dist/requests/generators/csharp.d.ts +6 -0
- package/dist/requests/generators/csharp.js +34 -32
- package/dist/requests/generators/curl.d.ts +6 -0
- package/dist/requests/generators/curl.js +24 -22
- package/dist/requests/generators/go.d.ts +6 -0
- package/dist/requests/generators/go.js +29 -27
- package/dist/requests/generators/index.d.ts +55 -0
- package/dist/requests/generators/index.js +37 -46
- package/dist/requests/generators/java.d.ts +6 -0
- package/dist/requests/generators/java.js +49 -47
- package/dist/requests/generators/javascript.d.ts +6 -0
- package/dist/requests/generators/javascript.js +31 -29
- package/dist/requests/generators/python.d.ts +6 -0
- package/dist/requests/generators/python.js +26 -24
- package/dist/requests/types.d.ts +1 -6
- package/dist/server/create.d.ts +5 -2
- package/dist/server/create.js +4 -6
- package/dist/types.d.ts +4 -4
- package/dist/ui/base.d.ts +22 -4
- package/dist/ui/base.js +8 -0
- package/dist/ui/client/index.d.ts +5 -0
- package/dist/ui/contexts/api.js +18 -7
- package/dist/ui/full.js +2 -3
- package/dist/ui/operation/client.js +9 -5
- package/dist/ui/operation/index.js +25 -8
- package/dist/ui/operation/usage-tabs/client.js +24 -12
- package/dist/ui/operation/usage-tabs/index.js +25 -32
- package/dist/ui/schema/client.js +81 -32
- package/dist/utils/process-document.js +0 -1
- package/package.json +31 -45
- package/dist/ui/operation/usage-tabs/index.d.ts +0 -26
|
@@ -1,57 +1,59 @@
|
|
|
1
|
-
'use client';
|
|
2
|
-
|
|
3
1
|
import { ident } from "../string-utils.js";
|
|
4
2
|
import { resolveMediaAdapter } from "../media/resolve-adapter.js";
|
|
5
3
|
import "../media/adapter.js";
|
|
6
4
|
|
|
7
5
|
//#region src/requests/generators/java.ts
|
|
8
|
-
const
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
6
|
+
const java = {
|
|
7
|
+
label: "Java",
|
|
8
|
+
lang: "java",
|
|
9
|
+
generate(url, data, { mediaAdapters }) {
|
|
10
|
+
const s = [];
|
|
11
|
+
const headers = { ...data.header };
|
|
12
|
+
const imports = new Set([
|
|
13
|
+
"java.net.URI",
|
|
14
|
+
"java.net.http.HttpClient",
|
|
15
|
+
"java.net.http.HttpRequest",
|
|
16
|
+
"java.net.http.HttpResponse",
|
|
17
|
+
"java.net.http.HttpResponse.BodyHandlers",
|
|
18
|
+
"java.time.Duration"
|
|
19
|
+
]);
|
|
20
|
+
let body;
|
|
21
|
+
if (data.body && data.bodyMediaType) body = resolveMediaAdapter(data.bodyMediaType, mediaAdapters)?.generateExample(data, {
|
|
22
|
+
lang: "java",
|
|
23
|
+
addImport(specifier) {
|
|
24
|
+
imports.add(specifier);
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
for (const value of imports.values()) s.push(`import ${value};`);
|
|
28
|
+
s.push("");
|
|
29
|
+
if (body) s.push(body);
|
|
30
|
+
s.push("HttpClient client = HttpClient.newBuilder()");
|
|
31
|
+
s.push(ident(".connectTimeout(Duration.ofSeconds(10))"));
|
|
32
|
+
s.push(ident(".build();"));
|
|
33
|
+
s.push("");
|
|
34
|
+
s.push("HttpRequest.Builder requestBuilder = HttpRequest.newBuilder()");
|
|
35
|
+
s.push(ident(`.uri(URI.create(${JSON.stringify(url)}))`));
|
|
36
|
+
for (const [key, param] of Object.entries(headers)) s.push(ident(`.header(${JSON.stringify(key)}, ${JSON.stringify(param.value)})`));
|
|
37
|
+
if (data.bodyMediaType) s.push(ident(`.header("Content-Type", "${data.bodyMediaType}")`));
|
|
38
|
+
const cookies = Object.entries(data.cookie);
|
|
39
|
+
if (cookies.length > 0) {
|
|
40
|
+
const cookieString = cookies.map(([key, param]) => `${key}=${param.value}`).join("; ");
|
|
41
|
+
s.push(ident(`.header("Cookie", ${JSON.stringify(cookieString)})`));
|
|
24
42
|
}
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
const cookies = Object.entries(data.cookie);
|
|
38
|
-
if (cookies.length > 0) {
|
|
39
|
-
const cookieString = cookies.map(([key, param]) => `${key}=${param.value}`).join("; ");
|
|
40
|
-
s.push(ident(`.header("Cookie", ${JSON.stringify(cookieString)})`));
|
|
43
|
+
const arg = body ? "body" : "";
|
|
44
|
+
s.push(ident(`.${data.method.toUpperCase()}(${arg})`));
|
|
45
|
+
s.push(ident(".build();"));
|
|
46
|
+
s.push("");
|
|
47
|
+
s.push("try {");
|
|
48
|
+
s.push(ident("HttpResponse<String> response = client.send(requestBuilder.build(), BodyHandlers.ofString());"));
|
|
49
|
+
s.push(ident("System.out.println(\"Status code: \" + response.statusCode());"));
|
|
50
|
+
s.push(ident("System.out.println(\"Response body: \" + response.body());"));
|
|
51
|
+
s.push("} catch (Exception e) {");
|
|
52
|
+
s.push(ident("e.printStackTrace();"));
|
|
53
|
+
s.push("}");
|
|
54
|
+
return s.join("\n");
|
|
41
55
|
}
|
|
42
|
-
const arg = body ? "body" : "";
|
|
43
|
-
s.push(ident(`.${data.method.toUpperCase()}(${arg})`));
|
|
44
|
-
s.push(ident(".build();"));
|
|
45
|
-
s.push("");
|
|
46
|
-
s.push("try {");
|
|
47
|
-
s.push(ident("HttpResponse<String> response = client.send(requestBuilder.build(), BodyHandlers.ofString());"));
|
|
48
|
-
s.push(ident("System.out.println(\"Status code: \" + response.statusCode());"));
|
|
49
|
-
s.push(ident("System.out.println(\"Response body: \" + response.body());"));
|
|
50
|
-
s.push("} catch (Exception e) {");
|
|
51
|
-
s.push(ident("e.printStackTrace();"));
|
|
52
|
-
s.push("}");
|
|
53
|
-
return s.join("\n");
|
|
54
56
|
};
|
|
55
57
|
|
|
56
58
|
//#endregion
|
|
57
|
-
export {
|
|
59
|
+
export { java };
|
|
@@ -1,39 +1,41 @@
|
|
|
1
|
-
'use client';
|
|
2
|
-
|
|
3
1
|
import { ident } from "../string-utils.js";
|
|
4
2
|
import { resolveMediaAdapter } from "../media/resolve-adapter.js";
|
|
5
3
|
import "../media/adapter.js";
|
|
6
4
|
|
|
7
5
|
//#region src/requests/generators/javascript.ts
|
|
8
|
-
const
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
6
|
+
const javascript = {
|
|
7
|
+
label: "JavaScript",
|
|
8
|
+
lang: "js",
|
|
9
|
+
generate(url, data, { mediaAdapters }) {
|
|
10
|
+
const s = [];
|
|
11
|
+
const options = /* @__PURE__ */ new Map();
|
|
12
|
+
const headers = {};
|
|
13
|
+
options.set("method", JSON.stringify(data.method));
|
|
14
|
+
if (data.bodyMediaType) headers["Content-Type"] = data.bodyMediaType;
|
|
15
|
+
for (const [k, v] of Object.entries(data.header)) headers[k] = v.value;
|
|
16
|
+
const cookies = Object.entries(data.cookie);
|
|
17
|
+
if (cookies.length > 0) headers["cookie"] = cookies.map(([key, param]) => `${key}=${param.value}`).join("; ");
|
|
18
|
+
if (Object.keys(headers).length > 0) options.set("headers", JSON.stringify(headers, null, 2));
|
|
19
|
+
let body;
|
|
20
|
+
if (data.body && data.bodyMediaType) body = resolveMediaAdapter(data.bodyMediaType, mediaAdapters)?.generateExample(data, {
|
|
21
|
+
lang: "js",
|
|
22
|
+
addImport(from, name) {
|
|
23
|
+
s.unshift(`import { ${name} } from "${from}"`);
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
if (body) {
|
|
27
|
+
s.push(body);
|
|
28
|
+
options.set("body", "body");
|
|
23
29
|
}
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
const str = Array.from(options.entries()).map(([k, v]) => ident(k === v ? k : `${k}: ${v}`)).join(",\n");
|
|
32
|
-
params.push(`{\n${str}\n}`);
|
|
30
|
+
const params = [JSON.stringify(url)];
|
|
31
|
+
if (options.size > 0) {
|
|
32
|
+
const str = Array.from(options.entries()).map(([k, v]) => ident(k === v ? k : `${k}: ${v}`)).join(",\n");
|
|
33
|
+
params.push(`{\n${str}\n}`);
|
|
34
|
+
}
|
|
35
|
+
s.push(`fetch(${params.join(", ")})`);
|
|
36
|
+
return s.join("\n\n");
|
|
33
37
|
}
|
|
34
|
-
s.push(`fetch(${params.join(", ")})`);
|
|
35
|
-
return s.join("\n\n");
|
|
36
38
|
};
|
|
37
39
|
|
|
38
40
|
//#endregion
|
|
39
|
-
export {
|
|
41
|
+
export { javascript };
|
|
@@ -1,38 +1,40 @@
|
|
|
1
|
-
'use client';
|
|
2
|
-
|
|
3
1
|
import { resolveMediaAdapter } from "../media/resolve-adapter.js";
|
|
4
2
|
import "../media/adapter.js";
|
|
5
3
|
import { generatePythonObject } from "../to-python-object.js";
|
|
6
4
|
|
|
7
5
|
//#region src/requests/generators/python.ts
|
|
8
|
-
const
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
body
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
6
|
+
const python = {
|
|
7
|
+
label: "Python",
|
|
8
|
+
lang: "python",
|
|
9
|
+
generate(url, data, { mediaAdapters }) {
|
|
10
|
+
const headers = {};
|
|
11
|
+
const imports = /* @__PURE__ */ new Set();
|
|
12
|
+
const params = [`"${data.method}"`, "url"];
|
|
13
|
+
let body;
|
|
14
|
+
imports.add("requests");
|
|
15
|
+
if (data.body && data.bodyMediaType) {
|
|
16
|
+
const adapter = resolveMediaAdapter(data.bodyMediaType, mediaAdapters);
|
|
17
|
+
headers["Content-Type"] = data.bodyMediaType;
|
|
18
|
+
body = adapter?.generateExample(data, { lang: "python" });
|
|
19
|
+
if (body) params.push("data = body");
|
|
20
|
+
}
|
|
21
|
+
for (const [k, v] of Object.entries(data.header)) headers[k] = v.value;
|
|
22
|
+
if (Object.keys(headers).length > 0) params.push(`headers = ${generatePythonObject(headers, imports)}`);
|
|
23
|
+
const inputCookies = Object.entries(data.cookie);
|
|
24
|
+
if (inputCookies.length > 0) {
|
|
25
|
+
const cookies = {};
|
|
26
|
+
for (const [k, v] of inputCookies) cookies[k] = v.value;
|
|
27
|
+
params.push(`cookies = ${generatePythonObject(cookies, imports)}`);
|
|
28
|
+
}
|
|
29
|
+
return `${Array.from(imports).map((name) => "import " + name).join("\n")}
|
|
29
30
|
|
|
30
31
|
url = ${JSON.stringify(url)}
|
|
31
32
|
${body ?? ""}
|
|
32
33
|
response = requests.request(${params.join(", ")})
|
|
33
34
|
|
|
34
35
|
print(response.text)`;
|
|
36
|
+
}
|
|
35
37
|
};
|
|
36
38
|
|
|
37
39
|
//#endregion
|
|
38
|
-
export {
|
|
40
|
+
export { python };
|
package/dist/requests/types.d.ts
CHANGED
|
@@ -1,11 +1,6 @@
|
|
|
1
|
-
import { MediaAdapter } from "./media/adapter.js";
|
|
2
1
|
import { EncodedParameter, EncodedParameterMultiple } from "./media/encode.js";
|
|
3
2
|
|
|
4
3
|
//#region src/requests/types.d.ts
|
|
5
|
-
type SampleGenerator<ServerContext = unknown> = (url: string, data: RequestData, context: {
|
|
6
|
-
mediaAdapters: Record<string, MediaAdapter>;
|
|
7
|
-
server: ServerContext;
|
|
8
|
-
}) => string;
|
|
9
4
|
interface RawRequestData {
|
|
10
5
|
method: string;
|
|
11
6
|
path: Record<string, unknown>;
|
|
@@ -25,4 +20,4 @@ interface RequestData {
|
|
|
25
20
|
bodyMediaType?: string;
|
|
26
21
|
}
|
|
27
22
|
//#endregion
|
|
28
|
-
export { RawRequestData, RequestData
|
|
23
|
+
export { RawRequestData, RequestData };
|
package/dist/server/create.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { createProxy } from "./proxy.js";
|
|
2
|
-
import {
|
|
2
|
+
import { InlineCodeUsageGenerator } from "../requests/generators/index.js";
|
|
3
3
|
import { Document } from "../types.js";
|
|
4
4
|
import { ProcessedDocument } from "../utils/process-document.js";
|
|
5
5
|
|
|
@@ -30,6 +30,9 @@ interface OpenAPIServer {
|
|
|
30
30
|
readonly options: OpenAPIOptions;
|
|
31
31
|
}
|
|
32
32
|
declare function createOpenAPI(options?: OpenAPIOptions): OpenAPIServer;
|
|
33
|
-
|
|
33
|
+
/**
|
|
34
|
+
* @deprecated
|
|
35
|
+
*/
|
|
36
|
+
declare function createCodeSample<T>(options: InlineCodeUsageGenerator<T>): InlineCodeUsageGenerator<T>;
|
|
34
37
|
//#endregion
|
|
35
38
|
export { OpenAPIOptions, OpenAPIServer, createCodeSample, createOpenAPI };
|
package/dist/server/create.js
CHANGED
|
@@ -30,13 +30,11 @@ function createOpenAPI(options = {}) {
|
|
|
30
30
|
}
|
|
31
31
|
};
|
|
32
32
|
}
|
|
33
|
+
/**
|
|
34
|
+
* @deprecated
|
|
35
|
+
*/
|
|
33
36
|
function createCodeSample(options) {
|
|
34
|
-
|
|
35
|
-
return {
|
|
36
|
-
id,
|
|
37
|
-
lang,
|
|
38
|
-
...rest
|
|
39
|
-
};
|
|
37
|
+
return options;
|
|
40
38
|
}
|
|
41
39
|
|
|
42
40
|
//#endregion
|
package/dist/types.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { OpenAPIV3, OpenAPIV3_2 } from "./_openapi/types.js";
|
|
2
2
|
import { NoReference } from "./utils/schema.js";
|
|
3
3
|
import { MediaAdapter } from "./requests/media/adapter.js";
|
|
4
|
-
import {
|
|
4
|
+
import { InlineCodeUsageGenerator } from "./requests/generators/index.js";
|
|
5
5
|
import { OpenAPIOptions } from "./server/create.js";
|
|
6
6
|
import "./server/index.js";
|
|
7
7
|
import { CreateAPIPageOptions } from "./ui/base.js";
|
|
@@ -28,11 +28,12 @@ type MediaTypeObject = OpenAPIV3_2.MediaTypeObject;
|
|
|
28
28
|
type RequestBodyObject = OpenAPIV3_2.RequestBodyObject;
|
|
29
29
|
type MethodInformation = NoReference<OperationObject> & {
|
|
30
30
|
method: string;
|
|
31
|
-
'x-codeSamples'?:
|
|
31
|
+
'x-codeSamples'?: InlineCodeUsageGenerator[];
|
|
32
32
|
'x-selectedCodeSample'?: string;
|
|
33
33
|
'x-exclusiveCodeSample'?: string;
|
|
34
34
|
};
|
|
35
|
-
|
|
35
|
+
type RequireKeys<T, K extends keyof T> = Omit<T, K> & Required<Pick<T, K>>;
|
|
36
|
+
interface RenderContext extends Pick<OpenAPIOptions, 'proxyUrl'>, RequireKeys<CreateAPIPageOptions, 'generateTypeScriptDefinitions' | 'renderMarkdown'> {
|
|
36
37
|
slugger: Slugger;
|
|
37
38
|
/**
|
|
38
39
|
* dereferenced schema
|
|
@@ -40,7 +41,6 @@ interface RenderContext extends Pick<OpenAPIOptions, 'proxyUrl'>, Omit<CreateAPI
|
|
|
40
41
|
schema: ProcessedDocument;
|
|
41
42
|
mediaAdapters: Record<string, MediaAdapter>;
|
|
42
43
|
renderHeading: (depth: number, text: string, props?: HTMLAttributes<HTMLHeadingElement>) => ReactNode;
|
|
43
|
-
renderMarkdown: (text: string) => ReactNode;
|
|
44
44
|
renderCodeBlock: (lang: string, code: string) => ReactNode;
|
|
45
45
|
}
|
|
46
46
|
type DistributiveOmit<T, K extends PropertyKey> = T extends unknown ? Omit<T, K> : never;
|
package/dist/ui/base.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { NoReference } from "../utils/schema.js";
|
|
2
2
|
import { MediaAdapter } from "../requests/media/adapter.js";
|
|
3
|
-
import {
|
|
3
|
+
import { CodeUsageGeneratorRegistry, InlineCodeUsageGenerator } from "../requests/generators/index.js";
|
|
4
4
|
import { OpenAPIServer } from "../server/create.js";
|
|
5
5
|
import { ApiPageProps, OperationItem, WebhookItem } from "./api-page.js";
|
|
6
6
|
import "../server/index.js";
|
|
@@ -12,6 +12,7 @@ import { Awaitable, DistributiveOmit, MethodInformation, RenderContext } from ".
|
|
|
12
12
|
import { FC, ReactNode } from "react";
|
|
13
13
|
import { CoreHighlightOptions } from "fumadocs-core/highlight/core";
|
|
14
14
|
import { ResolvedShikiConfig } from "fumadocs-core/highlight/config";
|
|
15
|
+
import { JSONSchema } from "json-schema-typed";
|
|
15
16
|
|
|
16
17
|
//#region src/ui/base.d.ts
|
|
17
18
|
interface CreateAPIPageOptions {
|
|
@@ -22,14 +23,31 @@ interface CreateAPIPageOptions {
|
|
|
22
23
|
*
|
|
23
24
|
* @param method - the operation object
|
|
24
25
|
* @param statusCode - status code
|
|
26
|
+
* @deprecated use `generateTypeScriptDefinitions` instead.
|
|
25
27
|
*/
|
|
26
28
|
generateTypeScriptSchema?: ((method: NoReference<MethodInformation>, statusCode: string, contentType: string, ctx: RenderContext) => Awaitable<string | undefined>) | false;
|
|
29
|
+
/**
|
|
30
|
+
* Generate TypeScript definitions from JSON schema.
|
|
31
|
+
*
|
|
32
|
+
* Pass `false` to disable it.
|
|
33
|
+
*/
|
|
34
|
+
generateTypeScriptDefinitions?: (schema: JSONSchema, ctx: RenderContext & {
|
|
35
|
+
operation: NoReference<MethodInformation>; /** @deprecated */
|
|
36
|
+
_internal_legacy?: {
|
|
37
|
+
statusCode: string;
|
|
38
|
+
contentType: string;
|
|
39
|
+
};
|
|
40
|
+
}) => Awaitable<string | undefined>;
|
|
41
|
+
/**
|
|
42
|
+
* Generate example code usage for endpoints.
|
|
43
|
+
*/
|
|
44
|
+
codeUsages?: CodeUsageGeneratorRegistry;
|
|
27
45
|
/**
|
|
28
46
|
* Generate example code usage for endpoints.
|
|
29
47
|
*/
|
|
30
|
-
generateCodeSamples?: (method: MethodInformation) => Awaitable<
|
|
48
|
+
generateCodeSamples?: (method: MethodInformation) => Awaitable<InlineCodeUsageGenerator[]>;
|
|
31
49
|
shiki: ResolvedShikiConfig;
|
|
32
|
-
renderMarkdown?: (md: string) =>
|
|
50
|
+
renderMarkdown?: (md: string) => ReactNode;
|
|
33
51
|
shikiOptions?: DistributiveOmit<CoreHighlightOptions, 'config' | 'lang' | 'components'>;
|
|
34
52
|
/**
|
|
35
53
|
* Show full response schema instead of only example response & Typescript definitions.
|
|
@@ -58,7 +76,7 @@ interface CreateAPIPageOptions {
|
|
|
58
76
|
/**
|
|
59
77
|
* @param generators - codegens for API example usages
|
|
60
78
|
*/
|
|
61
|
-
renderAPIExampleUsageTabs?: (generators:
|
|
79
|
+
renderAPIExampleUsageTabs?: (generators: CodeUsageGeneratorRegistry, ctx: RenderContext) => Awaitable<ReactNode>;
|
|
62
80
|
/**
|
|
63
81
|
* renderer of the entire page's layout (containing all operations & webhooks UI)
|
|
64
82
|
*/
|
package/dist/ui/base.js
CHANGED
|
@@ -55,6 +55,14 @@ function createAPIPage(server, options) {
|
|
|
55
55
|
children: text
|
|
56
56
|
}, id);
|
|
57
57
|
},
|
|
58
|
+
generateTypeScriptDefinitions(schema, ctx) {
|
|
59
|
+
const { generateTypeScriptSchema, generateTypeScriptDefinitions } = options;
|
|
60
|
+
if (generateTypeScriptSchema && ctx._internal_legacy) {
|
|
61
|
+
const { statusCode, contentType } = ctx._internal_legacy;
|
|
62
|
+
return generateTypeScriptSchema(ctx.operation, statusCode, contentType, ctx);
|
|
63
|
+
}
|
|
64
|
+
return generateTypeScriptDefinitions?.(schema, ctx);
|
|
65
|
+
},
|
|
58
66
|
async renderMarkdown(text) {
|
|
59
67
|
if (options.renderMarkdown) return options.renderMarkdown(text);
|
|
60
68
|
processor ??= createMarkdownProcessor();
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { MediaAdapter } from "../../requests/media/adapter.js";
|
|
2
|
+
import { CodeUsageGeneratorRegistry } from "../../requests/generators/index.js";
|
|
2
3
|
import { PlaygroundClientOptions } from "../../playground/client.js";
|
|
3
4
|
import { ExampleRequestItem } from "../operation/request-tabs.js";
|
|
4
5
|
import { FC } from "react";
|
|
@@ -19,6 +20,10 @@ interface APIPageClientOptions {
|
|
|
19
20
|
* Support other media types (for client-side serialization)
|
|
20
21
|
*/
|
|
21
22
|
mediaAdapters?: Record<string, MediaAdapter>;
|
|
23
|
+
/**
|
|
24
|
+
* generate code usage examples
|
|
25
|
+
*/
|
|
26
|
+
codeUsages?: CodeUsageGeneratorRegistry;
|
|
22
27
|
}
|
|
23
28
|
interface OperationClientOptions {
|
|
24
29
|
APIExampleSelector?: FC<{
|
package/dist/ui/contexts/api.js
CHANGED
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
import { defaultAdapters } from "../../requests/media/adapter.js";
|
|
4
4
|
import { useStorageKey } from "../client/storage-key.js";
|
|
5
|
+
import { createCodeUsageGeneratorRegistry } from "../../requests/generators/index.js";
|
|
6
|
+
import { registerDefault } from "../../requests/generators/all.js";
|
|
5
7
|
import { createContext, use, useEffect, useMemo, useRef, useState } from "react";
|
|
6
8
|
import { jsx } from "react/jsx-runtime";
|
|
7
9
|
|
|
@@ -24,14 +26,23 @@ function useServerSelectContext() {
|
|
|
24
26
|
}
|
|
25
27
|
function ApiProvider({ children, shikiOptions, client }) {
|
|
26
28
|
return /* @__PURE__ */ jsx(ApiContext, {
|
|
27
|
-
value: useMemo(() =>
|
|
28
|
-
|
|
29
|
-
client
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
29
|
+
value: useMemo(() => {
|
|
30
|
+
let codeUsages;
|
|
31
|
+
if (client.codeUsages) codeUsages = createCodeUsageGeneratorRegistry(client.codeUsages);
|
|
32
|
+
else {
|
|
33
|
+
codeUsages = createCodeUsageGeneratorRegistry();
|
|
34
|
+
registerDefault(codeUsages);
|
|
33
35
|
}
|
|
34
|
-
|
|
36
|
+
return {
|
|
37
|
+
shikiOptions,
|
|
38
|
+
client,
|
|
39
|
+
codeUsages,
|
|
40
|
+
mediaAdapters: {
|
|
41
|
+
...defaultAdapters,
|
|
42
|
+
...client.mediaAdapters
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
}, [client, shikiOptions]),
|
|
35
46
|
children
|
|
36
47
|
});
|
|
37
48
|
}
|
package/dist/ui/full.js
CHANGED
|
@@ -9,9 +9,8 @@ function createAPIPage(server, options = {}) {
|
|
|
9
9
|
const APIPage = createAPIPage$1(server, {
|
|
10
10
|
...options,
|
|
11
11
|
shiki: configDefault,
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
if (!schema || typeof schema !== "object") return;
|
|
12
|
+
generateTypeScriptDefinitions(schema, ctx) {
|
|
13
|
+
if (typeof schema !== "object") return;
|
|
15
14
|
return getTypescriptSchema(schema, ctx);
|
|
16
15
|
}
|
|
17
16
|
});
|
|
@@ -9,18 +9,22 @@ import { buttonVariants } from "fumadocs-ui/components/ui/button";
|
|
|
9
9
|
import { useCopyButton } from "fumadocs-ui/utils/use-copy-button";
|
|
10
10
|
|
|
11
11
|
//#region src/ui/operation/client.tsx
|
|
12
|
-
function
|
|
12
|
+
function CopyTypeScriptPanel({ name, code, className }) {
|
|
13
13
|
const [isChecked, onCopy] = useCopyButton(() => {
|
|
14
14
|
navigator.clipboard.writeText(code);
|
|
15
15
|
});
|
|
16
16
|
return /* @__PURE__ */ jsxs("div", {
|
|
17
|
-
className: "flex items-start justify-between gap-2 bg-fd-card text-fd-card-foreground border rounded-xl p-3 not-prose mb-4 last:mb-0",
|
|
17
|
+
className: cn("flex items-start justify-between gap-2 bg-fd-card text-fd-card-foreground border rounded-xl p-3 not-prose mb-4 last:mb-0", className),
|
|
18
18
|
children: [/* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx("p", {
|
|
19
19
|
className: "font-medium text-sm mb-2",
|
|
20
20
|
children: "TypeScript Definitions"
|
|
21
|
-
}), /* @__PURE__ */
|
|
21
|
+
}), /* @__PURE__ */ jsxs("p", {
|
|
22
22
|
className: "text-xs text-fd-muted-foreground",
|
|
23
|
-
children:
|
|
23
|
+
children: [
|
|
24
|
+
"Use the ",
|
|
25
|
+
name,
|
|
26
|
+
" type in TypeScript."
|
|
27
|
+
]
|
|
24
28
|
})] }), /* @__PURE__ */ jsxs("button", {
|
|
25
29
|
onClick: onCopy,
|
|
26
30
|
className: cn(buttonVariants({
|
|
@@ -67,4 +71,4 @@ function SelectTabTrigger({ items, className, ...props }) {
|
|
|
67
71
|
}
|
|
68
72
|
|
|
69
73
|
//#endregion
|
|
70
|
-
export {
|
|
74
|
+
export { CopyTypeScriptPanel, SelectTab, SelectTabTrigger, SelectTabs };
|
|
@@ -9,7 +9,7 @@ import { Schema } from "../schema/index.js";
|
|
|
9
9
|
import { UsageTabsProviderLazy } from "./usage-tabs/lazy.js";
|
|
10
10
|
import { AccordionContent, AccordionHeader, AccordionItem, AccordionTrigger, Accordions } from "../components/accordion.js";
|
|
11
11
|
import { UsageTabs } from "./usage-tabs/index.js";
|
|
12
|
-
import {
|
|
12
|
+
import { CopyTypeScriptPanel, SelectTab, SelectTabTrigger, SelectTabs } from "./client.js";
|
|
13
13
|
import { RequestTabs, getExampleRequests } from "./request-tabs.js";
|
|
14
14
|
import { ServerProviderLazy } from "../contexts/api.lazy.js";
|
|
15
15
|
import { Fragment } from "react";
|
|
@@ -59,11 +59,19 @@ async function Operation({ type = "operation", path, method, ctx, showTitle, sho
|
|
|
59
59
|
})]
|
|
60
60
|
}),
|
|
61
61
|
body.description && ctx.renderMarkdown(body.description),
|
|
62
|
-
contentTypes.map(([type, content]) => {
|
|
62
|
+
contentTypes.map(async ([type, content]) => {
|
|
63
63
|
if (!isMediaTypeSupported(type, ctx.mediaAdapters)) throw new Error(`Media type ${type} is not supported (in ${path})`);
|
|
64
|
-
|
|
64
|
+
const ts = content.schema ? await ctx.generateTypeScriptDefinitions(content.schema, {
|
|
65
|
+
operation: method,
|
|
66
|
+
...ctx
|
|
67
|
+
}) : void 0;
|
|
68
|
+
return /* @__PURE__ */ jsxs(SelectTab, {
|
|
65
69
|
value: type,
|
|
66
|
-
children: /* @__PURE__ */ jsx(
|
|
70
|
+
children: [ts && /* @__PURE__ */ jsx(CopyTypeScriptPanel, {
|
|
71
|
+
name: "request body",
|
|
72
|
+
code: ts,
|
|
73
|
+
className: "mt-4"
|
|
74
|
+
}), /* @__PURE__ */ jsx(Schema, {
|
|
67
75
|
client: {
|
|
68
76
|
name: "body",
|
|
69
77
|
as: "body",
|
|
@@ -73,7 +81,7 @@ async function Operation({ type = "operation", path, method, ctx, showTitle, sho
|
|
|
73
81
|
readOnly: method.method === "GET",
|
|
74
82
|
writeOnly: method.method !== "GET",
|
|
75
83
|
ctx
|
|
76
|
-
})
|
|
84
|
+
})]
|
|
77
85
|
}, type);
|
|
78
86
|
})
|
|
79
87
|
]
|
|
@@ -319,12 +327,21 @@ async function ResponseAccordion({ status, operation, ctx }) {
|
|
|
319
327
|
children: ctx.renderMarkdown(response.description)
|
|
320
328
|
}), contentTypes.map(async ([type, resType]) => {
|
|
321
329
|
const schema = resType.schema;
|
|
322
|
-
|
|
323
|
-
|
|
330
|
+
const ts = schema ? await ctx.generateTypeScriptDefinitions(schema, {
|
|
331
|
+
operation,
|
|
332
|
+
_internal_legacy: {
|
|
333
|
+
statusCode: status,
|
|
334
|
+
contentType: type
|
|
335
|
+
},
|
|
336
|
+
...ctx
|
|
337
|
+
}) : void 0;
|
|
324
338
|
return /* @__PURE__ */ jsxs(SelectTab, {
|
|
325
339
|
value: type,
|
|
326
340
|
className: "mb-2",
|
|
327
|
-
children: [ts && /* @__PURE__ */ jsx(
|
|
341
|
+
children: [ts && /* @__PURE__ */ jsx(CopyTypeScriptPanel, {
|
|
342
|
+
name: "response body",
|
|
343
|
+
code: ts
|
|
344
|
+
}), schema && /* @__PURE__ */ jsx("div", {
|
|
328
345
|
className: "border px-3 py-2 rounded-lg",
|
|
329
346
|
children: /* @__PURE__ */ jsx(Schema, {
|
|
330
347
|
client: {
|