@elysiajs/openapi 1.4.11 → 1.4.12

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/openapi.d.ts CHANGED
@@ -10,7 +10,7 @@ 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
14
  export declare const enumToOpenApi: <T extends TAnySchema | OpenAPIV3.SchemaObject | OpenAPIV3.ReferenceObject | undefined>(_schema: T) => T;
15
15
  /**
16
16
  * Converts Elysia routes to OpenAPI 3.0.3 paths schema
package/dist/openapi.mjs CHANGED
@@ -2,11 +2,7 @@
2
2
  import { t } from "elysia";
3
3
 
4
4
  // node_modules/@sinclair/typebox/build/esm/type/symbols/symbols.mjs
5
- var TransformKind = Symbol.for("TypeBox.Transform");
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);
@@ -71,6 +67,212 @@ openapi({
71
67
  })`
72
68
  };
73
69
  var warned = {};
70
+ var mergeObjectSchemas = (schemas) => {
71
+ if (schemas.length === 0)
72
+ return {
73
+ schema: void 0,
74
+ notObjects: []
75
+ };
76
+ if (schemas.length === 1)
77
+ return schemas[0].type === "object" ? {
78
+ schema: schemas[0],
79
+ notObjects: []
80
+ } : {
81
+ schema: void 0,
82
+ notObjects: schemas
83
+ };
84
+ let newSchema;
85
+ const notObjects = [];
86
+ let additionalPropertiesIsTrue = false;
87
+ let additionalPropertiesIsFalse = false;
88
+ for (const schema of schemas) {
89
+ if (!schema) continue;
90
+ if (schema.type !== "object") {
91
+ notObjects.push(schema);
92
+ continue;
93
+ }
94
+ if ("additionalProperties" in schema) {
95
+ if (schema.additionalProperties === true)
96
+ additionalPropertiesIsTrue = true;
97
+ else if (schema.additionalProperties === false)
98
+ additionalPropertiesIsFalse = true;
99
+ }
100
+ if (!newSchema) {
101
+ newSchema = schema;
102
+ continue;
103
+ }
104
+ newSchema = {
105
+ ...newSchema,
106
+ ...schema,
107
+ properties: {
108
+ ...newSchema.properties,
109
+ ...schema.properties
110
+ },
111
+ required: [
112
+ ...newSchema?.required ?? [],
113
+ ...schema.required ?? []
114
+ ]
115
+ };
116
+ }
117
+ if (newSchema) {
118
+ if (newSchema.required)
119
+ newSchema.required = [...new Set(newSchema.required)];
120
+ if (additionalPropertiesIsFalse) newSchema.additionalProperties = false;
121
+ else if (additionalPropertiesIsTrue)
122
+ newSchema.additionalProperties = true;
123
+ }
124
+ return {
125
+ schema: newSchema,
126
+ notObjects
127
+ };
128
+ };
129
+ var isTSchema = (value) => {
130
+ if (!value || typeof value !== "object") return false;
131
+ if (Kind in value) return true;
132
+ const keys = Object.keys(value);
133
+ if (keys.length > 0 && keys.every((k) => !isNaN(Number(k)))) {
134
+ return false;
135
+ }
136
+ return false;
137
+ };
138
+ var normalizeSchemaReference = (schema) => {
139
+ if (!schema) return void 0;
140
+ if (typeof schema !== "string") return schema;
141
+ return t.Ref(schema);
142
+ };
143
+ var mergeSchemaProperty = (existing, incoming, vendors) => {
144
+ if (!existing) return incoming;
145
+ if (!incoming) return existing;
146
+ const existingSchema = normalizeSchemaReference(existing);
147
+ let incomingSchema = normalizeSchemaReference(incoming);
148
+ if (!existingSchema) return incoming;
149
+ if (!incomingSchema) return existing;
150
+ if (!isTSchema(incomingSchema) && incomingSchema["~standard"])
151
+ incomingSchema = unwrapSchema(incomingSchema, vendors);
152
+ if (!incomingSchema) return existing;
153
+ const { schema: mergedSchema, notObjects } = mergeObjectSchemas([
154
+ existingSchema,
155
+ incomingSchema
156
+ ]);
157
+ if (notObjects.length > 0) {
158
+ if (mergedSchema) return t.Intersect([mergedSchema, ...notObjects]);
159
+ return notObjects.length === 1 ? notObjects[0] : t.Intersect(notObjects);
160
+ }
161
+ return mergedSchema;
162
+ };
163
+ var unwrapResponseSchema = (schema, vendors) => typeof schema === "string" ? normalizeSchemaReference(schema) : !schema ? void 0 : isTSchema(schema) ? schema : (
164
+ // @ts-ignore
165
+ schema["~standard"] ? unwrapSchema(schema, vendors, "output") : Object.fromEntries(
166
+ Object.entries(schema).map(([status, schema2]) => [
167
+ status,
168
+ typeof schema2 === "string" ? normalizeSchemaReference(schema2) : isTSchema(schema2) ? schema2 : unwrapSchema(schema2, vendors, "output")
169
+ ])
170
+ )
171
+ );
172
+ var mergeResponseSchema = (_existing, _incoming, vendors) => {
173
+ if (!_existing) return _incoming;
174
+ if (!_incoming) return _existing;
175
+ let existing = unwrapResponseSchema(_existing, vendors);
176
+ let incoming = unwrapResponseSchema(_incoming, vendors);
177
+ if (!existing && !incoming) return void 0;
178
+ if (incoming && !existing) return incoming;
179
+ if (existing && !incoming) return existing;
180
+ if (isTSchema(existing) || existing?.["~standard"])
181
+ existing = {
182
+ 200: existing
183
+ };
184
+ if (isTSchema(incoming) || incoming?.["~standard"])
185
+ incoming = {
186
+ 200: incoming
187
+ };
188
+ const schema = {
189
+ ...incoming
190
+ };
191
+ for (const status of Object.keys(existing ?? {})) {
192
+ const existingSchema = existing[status];
193
+ const incomingSchema = incoming[status];
194
+ if (existingSchema && incomingSchema)
195
+ schema[status] = mergeSchemaProperty(
196
+ existingSchema,
197
+ incomingSchema,
198
+ vendors
199
+ );
200
+ else if (existingSchema) schema[status] = existingSchema;
201
+ else if (incomingSchema) schema[status] = incomingSchema;
202
+ }
203
+ return schema;
204
+ };
205
+ var mergeStandaloneValidators = (hooks, vendors) => {
206
+ const merged = { ...hooks };
207
+ if (!hooks.standaloneValidator?.length) return merged;
208
+ for (const validator of hooks.standaloneValidator) {
209
+ if (validator.body)
210
+ merged.body = mergeSchemaProperty(
211
+ merged.body,
212
+ validator.body,
213
+ vendors
214
+ );
215
+ if (validator.headers)
216
+ merged.headers = mergeSchemaProperty(
217
+ merged.headers,
218
+ validator.headers,
219
+ vendors
220
+ );
221
+ if (validator.query)
222
+ merged.query = mergeSchemaProperty(
223
+ merged.query,
224
+ validator.query,
225
+ vendors
226
+ );
227
+ if (validator.params)
228
+ merged.params = mergeSchemaProperty(
229
+ merged.params,
230
+ validator.params,
231
+ vendors
232
+ );
233
+ if (validator.cookie)
234
+ merged.cookie = mergeSchemaProperty(
235
+ merged.cookie,
236
+ validator.cookie,
237
+ vendors
238
+ );
239
+ if (validator.response)
240
+ merged.response = mergeResponseSchema(
241
+ merged.response,
242
+ validator.response,
243
+ vendors
244
+ );
245
+ }
246
+ if (typeof merged.body === "string")
247
+ merged.body = normalizeSchemaReference(merged.body);
248
+ if (typeof merged.headers === "string")
249
+ merged.headers = normalizeSchemaReference(merged.headers);
250
+ if (typeof merged.query === "string")
251
+ merged.query = normalizeSchemaReference(merged.query);
252
+ if (typeof merged.params === "string")
253
+ merged.params = normalizeSchemaReference(merged.params);
254
+ if (typeof merged.cookie === "string")
255
+ merged.cookie = normalizeSchemaReference(merged.cookie);
256
+ if (merged.response && typeof merged.response !== "string") {
257
+ const response = merged.response;
258
+ if ("type" in response || "$ref" in response) {
259
+ if (typeof response === "string")
260
+ merged.response = normalizeSchemaReference(response);
261
+ } else {
262
+ for (const [status, schema] of Object.entries(response))
263
+ if (typeof schema === "string")
264
+ response[status] = normalizeSchemaReference(schema);
265
+ }
266
+ }
267
+ return merged;
268
+ };
269
+ var flattenRoutes = (routes, vendors) => routes.map((route) => {
270
+ if (!route.hooks?.standaloneValidator?.length) return route;
271
+ return {
272
+ ...route,
273
+ hooks: mergeStandaloneValidators(route.hooks, vendors)
274
+ };
275
+ });
74
276
  var unwrapReference = (schema, definitions) => {
75
277
  const ref = schema?.$ref;
76
278
  if (!ref) return schema;
@@ -78,13 +280,15 @@ var unwrapReference = (schema, definitions) => {
78
280
  if (ref && definitions[name]) schema = definitions[name];
79
281
  return enumToOpenApi(schema);
80
282
  };
81
- var unwrapSchema = (schema, mapJsonSchema) => {
283
+ var unwrapSchema = (schema, mapJsonSchema, io = "input") => {
82
284
  if (!schema) return;
83
285
  if (typeof schema === "string") schema = toRef(schema);
84
286
  if (Kind in schema) return enumToOpenApi(schema);
85
287
  if (Kind in schema || !schema?.["~standard"]) return;
86
288
  const vendor = schema["~standard"].vendor;
87
289
  try {
290
+ if (schema["~standard"]?.jsonSchema?.[io])
291
+ return schema["~standard"]?.jsonSchema?.[io]?.();
88
292
  if (mapJsonSchema?.[vendor] && typeof mapJsonSchema[vendor] === "function")
89
293
  return enumToOpenApi(mapJsonSchema[vendor](schema));
90
294
  switch (vendor) {
@@ -179,7 +383,6 @@ function toOpenAPISchema(app, exclude, references, vendors) {
179
383
  const excludePaths = Array.isArray(exclude?.paths) ? exclude.paths : typeof exclude?.paths !== "undefined" ? [exclude.paths] : [];
180
384
  const paths = /* @__PURE__ */ Object.create(null);
