@elysiajs/openapi 1.4.11 → 1.4.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bun.lock +79 -144
- package/dist/cjs/gen/index.js +1021 -344
- package/dist/cjs/index.js +1255 -351
- package/dist/cjs/openapi.d.ts +6 -1
- package/dist/cjs/openapi.js +233 -11
- package/dist/gen/index.mjs +1021 -344
- package/dist/index.mjs +1255 -351
- package/dist/openapi.d.ts +6 -1
- package/dist/openapi.mjs +233 -11
- package/package.json +3 -4
package/dist/openapi.d.ts
CHANGED
|
@@ -10,7 +10,12 @@ export declare const capitalize: (word: string) => string;
|
|
|
10
10
|
*/
|
|
11
11
|
export declare const getPossiblePath: (path: string) => string[];
|
|
12
12
|
export declare const getLoosePath: (path: string) => string;
|
|
13
|
-
export declare const unwrapSchema: (schema: InputSchema["body"], mapJsonSchema?: MapJsonSchema) => OpenAPIV3.SchemaObject | undefined;
|
|
13
|
+
export declare const unwrapSchema: (schema: InputSchema["body"], mapJsonSchema?: MapJsonSchema, io?: "input" | "output") => OpenAPIV3.SchemaObject | undefined;
|
|
14
|
+
/**
|
|
15
|
+
* Convert TypeBox enum-like Union schemas to OpenAPI enum schemas
|
|
16
|
+
*
|
|
17
|
+
* Otherwise, return the schema as is
|
|
18
|
+
*/
|
|
14
19
|
export declare const enumToOpenApi: <T extends TAnySchema | OpenAPIV3.SchemaObject | OpenAPIV3.ReferenceObject | undefined>(_schema: T) => T;
|
|
15
20
|
/**
|
|
16
21
|
* Converts Elysia routes to OpenAPI 3.0.3 paths schema
|
package/dist/openapi.mjs
CHANGED
|
@@ -2,15 +2,13 @@
|
|
|
2
2
|
import { t } from "elysia";
|
|
3
3
|
|
|
4
4
|
// node_modules/@sinclair/typebox/build/esm/type/symbols/symbols.mjs
|
|
5
|
-
var
|
|
6
|
-
var ReadonlyKind = Symbol.for("TypeBox.Readonly");
|
|
7
|
-
var OptionalKind = Symbol.for("TypeBox.Optional");
|
|
8
|
-
var Hint = Symbol.for("TypeBox.Hint");
|
|
9
|
-
var Kind = Symbol.for("TypeBox.Kind");
|
|
5
|
+
var Kind = /* @__PURE__ */ Symbol.for("TypeBox.Kind");
|
|
10
6
|
|
|
11
7
|
// src/openapi.ts
|
|
12
8
|
var capitalize = (word) => word.charAt(0).toUpperCase() + word.slice(1);
|
|
13
|
-
var toRef = (name) => t.Ref(
|
|
9
|
+
var toRef = (name) => t.Ref(
|
|
10
|
+
name.startsWith("#/") ? name : `#/components/schemas/${name}`
|
|
11
|
+
);
|
|
14
12
|
var toOperationId = (method, paths) => {
|
|
15
13
|
let operationId = method.toLowerCase();
|
|
16
14
|
if (!paths || paths === "/") return operationId + "Index";
|
|
@@ -71,6 +69,219 @@ openapi({
|
|
|
71
69
|
})`
|
|
72
70
|
};
|
|
73
71
|
var warned = {};
|
|
72
|
+
var mergeObjectSchemas = (schemas) => {
|
|
73
|
+
if (schemas.length === 0)
|
|
74
|
+
return {
|
|
75
|
+
schema: void 0,
|
|
76
|
+
notObjects: []
|
|
77
|
+
};
|
|
78
|
+
if (schemas.length === 1)
|
|
79
|
+
return schemas[0].type === "object" ? {
|
|
80
|
+
schema: schemas[0],
|
|
81
|
+
notObjects: []
|
|
82
|
+
} : {
|
|
83
|
+
schema: void 0,
|
|
84
|
+
notObjects: schemas
|
|
85
|
+
};
|
|
86
|
+
let newSchema;
|
|
87
|
+
const notObjects = [];
|
|
88
|
+
let additionalPropertiesIsTrue = false;
|
|
89
|
+
let additionalPropertiesIsFalse = false;
|
|
90
|
+
for (const schema of schemas) {
|
|
91
|
+
if (!schema) continue;
|
|
92
|
+
if (schema.type !== "object") {
|
|
93
|
+
notObjects.push(schema);
|
|
94
|
+
continue;
|
|
95
|
+
}
|
|
96
|
+
if ("additionalProperties" in schema) {
|
|
97
|
+
if (schema.additionalProperties === true)
|
|
98
|
+
additionalPropertiesIsTrue = true;
|
|
99
|
+
else if (schema.additionalProperties === false)
|
|
100
|
+
additionalPropertiesIsFalse = true;
|
|
101
|
+
}
|
|
102
|
+
if (!newSchema) {
|
|
103
|
+
newSchema = schema;
|
|
104
|
+
continue;
|
|
105
|
+
}
|
|
106
|
+
newSchema = {
|
|
107
|
+
...newSchema,
|
|
108
|
+
...schema,
|
|
109
|
+
properties: {
|
|
110
|
+
...newSchema.properties,
|
|
111
|
+
...schema.properties
|
|
112
|
+
},
|
|
113
|
+
required: [
|
|
114
|
+
...newSchema?.required ?? [],
|
|
115
|
+
...schema.required ?? []
|
|
116
|
+
]
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
if (newSchema) {
|
|
120
|
+
if (newSchema.required)
|
|
121
|
+
newSchema.required = [...new Set(newSchema.required)];
|
|
122
|
+
if (additionalPropertiesIsFalse) newSchema.additionalProperties = false;
|
|
123
|
+
else if (additionalPropertiesIsTrue)
|
|
124
|
+
newSchema.additionalProperties = true;
|
|
125
|
+
}
|
|
126
|
+
return {
|
|
127
|
+
schema: newSchema,
|
|
128
|
+
notObjects
|
|
129
|
+
};
|
|
130
|
+
};
|
|
131
|
+
var isTSchema = (value) => {
|
|
132
|
+
if (!value || typeof value !== "object") return false;
|
|
133
|
+
if (Kind in value) return true;
|
|
134
|
+
const keys = Object.keys(value);
|
|
135
|
+
if (keys.length > 0 && keys.every((k) => !isNaN(Number(k)))) {
|
|
136
|
+
return false;
|
|
137
|
+
}
|
|
138
|
+
return false;
|
|
139
|
+
};
|
|
140
|
+
var normalizeSchemaReference = (schema) => {
|
|
141
|
+
if (!schema) return void 0;
|
|
142
|
+
if (typeof schema !== "string") return schema;
|
|
143
|
+
return toRef(schema);
|
|
144
|
+
};
|
|
145
|
+
var mergeSchemaProperty = (existing, incoming, vendors) => {
|
|
146
|
+
if (!existing) return incoming;
|
|
147
|
+
if (!incoming) return existing;
|
|
148
|
+
let existingSchema = normalizeSchemaReference(existing);
|
|
149
|
+
let incomingSchema = normalizeSchemaReference(incoming);
|
|
150
|
+
if (!existingSchema) return incoming;
|
|
151
|
+
if (!incomingSchema) return existing;
|
|
152
|
+
if (!isTSchema(incomingSchema) && incomingSchema["~standard"])
|
|
153
|
+
incomingSchema = unwrapSchema(incomingSchema, vendors);
|
|
154
|
+
if (!isTSchema(existingSchema) && existingSchema["~standard"])
|
|
155
|
+
existingSchema = unwrapSchema(existingSchema, vendors);
|
|
156
|
+
if (!incomingSchema) return existingSchema;
|
|
157
|
+
if (!existingSchema) return incomingSchema;
|
|
158
|
+
const { schema: mergedSchema, notObjects } = mergeObjectSchemas([
|
|
159
|
+
existingSchema,
|
|
160
|
+
incomingSchema
|
|
161
|
+
]);
|
|
162
|
+
if (notObjects.length > 0) {
|
|
163
|
+
if (mergedSchema) return t.Intersect([mergedSchema, ...notObjects]);
|
|
164
|
+
return notObjects.length === 1 ? notObjects[0] : t.Intersect(notObjects);
|
|
165
|
+
}
|
|
166
|
+
return mergedSchema;
|
|
167
|
+
};
|
|
168
|
+
var unwrapResponseSchema = (schema, vendors) => typeof schema === "string" ? normalizeSchemaReference(schema) : !schema ? void 0 : isTSchema(schema) ? schema : (
|
|
169
|
+
// @ts-ignore
|
|
170
|
+
schema["~standard"] ? unwrapSchema(schema, vendors, "output") : Object.fromEntries(
|
|
171
|
+
Object.entries(schema).map(([status, schema2]) => [
|
|
172
|
+
status,
|
|
173
|
+
typeof schema2 === "string" ? normalizeSchemaReference(schema2) : isTSchema(schema2) ? schema2 : unwrapSchema(
|
|
174
|
+
schema2,
|
|
175
|
+
vendors,
|
|
176
|
+
"output"
|
|
177
|
+
)
|
|
178
|
+
])
|
|
179
|
+
)
|
|
180
|
+
);
|
|
181
|
+
var mergeResponseSchema = (_existing, _incoming, vendors) => {
|
|
182
|
+
if (!_existing) return _incoming;
|
|
183
|
+
if (!_incoming) return _existing;
|
|
184
|
+
let existing = unwrapResponseSchema(_existing, vendors);
|
|
185
|
+
let incoming = unwrapResponseSchema(_incoming, vendors);
|
|
186
|
+
if (!existing && !incoming) return void 0;
|
|
187
|
+
if (incoming && !existing) return incoming;
|
|
188
|
+
if (existing && !incoming) return existing;
|
|
189
|
+
if (isTSchema(existing) || existing?.["~standard"])
|
|
190
|
+
existing = {
|
|
191
|
+
200: existing
|
|
192
|
+
};
|
|
193
|
+
if (isTSchema(incoming) || incoming?.["~standard"])
|
|
194
|
+
incoming = {
|
|
195
|
+
200: incoming
|
|
196
|
+
};
|
|
197
|
+
const schema = {
|
|
198
|
+
...incoming
|
|
199
|
+
};
|
|
200
|
+
for (const status of Object.keys(existing ?? {})) {
|
|
201
|
+
const existingSchema = existing[status];
|
|
202
|
+
const incomingSchema = incoming[status];
|
|
203
|
+
if (existingSchema && incomingSchema)
|
|
204
|
+
schema[status] = mergeSchemaProperty(
|
|
205
|
+
existingSchema,
|
|
206
|
+
incomingSchema,
|
|
207
|
+
vendors
|
|
208
|
+
);
|
|
209
|
+
else if (existingSchema) schema[status] = existingSchema;
|
|
210
|
+
else if (incomingSchema) schema[status] = incomingSchema;
|
|
211
|
+
}
|
|
212
|
+
return schema;
|
|
213
|
+
};
|
|
214
|
+
var mergeStandaloneValidators = (hooks, vendors) => {
|
|
215
|
+
const merged = { ...hooks };
|
|
216
|
+
if (!hooks.standaloneValidator?.length) return merged;
|
|
217
|
+
for (const validator of hooks.standaloneValidator) {
|
|
218
|
+
if (validator.body)
|
|
219
|
+
merged.body = mergeSchemaProperty(
|
|
220
|
+
merged.body,
|
|
221
|
+
validator.body,
|
|
222
|
+
vendors
|
|
223
|
+
);
|
|
224
|
+
if (validator.headers)
|
|
225
|
+
merged.headers = mergeSchemaProperty(
|
|
226
|
+
merged.headers,
|
|
227
|
+
validator.headers,
|
|
228
|
+
vendors
|
|
229
|
+
);
|
|
230
|
+
if (validator.query)
|
|
231
|
+
merged.query = mergeSchemaProperty(
|
|
232
|
+
merged.query,
|
|
233
|
+
validator.query,
|
|
234
|
+
vendors
|
|
235
|
+
);
|
|
236
|
+
if (validator.params)
|
|
237
|
+
merged.params = mergeSchemaProperty(
|
|
238
|
+
merged.params,
|
|
239
|
+
validator.params,
|
|
240
|
+
vendors
|
|
241
|
+
);
|
|
242
|
+
if (validator.cookie)
|
|
243
|
+
merged.cookie = mergeSchemaProperty(
|
|
244
|
+
merged.cookie,
|
|
245
|
+
validator.cookie,
|
|
246
|
+
vendors
|
|
247
|
+
);
|
|
248
|
+
if (validator.response)
|
|
249
|
+
merged.response = mergeResponseSchema(
|
|
250
|
+
merged.response,
|
|
251
|
+
validator.response,
|
|
252
|
+
vendors
|
|
253
|
+
);
|
|
254
|
+
}
|
|
255
|
+
if (typeof merged.body === "string")
|
|
256
|
+
merged.body = normalizeSchemaReference(merged.body);
|
|
257
|
+
if (typeof merged.headers === "string")
|
|
258
|
+
merged.headers = normalizeSchemaReference(merged.headers);
|
|
259
|
+
if (typeof merged.query === "string")
|
|
260
|
+
merged.query = normalizeSchemaReference(merged.query);
|
|
261
|
+
if (typeof merged.params === "string")
|
|
262
|
+
merged.params = normalizeSchemaReference(merged.params);
|
|
263
|
+
if (typeof merged.cookie === "string")
|
|
264
|
+
merged.cookie = normalizeSchemaReference(merged.cookie);
|
|
265
|
+
if (merged.response && typeof merged.response !== "string") {
|
|
266
|
+
const response = merged.response;
|
|
267
|
+
if ("type" in response || "$ref" in response) {
|
|
268
|
+
if (typeof response === "string")
|
|
269
|
+
merged.response = normalizeSchemaReference(response);
|
|
270
|
+
} else {
|
|
271
|
+
for (const [status, schema] of Object.entries(response))
|
|
272
|
+
if (typeof schema === "string")
|
|
273
|
+
response[status] = normalizeSchemaReference(schema);
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
return merged;
|
|
277
|
+
};
|
|
278
|
+
var flattenRoutes = (routes, vendors) => routes.map((route) => {
|
|
279
|
+
if (!route.hooks?.standaloneValidator?.length) return route;
|
|
280
|
+
return {
|
|
281
|
+
...route,
|
|
282
|
+
hooks: mergeStandaloneValidators(route.hooks, vendors)
|
|
283
|
+
};
|
|
284
|
+
});
|
|
74
285
|
var unwrapReference = (schema, definitions) => {
|
|
75
286
|
const ref = schema?.$ref;
|
|
76
287
|
if (!ref) return schema;
|
|
@@ -78,13 +289,20 @@ var unwrapReference = (schema, definitions) => {
|
|
|
78
289
|
if (ref && definitions[name]) schema = definitions[name];
|
|
79
290
|
return enumToOpenApi(schema);
|
|
80
291
|
};
|
|
81
|
-
var unwrapSchema = (schema, mapJsonSchema) => {
|
|
292
|
+
var unwrapSchema = (schema, mapJsonSchema, io = "input") => {
|
|
82
293
|
if (!schema) return;
|
|
83
294
|
if (typeof schema === "string") schema = toRef(schema);
|
|
84
295
|
if (Kind in schema) return enumToOpenApi(schema);
|
|
85
|
-
if (
|
|
296
|
+
if (!schema?.["~standard"] && // @ts-ignore
|
|
297
|
+
(schema.$schema || schema.type || schema.properties || schema.items))
|
|
298
|
+
return schema;
|
|
299
|
+
if (!schema?.["~standard"]) return;
|
|
86
300
|
const vendor = schema["~standard"].vendor;
|
|
87
301
|
try {
|
|
302
|
+
if (schema["~standard"]?.jsonSchema?.[io])
|
|
303
|
+
return schema["~standard"]?.jsonSchema?.[io]?.({
|
|
304
|
+
target: "draft-2020-12"
|
|
305
|
+
});
|
|
88
306
|
if (mapJsonSchema?.[vendor] && typeof mapJsonSchema[vendor] === "function")
|
|
89
307
|
return enumToOpenApi(mapJsonSchema[vendor](schema));
|
|
90
308
|
switch (vendor) {
|
|
@@ -179,7 +397,6 @@ function toOpenAPISchema(app, exclude, references, vendors) {
|
|
|
179
397
|
const excludePaths = Array.isArray(exclude?.paths) ? exclude.paths : typeof exclude?.paths !== "undefined" ? [exclude.paths] : [];
|
|
180
398
|
const paths = /* @__PURE__ */ Object.create(null);
|
|
181
399
|
const definitions = app.getGlobalDefinitions?.().type;
|
|
182
|
-
const routes = app.getGlobalRoutes();
|
|
183
400
|
if (references) {
|
|
184
401
|
if (!Array.isArray(references)) references = [references];
|
|
185
402
|
for (let i = 0; i < references.length; i++) {
|
|
@@ -187,6 +404,7 @@ function toOpenAPISchema(app, exclude, references, vendors) {
|
|
|
187
404
|
if (typeof reference === "function") references[i] = reference();
|
|
188
405
|
}
|
|
189
406
|
}
|
|
407
|
+
const routes = flattenRoutes(app.getGlobalRoutes(), vendors);
|
|
190
408
|
for (const route of routes) {
|
|
191
409
|
if (route.hooks?.detail?.hide) continue;
|
|
192
410
|
const method = route.method.toLowerCase();
|
|
@@ -376,7 +594,7 @@ function toOpenAPISchema(app, exclude, references, vendors) {
|
|
|
376
594
|
if (typeof hooks.response === "object" && // TypeBox
|
|
377
595
|
!hooks.response.type && !hooks.response.$ref && !hooks.response["~standard"]) {
|
|
378
596
|
for (let [status, schema] of Object.entries(hooks.response)) {
|
|
379
|
-
const response = unwrapSchema(schema, vendors);
|
|
597
|
+
const response = unwrapSchema(schema, vendors, "output");
|
|
380
598
|
if (!response) continue;
|
|
381
599
|
const { type, description, $ref, ..._options } = unwrapReference(response, definitions);
|
|
382
600
|
operation.responses[status] = {
|
|
@@ -393,7 +611,11 @@ function toOpenAPISchema(app, exclude, references, vendors) {
|
|
|
393
611
|
};
|
|
394
612
|
}
|
|
395
613
|
} else {
|
|
396
|
-
const response = unwrapSchema(
|
|
614
|
+
const response = unwrapSchema(
|
|
615
|
+
hooks.response,
|
|
616
|
+
vendors,
|
|
617
|
+
"output"
|
|
618
|
+
);
|
|
397
619
|
if (response) {
|
|
398
620
|
const {
|
|
399
621
|
type: _type,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@elysiajs/openapi",
|
|
3
|
-
"version": "1.4.
|
|
3
|
+
"version": "1.4.13",
|
|
4
4
|
"description": "Plugin for Elysia to auto-generate API documentation",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "saltyAom",
|
|
@@ -73,19 +73,18 @@
|
|
|
73
73
|
"build": "bun build.ts",
|
|
74
74
|
"release": "npm run build && npm run test && npm publish --access public"
|
|
75
75
|
},
|
|
76
|
-
"dependencies": {},
|
|
77
76
|
"devDependencies": {
|
|
78
77
|
"@apidevtools/swagger-parser": "^12.0.0",
|
|
79
78
|
"@scalar/types": "^0.2.13",
|
|
80
79
|
"@sinclair/typemap": "^0.10.1",
|
|
81
80
|
"@types/bun": "1.2.20",
|
|
82
81
|
"effect": "^3.17.13",
|
|
83
|
-
"elysia": "1.4.
|
|
82
|
+
"elysia": "1.4.19",
|
|
84
83
|
"eslint": "9.6.0",
|
|
85
84
|
"openapi-types": "^12.1.3",
|
|
86
85
|
"tsup": "^8.5.0",
|
|
87
86
|
"typescript": "^5.9.2",
|
|
88
|
-
"zod": "^4.1
|
|
87
|
+
"zod": "^4.2.1"
|
|
89
88
|
},
|
|
90
89
|
"peerDependencies": {
|
|
91
90
|
"elysia": ">= 1.4.0"
|