fumadocs-openapi 6.0.1 → 6.0.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/dist/build-routes.d.ts +15 -0
- package/dist/build-routes.d.ts.map +1 -0
- package/dist/build-routes.js +38 -0
- package/dist/generate-file.d.ts +38 -0
- package/dist/generate-file.d.ts.map +1 -0
- package/dist/generate-file.js +118 -0
- package/dist/generate.d.ts +48 -0
- package/dist/generate.d.ts.map +1 -0
- package/dist/generate.js +129 -0
- package/dist/index.d.ts +4 -274
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +3 -389
- package/dist/render/codeblock.d.ts +9 -0
- package/dist/render/codeblock.d.ts.map +1 -0
- package/dist/render/codeblock.js +13 -0
- package/dist/render/heading.d.ts +4 -0
- package/dist/render/heading.d.ts.map +1 -0
- package/dist/render/heading.js +6 -0
- package/dist/render/markdown.d.ts +5 -0
- package/dist/render/markdown.d.ts.map +1 -0
- package/dist/render/markdown.js +25 -0
- package/dist/render/operation.d.ts +17 -0
- package/dist/render/operation.d.ts.map +1 -0
- package/dist/render/operation.js +230 -0
- package/dist/render/playground.d.ts +66 -0
- package/dist/render/playground.d.ts.map +1 -0
- package/dist/render/playground.js +181 -0
- package/dist/render/renderer.d.ts +76 -0
- package/dist/render/renderer.d.ts.map +1 -0
- package/dist/render/renderer.js +23 -0
- package/dist/render/schema.d.ts +29 -0
- package/dist/render/schema.d.ts.map +1 -0
- package/dist/render/schema.js +151 -0
- package/dist/requests/curl.d.ts +3 -0
- package/dist/requests/curl.d.ts.map +1 -0
- package/dist/requests/curl.js +33 -0
- package/dist/requests/go.d.ts +3 -0
- package/dist/requests/go.d.ts.map +1 -0
- package/dist/requests/go.js +54 -0
- package/dist/requests/javascript.d.ts +3 -0
- package/dist/requests/javascript.d.ts.map +1 -0
- package/dist/requests/javascript.js +49 -0
- package/dist/requests/python.d.ts +3 -0
- package/dist/requests/python.d.ts.map +1 -0
- package/dist/requests/python.js +45 -0
- package/dist/scalar/client.d.ts +6 -0
- package/dist/scalar/client.d.ts.map +1 -0
- package/dist/scalar/client.js +25 -0
- package/dist/scalar/index.d.ts +4 -173
- package/dist/scalar/index.d.ts.map +1 -0
- package/dist/scalar/index.js +4 -11
- package/dist/server/api-page.d.ts +33 -0
- package/dist/server/api-page.d.ts.map +1 -0
- package/dist/server/api-page.js +59 -0
- package/dist/server/create-method.d.ts +7 -0
- package/dist/server/create-method.d.ts.map +1 -0
- package/dist/server/create-method.js +12 -0
- package/dist/server/create.d.ts +16 -0
- package/dist/server/create.d.ts.map +1 -0
- package/dist/server/create.js +11 -0
- package/dist/server/index.d.ts +3 -221
- package/dist/server/index.d.ts.map +1 -0
- package/dist/server/index.js +2 -1493
- package/dist/server/proxy.d.ts +8 -0
- package/dist/server/proxy.d.ts.map +1 -0
- package/dist/server/proxy.js +53 -0
- package/dist/server/source-api.d.ts +8 -0
- package/dist/server/source-api.d.ts.map +1 -0
- package/dist/server/source-api.js +34 -0
- package/dist/types.d.ts +60 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +1 -0
- package/dist/ui/client.d.ts +22 -0
- package/dist/ui/client.d.ts.map +1 -0
- package/dist/ui/client.js +10 -0
- package/dist/ui/components/input.d.ts +6 -0
- package/dist/ui/components/input.d.ts.map +1 -0
- package/dist/ui/components/input.js +10 -0
- package/dist/ui/components/method-label.d.ts +5 -0
- package/dist/ui/components/method-label.d.ts.map +1 -0
- package/dist/ui/components/method-label.js +33 -0
- package/dist/ui/components/select.d.ts +14 -0
- package/dist/ui/components/select.d.ts.map +1 -0
- package/dist/ui/components/select.js +24 -0
- package/dist/ui/components/variants.d.ts +6 -0
- package/dist/ui/components/variants.d.ts.map +1 -0
- package/dist/ui/components/variants.js +26 -0
- package/dist/ui/contexts/api.d.ts +28 -0
- package/dist/ui/contexts/api.d.ts.map +1 -0
- package/dist/ui/contexts/api.js +74 -0
- package/dist/ui/contexts/schema.d.ts +17 -0
- package/dist/ui/contexts/schema.d.ts.map +1 -0
- package/dist/ui/contexts/schema.js +8 -0
- package/dist/ui/index.d.ts +12 -302
- package/dist/ui/index.d.ts.map +1 -0
- package/dist/ui/index.js +18 -98
- package/dist/ui/playground/fetcher.d.ts +34 -0
- package/dist/ui/playground/fetcher.d.ts.map +1 -0
- package/dist/ui/{fetcher-CsHhplmD.js → playground/fetcher.js} +45 -44
- package/dist/ui/playground/get-default-values.d.ts +4 -0
- package/dist/ui/playground/get-default-values.d.ts.map +1 -0
- package/dist/ui/playground/get-default-values.js +24 -0
- package/dist/ui/playground/index.d.ts +44 -0
- package/dist/ui/playground/index.d.ts.map +1 -0
- package/dist/ui/playground/index.js +187 -0
- package/dist/ui/playground/inputs.d.ts +23 -0
- package/dist/ui/playground/inputs.d.ts.map +1 -0
- package/dist/ui/playground/inputs.js +172 -0
- package/dist/ui/playground/resolve.d.ts +6 -0
- package/dist/ui/playground/resolve.d.ts.map +1 -0
- package/dist/ui/playground/resolve.js +14 -0
- package/dist/ui/playground/status-info.d.ts +8 -0
- package/dist/ui/playground/status-info.d.ts.map +1 -0
- package/dist/ui/playground/status-info.js +40 -0
- package/dist/ui/server-select.d.ts +3 -0
- package/dist/ui/server-select.d.ts.map +1 -0
- package/dist/ui/server-select.js +27 -0
- package/dist/utils/combine-schema.d.ts +6 -0
- package/dist/utils/combine-schema.d.ts.map +1 -0
- package/dist/utils/combine-schema.js +46 -0
- package/dist/utils/generate-document.d.ts +20 -0
- package/dist/utils/generate-document.d.ts.map +1 -0
- package/dist/utils/generate-document.js +82 -0
- package/dist/utils/generate-sample.d.ts +33 -0
- package/dist/utils/generate-sample.d.ts.map +1 -0
- package/dist/utils/generate-sample.js +97 -0
- package/dist/utils/get-security.d.ts +8 -0
- package/dist/utils/get-security.d.ts.map +1 -0
- package/dist/utils/get-security.js +23 -0
- package/dist/utils/get-typescript-schema.d.ts +4 -0
- package/dist/utils/get-typescript-schema.d.ts.map +1 -0
- package/dist/utils/get-typescript-schema.js +18 -0
- package/dist/utils/id-to-title.d.ts +2 -0
- package/dist/utils/id-to-title.d.ts.map +1 -0
- package/dist/utils/id-to-title.js +17 -0
- package/dist/utils/input-to-string.d.ts +5 -0
- package/dist/utils/input-to-string.d.ts.map +1 -0
- package/dist/utils/input-to-string.js +21 -0
- package/dist/utils/process-document.d.ts +14 -0
- package/dist/utils/process-document.d.ts.map +1 -0
- package/dist/utils/process-document.js +32 -0
- package/dist/utils/schema.d.ts +9 -0
- package/dist/utils/schema.d.ts.map +1 -0
- package/dist/utils/schema.js +16 -0
- package/dist/utils/server-url.d.ts +2 -0
- package/dist/utils/server-url.d.ts.map +1 -0
- package/dist/utils/server-url.js +7 -0
- package/dist/utils/use-query.d.ts +6 -0
- package/dist/utils/use-query.d.ts.map +1 -0
- package/dist/utils/use-query.js +22 -0
- package/package.json +8 -8
- package/dist/scalar/client-client-BXAjVueF.js +0 -93
- package/dist/ui/client-client-CYO00OiB.js +0 -107
- package/dist/ui/index-client-BUeWwFWK.js +0 -1116
- package/dist/ui/server-select-client-Ct_HJ46K.js +0 -86
package/dist/server/index.js
CHANGED
|
@@ -1,1493 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
import { Fragment as Fragment$1 } from 'react';
|
|
4
|
-
import { sample } from 'openapi-sampler';
|
|
5
|
-
import { js2xml } from 'xml-js';
|
|
6
|
-
import { compile } from '@fumari/json-schema-to-typescript';
|
|
7
|
-
import { remarkGfm, remarkImage, rehypeCode } from 'fumadocs-core/mdx-plugins';
|
|
8
|
-
import defaultMdxComponents from 'fumadocs-ui/mdx';
|
|
9
|
-
import { remark } from 'remark';
|
|
10
|
-
import remarkRehype from 'remark-rehype';
|
|
11
|
-
import { toJsxRuntime } from 'hast-util-to-jsx-runtime';
|
|
12
|
-
import { Heading } from 'fumadocs-ui/components/heading';
|
|
13
|
-
import { Tabs, Tab } from 'fumadocs-ui/components/tabs';
|
|
14
|
-
import { Accordions, Accordion } from 'fumadocs-ui/components/accordion';
|
|
15
|
-
import * as Base from 'fumadocs-ui/components/codeblock';
|
|
16
|
-
import { highlight } from 'fumadocs-core/server';
|
|
17
|
-
import { APIPlayground, Root, API, APIInfo, APIExample as APIExample$1, Property, ObjectCollapsible } from '../ui/index.js';
|
|
18
|
-
import { load, upgrade, dereference } from '@scalar/openapi-parser';
|
|
19
|
-
import { fetchUrls } from '@scalar/openapi-parser/plugins/fetch-urls';
|
|
20
|
-
import { readFiles } from '@scalar/openapi-parser/plugins/read-files';
|
|
21
|
-
import { cva } from 'class-variance-authority';
|
|
22
|
-
|
|
23
|
-
function getPreferredType(body) {
|
|
24
|
-
if ('application/json' in body) return 'application/json';
|
|
25
|
-
return Object.keys(body)[0];
|
|
26
|
-
}
|
|
27
|
-
function isNullable(schema, includeOneOf = true) {
|
|
28
|
-
if (Array.isArray(schema.type) && schema.type.includes('null')) return true;
|
|
29
|
-
if (includeOneOf && (schema.anyOf || schema.oneOf)) {
|
|
30
|
-
if (schema.anyOf?.some((item)=>isNullable(item))) return true;
|
|
31
|
-
if (schema.oneOf?.some((item)=>isNullable(item))) return true;
|
|
32
|
-
}
|
|
33
|
-
return false;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
function getSecurities(requirement, document) {
|
|
37
|
-
const results = [];
|
|
38
|
-
const schemas = document.components?.securitySchemes ?? {};
|
|
39
|
-
for (const [key, scopes] of Object.entries(requirement)){
|
|
40
|
-
if (!(key in schemas)) return [];
|
|
41
|
-
const schema = schemas[key];
|
|
42
|
-
results.push({
|
|
43
|
-
...schema,
|
|
44
|
-
scopes
|
|
45
|
-
});
|
|
46
|
-
}
|
|
47
|
-
return results;
|
|
48
|
-
}
|
|
49
|
-
function getSecurityPrefix(security) {
|
|
50
|
-
if (security.type === 'http') return ({
|
|
51
|
-
basic: 'Basic',
|
|
52
|
-
bearer: 'Bearer'
|
|
53
|
-
})[security.scheme];
|
|
54
|
-
if (security.type === 'oauth2') return 'Bearer';
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
function generateSample(path, method, { baseUrl, schema: { document } }) {
|
|
58
|
-
const params = [];
|
|
59
|
-
const responses = {};
|
|
60
|
-
for (const param of method.parameters ?? []){
|
|
61
|
-
if (param.schema) {
|
|
62
|
-
params.push({
|
|
63
|
-
name: param.name,
|
|
64
|
-
in: param.in,
|
|
65
|
-
schema: param.schema,
|
|
66
|
-
sample: param.example ?? sample(param.schema)
|
|
67
|
-
});
|
|
68
|
-
} else if (param.content) {
|
|
69
|
-
const key = getPreferredType(param.content);
|
|
70
|
-
const content = key ? param.content[key] : undefined;
|
|
71
|
-
if (!key || !content) throw new Error(`Cannot find parameter schema for ${param.name} in ${path} ${method.method}`);
|
|
72
|
-
params.push({
|
|
73
|
-
name: param.name,
|
|
74
|
-
in: param.in,
|
|
75
|
-
schema: content.schema ?? {},
|
|
76
|
-
sample: content.example ?? param.example ?? sample(content.schema)
|
|
77
|
-
});
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
const requirements = method.security ?? document.security;
|
|
81
|
-
if (requirements && requirements.length > 0) {
|
|
82
|
-
for (const security of getSecurities(requirements[0], document)){
|
|
83
|
-
const prefix = getSecurityPrefix(security);
|
|
84
|
-
params.push({
|
|
85
|
-
name: security.type === 'apiKey' ? security.name : 'Authorization',
|
|
86
|
-
schema: {
|
|
87
|
-
type: 'string'
|
|
88
|
-
},
|
|
89
|
-
sample: prefix ? `${prefix} <token>` : '<token>',
|
|
90
|
-
in: 'header'
|
|
91
|
-
});
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
let bodyOutput;
|
|
95
|
-
if (method.requestBody) {
|
|
96
|
-
const body = method.requestBody.content;
|
|
97
|
-
const type = getPreferredType(body);
|
|
98
|
-
if (!type) throw new Error(`Cannot find body schema for ${path} ${method.method}: missing media type`);
|
|
99
|
-
const schema = (type ? body[type].schema : undefined) ?? {};
|
|
100
|
-
bodyOutput = {
|
|
101
|
-
schema,
|
|
102
|
-
mediaType: type,
|
|
103
|
-
sample: body[type].example ?? generateBody(method.method, schema)
|
|
104
|
-
};
|
|
105
|
-
}
|
|
106
|
-
for (const [code, response] of Object.entries(method.responses ?? {})){
|
|
107
|
-
const content = response.content;
|
|
108
|
-
if (!content) continue;
|
|
109
|
-
const mediaType = getPreferredType(content);
|
|
110
|
-
if (!mediaType) continue;
|
|
111
|
-
const responseSchema = content[mediaType].schema;
|
|
112
|
-
if (!responseSchema) continue;
|
|
113
|
-
responses[code] = {
|
|
114
|
-
mediaType,
|
|
115
|
-
sample: content[mediaType].example ?? generateBody(method.method, responseSchema),
|
|
116
|
-
schema: responseSchema
|
|
117
|
-
};
|
|
118
|
-
}
|
|
119
|
-
let pathWithParameters = path;
|
|
120
|
-
const queryParams = new URLSearchParams();
|
|
121
|
-
for (const param of params){
|
|
122
|
-
const value = generateBody(method.method, param.schema);
|
|
123
|
-
if (param.in === 'query') queryParams.append(param.name, String(value));
|
|
124
|
-
if (param.in === 'path') pathWithParameters = pathWithParameters.replace(`{${param.name}}`, String(value));
|
|
125
|
-
}
|
|
126
|
-
if (queryParams.size > 0) pathWithParameters = `${pathWithParameters}?${queryParams.toString()}`;
|
|
127
|
-
return {
|
|
128
|
-
url: new URL(`${baseUrl}${pathWithParameters}`).toString(),
|
|
129
|
-
body: bodyOutput,
|
|
130
|
-
responses,
|
|
131
|
-
method: method.method,
|
|
132
|
-
parameters: params
|
|
133
|
-
};
|
|
134
|
-
}
|
|
135
|
-
function generateBody(method, schema) {
|
|
136
|
-
return sample(schema, {
|
|
137
|
-
skipReadOnly: method !== 'GET',
|
|
138
|
-
skipWriteOnly: method === 'GET'
|
|
139
|
-
});
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
/**
|
|
143
|
-
* Convert input value to hardcoded string (with quotes)
|
|
144
|
-
*/ function inputToString(value, mediaType = 'application/json', multiLine = 'none') {
|
|
145
|
-
const getStr = (v)=>{
|
|
146
|
-
if (multiLine === 'none') return JSON.stringify(v);
|
|
147
|
-
const delimit = multiLine === 'backtick' ? `\`` : `'`;
|
|
148
|
-
return `${delimit}${v.replaceAll(delimit, `\\${delimit}`)}${delimit}`;
|
|
149
|
-
};
|
|
150
|
-
if (typeof value === 'string') return getStr(value);
|
|
151
|
-
if (mediaType === 'application/json' || mediaType === 'multipart/form-data') {
|
|
152
|
-
return getStr(JSON.stringify(value, null, 2));
|
|
153
|
-
}
|
|
154
|
-
if (mediaType === 'application/xml') {
|
|
155
|
-
return getStr(js2xml(value, {
|
|
156
|
-
compact: true,
|
|
157
|
-
spaces: 2
|
|
158
|
-
}));
|
|
159
|
-
}
|
|
160
|
-
throw new Error(`Unsupported media type: ${mediaType}`);
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
function getSampleRequest$3(endpoint) {
|
|
164
|
-
const s = [];
|
|
165
|
-
s.push(`curl -X ${endpoint.method} "${endpoint.url}"`);
|
|
166
|
-
for (const param of endpoint.parameters){
|
|
167
|
-
if (param.in === 'header') {
|
|
168
|
-
const header = `${param.name}: ${param.sample}`;
|
|
169
|
-
s.push(`-H "${header}"`);
|
|
170
|
-
}
|
|
171
|
-
if (param.in === 'cookie') {
|
|
172
|
-
const cookie = JSON.stringify(`${param.name}=${param.sample}`);
|
|
173
|
-
s.push(`--cookie ${cookie}`);
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
if (endpoint.body?.mediaType === 'multipart/form-data') {
|
|
177
|
-
const sample = endpoint.body.sample;
|
|
178
|
-
if (sample && typeof sample === 'object') {
|
|
179
|
-
for (const [key, value] of Object.entries(sample)){
|
|
180
|
-
s.push(`-F ${key}=${inputToString(value)}`);
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
} else if (endpoint.body) {
|
|
184
|
-
s.push(`-H "Content-Type: ${endpoint.body.mediaType}"`);
|
|
185
|
-
s.push(`-d ${inputToString(endpoint.body.sample, endpoint.body.mediaType, 'single-quote')}`);
|
|
186
|
-
}
|
|
187
|
-
return s.flatMap((v, i)=>v.split('\n').map((line)=>i > 0 ? ` ${line}` : line).join('\n')).join(' \\\n');
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
function getSampleRequest$2(endpoint) {
|
|
191
|
-
const s = [];
|
|
192
|
-
const options = new Map();
|
|
193
|
-
const headers = new Map();
|
|
194
|
-
const cookies = new Map();
|
|
195
|
-
for (const param of endpoint.parameters){
|
|
196
|
-
if (param.in === 'header') {
|
|
197
|
-
headers.set(param.name, param.sample);
|
|
198
|
-
}
|
|
199
|
-
if (param.in === 'cookie') {
|
|
200
|
-
cookies.set(param.name, param.sample);
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
|
-
if (cookies.size > 0) {
|
|
204
|
-
headers.set('cookie', Array.from(cookies.entries()).map(([key, value])=>`${key}=${value}`).join('; '));
|
|
205
|
-
}
|
|
206
|
-
if (headers.size > 0) {
|
|
207
|
-
options.set('headers', JSON.stringify(Object.fromEntries(headers.entries()), null, 2).replaceAll('\n', '\n '));
|
|
208
|
-
}
|
|
209
|
-
if (endpoint.body?.mediaType === 'multipart/form-data' && typeof endpoint.body.sample === 'object' && endpoint.body.sample) {
|
|
210
|
-
s.push(`const formData = new FormData();`);
|
|
211
|
-
for (const [key, value] of Object.entries(endpoint.body.sample))s.push(`formData.set(${key}, ${inputToString(value)})`);
|
|
212
|
-
options.set('body', 'formData');
|
|
213
|
-
} else if (endpoint.body) {
|
|
214
|
-
let code;
|
|
215
|
-
if (endpoint.body.mediaType === 'application/json') {
|
|
216
|
-
code = typeof endpoint.body.sample === 'string' ? inputToString(endpoint.body.sample, endpoint.body.mediaType, 'backtick') : `JSON.stringify(${JSON.stringify(endpoint.body.sample, null, 2)})`;
|
|
217
|
-
} else {
|
|
218
|
-
code = inputToString(endpoint.body.sample, endpoint.body.mediaType, 'backtick');
|
|
219
|
-
}
|
|
220
|
-
options.set('body', code.replaceAll('\n', '\n '));
|
|
221
|
-
}
|
|
222
|
-
const optionsStr = Array.from(options.entries()).map(([k, v])=>` ${k}: ${v}`).join(',\n');
|
|
223
|
-
s.push(`fetch(${JSON.stringify(endpoint.url)}, {\n${optionsStr}\n});`);
|
|
224
|
-
return s.join('\n\n');
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
function getSampleRequest$1(endpoint) {
|
|
228
|
-
const imports = [
|
|
229
|
-
'fmt',
|
|
230
|
-
'net/http',
|
|
231
|
-
'io/ioutil'
|
|
232
|
-
];
|
|
233
|
-
const headers = new Map();
|
|
234
|
-
const variables = new Map();
|
|
235
|
-
// additional lines before initializing request
|
|
236
|
-
const additional = [];
|
|
237
|
-
for (const p of endpoint.parameters){
|
|
238
|
-
if (p.in === 'header') headers.set(p.name, JSON.stringify(p.sample));
|
|
239
|
-
}
|
|
240
|
-
const cookies = endpoint.parameters.filter((p)=>p.in === 'cookie');
|
|
241
|
-
variables.set('url', JSON.stringify(endpoint.url));
|
|
242
|
-
if (cookies.length > 0) headers.set('Cookie', JSON.stringify(cookies.map((p)=>`${p.name}=${p.sample}`).join('; ')));
|
|
243
|
-
if (endpoint.body) {
|
|
244
|
-
headers.set('Content-Type', `"${endpoint.body.mediaType}"`);
|
|
245
|
-
if (endpoint.body.mediaType === 'multipart/form-data' && typeof endpoint.body.sample === 'object') {
|
|
246
|
-
imports.push('mime/multipart', 'bytes');
|
|
247
|
-
variables.set('payload', `new(bytes.Buffer)`);
|
|
248
|
-
variables.set('mp', 'multipart.NewWriter(payload)');
|
|
249
|
-
for (const [key, value] of Object.entries(endpoint.body.sample ?? {})){
|
|
250
|
-
additional.push(`mp.WriteField("${key}", ${inputToString(value, undefined, 'backtick')})`);
|
|
251
|
-
}
|
|
252
|
-
} else {
|
|
253
|
-
imports.push('strings');
|
|
254
|
-
variables.set('payload', `strings.NewReader(${inputToString(endpoint.body.sample, endpoint.body.mediaType, 'backtick').replaceAll('\n', '\n ')})`);
|
|
255
|
-
}
|
|
256
|
-
}
|
|
257
|
-
return `package main
|
|
258
|
-
|
|
259
|
-
import (
|
|
260
|
-
${imports.map((v)=>` "${v}"`).join('\n')}
|
|
261
|
-
)
|
|
262
|
-
|
|
263
|
-
func main() {
|
|
264
|
-
${Array.from(variables.entries()).map(([k, v])=>` ${k} := ${v}`).join('\n')}
|
|
265
|
-
${additional.join('\n ')}
|
|
266
|
-
req, _ := http.NewRequest("${endpoint.method}", url, ${variables.has('payload') ? 'payload' : 'nil'})
|
|
267
|
-
${Array.from(headers.entries()).map(([key, value])=>`req.Header.Add("${key}", ${value})`).join('\n ')}
|
|
268
|
-
res, _ := http.DefaultClient.Do(req)
|
|
269
|
-
defer res.Body.Close()
|
|
270
|
-
body, _ := ioutil.ReadAll(res.Body)
|
|
271
|
-
|
|
272
|
-
fmt.Println(res)
|
|
273
|
-
fmt.Println(string(body))
|
|
274
|
-
}`;
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
function getSampleRequest(endpoint) {
|
|
278
|
-
const headers = new Map();
|
|
279
|
-
const cookies = new Map();
|
|
280
|
-
const variables = new Map();
|
|
281
|
-
for (const param of endpoint.parameters){
|
|
282
|
-
if (param.in === 'header') headers.set(param.name, param.sample);
|
|
283
|
-
if (param.in === 'cookie') cookies.set(param.name, param.sample);
|
|
284
|
-
}
|
|
285
|
-
if (endpoint.body) {
|
|
286
|
-
switch(endpoint.body.mediaType){
|
|
287
|
-
case 'application/json':
|
|
288
|
-
variables.set('json', JSON.stringify(endpoint.body.sample, null, 2));
|
|
289
|
-
break;
|
|
290
|
-
case 'multipart/form-data':
|
|
291
|
-
headers.set('Content-Type', endpoint.body.mediaType);
|
|
292
|
-
variables.set('data', JSON.stringify(endpoint.body.sample, null, 2));
|
|
293
|
-
break;
|
|
294
|
-
default:
|
|
295
|
-
headers.set('Content-Type', endpoint.body.mediaType);
|
|
296
|
-
variables.set('data', inputToString(endpoint.body.sample, endpoint.body.mediaType, 'backtick'));
|
|
297
|
-
}
|
|
298
|
-
}
|
|
299
|
-
if (headers.size > 0) {
|
|
300
|
-
variables.set('headers', JSON.stringify(Object.fromEntries(headers.entries()), null, 2));
|
|
301
|
-
}
|
|
302
|
-
if (cookies.size > 0) {
|
|
303
|
-
variables.set('cookies', JSON.stringify(Object.fromEntries(cookies.entries()), null, 2));
|
|
304
|
-
}
|
|
305
|
-
return `import requests
|
|
306
|
-
|
|
307
|
-
url = ${JSON.stringify(endpoint.url)}
|
|
308
|
-
${Array.from(variables.entries()).map(([k, v])=>`${k} = ${v}`).join('\n')}
|
|
309
|
-
response = requests.request("${endpoint.method}", url${variables.size > 0 ? `, ${Array.from(variables.keys()).map((k)=>`${k}=${k}`).join(', ')}` : ''})
|
|
310
|
-
|
|
311
|
-
print(response.text)`;
|
|
312
|
-
}
|
|
313
|
-
|
|
314
|
-
async function getTypescriptSchema(endpoint, code, dereferenceMap) {
|
|
315
|
-
if (code in endpoint.responses) {
|
|
316
|
-
return compile(// re-running on the same schema results in error
|
|
317
|
-
// because it uses `defineProperty` to define internal references
|
|
318
|
-
// we clone the schema to fix this problem
|
|
319
|
-
// @ts-expect-error any types
|
|
320
|
-
endpoint.responses[code].schema, 'Response', {
|
|
321
|
-
$refOptions: false,
|
|
322
|
-
schemaToId: dereferenceMap,
|
|
323
|
-
bannerComment: '',
|
|
324
|
-
additionalProperties: false,
|
|
325
|
-
format: true,
|
|
326
|
-
enableConstEnums: false
|
|
327
|
-
});
|
|
328
|
-
}
|
|
329
|
-
}
|
|
330
|
-
|
|
331
|
-
function idToTitle(id) {
|
|
332
|
-
let result = [];
|
|
333
|
-
for (const c of id){
|
|
334
|
-
if (result.length === 0) result.push(c.toLocaleUpperCase());
|
|
335
|
-
else if (c === '.') result = [];
|
|
336
|
-
else if (/^[A-Z]$/.test(c) && result.at(-1) !== ' ') result.push(' ', c);
|
|
337
|
-
else if (c === '-') result.push(' ');
|
|
338
|
-
else result.push(c);
|
|
339
|
-
}
|
|
340
|
-
return result.join('');
|
|
341
|
-
}
|
|
342
|
-
|
|
343
|
-
const processor = remark().use(remarkGfm).use(remarkImage, {
|
|
344
|
-
useImport: false
|
|
345
|
-
}).use(remarkRehype).use(rehypeCode, {
|
|
346
|
-
langs: [],
|
|
347
|
-
lazy: true
|
|
348
|
-
});
|
|
349
|
-
async function Markdown({ text }) {
|
|
350
|
-
const nodes = processor.parse({
|
|
351
|
-
value: text
|
|
352
|
-
});
|
|
353
|
-
const hast = await processor.run(nodes);
|
|
354
|
-
return toJsxRuntime(hast, {
|
|
355
|
-
development: false,
|
|
356
|
-
jsx: jsx,
|
|
357
|
-
jsxs: jsxs,
|
|
358
|
-
Fragment,
|
|
359
|
-
components: defaultMdxComponents
|
|
360
|
-
});
|
|
361
|
-
}
|
|
362
|
-
|
|
363
|
-
function heading(depth, child, ctx) {
|
|
364
|
-
const id = ctx.slugger.slug(child);
|
|
365
|
-
return /*#__PURE__*/ jsx(Heading, {
|
|
366
|
-
id: id,
|
|
367
|
-
as: `h${depth.toString()}`,
|
|
368
|
-
children: child.trim()
|
|
369
|
-
}, id);
|
|
370
|
-
}
|
|
371
|
-
|
|
372
|
-
/**
|
|
373
|
-
* Combine multiple object schemas into one
|
|
374
|
-
*/ function combineSchema(schema) {
|
|
375
|
-
const result = {
|
|
376
|
-
type: undefined
|
|
377
|
-
};
|
|
378
|
-
function add(s) {
|
|
379
|
-
if (s.type) {
|
|
380
|
-
var _result;
|
|
381
|
-
(_result = result).type ?? (_result.type = []);
|
|
382
|
-
if (!Array.isArray(result.type)) {
|
|
383
|
-
result.type = [
|
|
384
|
-
result.type
|
|
385
|
-
];
|
|
386
|
-
}
|
|
387
|
-
for (const v of Array.isArray(s.type) ? s.type : [
|
|
388
|
-
s.type
|
|
389
|
-
]){
|
|
390
|
-
if (!result.type.includes(v)) {
|
|
391
|
-
result.type.push(v);
|
|
392
|
-
}
|
|
393
|
-
}
|
|
394
|
-
}
|
|
395
|
-
if (s.properties) {
|
|
396
|
-
var _result1;
|
|
397
|
-
(_result1 = result).properties ?? (_result1.properties = {});
|
|
398
|
-
Object.assign(result.properties, s.properties);
|
|
399
|
-
}
|
|
400
|
-
if (s.additionalProperties === true) {
|
|
401
|
-
result.additionalProperties = true;
|
|
402
|
-
} else if (s.additionalProperties && typeof result.additionalProperties !== 'boolean') {
|
|
403
|
-
var _result2;
|
|
404
|
-
(_result2 = result).additionalProperties ?? (_result2.additionalProperties = {});
|
|
405
|
-
Object.assign(result.additionalProperties, s.additionalProperties);
|
|
406
|
-
}
|
|
407
|
-
if (s.required) {
|
|
408
|
-
var _result3;
|
|
409
|
-
(_result3 = result).required ?? (_result3.required = []);
|
|
410
|
-
result.required.push(...s.required);
|
|
411
|
-
}
|
|
412
|
-
if (s.enum && s.enum.length > 0) {
|
|
413
|
-
var _result4;
|
|
414
|
-
(_result4 = result).enum ?? (_result4.enum = []);
|
|
415
|
-
result.enum.push(...s.enum);
|
|
416
|
-
}
|
|
417
|
-
if (s.allOf) {
|
|
418
|
-
s.allOf.forEach(add);
|
|
419
|
-
}
|
|
420
|
-
}
|
|
421
|
-
schema.forEach(add);
|
|
422
|
-
return result;
|
|
423
|
-
}
|
|
424
|
-
|
|
425
|
-
const keys$1 = {
|
|
426
|
-
default: 'Default',
|
|
427
|
-
minimum: 'Minimum',
|
|
428
|
-
maximum: 'Maximum',
|
|
429
|
-
minLength: 'Minimum length',
|
|
430
|
-
maxLength: 'Maximum length',
|
|
431
|
-
pattern: 'Pattern',
|
|
432
|
-
format: 'Format'
|
|
433
|
-
};
|
|
434
|
-
function isObject(schema) {
|
|
435
|
-
return schema.type === 'object' || schema.properties !== undefined || schema.additionalProperties !== undefined;
|
|
436
|
-
}
|
|
437
|
-
function Schema({ name, schema, ctx }) {
|
|
438
|
-
if (schema.readOnly === true && !ctx.readOnly || schema.writeOnly === true && !ctx.writeOnly) return null;
|
|
439
|
-
const parseObject = ctx.parseObject ?? true;
|
|
440
|
-
const stack = ctx.stack ?? [];
|
|
441
|
-
const { renderer } = ctx.render;
|
|
442
|
-
// object type
|
|
443
|
-
if (isObject(schema) && parseObject && (schema.additionalProperties || schema.properties)) {
|
|
444
|
-
let body = null;
|
|
445
|
-
let footer = null;
|
|
446
|
-
const { additionalProperties, properties } = schema;
|
|
447
|
-
if (additionalProperties === true) {
|
|
448
|
-
footer = /*#__PURE__*/ jsx(renderer.Property, {
|
|
449
|
-
name: "[key: string]",
|
|
450
|
-
type: "any"
|
|
451
|
-
});
|
|
452
|
-
} else if (additionalProperties) {
|
|
453
|
-
footer = /*#__PURE__*/ jsx(Schema, {
|
|
454
|
-
name: "[key: string]",
|
|
455
|
-
schema: additionalProperties,
|
|
456
|
-
ctx: {
|
|
457
|
-
...ctx,
|
|
458
|
-
required: false,
|
|
459
|
-
parseObject: false
|
|
460
|
-
}
|
|
461
|
-
});
|
|
462
|
-
}
|
|
463
|
-
if (properties) {
|
|
464
|
-
body = Object.entries(properties).map(([key, value])=>{
|
|
465
|
-
return /*#__PURE__*/ jsx(Schema, {
|
|
466
|
-
name: key,
|
|
467
|
-
schema: value,
|
|
468
|
-
ctx: {
|
|
469
|
-
...ctx,
|
|
470
|
-
required: schema.required?.includes(key) ?? false,
|
|
471
|
-
parseObject: false
|
|
472
|
-
}
|
|
473
|
-
}, key);
|
|
474
|
-
});
|
|
475
|
-
}
|
|
476
|
-
return /*#__PURE__*/ jsxs("div", {
|
|
477
|
-
className: "flex flex-col gap-4",
|
|
478
|
-
children: [
|
|
479
|
-
body,
|
|
480
|
-
footer
|
|
481
|
-
]
|
|
482
|
-
});
|
|
483
|
-
}
|
|
484
|
-
if (schema.allOf && parseObject) {
|
|
485
|
-
return /*#__PURE__*/ jsx(Schema, {
|
|
486
|
-
name: name,
|
|
487
|
-
schema: combineSchema(schema.allOf),
|
|
488
|
-
ctx: ctx
|
|
489
|
-
});
|
|
490
|
-
}
|
|
491
|
-
let footer = null;
|
|
492
|
-
const fields = [];
|
|
493
|
-
for (const [key, value] of Object.entries(keys$1)){
|
|
494
|
-
if (key in schema) {
|
|
495
|
-
fields.push({
|
|
496
|
-
key: value,
|
|
497
|
-
value: JSON.stringify(schema[key])
|
|
498
|
-
});
|
|
499
|
-
}
|
|
500
|
-
}
|
|
501
|
-
if (schema.enum) {
|
|
502
|
-
fields.push({
|
|
503
|
-
key: 'Value in',
|
|
504
|
-
value: schema.enum.map((value)=>JSON.stringify(value)).join(' | ')
|
|
505
|
-
});
|
|
506
|
-
}
|
|
507
|
-
if (isObject(schema) && !parseObject && !stack.includes(schema)) {
|
|
508
|
-
footer = /*#__PURE__*/ jsx(renderer.ObjectCollapsible, {
|
|
509
|
-
name: "Show Attributes",
|
|
510
|
-
children: /*#__PURE__*/ jsx(Schema, {
|
|
511
|
-
name: name,
|
|
512
|
-
schema: schema,
|
|
513
|
-
ctx: {
|
|
514
|
-
...ctx,
|
|
515
|
-
parseObject: true,
|
|
516
|
-
required: false,
|
|
517
|
-
stack: [
|
|
518
|
-
schema,
|
|
519
|
-
...stack
|
|
520
|
-
]
|
|
521
|
-
}
|
|
522
|
-
})
|
|
523
|
-
});
|
|
524
|
-
} else {
|
|
525
|
-
const mentionedObjectTypes = [
|
|
526
|
-
...schema.anyOf ?? schema.oneOf ?? [],
|
|
527
|
-
...schema.not ? [
|
|
528
|
-
schema.not
|
|
529
|
-
] : [],
|
|
530
|
-
...schema.type === 'array' ? [
|
|
531
|
-
schema.items
|
|
532
|
-
] : []
|
|
533
|
-
].filter((s)=>isComplexType(s) && !stack.includes(s));
|
|
534
|
-
footer = mentionedObjectTypes.map((s, idx)=>{
|
|
535
|
-
return /*#__PURE__*/ jsx(renderer.ObjectCollapsible, {
|
|
536
|
-
name: s.title ?? (mentionedObjectTypes.length === 1 ? 'Show Attributes' : `Object ${idx + 1}`),
|
|
537
|
-
children: /*#__PURE__*/ jsx(Schema, {
|
|
538
|
-
name: "element",
|
|
539
|
-
schema: s,
|
|
540
|
-
ctx: {
|
|
541
|
-
...ctx,
|
|
542
|
-
stack: [
|
|
543
|
-
schema,
|
|
544
|
-
...stack
|
|
545
|
-
],
|
|
546
|
-
parseObject: true,
|
|
547
|
-
required: false
|
|
548
|
-
}
|
|
549
|
-
})
|
|
550
|
-
}, idx);
|
|
551
|
-
});
|
|
552
|
-
}
|
|
553
|
-
return /*#__PURE__*/ jsxs(renderer.Property, {
|
|
554
|
-
name: name,
|
|
555
|
-
type: getSchemaType(schema, ctx),
|
|
556
|
-
required: ctx.required,
|
|
557
|
-
deprecated: schema.deprecated,
|
|
558
|
-
children: [
|
|
559
|
-
schema.description ? /*#__PURE__*/ jsx(Markdown, {
|
|
560
|
-
text: schema.description
|
|
561
|
-
}) : null,
|
|
562
|
-
fields.length > 0 ? /*#__PURE__*/ jsx("div", {
|
|
563
|
-
className: "flex flex-col gap-2",
|
|
564
|
-
children: fields.map((field)=>/*#__PURE__*/ jsxs("span", {
|
|
565
|
-
children: [
|
|
566
|
-
field.key,
|
|
567
|
-
": ",
|
|
568
|
-
/*#__PURE__*/ jsx("code", {
|
|
569
|
-
children: field.value
|
|
570
|
-
})
|
|
571
|
-
]
|
|
572
|
-
}, field.key))
|
|
573
|
-
}) : null,
|
|
574
|
-
footer
|
|
575
|
-
]
|
|
576
|
-
});
|
|
577
|
-
}
|
|
578
|
-
/**
|
|
579
|
-
* Check if the schema needs another collapsible to explain
|
|
580
|
-
*/ function isComplexType(schema) {
|
|
581
|
-
if (schema.anyOf ?? schema.oneOf ?? schema.allOf) return true;
|
|
582
|
-
return isObject(schema) || schema.type === 'array';
|
|
583
|
-
}
|
|
584
|
-
function getSchemaType(schema, ctx, isRoot = true) {
|
|
585
|
-
if (isNullable(schema) && isRoot) {
|
|
586
|
-
const type = getSchemaType(schema, ctx, false);
|
|
587
|
-
// null if schema only contains `nullable`
|
|
588
|
-
return type === 'unknown' ? 'null' : `${type} | null`;
|
|
589
|
-
}
|
|
590
|
-
if (schema.title) return schema.title;
|
|
591
|
-
if (schema.type === 'array') return `array<${getSchemaType(schema.items, ctx)}>`;
|
|
592
|
-
if (schema.oneOf) return schema.oneOf.map((one)=>getSchemaType(one, ctx, false)).filter((v)=>v !== 'unknown').join(' | ');
|
|
593
|
-
if (schema.allOf) {
|
|
594
|
-
return schema.allOf.map((one)=>getSchemaType(one, ctx, false)).filter((v)=>v !== 'unknown').join(' & ');
|
|
595
|
-
}
|
|
596
|
-
if (schema.not) return `not ${getSchemaType(schema.not, ctx, false)}`;
|
|
597
|
-
if (schema.anyOf) {
|
|
598
|
-
return `Any properties in ${schema.anyOf.map((one)=>getSchemaType(one, ctx, false)).filter((v)=>v !== 'unknown').join(', ')}`;
|
|
599
|
-
}
|
|
600
|
-
if (schema.type === 'string' && schema.format === 'binary' && ctx.allowFile) return 'file';
|
|
601
|
-
if (schema.type && Array.isArray(schema.type)) {
|
|
602
|
-
const nonNullTypes = schema.type.filter((v)=>v !== 'null');
|
|
603
|
-
if (nonNullTypes.length > 0) return nonNullTypes.join(' | ');
|
|
604
|
-
} else if (schema.type && schema.type !== 'null') {
|
|
605
|
-
return schema.type;
|
|
606
|
-
}
|
|
607
|
-
if (isObject(schema)) return 'object';
|
|
608
|
-
return 'unknown';
|
|
609
|
-
}
|
|
610
|
-
|
|
611
|
-
/**
|
|
612
|
-
* Summarize method endpoint information
|
|
613
|
-
*/ function createMethod(method, path, operation) {
|
|
614
|
-
return {
|
|
615
|
-
description: path.description,
|
|
616
|
-
summary: path.summary,
|
|
617
|
-
...operation,
|
|
618
|
-
parameters: [
|
|
619
|
-
...operation.parameters ?? [],
|
|
620
|
-
...path.parameters ?? []
|
|
621
|
-
],
|
|
622
|
-
method: method.toUpperCase()
|
|
623
|
-
};
|
|
624
|
-
}
|
|
625
|
-
|
|
626
|
-
const methodKeys = [
|
|
627
|
-
'get',
|
|
628
|
-
'post',
|
|
629
|
-
'patch',
|
|
630
|
-
'delete',
|
|
631
|
-
'head',
|
|
632
|
-
'put'
|
|
633
|
-
];
|
|
634
|
-
|
|
635
|
-
function Operation({ type = 'operation', path, method, ctx, hasHead, headingLevel = 2 }) {
|
|
636
|
-
const body = method.requestBody;
|
|
637
|
-
const security = method.security ?? ctx.schema.document.security;
|
|
638
|
-
let headNode = null;
|
|
639
|
-
let bodyNode = null;
|
|
640
|
-
let responseNode = null;
|
|
641
|
-
let callbacksNode = null;
|
|
642
|
-
if (hasHead) {
|
|
643
|
-
const title = method.summary ?? (method.operationId ? idToTitle(method.operationId) : path);
|
|
644
|
-
headNode = /*#__PURE__*/ jsxs(Fragment, {
|
|
645
|
-
children: [
|
|
646
|
-
heading(headingLevel, title, ctx),
|
|
647
|
-
method.description ? /*#__PURE__*/ jsx(Markdown, {
|
|
648
|
-
text: method.description
|
|
649
|
-
}, "description") : null
|
|
650
|
-
]
|
|
651
|
-
});
|
|
652
|
-
headingLevel++;
|
|
653
|
-
}
|
|
654
|
-
if (body) {
|
|
655
|
-
const type = getPreferredType(body.content);
|
|
656
|
-
if (!type) throw new Error(`No supported media type for body content: ${path}`);
|
|
657
|
-
bodyNode = /*#__PURE__*/ jsxs(Fragment, {
|
|
658
|
-
children: [
|
|
659
|
-
heading(headingLevel, 'Request Body', ctx),
|
|
660
|
-
/*#__PURE__*/ jsxs("div", {
|
|
661
|
-
className: "mb-8 flex flex-row items-center justify-between gap-2",
|
|
662
|
-
children: [
|
|
663
|
-
/*#__PURE__*/ jsx("code", {
|
|
664
|
-
children: type
|
|
665
|
-
}),
|
|
666
|
-
/*#__PURE__*/ jsx("span", {
|
|
667
|
-
children: body.required ? 'Required' : 'Optional'
|
|
668
|
-
})
|
|
669
|
-
]
|
|
670
|
-
}),
|
|
671
|
-
body.description ? /*#__PURE__*/ jsx(Markdown, {
|
|
672
|
-
text: body.description
|
|
673
|
-
}) : null,
|
|
674
|
-
/*#__PURE__*/ jsx(Schema, {
|
|
675
|
-
name: "body",
|
|
676
|
-
schema: body.content[type].schema ?? {},
|
|
677
|
-
ctx: {
|
|
678
|
-
readOnly: method.method === 'GET',
|
|
679
|
-
writeOnly: method.method !== 'GET',
|
|
680
|
-
required: body.required ?? false,
|
|
681
|
-
render: ctx,
|
|
682
|
-
allowFile: type === 'multipart/form-data'
|
|
683
|
-
}
|
|
684
|
-
})
|
|
685
|
-
]
|
|
686
|
-
});
|
|
687
|
-
}
|
|
688
|
-
if (method.responses && ctx.showResponseSchema) {
|
|
689
|
-
responseNode = /*#__PURE__*/ jsxs(Fragment, {
|
|
690
|
-
children: [
|
|
691
|
-
heading(headingLevel, 'Response Body', ctx),
|
|
692
|
-
Object.entries(method.responses).map(([status, response])=>{
|
|
693
|
-
if (!response.content) return;
|
|
694
|
-
const mediaType = getPreferredType(response.content);
|
|
695
|
-
if (!mediaType) return null;
|
|
696
|
-
const content = response.content[mediaType];
|
|
697
|
-
if (!content.schema) return null;
|
|
698
|
-
return /*#__PURE__*/ jsxs(Fragment$1, {
|
|
699
|
-
children: [
|
|
700
|
-
heading(headingLevel + 1, status, ctx),
|
|
701
|
-
/*#__PURE__*/ jsx(Markdown, {
|
|
702
|
-
text: response.description
|
|
703
|
-
}),
|
|
704
|
-
/*#__PURE__*/ jsx(Schema, {
|
|
705
|
-
name: "response",
|
|
706
|
-
schema: content.schema,
|
|
707
|
-
ctx: {
|
|
708
|
-
render: ctx,
|
|
709
|
-
writeOnly: false,
|
|
710
|
-
readOnly: true,
|
|
711
|
-
required: true
|
|
712
|
-
}
|
|
713
|
-
})
|
|
714
|
-
]
|
|
715
|
-
}, status);
|
|
716
|
-
})
|
|
717
|
-
]
|
|
718
|
-
});
|
|
719
|
-
}
|
|
720
|
-
const parameterGroups = new Map();
|
|
721
|
-
const endpoint = generateSample(path, method, ctx);
|
|
722
|
-
for (const param of method.parameters ?? []){
|
|
723
|
-
const pInfo = endpoint.parameters.find((item)=>item.name === param.name && item.in === param.in);
|
|
724
|
-
if (!pInfo) continue;
|
|
725
|
-
const schema = pInfo.schema;
|
|
726
|
-
const groupName = {
|
|
727
|
-
path: 'Path Parameters',
|
|
728
|
-
query: 'Query Parameters',
|
|
729
|
-
header: 'Header Parameters',
|
|
730
|
-
cookie: 'Cookie Parameters'
|
|
731
|
-
}[param.in] ?? 'Other Parameters';
|
|
732
|
-
const group = parameterGroups.get(groupName) ?? [];
|
|
733
|
-
group.push(/*#__PURE__*/ jsx(Schema, {
|
|
734
|
-
name: param.name,
|
|
735
|
-
schema: {
|
|
736
|
-
...schema,
|
|
737
|
-
description: param.description ?? schema.description,
|
|
738
|
-
deprecated: (param.deprecated ?? false) || (schema.deprecated ?? false)
|
|
739
|
-
},
|
|
740
|
-
ctx: {
|
|
741
|
-
parseObject: false,
|
|
742
|
-
readOnly: method.method === 'GET',
|
|
743
|
-
writeOnly: method.method !== 'GET',
|
|
744
|
-
required: param.required ?? false,
|
|
745
|
-
render: ctx
|
|
746
|
-
}
|
|
747
|
-
}, param.name));
|
|
748
|
-
parameterGroups.set(groupName, group);
|
|
749
|
-
}
|
|
750
|
-
if (method.callbacks) {
|
|
751
|
-
callbacksNode = /*#__PURE__*/ jsxs(Fragment, {
|
|
752
|
-
children: [
|
|
753
|
-
heading(headingLevel, 'Webhooks', ctx),
|
|
754
|
-
Object.entries(method.callbacks).map(([name, callback])=>/*#__PURE__*/ jsx(WebhookCallback, {
|
|
755
|
-
callback: callback,
|
|
756
|
-
ctx: ctx,
|
|
757
|
-
headingLevel: headingLevel
|
|
758
|
-
}, name))
|
|
759
|
-
]
|
|
760
|
-
});
|
|
761
|
-
}
|
|
762
|
-
const info = /*#__PURE__*/ jsxs(ctx.renderer.APIInfo, {
|
|
763
|
-
head: headNode,
|
|
764
|
-
method: method.method,
|
|
765
|
-
route: path,
|
|
766
|
-
children: [
|
|
767
|
-
type === 'operation' ? /*#__PURE__*/ jsx(ctx.renderer.APIPlayground, {
|
|
768
|
-
path: path,
|
|
769
|
-
method: method,
|
|
770
|
-
ctx: ctx
|
|
771
|
-
}) : null,
|
|
772
|
-
security ? /*#__PURE__*/ jsxs(Fragment, {
|
|
773
|
-
children: [
|
|
774
|
-
heading(headingLevel, 'Authorization', ctx),
|
|
775
|
-
/*#__PURE__*/ jsx(AuthSection, {
|
|
776
|
-
requirements: security,
|
|
777
|
-
ctx: ctx
|
|
778
|
-
})
|
|
779
|
-
]
|
|
780
|
-
}) : null,
|
|
781
|
-
bodyNode,
|
|
782
|
-
Array.from(parameterGroups.entries()).map(([group, params])=>{
|
|
783
|
-
return /*#__PURE__*/ jsxs(Fragment$1, {
|
|
784
|
-
children: [
|
|
785
|
-
heading(headingLevel, group, ctx),
|
|
786
|
-
params
|
|
787
|
-
]
|
|
788
|
-
}, group);
|
|
789
|
-
}),
|
|
790
|
-
responseNode,
|
|
791
|
-
callbacksNode
|
|
792
|
-
]
|
|
793
|
-
});
|
|
794
|
-
if (type === 'operation') {
|
|
795
|
-
return /*#__PURE__*/ jsxs(ctx.renderer.API, {
|
|
796
|
-
children: [
|
|
797
|
-
info,
|
|
798
|
-
/*#__PURE__*/ jsx(APIExample, {
|
|
799
|
-
method: method,
|
|
800
|
-
endpoint: endpoint,
|
|
801
|
-
ctx: ctx
|
|
802
|
-
})
|
|
803
|
-
]
|
|
804
|
-
});
|
|
805
|
-
} else {
|
|
806
|
-
return info;
|
|
807
|
-
}
|
|
808
|
-
}
|
|
809
|
-
const defaultSamples = [
|
|
810
|
-
{
|
|
811
|
-
label: 'cURL',
|
|
812
|
-
source: getSampleRequest$3,
|
|
813
|
-
lang: 'bash'
|
|
814
|
-
},
|
|
815
|
-
{
|
|
816
|
-
label: 'JavaScript',
|
|
817
|
-
source: getSampleRequest$2,
|
|
818
|
-
lang: 'js'
|
|
819
|
-
},
|
|
820
|
-
{
|
|
821
|
-
label: 'Go',
|
|
822
|
-
source: getSampleRequest$1,
|
|
823
|
-
lang: 'go'
|
|
824
|
-
},
|
|
825
|
-
{
|
|
826
|
-
label: 'Python',
|
|
827
|
-
source: getSampleRequest,
|
|
828
|
-
lang: 'python'
|
|
829
|
-
}
|
|
830
|
-
];
|
|
831
|
-
async function APIExample({ method, endpoint, ctx }) {
|
|
832
|
-
const renderer = ctx.renderer;
|
|
833
|
-
const children = [];
|
|
834
|
-
const samples = dedupe([
|
|
835
|
-
...defaultSamples,
|
|
836
|
-
...ctx.generateCodeSamples ? await ctx.generateCodeSamples(endpoint) : [],
|
|
837
|
-
...method['x-codeSamples'] ?? []
|
|
838
|
-
]).flatMap((sample)=>{
|
|
839
|
-
if (sample.source === false) return [];
|
|
840
|
-
const result = typeof sample.source === 'function' ? sample.source(endpoint) : sample.source;
|
|
841
|
-
if (result === undefined) return [];
|
|
842
|
-
return {
|
|
843
|
-
...sample,
|
|
844
|
-
source: result
|
|
845
|
-
};
|
|
846
|
-
});
|
|
847
|
-
if (samples.length > 0) {
|
|
848
|
-
children.push(/*#__PURE__*/ jsx(renderer.Requests, {
|
|
849
|
-
items: samples.map((s)=>s.label),
|
|
850
|
-
children: samples.map((s)=>/*#__PURE__*/ jsx(renderer.Request, {
|
|
851
|
-
name: s.label,
|
|
852
|
-
code: s.source,
|
|
853
|
-
language: s.lang
|
|
854
|
-
}, s.label))
|
|
855
|
-
}, "requests"));
|
|
856
|
-
}
|
|
857
|
-
children.push(/*#__PURE__*/ jsx(ResponseTabs, {
|
|
858
|
-
operation: method,
|
|
859
|
-
ctx: ctx,
|
|
860
|
-
endpoint: endpoint
|
|
861
|
-
}, "responses"));
|
|
862
|
-
return /*#__PURE__*/ jsx(renderer.APIExample, {
|
|
863
|
-
children: children
|
|
864
|
-
});
|
|
865
|
-
}
|
|
866
|
-
function WebhookCallback({ callback, ctx, headingLevel }) {
|
|
867
|
-
return Object.entries(callback).map(([path, pathItem])=>{
|
|
868
|
-
const pathNodes = methodKeys.map((method)=>{
|
|
869
|
-
const operation = pathItem[method];
|
|
870
|
-
if (!operation) return null;
|
|
871
|
-
return /*#__PURE__*/ jsx(Operation, {
|
|
872
|
-
type: "webhook",
|
|
873
|
-
hasHead: true,
|
|
874
|
-
path: path,
|
|
875
|
-
headingLevel: headingLevel + 1,
|
|
876
|
-
method: createMethod(method, pathItem, operation),
|
|
877
|
-
ctx: ctx
|
|
878
|
-
}, method);
|
|
879
|
-
});
|
|
880
|
-
return /*#__PURE__*/ jsx(Fragment$1, {
|
|
881
|
-
children: pathNodes
|
|
882
|
-
}, path);
|
|
883
|
-
});
|
|
884
|
-
}
|
|
885
|
-
/**
|
|
886
|
-
* Remove duplicated labels
|
|
887
|
-
*/ function dedupe(samples) {
|
|
888
|
-
const set = new Set();
|
|
889
|
-
const out = [];
|
|
890
|
-
for(let i = samples.length - 1; i >= 0; i--){
|
|
891
|
-
if (set.has(samples[i].label)) continue;
|
|
892
|
-
set.add(samples[i].label);
|
|
893
|
-
out.unshift(samples[i]);
|
|
894
|
-
}
|
|
895
|
-
return out;
|
|
896
|
-
}
|
|
897
|
-
function AuthSection({ ctx: { schema: { document }, renderer }, requirements }) {
|
|
898
|
-
let id = 0;
|
|
899
|
-
const info = [];
|
|
900
|
-
for (const requirement of requirements){
|
|
901
|
-
for (const schema of getSecurities(requirement, document)){
|
|
902
|
-
const prefix = getSecurityPrefix(schema);
|
|
903
|
-
const scopeElement = schema.scopes.length > 0 ? /*#__PURE__*/ jsxs("p", {
|
|
904
|
-
children: [
|
|
905
|
-
"Scope: ",
|
|
906
|
-
/*#__PURE__*/ jsx("code", {
|
|
907
|
-
children: schema.scopes.join(', ')
|
|
908
|
-
})
|
|
909
|
-
]
|
|
910
|
-
}) : null;
|
|
911
|
-
if (schema.type === 'http' || schema.type === 'oauth2') {
|
|
912
|
-
info.push(/*#__PURE__*/ jsxs(renderer.Property, {
|
|
913
|
-
name: "Authorization",
|
|
914
|
-
type: prefix ? `${prefix} <token>` : '<token>',
|
|
915
|
-
required: true,
|
|
916
|
-
children: [
|
|
917
|
-
schema.description ? /*#__PURE__*/ jsx(Markdown, {
|
|
918
|
-
text: schema.description
|
|
919
|
-
}) : null,
|
|
920
|
-
/*#__PURE__*/ jsxs("p", {
|
|
921
|
-
children: [
|
|
922
|
-
"In: ",
|
|
923
|
-
/*#__PURE__*/ jsx("code", {
|
|
924
|
-
children: "header"
|
|
925
|
-
})
|
|
926
|
-
]
|
|
927
|
-
}),
|
|
928
|
-
scopeElement
|
|
929
|
-
]
|
|
930
|
-
}, id++));
|
|
931
|
-
}
|
|
932
|
-
if (schema.type === 'apiKey') {
|
|
933
|
-
info.push(/*#__PURE__*/ jsxs(renderer.Property, {
|
|
934
|
-
name: schema.name,
|
|
935
|
-
type: "<token>",
|
|
936
|
-
children: [
|
|
937
|
-
schema.description ? /*#__PURE__*/ jsx(Markdown, {
|
|
938
|
-
text: schema.description
|
|
939
|
-
}) : null,
|
|
940
|
-
/*#__PURE__*/ jsxs("p", {
|
|
941
|
-
children: [
|
|
942
|
-
"In: ",
|
|
943
|
-
/*#__PURE__*/ jsx("code", {
|
|
944
|
-
children: schema.in
|
|
945
|
-
}),
|
|
946
|
-
scopeElement
|
|
947
|
-
]
|
|
948
|
-
})
|
|
949
|
-
]
|
|
950
|
-
}, id++));
|
|
951
|
-
}
|
|
952
|
-
if (schema.type === 'openIdConnect') {
|
|
953
|
-
info.push(/*#__PURE__*/ jsxs(renderer.Property, {
|
|
954
|
-
name: "OpenID Connect",
|
|
955
|
-
type: "<token>",
|
|
956
|
-
required: true,
|
|
957
|
-
children: [
|
|
958
|
-
schema.description ? /*#__PURE__*/ jsx(Markdown, {
|
|
959
|
-
text: schema.description
|
|
960
|
-
}) : null,
|
|
961
|
-
scopeElement
|
|
962
|
-
]
|
|
963
|
-
}, id++));
|
|
964
|
-
}
|
|
965
|
-
}
|
|
966
|
-
}
|
|
967
|
-
return info;
|
|
968
|
-
}
|
|
969
|
-
async function ResponseTabs({ endpoint, operation, ctx: { renderer, generateTypeScriptSchema, schema } }) {
|
|
970
|
-
const items = [];
|
|
971
|
-
const children = [];
|
|
972
|
-
if (!operation.responses) return null;
|
|
973
|
-
for (const code of Object.keys(operation.responses)){
|
|
974
|
-
const types = [];
|
|
975
|
-
let description = operation.responses[code].description;
|
|
976
|
-
if (!description && code in endpoint.responses) description = endpoint.responses[code].schema.description ?? '';
|
|
977
|
-
if (code in endpoint.responses) {
|
|
978
|
-
types.push({
|
|
979
|
-
lang: 'json',
|
|
980
|
-
label: 'Response',
|
|
981
|
-
code: JSON.stringify(endpoint.responses[code].sample, null, 2)
|
|
982
|
-
});
|
|
983
|
-
}
|
|
984
|
-
let ts;
|
|
985
|
-
if (generateTypeScriptSchema) {
|
|
986
|
-
ts = await generateTypeScriptSchema(endpoint, code);
|
|
987
|
-
} else if (generateTypeScriptSchema === undefined) {
|
|
988
|
-
ts = await getTypescriptSchema(endpoint, code, schema.dereferenceMap);
|
|
989
|
-
}
|
|
990
|
-
if (ts) {
|
|
991
|
-
types.push({
|
|
992
|
-
code: ts,
|
|
993
|
-
lang: 'ts',
|
|
994
|
-
label: 'TypeScript'
|
|
995
|
-
});
|
|
996
|
-
}
|
|
997
|
-
items.push(code);
|
|
998
|
-
children.push(/*#__PURE__*/ jsxs(renderer.Response, {
|
|
999
|
-
value: code,
|
|
1000
|
-
children: [
|
|
1001
|
-
/*#__PURE__*/ jsx(Markdown, {
|
|
1002
|
-
text: description
|
|
1003
|
-
}),
|
|
1004
|
-
types.length > 0 ? /*#__PURE__*/ jsx(renderer.ResponseTypes, {
|
|
1005
|
-
children: types.map((type)=>/*#__PURE__*/ jsx(renderer.ResponseType, {
|
|
1006
|
-
...type
|
|
1007
|
-
}, type.lang))
|
|
1008
|
-
}) : null
|
|
1009
|
-
]
|
|
1010
|
-
}, code));
|
|
1011
|
-
}
|
|
1012
|
-
if (items.length === 0) return null;
|
|
1013
|
-
return /*#__PURE__*/ jsx(renderer.Responses, {
|
|
1014
|
-
items: items,
|
|
1015
|
-
children: children
|
|
1016
|
-
});
|
|
1017
|
-
}
|
|
1018
|
-
|
|
1019
|
-
async function CodeBlock({ code, lang, options, ...rest }) {
|
|
1020
|
-
const rendered = await highlight(code, {
|
|
1021
|
-
lang,
|
|
1022
|
-
...options,
|
|
1023
|
-
components: {
|
|
1024
|
-
pre: (props)=>/*#__PURE__*/ jsx(Base.Pre, {
|
|
1025
|
-
...props,
|
|
1026
|
-
...rest
|
|
1027
|
-
})
|
|
1028
|
-
}
|
|
1029
|
-
});
|
|
1030
|
-
return /*#__PURE__*/ jsx(Base.CodeBlock, {
|
|
1031
|
-
className: "my-0",
|
|
1032
|
-
children: rendered
|
|
1033
|
-
});
|
|
1034
|
-
}
|
|
1035
|
-
|
|
1036
|
-
function Playground({ path, method, ctx }) {
|
|
1037
|
-
let currentId = 0;
|
|
1038
|
-
const bodyContent = method.requestBody?.content;
|
|
1039
|
-
const mediaType = bodyContent ? getPreferredType(bodyContent) : undefined;
|
|
1040
|
-
const context = {
|
|
1041
|
-
allowFile: mediaType === 'multipart/form-data',
|
|
1042
|
-
references: {},
|
|
1043
|
-
nextId () {
|
|
1044
|
-
return String(currentId++);
|
|
1045
|
-
},
|
|
1046
|
-
registered: new WeakMap(),
|
|
1047
|
-
render: ctx
|
|
1048
|
-
};
|
|
1049
|
-
const bodySchema = bodyContent && mediaType && bodyContent[mediaType].schema ? toSchema(bodyContent[mediaType].schema, true, context) : undefined;
|
|
1050
|
-
const props = {
|
|
1051
|
-
authorization: getAuthorizationField(method, ctx),
|
|
1052
|
-
method: method.method,
|
|
1053
|
-
route: path,
|
|
1054
|
-
path: method.parameters?.filter((v)=>v.in === 'path').map((v)=>parameterToField(v, context)),
|
|
1055
|
-
query: method.parameters?.filter((v)=>v.in === 'query').map((v)=>parameterToField(v, context)),
|
|
1056
|
-
header: method.parameters?.filter((v)=>v.in === 'header').map((v)=>parameterToField(v, context)),
|
|
1057
|
-
body: bodySchema && mediaType ? {
|
|
1058
|
-
...bodySchema,
|
|
1059
|
-
mediaType: mediaType
|
|
1060
|
-
} : undefined,
|
|
1061
|
-
schemas: context.references,
|
|
1062
|
-
proxyUrl: ctx.proxyUrl
|
|
1063
|
-
};
|
|
1064
|
-
return /*#__PURE__*/ jsx(APIPlayground, {
|
|
1065
|
-
...props
|
|
1066
|
-
});
|
|
1067
|
-
}
|
|
1068
|
-
function getAuthorizationField(method, { schema: { document } }) {
|
|
1069
|
-
const security = method.security ?? document.security ?? [];
|
|
1070
|
-
if (security.length === 0) return;
|
|
1071
|
-
const singular = security.find((requirements)=>Object.keys(requirements).length === 1);
|
|
1072
|
-
if (!singular) return;
|
|
1073
|
-
return getSecurities(singular, document)[0];
|
|
1074
|
-
}
|
|
1075
|
-
function getIdFromSchema(schema, required, ctx) {
|
|
1076
|
-
const registered = ctx.registered.get(schema);
|
|
1077
|
-
if (registered === undefined) {
|
|
1078
|
-
const id = ctx.nextId();
|
|
1079
|
-
ctx.registered.set(schema, id);
|
|
1080
|
-
ctx.references[id] = toSchema(schema, required, ctx);
|
|
1081
|
-
return id;
|
|
1082
|
-
}
|
|
1083
|
-
return registered;
|
|
1084
|
-
}
|
|
1085
|
-
function parameterToField(v, ctx) {
|
|
1086
|
-
return {
|
|
1087
|
-
name: v.name,
|
|
1088
|
-
...toSchema(v.schema ?? {
|
|
1089
|
-
type: 'string'
|
|
1090
|
-
}, v.required ?? false, ctx)
|
|
1091
|
-
};
|
|
1092
|
-
}
|
|
1093
|
-
function toReference(schema, required, ctx) {
|
|
1094
|
-
return {
|
|
1095
|
-
type: 'ref',
|
|
1096
|
-
isRequired: required,
|
|
1097
|
-
schema: getIdFromSchema(schema, false, ctx)
|
|
1098
|
-
};
|
|
1099
|
-
}
|
|
1100
|
-
function toSchema(schema, required, ctx) {
|
|
1101
|
-
if (schema.type === 'array') {
|
|
1102
|
-
return {
|
|
1103
|
-
type: 'array',
|
|
1104
|
-
description: schema.description ?? schema.title,
|
|
1105
|
-
isRequired: required,
|
|
1106
|
-
items: getIdFromSchema(schema.items, false, ctx)
|
|
1107
|
-
};
|
|
1108
|
-
}
|
|
1109
|
-
if (schema.type === 'object' || schema.properties !== undefined || schema.allOf !== undefined) {
|
|
1110
|
-
const properties = {};
|
|
1111
|
-
Object.entries(schema.properties ?? {}).forEach(([key, prop])=>{
|
|
1112
|
-
properties[key] = toReference(prop, schema.required?.includes(key) ?? false, ctx);
|
|
1113
|
-
});
|
|
1114
|
-
schema.allOf?.forEach((c)=>{
|
|
1115
|
-
const field = toSchema(c, true, ctx);
|
|
1116
|
-
if (field.type === 'object') Object.assign(properties, field.properties);
|
|
1117
|
-
});
|
|
1118
|
-
const additional = schema.additionalProperties;
|
|
1119
|
-
let additionalProperties;
|
|
1120
|
-
if (additional && typeof additional === 'object') {
|
|
1121
|
-
if ((!additional.type || additional.type.length === 0) && !additional.anyOf && !additional.allOf && !additional.oneOf) {
|
|
1122
|
-
additionalProperties = true;
|
|
1123
|
-
} else {
|
|
1124
|
-
additionalProperties = getIdFromSchema(additional, false, ctx);
|
|
1125
|
-
}
|
|
1126
|
-
} else {
|
|
1127
|
-
additionalProperties = additional;
|
|
1128
|
-
}
|
|
1129
|
-
return {
|
|
1130
|
-
type: 'object',
|
|
1131
|
-
isRequired: required,
|
|
1132
|
-
description: schema.description ?? schema.title,
|
|
1133
|
-
properties,
|
|
1134
|
-
additionalProperties
|
|
1135
|
-
};
|
|
1136
|
-
}
|
|
1137
|
-
if (schema.type === undefined) {
|
|
1138
|
-
const combine = schema.anyOf ?? schema.oneOf;
|
|
1139
|
-
if (combine) {
|
|
1140
|
-
return {
|
|
1141
|
-
type: 'switcher',
|
|
1142
|
-
description: schema.description ?? schema.title,
|
|
1143
|
-
items: Object.fromEntries(combine.map((item, idx)=>{
|
|
1144
|
-
return [
|
|
1145
|
-
item.title ?? item.type ?? `Item ${idx.toString()}`,
|
|
1146
|
-
toReference(item, true, ctx)
|
|
1147
|
-
];
|
|
1148
|
-
})),
|
|
1149
|
-
isRequired: required
|
|
1150
|
-
};
|
|
1151
|
-
}
|
|
1152
|
-
return {
|
|
1153
|
-
type: 'null',
|
|
1154
|
-
isRequired: false
|
|
1155
|
-
};
|
|
1156
|
-
}
|
|
1157
|
-
if (ctx.allowFile && schema.type === 'string' && schema.format === 'binary') {
|
|
1158
|
-
return {
|
|
1159
|
-
type: 'file',
|
|
1160
|
-
isRequired: required,
|
|
1161
|
-
description: schema.description ?? schema.title
|
|
1162
|
-
};
|
|
1163
|
-
}
|
|
1164
|
-
if (Array.isArray(schema.type)) {
|
|
1165
|
-
const items = {};
|
|
1166
|
-
for (const type of schema.type){
|
|
1167
|
-
if (type === 'array') {
|
|
1168
|
-
items[type] = {
|
|
1169
|
-
type,
|
|
1170
|
-
items: 'items' in schema && schema.items ? toSchema(schema.items, false, ctx) : toSchema({}, required, ctx),
|
|
1171
|
-
isRequired: required
|
|
1172
|
-
};
|
|
1173
|
-
} else {
|
|
1174
|
-
items[type] = toSchema({
|
|
1175
|
-
...schema,
|
|
1176
|
-
type
|
|
1177
|
-
}, required, ctx);
|
|
1178
|
-
}
|
|
1179
|
-
}
|
|
1180
|
-
return {
|
|
1181
|
-
type: 'switcher',
|
|
1182
|
-
description: schema.description ?? schema.title,
|
|
1183
|
-
items,
|
|
1184
|
-
isRequired: required
|
|
1185
|
-
};
|
|
1186
|
-
}
|
|
1187
|
-
return {
|
|
1188
|
-
type: schema.type === 'integer' ? 'number' : schema.type,
|
|
1189
|
-
defaultValue: schema.example ?? '',
|
|
1190
|
-
isRequired: required,
|
|
1191
|
-
description: schema.description ?? schema.title
|
|
1192
|
-
};
|
|
1193
|
-
}
|
|
1194
|
-
|
|
1195
|
-
function createRenders(shikiOptions) {
|
|
1196
|
-
return {
|
|
1197
|
-
Root: (props)=>/*#__PURE__*/ jsx(Root, {
|
|
1198
|
-
shikiOptions: shikiOptions,
|
|
1199
|
-
...props,
|
|
1200
|
-
children: props.children
|
|
1201
|
-
}),
|
|
1202
|
-
API,
|
|
1203
|
-
APIInfo: ({ children, head })=>/*#__PURE__*/ jsxs(APIInfo, {
|
|
1204
|
-
children: [
|
|
1205
|
-
head,
|
|
1206
|
-
children
|
|
1207
|
-
]
|
|
1208
|
-
}),
|
|
1209
|
-
APIExample: APIExample$1,
|
|
1210
|
-
Responses: Tabs,
|
|
1211
|
-
Response: Tab,
|
|
1212
|
-
ResponseTypes: (props)=>/*#__PURE__*/ jsx(Accordions, {
|
|
1213
|
-
type: "single",
|
|
1214
|
-
className: "!-m-4 border-none pt-2",
|
|
1215
|
-
defaultValue: "Response",
|
|
1216
|
-
children: props.children
|
|
1217
|
-
}),
|
|
1218
|
-
ResponseType: (props)=>/*#__PURE__*/ jsx(Accordion, {
|
|
1219
|
-
title: props.label,
|
|
1220
|
-
children: /*#__PURE__*/ jsx(CodeBlock, {
|
|
1221
|
-
code: props.code,
|
|
1222
|
-
lang: props.lang,
|
|
1223
|
-
options: shikiOptions
|
|
1224
|
-
})
|
|
1225
|
-
}),
|
|
1226
|
-
Property,
|
|
1227
|
-
ObjectCollapsible,
|
|
1228
|
-
Requests: (props)=>/*#__PURE__*/ jsx(Tabs, {
|
|
1229
|
-
groupId: "fumadocs_openapi_requests",
|
|
1230
|
-
...props
|
|
1231
|
-
}),
|
|
1232
|
-
Request: (props)=>/*#__PURE__*/ jsx(Tab, {
|
|
1233
|
-
value: props.name,
|
|
1234
|
-
children: /*#__PURE__*/ jsx(CodeBlock, {
|
|
1235
|
-
lang: props.language,
|
|
1236
|
-
code: props.code,
|
|
1237
|
-
options: shikiOptions
|
|
1238
|
-
})
|
|
1239
|
-
}),
|
|
1240
|
-
APIPlayground: Playground
|
|
1241
|
-
};
|
|
1242
|
-
}
|
|
1243
|
-
|
|
1244
|
-
const cache = new Map();
|
|
1245
|
-
/**
|
|
1246
|
-
* process & reference input document to a Fumadocs OpenAPI compatible format
|
|
1247
|
-
*/ async function processDocument(document, disableCache = false) {
|
|
1248
|
-
const cached = !disableCache && typeof document === 'string' ? cache.get(document) : null;
|
|
1249
|
-
if (cached) return cached;
|
|
1250
|
-
const dereferenceMap = new Map();
|
|
1251
|
-
const loaded = await load(document, {
|
|
1252
|
-
plugins: [
|
|
1253
|
-
readFiles(),
|
|
1254
|
-
fetchUrls()
|
|
1255
|
-
]
|
|
1256
|
-
});
|
|
1257
|
-
// upgrade
|
|
1258
|
-
loaded.specification = upgrade(loaded.specification).specification;
|
|
1259
|
-
const { schema: dereferenced } = await dereference(loaded.filesystem, {
|
|
1260
|
-
onDereference ({ ref, schema }) {
|
|
1261
|
-
dereferenceMap.set(schema, ref);
|
|
1262
|
-
}
|
|
1263
|
-
});
|
|
1264
|
-
const processed = {
|
|
1265
|
-
document: dereferenced,
|
|
1266
|
-
dereferenceMap,
|
|
1267
|
-
downloaded: loaded.specification
|
|
1268
|
-
};
|
|
1269
|
-
if (!disableCache && typeof document === 'string') {
|
|
1270
|
-
cache.set(document, processed);
|
|
1271
|
-
}
|
|
1272
|
-
return processed;
|
|
1273
|
-
}
|
|
1274
|
-
|
|
1275
|
-
function getUrl(url, variables) {
|
|
1276
|
-
let out = url;
|
|
1277
|
-
for (const [key, value] of Object.entries(variables)){
|
|
1278
|
-
out = out.replaceAll(`{${key}}`, value);
|
|
1279
|
-
}
|
|
1280
|
-
return out;
|
|
1281
|
-
}
|
|
1282
|
-
|
|
1283
|
-
async function APIPage(props) {
|
|
1284
|
-
const { operations, hasHead = true, webhooks, disableCache = process.env.NODE_ENV === 'development' } = props;
|
|
1285
|
-
const processed = await processDocument(props.document, disableCache);
|
|
1286
|
-
const ctx = await getContext(processed, props);
|
|
1287
|
-
const { document } = processed;
|
|
1288
|
-
return /*#__PURE__*/ jsxs(ctx.renderer.Root, {
|
|
1289
|
-
baseUrl: ctx.baseUrl,
|
|
1290
|
-
servers: ctx.servers,
|
|
1291
|
-
children: [
|
|
1292
|
-
operations?.map((item)=>{
|
|
1293
|
-
const pathItem = document.paths?.[item.path];
|
|
1294
|
-
if (!pathItem) return null;
|
|
1295
|
-
const operation = pathItem[item.method];
|
|
1296
|
-
if (!operation) return null;
|
|
1297
|
-
const method = createMethod(item.method, pathItem, operation);
|
|
1298
|
-
return /*#__PURE__*/ jsx(Operation, {
|
|
1299
|
-
method: method,
|
|
1300
|
-
path: item.path,
|
|
1301
|
-
ctx: ctx,
|
|
1302
|
-
hasHead: hasHead
|
|
1303
|
-
}, `${item.path}:${item.method}`);
|
|
1304
|
-
}),
|
|
1305
|
-
webhooks?.map((item)=>{
|
|
1306
|
-
const webhook = document.webhooks?.[item.name];
|
|
1307
|
-
if (!webhook) return;
|
|
1308
|
-
const hook = webhook[item.method];
|
|
1309
|
-
if (!hook) return;
|
|
1310
|
-
const method = createMethod(item.method, webhook, hook);
|
|
1311
|
-
return /*#__PURE__*/ jsx(Operation, {
|
|
1312
|
-
type: "webhook",
|
|
1313
|
-
method: method,
|
|
1314
|
-
ctx: {
|
|
1315
|
-
...ctx,
|
|
1316
|
-
baseUrl: 'http://localhost:8080'
|
|
1317
|
-
},
|
|
1318
|
-
path: `/${item.name}`,
|
|
1319
|
-
hasHead: hasHead
|
|
1320
|
-
}, `${item.name}:${item.method}`);
|
|
1321
|
-
})
|
|
1322
|
-
]
|
|
1323
|
-
});
|
|
1324
|
-
}
|
|
1325
|
-
async function getContext(schema, options = {}) {
|
|
1326
|
-
const document = schema.document;
|
|
1327
|
-
const servers = document.servers && document.servers.length > 0 ? document.servers : [
|
|
1328
|
-
{
|
|
1329
|
-
url: 'https://example.com'
|
|
1330
|
-
}
|
|
1331
|
-
];
|
|
1332
|
-
const server = servers[0];
|
|
1333
|
-
return {
|
|
1334
|
-
schema,
|
|
1335
|
-
proxyUrl: options.proxyUrl,
|
|
1336
|
-
showResponseSchema: options.showResponseSchema,
|
|
1337
|
-
renderer: {
|
|
1338
|
-
...createRenders(options.shikiOptions),
|
|
1339
|
-
...options.renderer
|
|
1340
|
-
},
|
|
1341
|
-
shikiOptions: options.shikiOptions,
|
|
1342
|
-
generateTypeScriptSchema: options.generateTypeScriptSchema,
|
|
1343
|
-
generateCodeSamples: options.generateCodeSamples,
|
|
1344
|
-
baseUrl: getUrl(server.url, server.variables ? Object.fromEntries(Object.entries(server.variables).map(([k, v])=>[
|
|
1345
|
-
k,
|
|
1346
|
-
v.default
|
|
1347
|
-
])) : {}),
|
|
1348
|
-
servers,
|
|
1349
|
-
slugger: new Slugger()
|
|
1350
|
-
};
|
|
1351
|
-
}
|
|
1352
|
-
|
|
1353
|
-
const keys = [
|
|
1354
|
-
'GET',
|
|
1355
|
-
'POST',
|
|
1356
|
-
'PUT',
|
|
1357
|
-
'DELETE',
|
|
1358
|
-
'PATCH',
|
|
1359
|
-
'HEAD'
|
|
1360
|
-
];
|
|
1361
|
-
function createProxy(allowedUrls) {
|
|
1362
|
-
const handlers = {};
|
|
1363
|
-
async function handler(req) {
|
|
1364
|
-
const url = req.nextUrl.searchParams.get('url');
|
|
1365
|
-
if (!url) {
|
|
1366
|
-
return Response.json('A `url` query parameter is required for proxy url', {
|
|
1367
|
-
status: 400
|
|
1368
|
-
});
|
|
1369
|
-
}
|
|
1370
|
-
if (allowedUrls && allowedUrls.every((allowedUrl)=>!allowedUrl.startsWith(url))) {
|
|
1371
|
-
return Response.json('The given `url` query parameter is not allowed', {
|
|
1372
|
-
status: 400
|
|
1373
|
-
});
|
|
1374
|
-
}
|
|
1375
|
-
const clonedReq = new Request(url, {
|
|
1376
|
-
...req,
|
|
1377
|
-
cache: 'no-cache',
|
|
1378
|
-
mode: 'cors'
|
|
1379
|
-
});
|
|
1380
|
-
clonedReq.headers.forEach((_value, originalKey)=>{
|
|
1381
|
-
const key = originalKey.toLowerCase();
|
|
1382
|
-
const notAllowed = key === 'origin';
|
|
1383
|
-
if (notAllowed) {
|
|
1384
|
-
clonedReq.headers.delete(originalKey);
|
|
1385
|
-
}
|
|
1386
|
-
});
|
|
1387
|
-
const res = await fetch(clonedReq).catch((e)=>new Error(e.toString()));
|
|
1388
|
-
if (res instanceof Error) {
|
|
1389
|
-
return Response.json(`Failed to proxy request: ${res.message}`, {
|
|
1390
|
-
status: 400
|
|
1391
|
-
});
|
|
1392
|
-
}
|
|
1393
|
-
const headers = new Headers(res.headers);
|
|
1394
|
-
headers.forEach((_value, originalKey)=>{
|
|
1395
|
-
const key = originalKey.toLowerCase();
|
|
1396
|
-
const notAllowed = key.startsWith('access-control-') || key === 'content-encoding';
|
|
1397
|
-
if (notAllowed) {
|
|
1398
|
-
headers.delete(originalKey);
|
|
1399
|
-
}
|
|
1400
|
-
});
|
|
1401
|
-
headers.set('X-Forwarded-Host', res.url);
|
|
1402
|
-
return new Response(res.body, {
|
|
1403
|
-
...res,
|
|
1404
|
-
headers
|
|
1405
|
-
});
|
|
1406
|
-
}
|
|
1407
|
-
for (const key of keys){
|
|
1408
|
-
handlers[key] = handler;
|
|
1409
|
-
}
|
|
1410
|
-
return handlers;
|
|
1411
|
-
}
|
|
1412
|
-
|
|
1413
|
-
function createOpenAPI(options = {}) {
|
|
1414
|
-
return {
|
|
1415
|
-
createProxy,
|
|
1416
|
-
APIPage (props) {
|
|
1417
|
-
return /*#__PURE__*/ jsx(APIPage, {
|
|
1418
|
-
...options,
|
|
1419
|
-
...props
|
|
1420
|
-
});
|
|
1421
|
-
}
|
|
1422
|
-
};
|
|
1423
|
-
}
|
|
1424
|
-
|
|
1425
|
-
cva('rounded-xl border px-1.5 py-1 text-xs font-medium leading-[12px]', {
|
|
1426
|
-
variants: {
|
|
1427
|
-
color: {
|
|
1428
|
-
green: 'bg-green-400/20 text-green-600 dark:text-green-400',
|
|
1429
|
-
yellow: 'bg-yellow-400/20 text-yellow-600 dark:text-yellow-400',
|
|
1430
|
-
red: 'bg-red-400/20 text-red-600 dark:text-red-400',
|
|
1431
|
-
blue: 'bg-blue-400/20 text-blue-600 dark:text-blue-400',
|
|
1432
|
-
orange: 'bg-orange-400/20 text-orange-600 dark:text-orange-400'
|
|
1433
|
-
}
|
|
1434
|
-
}
|
|
1435
|
-
});
|
|
1436
|
-
function getBadgeColor(method) {
|
|
1437
|
-
switch(method){
|
|
1438
|
-
case 'PUT':
|
|
1439
|
-
return 'yellow';
|
|
1440
|
-
case 'PATCH':
|
|
1441
|
-
return 'orange';
|
|
1442
|
-
case 'POST':
|
|
1443
|
-
return 'blue';
|
|
1444
|
-
case 'DELETE':
|
|
1445
|
-
return 'red';
|
|
1446
|
-
default:
|
|
1447
|
-
return 'green';
|
|
1448
|
-
}
|
|
1449
|
-
}
|
|
1450
|
-
|
|
1451
|
-
/**
|
|
1452
|
-
* Source API Integration
|
|
1453
|
-
*
|
|
1454
|
-
* Add this to page tree builder options
|
|
1455
|
-
*/ const attachFile = (node, file)=>{
|
|
1456
|
-
if (!file) return node;
|
|
1457
|
-
const data = file.data.data;
|
|
1458
|
-
let method;
|
|
1459
|
-
if ('_openapi' in data && typeof data._openapi === 'object') {
|
|
1460
|
-
const meta = data._openapi;
|
|
1461
|
-
method = meta.method;
|
|
1462
|
-
}
|
|
1463
|
-
if (method) {
|
|
1464
|
-
const color = getBadgeColor(method);
|
|
1465
|
-
node.name = /*#__PURE__*/ jsxs(Fragment, {
|
|
1466
|
-
children: [
|
|
1467
|
-
node.name,
|
|
1468
|
-
' ',
|
|
1469
|
-
/*#__PURE__*/ jsx("span", {
|
|
1470
|
-
className: badgeVariants({
|
|
1471
|
-
className: 'ms-auto text-nowrap',
|
|
1472
|
-
color
|
|
1473
|
-
}),
|
|
1474
|
-
children: method
|
|
1475
|
-
})
|
|
1476
|
-
]
|
|
1477
|
-
});
|
|
1478
|
-
}
|
|
1479
|
-
return node;
|
|
1480
|
-
};
|
|
1481
|
-
const badgeVariants = cva('rounded-full border px-1.5 text-xs font-medium', {
|
|
1482
|
-
variants: {
|
|
1483
|
-
color: {
|
|
1484
|
-
green: 'bg-green-400/20 text-green-600 dark:text-green-400',
|
|
1485
|
-
yellow: 'bg-yellow-400/20 text-yellow-600 dark:text-yellow-400',
|
|
1486
|
-
red: 'bg-red-400/20 text-red-600 dark:text-red-400',
|
|
1487
|
-
blue: 'bg-blue-400/20 text-blue-600 dark:text-blue-400',
|
|
1488
|
-
orange: 'bg-orange-400/20 text-orange-600 dark:text-orange-400'
|
|
1489
|
-
}
|
|
1490
|
-
}
|
|
1491
|
-
});
|
|
1492
|
-
|
|
1493
|
-
export { attachFile, createOpenAPI };
|
|
1
|
+
export * from './create.js';
|
|
2
|
+
export * from './source-api.js';
|