@@ -12,13 +12,10 @@ import { TypeBox } from '@sinclair/typemap'
1212import { tmpdir } from 'os'
1313import { join } from 'path'
1414import { spawnSync } from 'child_process'
15- import { AdditionalReference , AdditionalReferences } from '../types'
16- import { Kind , TObject } from '@sinclair/typebox/type'
17- import { readdir } from 'fs/promises'
15+ import { AdditionalReference } from '../types'
1816
1917const matchRoute = / : E l y s i a < ( .* ) > / gs
20- const matchStatus = / ( \d { 3 } ) : / g
21- const wrapStatusInQuote = ( value : string ) => value . replace ( matchStatus , '"$1":' )
18+ const numberKey = / ( \d + ) : / g
2219
2320interface OpenAPIGeneratorOptions {
2421 /**
@@ -90,7 +87,6 @@ function extractRootObjects(code: string) {
9087 const colonIdx = code . indexOf ( ':' , i )
9188 if ( colonIdx === - 1 ) break
9289
93- // --- find key ---
9490 // walk backwards from colon to find start of key
9591 let keyEnd = colonIdx - 1
9692 while ( keyEnd >= 0 && / \s / . test ( code [ keyEnd ] ) ) keyEnd --
@@ -127,6 +123,52 @@ function extractRootObjects(code: string) {
127123 return results
128124}
129125
126+ export function declarationToJSONSchema ( declaration : string ) {
127+ const routes : AdditionalReference = { }
128+
129+ // Treaty is a collection of { ... } & { ... } & { ... }
130+ for ( const route of extractRootObjects (
131+ declaration . replace ( numberKey , '"$1":' )
132+ ) ) {
133+ let schema = TypeBox ( route . replaceAll ( / r e a d o n l y / g, '' ) )
134+ if ( schema . type !== 'object' ) continue
135+
136+ const paths = [ ]
137+
138+ while ( true ) {
139+ const keys = Object . keys ( schema . properties )
140+ if ( keys . length !== 1 ) break
141+
142+ paths . push ( keys [ 0 ] )
143+
144+ schema = schema . properties [ keys [ 0 ] ] as any
145+ if ( ! schema ?. properties ) break
146+ }
147+
148+ const method = paths . pop ( ) !
149+ // For whatever reason, if failed to infer route correctly
150+ if ( ! method ) continue
151+
152+ const path = '/' + paths . join ( '/' )
153+ schema = schema . properties
154+
155+ if ( schema ?. response ?. type === 'object' ) {
156+ const responseSchema : Record < string , any > = { }
157+
158+ for ( const key in schema . response . properties )
159+ responseSchema [ key ] = schema . response . properties [ key ]
160+
161+ schema . response = responseSchema
162+ }
163+
164+ if ( ! routes [ path ] ) routes [ path ] = { }
165+ // @ts -ignore
166+ routes [ path ] [ method . toLowerCase ( ) ] = schema
167+ }
168+
169+ return routes
170+ }
171+
130172/**
131173 * Auto generate OpenAPI schema from Elysia instance
132174 *
@@ -155,6 +197,10 @@ export const fromTypes =
155197 ) =>
156198 ( ) => {
157199 try {
200+ // targetFilePath is an actual dts reference
201+ if ( targetFilePath . trim ( ) . startsWith ( '{' ) )
202+ return declarationToJSONSchema ( targetFilePath )
203+
158204 if (
159205 ! targetFilePath . endsWith ( '.ts' ) &&
160206 ! targetFilePath . endsWith ( '.tsx' )
@@ -326,49 +372,7 @@ export const fromTypes =
326372 )
327373 )
328374
329- const routes : AdditionalReference = { }
330-
331- // Treaty is a collection of { ... } & { ... } & { ... }
332- for ( const route of extractRootObjects (
333- instance . slice ( 2 ) . replace ( matchStatus , '"$1":' )
334- ) ) {
335- let schema = TypeBox ( route . replaceAll ( / r e a d o n l y / g, '' ) )
336- if ( schema . type !== 'object' ) continue
337-
338- const paths = [ ]
339-
340- while ( true ) {
341- const keys = Object . keys ( schema . properties )
342- if ( keys . length !== 1 ) break
343-
344- paths . push ( keys [ 0 ] )
345-
346- schema = schema . properties [ keys [ 0 ] ] as any
347- if ( ! schema ?. properties ) break
348- }
349-
350- const method = paths . pop ( ) !
351- // For whatever reason, if failed to infer route correctly
352- if ( ! method ) continue
353-
354- const path = '/' + paths . join ( '/' )
355- schema = schema . properties
356-
357- if ( schema ?. response ?. type === 'object' ) {
358- const responseSchema : Record < string , any > = { }
359-
360- for ( const key in schema . response . properties )
361- responseSchema [ key ] = schema . response . properties [ key ]
362-
363- schema . response = responseSchema
364- }
365-
366- if ( ! routes [ path ] ) routes [ path ] = { }
367- // @ts -ignore
368- routes [ path ] [ method . toLowerCase ( ) ] = schema
369- }
370-
371- return routes
375+ return declarationToJSONSchema ( instance . slice ( 2 ) )
372376 } catch ( error ) {
373377 console . warn (
374378 '[@elysiajs/openapi/gen] Failed to generate OpenAPI schema'
0 commit comments