Skip to content

Commit dfd4325

Browse files
committed
🔧 fix: mapJsonSchema
1 parent 7c5f1af commit dfd4325

File tree

5 files changed

+248
-214
lines changed

5 files changed

+248
-214
lines changed

CHANGELOG.md

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,14 @@
1-
# 1.4.0
1+
# 1.4.1 - 14 Sep 2025
2+
Feature:
3+
- add `mapJsonSchema` to add custom JSON Schema mapping
4+
5+
Bug fix:
6+
- build error when using --compile
7+
8+
Change:
9+
- remove xsschema
10+
11+
# 1.4.0 - 13 Sep 2025
212
Improvement:
313
- support Standard Schema to OpenAPI
414
- use respective content type based on schema

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@elysiajs/openapi",
3-
"version": "1.4.0",
3+
"version": "1.4.1",
44
"description": "Plugin for Elysia to auto-generate API documentation",
55
"author": {
66
"name": "saltyAom",

src/index.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,8 @@ export const openapi = <
2727
exclude,
2828
swagger,
2929
scalar,
30-
references
30+
references,
31+
mapJsonSchema
3132
}: ElysiaOpenAPIConfig<Enabled, Path, Provider> = {}) => {
3233
if (!enabled) return new Elysia({ name: '@elysiajs/openapi' })
3334

@@ -80,15 +81,15 @@ export const openapi = <
8081
})
8182
.get(
8283
specPath,
83-
async function openAPISchema() {
84+
function openAPISchema() {
8485
if (totalRoutes === app.routes.length) return cachedSchema
8586

8687
totalRoutes = app.routes.length
8788

8889
const {
8990
paths,
9091
components: { schemas }
91-
} = await toOpenAPISchema(app, exclude, references)
92+
} = toOpenAPISchema(app, exclude, references, mapJsonSchema)
9293

9394
return (cachedSchema = {
9495
openapi: '3.0.3',

src/openapi.ts

Lines changed: 34 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,11 @@ import type { HookContainer, StandardSchemaV1Like } from 'elysia/types'
44
import type { OpenAPIV3 } from 'openapi-types'
55
import { Kind, type TProperties } from '@sinclair/typebox'
66

7-
import { toJsonSchema } from 'xsschema'
8-
97
import type {
108
AdditionalReference,
119
AdditionalReferences,
12-
ElysiaOpenAPIConfig
10+
ElysiaOpenAPIConfig,
11+
MapJsonSchema
1312
} from './types'
1413

1514
export const capitalize = (word: string) =>
@@ -69,29 +68,45 @@ export const getLoosePath = (path: string) => {
6968
return path + '/'
7069
}
7170

72-
type MaybePromise<T> = T | Promise<T>
73-
7471
export const unwrapSchema = (
75-
schema: InputSchema['body']
76-
): MaybePromise<OpenAPIV3.SchemaObject | undefined> => {
72+
schema: InputSchema['body'],
73+
mapJsonSchema?: MapJsonSchema
74+
): OpenAPIV3.SchemaObject | undefined => {
7775
if (!schema) return
7876

7977
if (typeof schema === 'string') schema = toRef(schema)
8078
if (Kind in schema) return schema
8179

82-
if (Kind in schema === false && schema['~standard'])
83-
return toJsonSchema(schema as any) as Promise<OpenAPIV3.SchemaObject>
80+
if (Kind in schema || !schema?.['~standard']) return
81+
82+
// @ts-ignore
83+
const vendor = schema['~standard'].vendor
84+
85+
if (mapJsonSchema?.[vendor] && typeof mapJsonSchema[vendor] === 'function')
86+
return mapJsonSchema[vendor](schema)
87+
88+
if (vendor === 'zod' || vendor === 'sury')
89+
// @ts-ignore
90+
return schema.toJSONSchema?.()
91+
92+
if (vendor === 'arktype')
93+
// @ts-ignore
94+
return schema?.toJsonSchema?.()
95+
96+
// @ts-ignore
97+
return schema.toJSONSchema?.() ?? schema?.toJsonSchema?.()
8498
}
8599

86100
/**
87101
* Converts Elysia routes to OpenAPI 3.0.3 paths schema
88102
* @param routes Array of Elysia route objects
89103
* @returns OpenAPI paths object
90104
*/
91-
export async function toOpenAPISchema(
105+
export function toOpenAPISchema(
92106
app: AnyElysia,
93107
exclude?: ElysiaOpenAPIConfig['exclude'],
94-
references?: AdditionalReferences
108+
references?: AdditionalReferences,
109+
vendors?: MapJsonSchema
95110
) {
96111
const {
97112
methods: excludeMethods = ['OPTIONS'],
@@ -195,8 +210,7 @@ export async function toOpenAPISchema(
195210

196211
// Handle path parameters
197212
if (hooks.params) {
198-
let params = unwrapSchema(hooks.params)
199-
if (params) params = await params
213+
const params = unwrapSchema(hooks.params, vendors)
200214

201215
if (params && params.type === 'object' && params.properties)
202216
for (const [paramName, paramSchema] of Object.entries(
@@ -212,8 +226,7 @@ export async function toOpenAPISchema(
212226

213227
// Handle query parameters
214228
if (hooks.query) {
215-
let query = unwrapSchema(hooks.query)
216-
if (query) query = await query
229+
let query = unwrapSchema(hooks.query, vendors)
217230

218231
if (query && query.type === 'object' && query.properties) {
219232
const required = query.required || []
@@ -231,8 +244,7 @@ export async function toOpenAPISchema(
231244

232245
// Handle header parameters
233246
if (hooks.headers) {
234-
let headers = unwrapSchema(hooks.query)
235-
if (headers) headers = await headers
247+
const headers = unwrapSchema(hooks.query, vendors)
236248

237249
if (headers && headers.type === 'object' && headers.properties) {
238250
const required = headers.required || []
@@ -250,8 +262,7 @@ export async function toOpenAPISchema(
250262

251263
// Handle cookie parameters
252264
if (hooks.cookie) {
253-
let cookie = unwrapSchema(hooks.cookie)
254-
if (cookie) cookie = await cookie
265+
const cookie = unwrapSchema(hooks.cookie, vendors)
255266

256267
if (cookie && cookie.type === 'object' && cookie.properties) {
257268
const required = cookie.required || []
@@ -272,8 +283,7 @@ export async function toOpenAPISchema(
272283

273284
// Handle request body
274285
if (hooks.body && method !== 'get' && method !== 'head') {
275-
let body = unwrapSchema(hooks.body)
276-
if (body) body = await body
286+
const body = unwrapSchema(hooks.body, vendors)
277287

278288
if (body) {
279289
// @ts-ignore
@@ -363,8 +373,7 @@ export async function toOpenAPISchema(
363373
!(hooks.response as TSchema).$ref
364374
) {
365375
for (let [status, schema] of Object.entries(hooks.response)) {
366-
let response = unwrapSchema(schema)
367-
if (response) response = await response
376+
const response = unwrapSchema(schema, vendors)
368377

369378
if (!response) continue
370379

@@ -398,8 +407,7 @@ export async function toOpenAPISchema(
398407
}
399408
}
400409
} else {
401-
let response = unwrapSchema(hooks.response as any)
402-
if (response) response = await response
410+
const response = unwrapSchema(hooks.response as any, vendors)
403411

404412
if (response) {
405413
// @ts-ignore
@@ -470,17 +478,14 @@ export async function toOpenAPISchema(
470478

471479
// @ts-ignore private property
472480
const _schemas = app.getGlobalDefinitions?.().type
473-
474481
const schemas = Object.create(null)
475482

476483
if (_schemas)
477484
for (const [name, schema] of Object.entries(_schemas)) {
478-
let jsonSchema = unwrapSchema(schema as any) as
485+
const jsonSchema = unwrapSchema(schema as any, vendors) as
479486
| OpenAPIV3.SchemaObject
480487
| undefined
481488

482-
if (jsonSchema instanceof Promise) jsonSchema = await jsonSchema
483-
484489
if (jsonSchema) schemas[name] = jsonSchema
485490
}
486491

0 commit comments

Comments
 (0)