181
385
  const definitions = app.getGlobalDefinitions?.().type;
182
- const routes = app.getGlobalRoutes();
183
386
  if (references) {
184
387
  if (!Array.isArray(references)) references = [references];
185
388
  for (let i = 0; i < references.length; i++) {
@@ -187,6 +390,7 @@ function toOpenAPISchema(app, exclude, references, vendors) {
187
390
  if (typeof reference === "function") references[i] = reference();
188
391
  }
189
392
  }
393
+ const routes = flattenRoutes(app.getGlobalRoutes(), vendors);
190
394
  for (const route of routes) {
191
395
  if (route.hooks?.detail?.hide) continue;
192
396
  const method = route.method.toLowerCase();
@@ -376,7 +580,7 @@ function toOpenAPISchema(app, exclude, references, vendors) {
376
580
  if (typeof hooks.response === "object" && // TypeBox
377
581
  !hooks.response.type && !hooks.response.$ref && !hooks.response["~standard"]) {
378
582
  for (let [status, schema] of Object.entries(hooks.response)) {
379
- const response = unwrapSchema(schema, vendors);
583
+ const response = unwrapSchema(schema, vendors, "output");
380
584
  if (!response) continue;
381
585
  const { type, description, $ref, ..._options } = unwrapReference(response, definitions);
382
586
  operation.responses[status] = {
@@ -393,7 +597,7 @@ function toOpenAPISchema(app, exclude, references, vendors) {
393
597
  };
394
598
  }
395
599
  } else {
396
- const response = unwrapSchema(hooks.response, vendors);
600
+ const response = unwrapSchema(hooks.response, vendors, "output");
397
601
  if (response) {
398
602
  const {
399
603
  type: _type,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@elysiajs/openapi",
3
- "version": "1.4.11",
3
+ "version": "1.4.12",
4
4
  "description": "Plugin for Elysia to auto-generate API documentation",
5
5
  "author": {
6
6
  "name": "saltyAom",
@@ -80,12 +80,12 @@
80
80
  "@sinclair/typemap": "^0.10.1",
81
81
  "@types/bun": "1.2.20",
82
82
  "effect": "^3.17.13",
83
- "elysia": "1.4.6",
83
+ "elysia": "1.4.19",
84
84
  "eslint": "9.6.0",
85
85
  "openapi-types": "^12.1.3",
86
86
  "tsup": "^8.5.0",
87
87
  "typescript": "^5.9.2",
88
- "zod": "^4.1.5"
88
+ "zod": "^4.2.1"
89
89
  },
90
90
  "peerDependencies": {
91
91
  "elysia": ">= 1.4.0"