@elysiajs/openapi 1.4.9 → 1.4.11
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/README.md +1 -1
- package/dist/cjs/gen/index.js +91 -59
- package/dist/cjs/index.d.ts +2 -1
- package/dist/cjs/index.js +9027 -446
- package/dist/cjs/openapi.d.ts +2 -1
- package/dist/cjs/openapi.js +113 -73
- package/dist/cjs/scalar/index.js +9 -2
- package/dist/cjs/types.d.ts +8 -0
- package/dist/gen/index.d.ts +6 -4
- package/dist/gen/index.mjs +81 -60
- package/dist/index.d.ts +2 -1
- package/dist/index.mjs +9032 -446
- package/dist/openapi.d.ts +2 -1
- package/dist/openapi.mjs +112 -73
- package/dist/scalar/index.d.ts +1 -1
- package/dist/scalar/index.mjs +9 -2
- package/dist/types.d.ts +8 -0
- package/package.json +1 -1
package/dist/cjs/openapi.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { type AnyElysia, type TSchema, type InputSchema } from 'elysia';
|
|
2
2
|
import type { OpenAPIV3 } from 'openapi-types';
|
|
3
|
-
import { type TProperties } from '@sinclair/typebox';
|
|
3
|
+
import { TAnySchema, type TProperties } from '@sinclair/typebox';
|
|
4
4
|
import type { AdditionalReferences, ElysiaOpenAPIConfig, MapJsonSchema } from './types';
|
|
5
5
|
export declare const capitalize: (word: string) => string;
|
|
6
6
|
/**
|
|
@@ -11,6 +11,7 @@ export declare const capitalize: (word: string) => string;
|
|
|
11
11
|
export declare const getPossiblePath: (path: string) => string[];
|
|
12
12
|
export declare const getLoosePath: (path: string) => string;
|
|
13
13
|
export declare const unwrapSchema: (schema: InputSchema["body"], mapJsonSchema?: MapJsonSchema) => OpenAPIV3.SchemaObject | undefined;
|
|
14
|
+
export declare const enumToOpenApi: <T extends TAnySchema | OpenAPIV3.SchemaObject | OpenAPIV3.ReferenceObject | undefined>(_schema: T) => T;
|
|
14
15
|
/**
|
|
15
16
|
* Converts Elysia routes to OpenAPI 3.0.3 paths schema
|
|
16
17
|
* @param routes Array of Elysia route objects
|
package/dist/cjs/openapi.js
CHANGED
|
@@ -21,6 +21,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
21
21
|
var openapi_exports = {};
|
|
22
22
|
__export(openapi_exports, {
|
|
23
23
|
capitalize: () => capitalize,
|
|
24
|
+
enumToOpenApi: () => enumToOpenApi,
|
|
24
25
|
getLoosePath: () => getLoosePath,
|
|
25
26
|
getPossiblePath: () => getPossiblePath,
|
|
26
27
|
toOpenAPISchema: () => toOpenAPISchema,
|
|
@@ -105,62 +106,98 @@ var unwrapReference = (schema, definitions) => {
|
|
|
105
106
|
if (!ref) return schema;
|
|
106
107
|
const name = ref.slice(ref.lastIndexOf("/") + 1);
|
|
107
108
|
if (ref && definitions[name]) schema = definitions[name];
|
|
108
|
-
return schema;
|
|
109
|
+
return enumToOpenApi(schema);
|
|
109
110
|
};
|
|
110
111
|
var unwrapSchema = (schema, mapJsonSchema) => {
|
|
111
112
|
if (!schema) return;
|
|
112
113
|
if (typeof schema === "string") schema = toRef(schema);
|
|
113
|
-
if (Kind in schema) return schema;
|
|
114
|
+
if (Kind in schema) return enumToOpenApi(schema);
|
|
114
115
|
if (Kind in schema || !schema?.["~standard"]) return;
|
|
115
116
|
const vendor = schema["~standard"].vendor;
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
"[@elysiajs/openapi] Zod doesn't provide JSON Schema method on the schema"
|
|
123
|
-
);
|
|
124
|
-
if ("_zod" in schema) {
|
|
125
|
-
warned.zod4 = true;
|
|
117
|
+
try {
|
|
118
|
+
if (mapJsonSchema?.[vendor] && typeof mapJsonSchema[vendor] === "function")
|
|
119
|
+
return enumToOpenApi(mapJsonSchema[vendor](schema));
|
|
120
|
+
switch (vendor) {
|
|
121
|
+
case "zod":
|
|
122
|
+
if (warned.zod4 || warned.zod3) break;
|
|
126
123
|
console.warn(
|
|
127
|
-
"
|
|
124
|
+
"[@elysiajs/openapi] Zod doesn't provide JSON Schema method on the schema"
|
|
128
125
|
);
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
126
|
+
if ("_zod" in schema) {
|
|
127
|
+
warned.zod4 = true;
|
|
128
|
+
console.warn(
|
|
129
|
+
"For Zod v4, please provide z.toJSONSchema as follows:\n"
|
|
130
|
+
);
|
|
131
|
+
console.warn(warnings.zod4);
|
|
132
|
+
} else {
|
|
133
|
+
warned.zod3 = true;
|
|
134
|
+
console.warn(
|
|
135
|
+
"For Zod v3, please install zod-to-json-schema package and use it like this:\n"
|
|
136
|
+
);
|
|
137
|
+
console.warn(warnings.zod3);
|
|
138
|
+
}
|
|
139
|
+
break;
|
|
140
|
+
case "valibot":
|
|
141
|
+
if (warned.valibot) break;
|
|
142
|
+
warned.valibot = true;
|
|
132
143
|
console.warn(
|
|
133
|
-
"
|
|
144
|
+
"[@elysiajs/openapi] Valibot require a separate package for JSON Schema conversion"
|
|
134
145
|
);
|
|
135
|
-
console.warn(
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
146
|
+
console.warn(
|
|
147
|
+
"Please install @valibot/to-json-schema package and use it like this:\n"
|
|
148
|
+
);
|
|
149
|
+
console.warn(warnings.valibot);
|
|
150
|
+
break;
|
|
151
|
+
case "effect":
|
|
152
|
+
if (warned.effect) break;
|
|
153
|
+
warned.effect = true;
|
|
154
|
+
console.warn(
|
|
155
|
+
"[@elysiajs/openapi] Effect Schema doesn't provide JSON Schema method on the schema"
|
|
156
|
+
);
|
|
157
|
+
console.warn(
|
|
158
|
+
"please provide JSONSchema from 'effect' package as follows:\n"
|
|
159
|
+
);
|
|
160
|
+
console.warn(warnings.effect);
|
|
161
|
+
break;
|
|
162
|
+
}
|
|
163
|
+
if (vendor === "arktype")
|
|
164
|
+
return enumToOpenApi(schema?.toJsonSchema?.());
|
|
165
|
+
return enumToOpenApi(
|
|
166
|
+
// @ts-ignore
|
|
167
|
+
schema.toJSONSchema?.() ?? schema?.toJsonSchema?.()
|
|
168
|
+
);
|
|
169
|
+
} catch (error) {
|
|
170
|
+
console.warn(error);
|
|
171
|
+
}
|
|
172
|
+
};
|
|
173
|
+
var enumToOpenApi = (_schema) => {
|
|
174
|
+
if (!_schema || typeof _schema !== "object") return _schema;
|
|
175
|
+
if (Kind in _schema) {
|
|
176
|
+
const schema2 = _schema;
|
|
177
|
+
if (schema2[Kind] === "Union" && schema2.anyOf && Array.isArray(schema2.anyOf) && schema2.anyOf.length > 0 && schema2.anyOf.every(
|
|
178
|
+
(item) => item && typeof item === "object" && item.const !== void 0
|
|
179
|
+
))
|
|
180
|
+
return {
|
|
181
|
+
type: "string",
|
|
182
|
+
enum: schema2.anyOf.map((item) => item.const)
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
const schema = _schema;
|
|
186
|
+
if (schema.type === "object" && schema.properties) {
|
|
187
|
+
const properties = {};
|
|
188
|
+
for (const [key, value] of Object.entries(schema.properties))
|
|
189
|
+
properties[key] = enumToOpenApi(value);
|
|
190
|
+
return {
|
|
191
|
+
...schema,
|
|
192
|
+
properties
|
|
193
|
+
};
|
|
160
194
|
}
|
|
161
|
-
if (
|
|
162
|
-
return
|
|
163
|
-
|
|
195
|
+
if (schema.type === "array" && schema.items)
|
|
196
|
+
return {
|
|
197
|
+
...schema,
|
|
198
|
+
items: enumToOpenApi(schema.items)
|
|
199
|
+
};
|
|
200
|
+
return schema;
|
|
164
201
|
};
|
|
165
202
|
function toOpenAPISchema(app, exclude, references, vendors) {
|
|
166
203
|
let {
|
|
@@ -233,16 +270,24 @@ function toOpenAPISchema(app, exclude, references, vendors) {
|
|
|
233
270
|
definitions
|
|
234
271
|
);
|
|
235
272
|
if (params && params.type === "object" && params.properties)
|
|
236
|
-
for (const [
|
|
237
|
-
params.properties
|
|
238
|
-
))
|
|
273
|
+
for (const [name, schema] of Object.entries(params.properties))
|
|
239
274
|
parameters.push({
|
|
240
|
-
name
|
|
275
|
+
name,
|
|
241
276
|
in: "path",
|
|
242
277
|
required: true,
|
|
243
278
|
// Path parameters are always required
|
|
244
|
-
schema
|
|
279
|
+
schema
|
|
245
280
|
});
|
|
281
|
+
} else {
|
|
282
|
+
for (const match of route.path.matchAll(/:([^/]+)/g)) {
|
|
283
|
+
const name = match[1].replace("?", "");
|
|
284
|
+
parameters.push({
|
|
285
|
+
name,
|
|
286
|
+
in: "path",
|
|
287
|
+
required: true,
|
|
288
|
+
schema: { type: "string" }
|
|
289
|
+
});
|
|
290
|
+
}
|
|
246
291
|
}
|
|
247
292
|
if (hooks.query) {
|
|
248
293
|
const query = unwrapReference(
|
|
@@ -251,32 +296,28 @@ function toOpenAPISchema(app, exclude, references, vendors) {
|
|
|
251
296
|
);
|
|
252
297
|
if (query && query.type === "object" && query.properties) {
|
|
253
298
|
const required = query.required || [];
|
|
254
|
-
for (const [
|
|
255
|
-
query.properties
|
|
256
|
-
))
|
|
299
|
+
for (const [name, schema] of Object.entries(query.properties))
|
|
257
300
|
parameters.push({
|
|
258
|
-
name
|
|
301
|
+
name,
|
|
259
302
|
in: "query",
|
|
260
|
-
required: required.includes(
|
|
261
|
-
schema
|
|
303
|
+
required: required.includes(name),
|
|
304
|
+
schema
|
|
262
305
|
});
|
|
263
306
|
}
|
|
264
307
|
}
|
|
265
308
|
if (hooks.headers) {
|
|
266
309
|
const headers = unwrapReference(
|
|
267
|
-
unwrapSchema(hooks.
|
|
310
|
+
unwrapSchema(hooks.headers, vendors),
|
|
268
311
|
definitions
|
|
269
312
|
);
|
|
270
313
|
if (headers && headers.type === "object" && headers.properties) {
|
|
271
314
|
const required = headers.required || [];
|
|
272
|
-
for (const [
|
|
273
|
-
headers.properties
|
|
274
|
-
))
|
|
315
|
+
for (const [name, schema] of Object.entries(headers.properties))
|
|
275
316
|
parameters.push({
|
|
276
|
-
name
|
|
317
|
+
name,
|
|
277
318
|
in: "header",
|
|
278
|
-
required: required.includes(
|
|
279
|
-
schema
|
|
319
|
+
required: required.includes(name),
|
|
320
|
+
schema
|
|
280
321
|
});
|
|
281
322
|
}
|
|
282
323
|
}
|
|
@@ -287,14 +328,12 @@ function toOpenAPISchema(app, exclude, references, vendors) {
|
|
|
287
328
|
);
|
|
288
329
|
if (cookie && cookie.type === "object" && cookie.properties) {
|
|
289
330
|
const required = cookie.required || [];
|
|
290
|
-
for (const [
|
|
291
|
-
cookie.properties
|
|
292
|
-
))
|
|
331
|
+
for (const [name, schema] of Object.entries(cookie.properties))
|
|
293
332
|
parameters.push({
|
|
294
|
-
name
|
|
333
|
+
name,
|
|
295
334
|
in: "cookie",
|
|
296
|
-
required: required.includes(
|
|
297
|
-
schema
|
|
335
|
+
required: required.includes(name),
|
|
336
|
+
schema
|
|
298
337
|
});
|
|
299
338
|
}
|
|
300
339
|
}
|
|
@@ -342,6 +381,7 @@ function toOpenAPISchema(app, exclude, references, vendors) {
|
|
|
342
381
|
} else {
|
|
343
382
|
operation.requestBody = {
|
|
344
383
|
description,
|
|
384
|
+
required: true,
|
|
345
385
|
content: type === "string" || type === "number" || type === "integer" || type === "boolean" ? {
|
|
346
386
|
"text/plain": {
|
|
347
387
|
schema: body
|
|
@@ -356,8 +396,7 @@ function toOpenAPISchema(app, exclude, references, vendors) {
|
|
|
356
396
|
"multipart/form-data": {
|
|
357
397
|
schema: body
|
|
358
398
|
}
|
|
359
|
-
}
|
|
360
|
-
required: true
|
|
399
|
+
}
|
|
361
400
|
};
|
|
362
401
|
}
|
|
363
402
|
}
|
|
@@ -369,7 +408,7 @@ function toOpenAPISchema(app, exclude, references, vendors) {
|
|
|
369
408
|
for (let [status, schema] of Object.entries(hooks.response)) {
|
|
370
409
|
const response = unwrapSchema(schema, vendors);
|
|
371
410
|
if (!response) continue;
|
|
372
|
-
const { type, description, $ref, ...
|
|
411
|
+
const { type, description, $ref, ..._options } = unwrapReference(response, definitions);
|
|
373
412
|
operation.responses[status] = {
|
|
374
413
|
description: description ?? `Response for status ${status}`,
|
|
375
414
|
content: type === "void" || type === "null" || type === "undefined" ? { type, description } : type === "string" || type === "number" || type === "integer" || type === "boolean" ? {
|
|
@@ -408,7 +447,7 @@ function toOpenAPISchema(app, exclude, references, vendors) {
|
|
|
408
447
|
}
|
|
409
448
|
}
|
|
410
449
|
for (let path of getPossiblePath(route.path)) {
|
|
411
|
-
const operationId = toOperationId(route.method, path);
|
|
450
|
+
const operationId = hooks.detail?.operationId ?? toOperationId(route.method, path);
|
|
412
451
|
path = path.replace(/:([^/]+)/g, "{$1}");
|
|
413
452
|
if (!paths[path]) paths[path] = {};
|
|
414
453
|
const current = paths[path];
|
|
@@ -454,6 +493,7 @@ var withHeaders = (schema, headers) => Object.assign(schema, {
|
|
|
454
493
|
// Annotate the CommonJS export names for ESM import in node:
|
|
455
494
|
0 && (module.exports = {
|
|
456
495
|
capitalize,
|
|
496
|
+
enumToOpenApi,
|
|
457
497
|
getLoosePath,
|
|
458
498
|
getPossiblePath,
|
|
459
499
|
toOpenAPISchema,
|
package/dist/cjs/scalar/index.js
CHANGED
|
@@ -143,7 +143,7 @@ var elysiaCSS = `.light-mode {
|
|
|
143
143
|
background-image: var(--stripes), var(--rainbow);
|
|
144
144
|
filter: opacity(4%) saturate(200%);
|
|
145
145
|
}`;
|
|
146
|
-
var ScalarRender = (info, config) => `<!doctype html>
|
|
146
|
+
var ScalarRender = (info, config, embedSpec) => `<!doctype html>
|
|
147
147
|
<html>
|
|
148
148
|
<head>
|
|
149
149
|
<title>${info.title}</title>
|
|
@@ -171,7 +171,14 @@ var ScalarRender = (info, config) => `<!doctype html>
|
|
|
171
171
|
<body>
|
|
172
172
|
<script
|
|
173
173
|
id="api-reference"
|
|
174
|
-
data-
|
|
174
|
+
data-configuration='${JSON.stringify(
|
|
175
|
+
Object.assign(
|
|
176
|
+
config,
|
|
177
|
+
{
|
|
178
|
+
content: embedSpec
|
|
179
|
+
}
|
|
180
|
+
)
|
|
181
|
+
)}'
|
|
175
182
|
>
|
|
176
183
|
</script>
|
|
177
184
|
<script src="${config.cdn}" crossorigin></script>
|
package/dist/cjs/types.d.ts
CHANGED
|
@@ -74,6 +74,14 @@ export interface ElysiaOpenAPIConfig<Enabled extends boolean = true, Path extend
|
|
|
74
74
|
* Additional reference for each endpoint
|
|
75
75
|
*/
|
|
76
76
|
references?: AdditionalReferences;
|
|
77
|
+
/**
|
|
78
|
+
* Embed OpenAPI schema to provider body if possible
|
|
79
|
+
*
|
|
80
|
+
* This is highly discouraged, unless you really have to inline OpenAPI schema
|
|
81
|
+
*
|
|
82
|
+
* @default false
|
|
83
|
+
*/
|
|
84
|
+
embedSpec?: boolean;
|
|
77
85
|
/**
|
|
78
86
|
* Mapping function from Standard schema to OpenAPI schema
|
|
79
87
|
*
|
package/dist/gen/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { AdditionalReference } from '../types';
|
|
2
|
-
interface OpenAPIGeneratorOptions {
|
|
1
|
+
import type { AdditionalReference } from '../types';
|
|
2
|
+
export interface OpenAPIGeneratorOptions {
|
|
3
3
|
/**
|
|
4
4
|
* Path to tsconfig.json
|
|
5
5
|
* @default tsconfig.json
|
|
@@ -52,6 +52,8 @@ interface OpenAPIGeneratorOptions {
|
|
|
52
52
|
*/
|
|
53
53
|
silent?: boolean;
|
|
54
54
|
}
|
|
55
|
+
export declare function extractRootObjects(code: string): string[];
|
|
56
|
+
export declare function declarationToJSONSchema(declaration: string): AdditionalReference;
|
|
55
57
|
/**
|
|
56
58
|
* Auto generate OpenAPI schema from Elysia instance
|
|
57
59
|
*
|
|
@@ -64,6 +66,6 @@ export declare const fromTypes: (
|
|
|
64
66
|
* Path to file where Elysia instance is
|
|
65
67
|
*
|
|
66
68
|
* The path must export an Elysia instance
|
|
69
|
+
* or a literal TypeScript declaration
|
|
67
70
|
*/
|
|
68
|
-
targetFilePath
|
|
69
|
-
export {};
|
|
71
|
+
targetFilePath?: string, { tsconfigPath, instanceName, projectRoot, overrideOutputPath, debug, compilerOptions, tmpRoot, silent }?: OpenAPIGeneratorOptions) => () => AdditionalReference | undefined;
|
package/dist/gen/index.mjs
CHANGED
|
@@ -4,16 +4,6 @@ var __export = (target, all) => {
|
|
|
4
4
|
__defProp(target, name, { get: all[name], enumerable: true });
|
|
5
5
|
};
|
|
6
6
|
|
|
7
|
-
// src/gen/index.ts
|
|
8
|
-
import {
|
|
9
|
-
readFileSync,
|
|
10
|
-
mkdirSync,
|
|
11
|
-
writeFileSync,
|
|
12
|
-
rmSync,
|
|
13
|
-
existsSync,
|
|
14
|
-
readdirSync
|
|
15
|
-
} from "fs";
|
|
16
|
-
|
|
17
7
|
// node_modules/@sinclair/typebox/build/esm/value/guard/guard.mjs
|
|
18
8
|
function IsObject(value) {
|
|
19
9
|
return value !== null && typeof value === "object";
|
|
@@ -8298,11 +8288,9 @@ function TypeBox(...args) {
|
|
|
8298
8288
|
}
|
|
8299
8289
|
|
|
8300
8290
|
// src/gen/index.ts
|
|
8301
|
-
import { tmpdir } from "os";
|
|
8302
|
-
import { join } from "path";
|
|
8303
|
-
import { spawnSync } from "child_process";
|
|
8304
8291
|
var matchRoute = /: Elysia<(.*)>/gs;
|
|
8305
|
-
var
|
|
8292
|
+
var numberKey = /(\d+):/g;
|
|
8293
|
+
var join = (...parts) => parts.join("/").replace(/\/{1,}/g, "/");
|
|
8306
8294
|
function extractRootObjects(code) {
|
|
8307
8295
|
const results = [];
|
|
8308
8296
|
let i = 0;
|
|
@@ -8334,41 +8322,89 @@ function extractRootObjects(code) {
|
|
|
8334
8322
|
}
|
|
8335
8323
|
return results;
|
|
8336
8324
|
}
|
|
8337
|
-
|
|
8325
|
+
function declarationToJSONSchema(declaration) {
|
|
8326
|
+
const routes = {};
|
|
8327
|
+
for (const route of extractRootObjects(
|
|
8328
|
+
declaration.replace(numberKey, '"$1":')
|
|
8329
|
+
)) {
|
|
8330
|
+
let schema = TypeBox(route.replaceAll(/readonly/g, ""));
|
|
8331
|
+
if (schema.type !== "object") continue;
|
|
8332
|
+
const paths = [];
|
|
8333
|
+
while (true) {
|
|
8334
|
+
const keys = Object.keys(schema.properties);
|
|
8335
|
+
if (keys.length !== 1) break;
|
|
8336
|
+
paths.push(keys[0]);
|
|
8337
|
+
schema = schema.properties[keys[0]];
|
|
8338
|
+
if (!schema?.properties) break;
|
|
8339
|
+
}
|
|
8340
|
+
const method = paths.pop();
|
|
8341
|
+
if (!method) continue;
|
|
8342
|
+
const path = "/" + paths.join("/");
|
|
8343
|
+
schema = schema.properties;
|
|
8344
|
+
if (schema?.response?.type === "object") {
|
|
8345
|
+
const responseSchema = {};
|
|
8346
|
+
for (const key in schema.response.properties)
|
|
8347
|
+
responseSchema[key] = schema.response.properties[key];
|
|
8348
|
+
schema.response = responseSchema;
|
|
8349
|
+
}
|
|
8350
|
+
if (!routes[path]) routes[path] = {};
|
|
8351
|
+
routes[path][method.toLowerCase()] = schema;
|
|
8352
|
+
}
|
|
8353
|
+
return routes;
|
|
8354
|
+
}
|
|
8355
|
+
var fromTypes = (targetFilePath = "src/index.ts", {
|
|
8338
8356
|
tsconfigPath = "tsconfig.json",
|
|
8339
8357
|
instanceName,
|
|
8340
8358
|
projectRoot = process.cwd(),
|
|
8341
8359
|
overrideOutputPath,
|
|
8342
8360
|
debug = false,
|
|
8343
8361
|
compilerOptions,
|
|
8344
|
-
tmpRoot
|
|
8362
|
+
tmpRoot,
|
|
8345
8363
|
silent = false
|
|
8346
8364
|
} = {}) => () => {
|
|
8365
|
+
if (targetFilePath.trimStart().startsWith("{") && targetFilePath.trimEnd().endsWith("}"))
|
|
8366
|
+
return declarationToJSONSchema(targetFilePath);
|
|
8367
|
+
if (typeof process === "undefined" || typeof process.getBuiltinModule !== "function")
|
|
8368
|
+
throw new Error(
|
|
8369
|
+
"[@elysiajs/openapi/gen] `fromTypes` from file path is only available in Node.js/Bun environment or environments"
|
|
8370
|
+
);
|
|
8371
|
+
const fs = process.getBuiltinModule("fs");
|
|
8372
|
+
if (!fs)
|
|
8373
|
+
throw new Error(
|
|
8374
|
+
"[@elysiajs/openapi/gen] `fromTypes` require `fs` module which is not available in this environment"
|
|
8375
|
+
);
|
|
8347
8376
|
try {
|
|
8348
8377
|
if (!targetFilePath.endsWith(".ts") && !targetFilePath.endsWith(".tsx"))
|
|
8349
8378
|
throw new Error("Only .ts files are supported");
|
|
8350
8379
|
if (targetFilePath.startsWith("./"))
|
|
8351
8380
|
targetFilePath = targetFilePath.slice(2);
|
|
8352
8381
|
let src = targetFilePath.startsWith("/") ? targetFilePath : join(projectRoot, targetFilePath);
|
|
8353
|
-
if (!existsSync(src))
|
|
8382
|
+
if (!fs.existsSync(src))
|
|
8354
8383
|
throw new Error(
|
|
8355
8384
|
`Couldn't find "${targetFilePath}" from ${projectRoot}`
|
|
8356
8385
|
);
|
|
8357
8386
|
let targetFile;
|
|
8387
|
+
if (!tmpRoot) {
|
|
8388
|
+
const os = process.getBuiltinModule("os");
|
|
8389
|
+
tmpRoot = join(
|
|
8390
|
+
os && typeof os.tmpdir === "function" ? os.tmpdir() : projectRoot,
|
|
8391
|
+
".ElysiaAutoOpenAPI"
|
|
8392
|
+
);
|
|
8393
|
+
}
|
|
8358
8394
|
if (targetFilePath.endsWith(".d.ts")) targetFile = targetFilePath;
|
|
8359
8395
|
else {
|
|
8360
|
-
if (existsSync(tmpRoot))
|
|
8361
|
-
rmSync(tmpRoot, { recursive: true, force: true });
|
|
8362
|
-
mkdirSync(tmpRoot, { recursive: true });
|
|
8396
|
+
if (fs.existsSync(tmpRoot))
|
|
8397
|
+
fs.rmSync(tmpRoot, { recursive: true, force: true });
|
|
8398
|
+
fs.mkdirSync(tmpRoot, { recursive: true });
|
|
8363
8399
|
const tsconfig = tsconfigPath.startsWith("/") ? tsconfigPath : join(projectRoot, tsconfigPath);
|
|
8364
|
-
let extendsRef = existsSync(tsconfig) ? `"extends": "${join(projectRoot, "tsconfig.json")}",` : "";
|
|
8400
|
+
let extendsRef = fs.existsSync(tsconfig) ? `"extends": "${join(projectRoot, "tsconfig.json")}",` : "";
|
|
8365
8401
|
let distDir = join(tmpRoot, "dist");
|
|
8366
8402
|
if (typeof process !== "undefined" && process.platform === "win32") {
|
|
8367
8403
|
extendsRef = extendsRef.replace(/\\/g, "/");
|
|
8368
8404
|
src = src.replace(/\\/g, "/");
|
|
8369
8405
|
distDir = distDir.replace(/\\/g, "/");
|
|
8370
8406
|
}
|
|
8371
|
-
writeFileSync(
|
|
8407
|
+
fs.writeFileSync(
|
|
8372
8408
|
join(tmpRoot, "tsconfig.json"),
|
|
8373
8409
|
`{
|
|
8374
8410
|
${extendsRef}
|
|
@@ -8386,6 +8422,16 @@ var fromTypes = (targetFilePath, {
|
|
|
8386
8422
|
"include": ["${src}"]
|
|
8387
8423
|
}`
|
|
8388
8424
|
);
|
|
8425
|
+
const child_process = process.getBuiltinModule("child_process");
|
|
8426
|
+
if (!child_process)
|
|
8427
|
+
throw new Error(
|
|
8428
|
+
"[@elysiajs/openapi/gen] `fromTypes` declaration generation require `child_process` module which is not available in this environment"
|
|
8429
|
+
);
|
|
8430
|
+
const { spawnSync } = child_process;
|
|
8431
|
+
if (typeof spawnSync !== "function")
|
|
8432
|
+
throw new Error(
|
|
8433
|
+
"[@elysiajs/openapi/gen] `fromTypes` declaration generation require child_process.spawnSync which is not available in this environment"
|
|
8434
|
+
);
|
|
8389
8435
|
spawnSync(`tsc`, {
|
|
8390
8436
|
shell: true,
|
|
8391
8437
|
cwd: tmpRoot,
|
|
@@ -8398,7 +8444,7 @@ var fromTypes = (targetFilePath, {
|
|
|
8398
8444
|
// remove leading like src or something similar
|
|
8399
8445
|
fileName.slice(fileName.indexOf("/") + 1)
|
|
8400
8446
|
);
|
|
8401
|
-
let existed = existsSync(targetFile);
|
|
8447
|
+
let existed = fs.existsSync(targetFile);
|
|
8402
8448
|
if (!existed && !overrideOutputPath) {
|
|
8403
8449
|
targetFile = join(
|
|
8404
8450
|
tmpRoot,
|
|
@@ -8406,16 +8452,16 @@ var fromTypes = (targetFilePath, {
|
|
|
8406
8452
|
// use original file name as-is eg. in monorepo
|
|
8407
8453
|
fileName
|
|
8408
8454
|
);
|
|
8409
|
-
existed = existsSync(targetFile);
|
|
8455
|
+
existed = fs.existsSync(targetFile);
|
|
8410
8456
|
}
|
|
8411
8457
|
if (!existed) {
|
|
8412
|
-
rmSync(join(tmpRoot, "tsconfig.json"));
|
|
8458
|
+
fs.rmSync(join(tmpRoot, "tsconfig.json"));
|
|
8413
8459
|
console.warn(
|
|
8414
8460
|
"[@elysiajs/openapi/gen] Failed to generate OpenAPI schema"
|
|
8415
8461
|
);
|
|
8416
8462
|
console.warn("Couldn't find generated declaration file");
|
|
8417
|
-
if (existsSync(join(tmpRoot, "dist"))) {
|
|
8418
|
-
const tempFiles = readdirSync(join(tmpRoot, "dist"), {
|
|
8463
|
+
if (fs.existsSync(join(tmpRoot, "dist"))) {
|
|
8464
|
+
const tempFiles = fs.readdirSync(join(tmpRoot, "dist"), {
|
|
8419
8465
|
recursive: true
|
|
8420
8466
|
}).filter((x) => x.toString().endsWith(".d.ts")).map((x) => `- ${x}`).join("\n");
|
|
8421
8467
|
if (tempFiles) {
|
|
@@ -8433,9 +8479,9 @@ var fromTypes = (targetFilePath, {
|
|
|
8433
8479
|
return;
|
|
8434
8480
|
}
|
|
8435
8481
|
}
|
|
8436
|
-
const declaration = readFileSync(targetFile, "utf8");
|
|
8437
|
-
if (!debug && existsSync(tmpRoot))
|
|
8438
|
-
rmSync(tmpRoot, { recursive: true, force: true });
|
|
8482
|
+
const declaration = fs.readFileSync(targetFile, "utf8");
|
|
8483
|
+
if (!debug && fs.existsSync(tmpRoot))
|
|
8484
|
+
fs.rmSync(tmpRoot, { recursive: true, force: true });
|
|
8439
8485
|
let instance = declaration.match(
|
|
8440
8486
|
instanceName ? new RegExp(`${instanceName}: Elysia<(.*)`, "gs") : matchRoute
|
|
8441
8487
|
)?.[0];
|
|
@@ -8448,34 +8494,7 @@ var fromTypes = (targetFilePath, {
|
|
|
8448
8494
|
3
|
|
8449
8495
|
)
|
|
8450
8496
|
);
|
|
8451
|
-
|
|
8452
|
-
for (const route of extractRootObjects(
|
|
8453
|
-
instance.slice(2).replace(matchStatus, '"$1":')
|
|
8454
|
-
)) {
|
|
8455
|
-
let schema = TypeBox(route.replaceAll(/readonly/g, ""));
|
|
8456
|
-
if (schema.type !== "object") continue;
|
|
8457
|
-
const paths = [];
|
|
8458
|
-
while (true) {
|
|
8459
|
-
const keys = Object.keys(schema.properties);
|
|
8460
|
-
if (keys.length !== 1) break;
|
|
8461
|
-
paths.push(keys[0]);
|
|
8462
|
-
schema = schema.properties[keys[0]];
|
|
8463
|
-
if (!schema?.properties) break;
|
|
8464
|
-
}
|
|
8465
|
-
const method = paths.pop();
|
|
8466
|
-
if (!method) continue;
|
|
8467
|
-
const path = "/" + paths.join("/");
|
|
8468
|
-
schema = schema.properties;
|
|
8469
|
-
if (schema?.response?.type === "object") {
|
|
8470
|
-
const responseSchema = {};
|
|
8471
|
-
for (const key in schema.response.properties)
|
|
8472
|
-
responseSchema[key] = schema.response.properties[key];
|
|
8473
|
-
schema.response = responseSchema;
|
|
8474
|
-
}
|
|
8475
|
-
if (!routes[path]) routes[path] = {};
|
|
8476
|
-
routes[path][method.toLowerCase()] = schema;
|
|
8477
|
-
}
|
|
8478
|
-
return routes;
|
|
8497
|
+
return declarationToJSONSchema(instance.slice(2));
|
|
8479
8498
|
} catch (error) {
|
|
8480
8499
|
console.warn(
|
|
8481
8500
|
"[@elysiajs/openapi/gen] Failed to generate OpenAPI schema"
|
|
@@ -8483,10 +8502,12 @@ var fromTypes = (targetFilePath, {
|
|
|
8483
8502
|
console.warn(error);
|
|
8484
8503
|
return;
|
|
8485
8504
|
} finally {
|
|
8486
|
-
if (!debug && existsSync(tmpRoot))
|
|
8487
|
-
rmSync(tmpRoot, { recursive: true, force: true });
|
|
8505
|
+
if (!debug && tmpRoot && fs.existsSync(tmpRoot))
|
|
8506
|
+
fs.rmSync(tmpRoot, { recursive: true, force: true });
|
|
8488
8507
|
}
|
|
8489
8508
|
};
|
|
8490
8509
|
export {
|
|
8510
|
+
declarationToJSONSchema,
|
|
8511
|
+
extractRootObjects,
|
|
8491
8512
|
fromTypes
|
|
8492
8513
|
};
|
package/dist/index.d.ts
CHANGED
|
@@ -5,7 +5,7 @@ import type { ElysiaOpenAPIConfig } from './types';
|
|
|
5
5
|
*
|
|
6
6
|
* @see https://github.com/elysiajs/elysia-swagger
|
|
7
7
|
*/
|
|
8
|
-
export declare const openapi: <const Enabled extends boolean = true, const Path extends string = "/openapi">({ enabled, path, provider, specPath, documentation, exclude, swagger, scalar, references, mapJsonSchema }?: ElysiaOpenAPIConfig<Enabled, Path>) => Elysia<"", {
|
|
8
|
+
export declare const openapi: <const Enabled extends boolean = true, const Path extends string = "/openapi">({ enabled, path, provider, specPath, documentation, exclude, swagger, scalar, references, mapJsonSchema, embedSpec }?: ElysiaOpenAPIConfig<Enabled, Path>) => Elysia<"", {
|
|
9
9
|
decorator: {};
|
|
10
10
|
store: {};
|
|
11
11
|
derive: {};
|
|
@@ -33,6 +33,7 @@ export declare const openapi: <const Enabled extends boolean = true, const Path
|
|
|
33
33
|
standaloneSchema: {};
|
|
34
34
|
response: {};
|
|
35
35
|
}>;
|
|
36
|
+
export { fromTypes } from './gen';
|
|
36
37
|
export { toOpenAPISchema, withHeaders } from './openapi';
|
|
37
38
|
export type { ElysiaOpenAPIConfig };
|
|
38
39
|
export default openapi;
|