@elysiajs/openapi 1.3.2
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/LICENSE +7 -0
- package/README.md +101 -0
- package/bun.lock +537 -0
- package/bunfig.toml +2 -0
- package/dist/cjs/gen/index.js +127 -0
- package/dist/cjs/index.d.ts +35 -0
- package/dist/cjs/index.js +639 -0
- package/dist/cjs/openapi.d.ts +25 -0
- package/dist/cjs/openapi.js +285 -0
- package/dist/cjs/scalar/index.js +183 -0
- package/dist/cjs/swagger/index.js +129 -0
- package/dist/cjs/swagger/types.js +18 -0
- package/dist/cjs/types.d.ts +137 -0
- package/dist/cjs/types.js +18 -0
- package/dist/gen/index.d.ts +36 -0
- package/dist/gen/index.mjs +108 -0
- package/dist/index.d.ts +35 -0
- package/dist/index.mjs +612 -0
- package/dist/openapi.d.ts +25 -0
- package/dist/openapi.mjs +257 -0
- package/dist/scalar/index.d.ts +3 -0
- package/dist/scalar/index.mjs +158 -0
- package/dist/swagger/index.d.ts +7 -0
- package/dist/swagger/index.mjs +103 -0
- package/dist/swagger/types.d.ts +274 -0
- package/dist/swagger/types.mjs +0 -0
- package/dist/types.d.ts +137 -0
- package/dist/types.mjs +0 -0
- package/package.json +92 -0
package/dist/openapi.mjs
ADDED
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
// src/openapi.ts
|
|
2
|
+
import { t } from "elysia";
|
|
3
|
+
var capitalize = (word) => word.charAt(0).toUpperCase() + word.slice(1);
|
|
4
|
+
var toRef = (name) => t.Ref(`#/components/schemas/${name}`);
|
|
5
|
+
var toOperationId = (method, paths) => {
|
|
6
|
+
let operationId = method.toLowerCase();
|
|
7
|
+
if (!paths || paths === "/") return operationId + "Index";
|
|
8
|
+
for (const path of paths.split("/"))
|
|
9
|
+
operationId += path.includes(":") ? "By" + capitalize(path.replace(":", "")) : capitalize(path);
|
|
10
|
+
operationId = operationId.replace(/\?/g, "Optional");
|
|
11
|
+
return operationId;
|
|
12
|
+
};
|
|
13
|
+
var optionalParamsRegex = /(\/:\w+\?)/g;
|
|
14
|
+
var getPossiblePath = (path) => {
|
|
15
|
+
const optionalParams = path.match(optionalParamsRegex);
|
|
16
|
+
if (!optionalParams) return [path];
|
|
17
|
+
const originalPath = path.replace(/\?/g, "");
|
|
18
|
+
const paths = [originalPath];
|
|
19
|
+
for (let i = 0; i < optionalParams.length; i++) {
|
|
20
|
+
const newPath = path.replace(optionalParams[i], "");
|
|
21
|
+
paths.push(...getPossiblePath(newPath));
|
|
22
|
+
}
|
|
23
|
+
return paths;
|
|
24
|
+
};
|
|
25
|
+
function toOpenAPISchema(app, exclude, references) {
|
|
26
|
+
const {
|
|
27
|
+
methods: excludeMethods = ["OPTIONS"],
|
|
28
|
+
staticFile: excludeStaticFile = true,
|
|
29
|
+
tags: excludeTags
|
|
30
|
+
} = exclude ?? {};
|
|
31
|
+
const excludePaths = Array.isArray(exclude?.paths) ? exclude.paths : typeof exclude?.paths !== "undefined" ? [exclude.paths] : [];
|
|
32
|
+
const paths = /* @__PURE__ */ Object.create(null);
|
|
33
|
+
const routes = app.getGlobalRoutes();
|
|
34
|
+
if (references) {
|
|
35
|
+
if (!Array.isArray(references)) references = [references];
|
|
36
|
+
for (let i = 0; i < references.length; i++) {
|
|
37
|
+
const reference = references[i];
|
|
38
|
+
if (typeof reference === "function") references[i] = reference();
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
for (const route of routes) {
|
|
42
|
+
if (route.hooks?.detail?.hide) continue;
|
|
43
|
+
const method = route.method.toLowerCase();
|
|
44
|
+
if (excludeStaticFile && route.path.includes(".") || excludePaths.includes(route.path) || excludeMethods.includes(method))
|
|
45
|
+
continue;
|
|
46
|
+
const hooks = route.hooks ?? {};
|
|
47
|
+
if (references)
|
|
48
|
+
for (const reference of references) {
|
|
49
|
+
const refer = reference[route.path]?.[method];
|
|
50
|
+
if (!refer) continue;
|
|
51
|
+
if (!hooks.body && refer.body) hooks.body = refer.body;
|
|
52
|
+
if (!hooks.query && refer.query) hooks.query = refer.query;
|
|
53
|
+
if (!hooks.params && refer.params) hooks.params = refer.params;
|
|
54
|
+
if (!hooks.headers && refer.headers)
|
|
55
|
+
hooks.headers = refer.headers;
|
|
56
|
+
if (!hooks.response && refer.response) {
|
|
57
|
+
hooks.response = {};
|
|
58
|
+
for (const [status, schema] of Object.entries(
|
|
59
|
+
refer.response
|
|
60
|
+
))
|
|
61
|
+
if (!hooks.response[status])
|
|
62
|
+
hooks.response[status] = schema;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
if (excludeTags && hooks.detail.tags?.some((tag) => excludeTags?.includes(tag)))
|
|
66
|
+
continue;
|
|
67
|
+
const operation = {
|
|
68
|
+
...hooks.detail
|
|
69
|
+
};
|
|
70
|
+
const parameters = [];
|
|
71
|
+
if (hooks.params) {
|
|
72
|
+
if (typeof hooks.params === "string")
|
|
73
|
+
hooks.params = toRef(hooks.params);
|
|
74
|
+
if (hooks.params.type === "object" && hooks.params.properties) {
|
|
75
|
+
for (const [paramName, paramSchema] of Object.entries(
|
|
76
|
+
hooks.params.properties
|
|
77
|
+
))
|
|
78
|
+
parameters.push({
|
|
79
|
+
name: paramName,
|
|
80
|
+
in: "path",
|
|
81
|
+
required: true,
|
|
82
|
+
// Path parameters are always required
|
|
83
|
+
schema: paramSchema
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
if (hooks.query) {
|
|
88
|
+
if (typeof hooks.query === "string")
|
|
89
|
+
hooks.query = toRef(hooks.query);
|
|
90
|
+
if (hooks.query.type === "object" && hooks.query.properties) {
|
|
91
|
+
const required = hooks.query.required || [];
|
|
92
|
+
for (const [queryName, querySchema] of Object.entries(
|
|
93
|
+
hooks.query.properties
|
|
94
|
+
))
|
|
95
|
+
parameters.push({
|
|
96
|
+
name: queryName,
|
|
97
|
+
in: "query",
|
|
98
|
+
required: required.includes(queryName),
|
|
99
|
+
schema: querySchema
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
if (hooks.headers) {
|
|
104
|
+
if (typeof hooks.headers === "string")
|
|
105
|
+
hooks.headers = toRef(hooks.headers);
|
|
106
|
+
if (hooks.headers.type === "object" && hooks.headers.properties) {
|
|
107
|
+
const required = hooks.headers.required || [];
|
|
108
|
+
for (const [headerName, headerSchema] of Object.entries(
|
|
109
|
+
hooks.headers.properties
|
|
110
|
+
))
|
|
111
|
+
parameters.push({
|
|
112
|
+
name: headerName,
|
|
113
|
+
in: "header",
|
|
114
|
+
required: required.includes(headerName),
|
|
115
|
+
schema: headerSchema
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
if (hooks.cookie) {
|
|
120
|
+
if (typeof hooks.cookie === "string")
|
|
121
|
+
hooks.cookie = toRef(hooks.cookie);
|
|
122
|
+
if (hooks.cookie.type === "object" && hooks.cookie.properties) {
|
|
123
|
+
const required = hooks.cookie.required || [];
|
|
124
|
+
for (const [cookieName, cookieSchema] of Object.entries(
|
|
125
|
+
hooks.cookie.properties
|
|
126
|
+
))
|
|
127
|
+
parameters.push({
|
|
128
|
+
name: cookieName,
|
|
129
|
+
in: "cookie",
|
|
130
|
+
required: required.includes(cookieName),
|
|
131
|
+
schema: cookieSchema
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
if (parameters.length > 0) operation.parameters = parameters;
|
|
136
|
+
if (hooks.body) {
|
|
137
|
+
if (typeof hooks.body === "string") hooks.body = toRef(hooks.body);
|
|
138
|
+
if (hooks.parse) {
|
|
139
|
+
const content = {};
|
|
140
|
+
const parsers = hooks.parse;
|
|
141
|
+
for (const parser of parsers) {
|
|
142
|
+
if (typeof parser.fn === "function") continue;
|
|
143
|
+
switch (parser.fn) {
|
|
144
|
+
case "text":
|
|
145
|
+
case "text/plain":
|
|
146
|
+
content["text/plain"] = { schema: hooks.body };
|
|
147
|
+
continue;
|
|
148
|
+
case "urlencoded":
|
|
149
|
+
case "application/x-www-form-urlencoded":
|
|
150
|
+
content["application/x-www-form-urlencoded"] = {
|
|
151
|
+
schema: hooks.body
|
|
152
|
+
};
|
|
153
|
+
continue;
|
|
154
|
+
case "json":
|
|
155
|
+
case "application/json":
|
|
156
|
+
content["application/json"] = { schema: hooks.body };
|
|
157
|
+
continue;
|
|
158
|
+
case "formdata":
|
|
159
|
+
case "multipart/form-data":
|
|
160
|
+
content["multipart/form-data"] = {
|
|
161
|
+
schema: hooks.body
|
|
162
|
+
};
|
|
163
|
+
continue;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
operation.requestBody = { content, required: true };
|
|
167
|
+
} else {
|
|
168
|
+
operation.requestBody = {
|
|
169
|
+
content: {
|
|
170
|
+
"application/json": {
|
|
171
|
+
schema: hooks.body
|
|
172
|
+
},
|
|
173
|
+
"application/x-www-form-urlencoded": {
|
|
174
|
+
schema: hooks.body
|
|
175
|
+
},
|
|
176
|
+
"multipart/form-data": {
|
|
177
|
+
schema: hooks.body
|
|
178
|
+
}
|
|
179
|
+
},
|
|
180
|
+
required: true
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
if (hooks.response) {
|
|
185
|
+
operation.responses = {};
|
|
186
|
+
if (typeof hooks.response === "object" && !hooks.response.type && !hooks.response.$ref) {
|
|
187
|
+
for (let [status, schema] of Object.entries(hooks.response)) {
|
|
188
|
+
if (typeof schema === "string") schema = toRef(schema);
|
|
189
|
+
const { type, examples, $ref, ...options } = schema;
|
|
190
|
+
operation.responses[status] = {
|
|
191
|
+
description: `Response for status ${status}`,
|
|
192
|
+
...options,
|
|
193
|
+
content: type === "void" || type === "null" || type === "undefined" ? schema : {
|
|
194
|
+
"application/json": {
|
|
195
|
+
schema
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
} else {
|
|
201
|
+
if (typeof hooks.response === "string")
|
|
202
|
+
hooks.response = toRef(hooks.response);
|
|
203
|
+
operation.responses["200"] = {
|
|
204
|
+
description: "Successful response",
|
|
205
|
+
content: {
|
|
206
|
+
"application/json": {
|
|
207
|
+
schema: hooks.response
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
for (let path of getPossiblePath(route.path)) {
|
|
214
|
+
const operationId = toOperationId(route.method, path);
|
|
215
|
+
path = path.replace(/:([^/]+)/g, "{$1}");
|
|
216
|
+
if (!paths[path]) paths[path] = {};
|
|
217
|
+
const current = paths[path];
|
|
218
|
+
if (method !== "all") {
|
|
219
|
+
current[method] = {
|
|
220
|
+
...operation,
|
|
221
|
+
operationId
|
|
222
|
+
};
|
|
223
|
+
continue;
|
|
224
|
+
}
|
|
225
|
+
for (const method2 of [
|
|
226
|
+
"get",
|
|
227
|
+
"post",
|
|
228
|
+
"put",
|
|
229
|
+
"delete",
|
|
230
|
+
"patch",
|
|
231
|
+
"head",
|
|
232
|
+
"options",
|
|
233
|
+
"trace"
|
|
234
|
+
])
|
|
235
|
+
current[method2] = {
|
|
236
|
+
...operation,
|
|
237
|
+
operationId
|
|
238
|
+
};
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
const schemas = app.getGlobalDefinitions?.().type;
|
|
242
|
+
return {
|
|
243
|
+
components: {
|
|
244
|
+
schemas
|
|
245
|
+
},
|
|
246
|
+
paths
|
|
247
|
+
};
|
|
248
|
+
}
|
|
249
|
+
var withHeaders = (schema, headers) => Object.assign(schema, {
|
|
250
|
+
headers
|
|
251
|
+
});
|
|
252
|
+
export {
|
|
253
|
+
capitalize,
|
|
254
|
+
getPossiblePath,
|
|
255
|
+
toOpenAPISchema,
|
|
256
|
+
withHeaders
|
|
257
|
+
};
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
// src/scalar/index.ts
|
|
2
|
+
var elysiaCSS = `.light-mode {
|
|
3
|
+
--scalar-color-1: #2a2f45;
|
|
4
|
+
--scalar-color-2: #757575;
|
|
5
|
+
--scalar-color-3: #8e8e8e;
|
|
6
|
+
--scalar-color-accent: #f06292;
|
|
7
|
+
|
|
8
|
+
--scalar-background-1: #fff;
|
|
9
|
+
--scalar-background-2: #f6f6f6;
|
|
10
|
+
--scalar-background-3: #e7e7e7;
|
|
11
|
+
|
|
12
|
+
--scalar-border-color: rgba(0, 0, 0, 0.1);
|
|
13
|
+
}
|
|
14
|
+
.dark-mode {
|
|
15
|
+
--scalar-color-1: rgba(255, 255, 255, 0.9);
|
|
16
|
+
--scalar-color-2: rgba(156, 163, 175, 1);
|
|
17
|
+
--scalar-color-3: rgba(255, 255, 255, 0.44);
|
|
18
|
+
--scalar-color-accent: #f06292;
|
|
19
|
+
|
|
20
|
+
--scalar-background-1: #111728;
|
|
21
|
+
--scalar-background-2: #1e293b;
|
|
22
|
+
--scalar-background-3: #334155;
|
|
23
|
+
--scalar-background-accent: #f062921f;
|
|
24
|
+
|
|
25
|
+
--scalar-border-color: rgba(255, 255, 255, 0.1);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/* Document Sidebar */
|
|
29
|
+
.light-mode .t-doc__sidebar,
|
|
30
|
+
.dark-mode .t-doc__sidebar {
|
|
31
|
+
--scalar-sidebar-background-1: var(--scalar-background-1);
|
|
32
|
+
--scalar-sidebar-color-1: var(--scalar-color-1);
|
|
33
|
+
--scalar-sidebar-color-2: var(--scalar-color-2);
|
|
34
|
+
--scalar-sidebar-border-color: var(--scalar-border-color);
|
|
35
|
+
|
|
36
|
+
--scalar-sidebar-item-hover-background: var(--scalar-background-2);
|
|
37
|
+
--scalar-sidebar-item-hover-color: currentColor;
|
|
38
|
+
|
|
39
|
+
--scalar-sidebar-item-active-background: #f062921f;
|
|
40
|
+
--scalar-sidebar-color-active: var(--scalar-color-accent);
|
|
41
|
+
|
|
42
|
+
--scalar-sidebar-search-background: transparent;
|
|
43
|
+
--scalar-sidebar-search-color: var(--scalar-color-3);
|
|
44
|
+
--scalar-sidebar-search-border-color: var(--scalar-border-color);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/* advanced */
|
|
48
|
+
.light-mode {
|
|
49
|
+
--scalar-button-1: rgb(49 53 56);
|
|
50
|
+
--scalar-button-1-color: #fff;
|
|
51
|
+
--scalar-button-1-hover: rgb(28 31 33);
|
|
52
|
+
|
|
53
|
+
--scalar-color-green: #069061;
|
|
54
|
+
--scalar-color-red: #ef0006;
|
|
55
|
+
--scalar-color-yellow: #edbe20;
|
|
56
|
+
--scalar-color-blue: #0082d0;
|
|
57
|
+
--scalar-color-orange: #fb892c;
|
|
58
|
+
--scalar-color-purple: #5203d1;
|
|
59
|
+
|
|
60
|
+
--scalar-scrollbar-color: rgba(0, 0, 0, 0.18);
|
|
61
|
+
--scalar-scrollbar-color-active: rgba(0, 0, 0, 0.36);
|
|
62
|
+
}
|
|
63
|
+
.dark-mode {
|
|
64
|
+
--scalar-button-1: #f6f6f6;
|
|
65
|
+
--scalar-button-1-color: #000;
|
|
66
|
+
--scalar-button-1-hover: #e7e7e7;
|
|
67
|
+
|
|
68
|
+
--scalar-color-green: #a3ffa9;
|
|
69
|
+
--scalar-color-red: #ffa3a3;
|
|
70
|
+
--scalar-color-yellow: #fffca3;
|
|
71
|
+
--scalar-color-blue: #a5d6ff;
|
|
72
|
+
--scalar-color-orange: #e2ae83;
|
|
73
|
+
--scalar-color-purple: #d2a8ff;
|
|
74
|
+
|
|
75
|
+
--scalar-scrollbar-color: rgba(255, 255, 255, 0.24);
|
|
76
|
+
--scalar-scrollbar-color-active: rgba(255, 255, 255, 0.48);
|
|
77
|
+
}
|
|
78
|
+
.section-flare {
|
|
79
|
+
width: 100%;
|
|
80
|
+
height: 400px;
|
|
81
|
+
position: absolute;
|
|
82
|
+
}
|
|
83
|
+
.section-flare-item:first-of-type:before {
|
|
84
|
+
content: "";
|
|
85
|
+
position: absolute;
|
|
86
|
+
top: 0;
|
|
87
|
+
right: 0;
|
|
88
|
+
bottom: 0;
|
|
89
|
+
left: 0;
|
|
90
|
+
--stripes: repeating-linear-gradient(100deg, #fff 0%, #fff 0%, transparent 2%, transparent 12%, #fff 17%);
|
|
91
|
+
--stripesDark: repeating-linear-gradient(100deg, #000 0%, #000 0%, transparent 10%, transparent 12%, #000 17%);
|
|
92
|
+
--rainbow: repeating-linear-gradient(100deg, #60a5fa 10%, #e879f9 16%, #5eead4 22%, #60a5fa 30%);
|
|
93
|
+
contain: strict;
|
|
94
|
+
contain-intrinsic-size: 100vw 40vh;
|
|
95
|
+
background-image: var(--stripesDark), var(--rainbow);
|
|
96
|
+
background-size: 300%, 200%;
|
|
97
|
+
background-position: 50% 50%, 50% 50%;
|
|
98
|
+
filter: opacity(20%) saturate(200%);
|
|
99
|
+
-webkit-mask-image: radial-gradient(ellipse at 100% 0%, black 40%, transparent 70%);
|
|
100
|
+
mask-image: radial-gradient(ellipse at 100% 0%, black 40%, transparent 70%);
|
|
101
|
+
pointer-events: none;
|
|
102
|
+
}
|
|
103
|
+
.section-flare-item:first-of-type:after {
|
|
104
|
+
content: "";
|
|
105
|
+
position: absolute;
|
|
106
|
+
top: 0;
|
|
107
|
+
right: 0;
|
|
108
|
+
bottom: 0;
|
|
109
|
+
left: 0;
|
|
110
|
+
background-image: var(--stripes), var(--rainbow);
|
|
111
|
+
background-size: 200%, 100%;
|
|
112
|
+
background-attachment: fixed;
|
|
113
|
+
mix-blend-mode: difference;
|
|
114
|
+
background-image: var(--stripesDark), var(--rainbow);
|
|
115
|
+
pointer-events: none;
|
|
116
|
+
}
|
|
117
|
+
.light-mode .section-flare-item:first-of-type:after,
|
|
118
|
+
.light-mode .section-flare-item:first-of-type:before {
|
|
119
|
+
background-image: var(--stripes), var(--rainbow);
|
|
120
|
+
filter: opacity(4%) saturate(200%);
|
|
121
|
+
}`;
|
|
122
|
+
var ScalarRender = (info, config) => `<!doctype html>
|
|
123
|
+
<html>
|
|
124
|
+
<head>
|
|
125
|
+
<title>${info.title}</title>
|
|
126
|
+
<meta
|
|
127
|
+
name="description"
|
|
128
|
+
content="${info.description}"
|
|
129
|
+
/>
|
|
130
|
+
<meta
|
|
131
|
+
name="og:description"
|
|
132
|
+
content="${info.description}"
|
|
133
|
+
/>
|
|
134
|
+
<meta charset="utf-8" />
|
|
135
|
+
<meta
|
|
136
|
+
name="viewport"
|
|
137
|
+
content="width=device-width, initial-scale=1" />
|
|
138
|
+
<style>
|
|
139
|
+
body {
|
|
140
|
+
margin: 0;
|
|
141
|
+
}
|
|
142
|
+
</style>
|
|
143
|
+
<style>
|
|
144
|
+
${config.customCss ?? elysiaCSS}
|
|
145
|
+
</style>
|
|
146
|
+
</head>
|
|
147
|
+
<body>
|
|
148
|
+
<script
|
|
149
|
+
id="api-reference"
|
|
150
|
+
data-url="${config.url}"
|
|
151
|
+
>
|
|
152
|
+
</script>
|
|
153
|
+
<script src="${config.cdn}" crossorigin></script>
|
|
154
|
+
</body>
|
|
155
|
+
</html>`;
|
|
156
|
+
export {
|
|
157
|
+
ScalarRender
|
|
158
|
+
};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { OpenAPIV3 } from 'openapi-types';
|
|
2
|
+
import { ElysiaOpenAPIConfig } from '../types';
|
|
3
|
+
import { SwaggerUIOptions } from './types';
|
|
4
|
+
type SchemaObject = OpenAPIV3.SchemaObject | OpenAPIV3.ReferenceObject;
|
|
5
|
+
export declare function transformDateProperties(schema: SchemaObject): SchemaObject;
|
|
6
|
+
export declare const SwaggerUIRender: (info: OpenAPIV3.InfoObject, config: NonNullable<ElysiaOpenAPIConfig["swagger"]> & SwaggerUIOptions) => string;
|
|
7
|
+
export {};
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
// src/swagger/index.ts
|
|
2
|
+
function isSchemaObject(schema) {
|
|
3
|
+
return "type" in schema || "properties" in schema || "items" in schema;
|
|
4
|
+
}
|
|
5
|
+
function isDateTimeProperty(key, schema) {
|
|
6
|
+
return (key === "createdAt" || key === "updatedAt") && "anyOf" in schema && Array.isArray(schema.anyOf);
|
|
7
|
+
}
|
|
8
|
+
function transformDateProperties(schema) {
|
|
9
|
+
if (!isSchemaObject(schema) || typeof schema !== "object" || schema === null)
|
|
10
|
+
return schema;
|
|
11
|
+
const newSchema = { ...schema };
|
|
12
|
+
Object.entries(newSchema).forEach(([key, value]) => {
|
|
13
|
+
if (isSchemaObject(value)) {
|
|
14
|
+
if (isDateTimeProperty(key, value)) {
|
|
15
|
+
const dateTimeFormat = value.anyOf?.find(
|
|
16
|
+
(item) => isSchemaObject(item) && item.format === "date-time"
|
|
17
|
+
);
|
|
18
|
+
if (dateTimeFormat) {
|
|
19
|
+
const dateTimeSchema = {
|
|
20
|
+
type: "string",
|
|
21
|
+
format: "date-time",
|
|
22
|
+
default: dateTimeFormat.default
|
|
23
|
+
};
|
|
24
|
+
newSchema[key] = dateTimeSchema;
|
|
25
|
+
}
|
|
26
|
+
} else {
|
|
27
|
+
;
|
|
28
|
+
newSchema[key] = transformDateProperties(value);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
return newSchema;
|
|
33
|
+
}
|
|
34
|
+
var SwaggerUIRender = (info, config) => {
|
|
35
|
+
const {
|
|
36
|
+
version = "latest",
|
|
37
|
+
theme = `https://unpkg.com/swagger-ui-dist@${version ?? "latest"}/swagger-ui.css`,
|
|
38
|
+
cdn = `https://unpkg.com/swagger-ui-dist@${version}/swagger-ui-bundle.js`,
|
|
39
|
+
autoDarkMode = true,
|
|
40
|
+
...rest
|
|
41
|
+
} = config;
|
|
42
|
+
const stringifiedOptions = JSON.stringify(
|
|
43
|
+
{
|
|
44
|
+
dom_id: "#swagger-ui",
|
|
45
|
+
...rest
|
|
46
|
+
},
|
|
47
|
+
(_, value) => typeof value === "function" ? void 0 : value
|
|
48
|
+
);
|
|
49
|
+
const options = JSON.parse(stringifiedOptions);
|
|
50
|
+
if (options.components && options.components.schemas)
|
|
51
|
+
options.components.schemas = Object.fromEntries(
|
|
52
|
+
Object.entries(options.components.schemas).map(([key, schema]) => [
|
|
53
|
+
key,
|
|
54
|
+
transformDateProperties(schema)
|
|
55
|
+
])
|
|
56
|
+
);
|
|
57
|
+
return `<!DOCTYPE html>
|
|
58
|
+
<html lang="en">
|
|
59
|
+
<head>
|
|
60
|
+
<meta charset="utf-8" />
|
|
61
|
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
62
|
+
<title>${info.title}</title>
|
|
63
|
+
<meta
|
|
64
|
+
name="description"
|
|
65
|
+
content="${info.description}"
|
|
66
|
+
/>
|
|
67
|
+
<meta
|
|
68
|
+
name="og:description"
|
|
69
|
+
content="${info.description}"
|
|
70
|
+
/>
|
|
71
|
+
${autoDarkMode && typeof theme === "string" ? `<style>
|
|
72
|
+
@media (prefers-color-scheme: dark) {
|
|
73
|
+
body {
|
|
74
|
+
background-color: #222;
|
|
75
|
+
color: #faf9a;
|
|
76
|
+
}
|
|
77
|
+
.swagger-ui {
|
|
78
|
+
filter: invert(92%) hue-rotate(180deg);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
.swagger-ui .microlight {
|
|
82
|
+
filter: invert(100%) hue-rotate(180deg);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
</style>` : ""}
|
|
86
|
+
${typeof theme === "string" ? `<link rel="stylesheet" href="${theme}" />` : `<link rel="stylesheet" media="(prefers-color-scheme: light)" href="${theme.light}" />
|
|
87
|
+
<link rel="stylesheet" media="(prefers-color-scheme: dark)" href="${theme.dark}" />`}
|
|
88
|
+
</head>
|
|
89
|
+
<body>
|
|
90
|
+
<div id="swagger-ui"></div>
|
|
91
|
+
<script src="${cdn}" crossorigin></script>
|
|
92
|
+
<script>
|
|
93
|
+
window.onload = () => {
|
|
94
|
+
window.ui = SwaggerUIBundle(${stringifiedOptions});
|
|
95
|
+
};
|
|
96
|
+
</script>
|
|
97
|
+
</body>
|
|
98
|
+
</html>`;
|
|
99
|
+
};
|
|
100
|
+
export {
|
|
101
|
+
SwaggerUIRender,
|
|
102
|
+
transformDateProperties
|
|
103
|
+
};
|