66 rmSync ,
77 existsSync ,
88 cpSync ,
9- exists
9+ exists ,
10+ readdirSync
1011} from 'fs'
1112import { TypeBox } from '@sinclair/typemap'
1213
@@ -15,18 +16,12 @@ import { join } from 'path'
1516import { spawnSync } from 'child_process'
1617import { AdditionalReference , AdditionalReferences } from '../types'
1718import { Kind , TObject } from '@sinclair/typebox/type'
19+ import { readdir } from 'fs/promises'
1820
1921const matchRoute = / : E l y s i a < ( .* ) > / gs
2022const matchStatus = / ( \d { 3 } ) : / g
2123const wrapStatusInQuote = ( value : string ) => value . replace ( matchStatus , '"$1":' )
2224
23- const exec = ( command : string , cwd : string ) =>
24- spawnSync ( command , {
25- shell : true ,
26- cwd,
27- stdio : 'inherit'
28- } )
29-
3025interface OpenAPIGeneratorOptions {
3126 /**
3227 * Path to tsconfig.json
@@ -55,7 +50,14 @@ interface OpenAPIGeneratorOptions {
5550 * Under any circumstance, that Elysia failed to find a correct schema,
5651 * Put your own schema in this path
5752 */
58- overrideOutputPath ?( tempDir : string ) : string
53+ overrideOutputPath ?: string | ( ( tempDir : string ) => string )
54+
55+ /**
56+ * don't remove temporary files
57+ * for debugging purpose
58+ * @default false
59+ */
60+ debug ?: boolean
5961}
6062
6163/**
@@ -77,29 +79,48 @@ export const fromTypes =
7779 tsconfigPath = 'tsconfig.json' ,
7880 instanceName,
7981 projectRoot = process . cwd ( ) ,
80- overrideOutputPath
82+ overrideOutputPath,
83+ debug = false
8184 } : OpenAPIGeneratorOptions = { }
8285 ) =>
8386 ( ) => {
84- if ( ! targetFilePath . endsWith ( '.ts' ) && ! targetFilePath . endsWith ( '.tsx' ) )
85- throw new Error ( 'Only .ts files are supported' )
86-
8787 const tmpRoot = join ( tmpdir ( ) , '.ElysiaAutoOpenAPI' )
8888
89- if ( existsSync ( tmpRoot ) )
90- rmSync ( tmpRoot , { recursive : true , force : true } )
91- mkdirSync ( tmpRoot , { recursive : true } )
89+ try {
90+ if (
91+ ! targetFilePath . endsWith ( '.ts' ) &&
92+ ! targetFilePath . endsWith ( '.tsx' )
93+ )
94+ throw new Error ( 'Only .ts files are supported' )
95+
96+ if ( targetFilePath . startsWith ( './' ) )
97+ targetFilePath = targetFilePath . slice ( 2 )
98+
99+ const src = targetFilePath . startsWith ( '/' )
100+ ? targetFilePath
101+ : join ( projectRoot , targetFilePath )
102+
103+ if ( ! existsSync ( src ) )
104+ throw new Error (
105+ `Couldn't find "${ targetFilePath } " from ${ projectRoot } `
106+ )
107+
108+ if ( existsSync ( tmpRoot ) )
109+ rmSync ( tmpRoot , { recursive : true , force : true } )
110+
111+ mkdirSync ( tmpRoot , { recursive : true } )
92112
93- const extendsRef = existsSync ( join ( projectRoot , 'tsconfig.json' ) )
94- ? `"extends": " ${ join ( projectRoot , 'tsconfig.json' ) } ",`
95- : ''
113+ const tsconfig = tsconfigPath . startsWith ( '/' )
114+ ? tsconfigPath
115+ : join ( projectRoot , tsconfigPath )
96116
97- if ( ! join ( projectRoot , targetFilePath ) )
98- throw new Error ( 'Target file does not exist' )
117+ const extendsRef = existsSync ( tsconfig )
118+ ? `"extends": "${ join ( projectRoot , 'tsconfig.json' ) } ",`
119+ : ''
99120
100- writeFileSync (
101- join ( tmpRoot , tsconfigPath ) ,
102- `{
121+ writeFileSync (
122+ join ( tmpRoot , 'tsconfig.json' ) ,
123+ `{
103124 ${ extendsRef }
104125 "compilerOptions": {
105126 "lib": ["ESNext"],
@@ -112,19 +133,28 @@ export const fromTypes =
112133 "skipDefaultLibCheck": true,
113134 "outDir": "./dist"
114135 },
115- "include": ["${ join ( projectRoot , targetFilePath ) } "]
136+ "include": ["${ src } "]
116137 }`
117- )
138+ )
118139
119- exec ( `tsc` , tmpRoot )
140+ spawnSync ( `tsc` , {
141+ shell : true ,
142+ cwd : tmpRoot ,
143+ stdio : debug ? 'inherit' : undefined
144+ } )
120145
121- try {
122146 const fileName = targetFilePath
123147 . replace ( / .t s x $ / , '.ts' )
124148 . replace ( / .t s $ / , '.d.ts' )
125149
126150 let targetFile =
127- overrideOutputPath ?.( tmpRoot ) ?? join ( tmpRoot , 'dist' , fileName )
151+ ( overrideOutputPath
152+ ? typeof overrideOutputPath === 'string'
153+ ? overrideOutputPath . startsWith ( '/' )
154+ ? overrideOutputPath
155+ : join ( tmpRoot , 'dist' , overrideOutputPath )
156+ : overrideOutputPath ( tmpRoot )
157+ : undefined ) ?? join ( tmpRoot , 'dist' , fileName )
128158
129159 {
130160 const _targetFile = join (
@@ -133,7 +163,34 @@ export const fromTypes =
133163 fileName . slice ( fileName . indexOf ( '/' ) + 1 )
134164 )
135165
136- if ( existsSync ( _targetFile ) ) targetFile = _targetFile
166+ if ( ! existsSync ( _targetFile ) ) {
167+ rmSync ( join ( tmpRoot , 'tsconfig.json' ) )
168+
169+ console . warn (
170+ '[@elysiajs/openapi/gen] Failed to generate OpenAPI schema'
171+ )
172+ console . warn ( "Couldn't find generated declaration file" )
173+
174+ if ( existsSync ( join ( tmpRoot , 'dist' ) ) ) {
175+ const tempFiles = readdirSync ( join ( tmpRoot , 'dist' ) , {
176+ recursive : true
177+ } )
178+ . filter ( ( x ) => x . toString ( ) . endsWith ( '.d.ts' ) )
179+ . map ( ( x ) => `- ${ x } ` )
180+ . join ( '\n' )
181+
182+ if ( tempFiles ) {
183+ console . warn (
184+ 'You can override with `overrideOutputPath` with one of the following:'
185+ )
186+ console . warn ( tempFiles )
187+ }
188+ }
189+
190+ return
191+ }
192+
193+ targetFile = _targetFile
137194 }
138195
139196 const declaration = readFileSync ( targetFile , 'utf8' )
@@ -219,6 +276,7 @@ export const fromTypes =
219276
220277 return
221278 } finally {
222- rmSync ( tmpRoot , { recursive : true , force : true } )
279+ if ( ! debug && existsSync ( tmpRoot ) )
280+ rmSync ( tmpRoot , { recursive : true , force : true } )
223281 }
224282 }
0 commit comments