Skip to content

Commit ebdf2f5

Browse files
committed
🔧 fix: #256 export fromTypes from index
1 parent 8a775ca commit ebdf2f5

File tree

4 files changed

+73
-42
lines changed

4 files changed

+73
-42
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@ Improvement:
55
- type gen: accept number as path segment
66
- add test case for type gen, and OpenAPI schema
77
- when failed to convert type to OpenAPI, log the error and continue
8+
- type gen: use `process.getBuiltinModule` to import native node module conditionally
9+
- type gen: `fromTypes` now accept direct declaration
10+
- export `fromTypes` from index
811

912
Bug fix:
1013
- [#226](https://github.com/elysiajs/elysia-openapi/issues/266) accept operationId

example/index.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,6 @@ import { JSONSchema, Schema } from 'effect'
44

55
import { openapi, withHeaders } from '../src/index'
66

7-
// const a = z.toJSONSchema(z.void())
8-
97
const app = new Elysia()
108
.use(
119
openapi({

src/gen/index.ts

Lines changed: 69 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,10 @@
1-
import type { InputSchema, InternalRoute, TSchema } from 'elysia'
2-
import {
3-
readFileSync,
4-
mkdirSync,
5-
writeFileSync,
6-
rmSync,
7-
existsSync,
8-
readdirSync
9-
} from 'fs'
101
import { TypeBox } from '@sinclair/typemap'
11-
12-
import { tmpdir } from 'os'
13-
import { join } from 'path'
14-
import { spawnSync } from 'child_process'
15-
import { AdditionalReference } from '../types'
2+
import type { AdditionalReference } from '../types'
163

174
const matchRoute = /: Elysia<(.*)>/gs
185
const numberKey = /(\d+):/g
196

20-
interface OpenAPIGeneratorOptions {
7+
export interface OpenAPIGeneratorOptions {
218
/**
229
* Path to tsconfig.json
2310
* @default tsconfig.json
@@ -78,7 +65,12 @@ interface OpenAPIGeneratorOptions {
7865
silent?: boolean
7966
}
8067

81-
function extractRootObjects(code: string) {
68+
/**
69+
* Polyfill path join for environments without Node.js path module
70+
*/
71+
const join = (...parts: string[]) => parts.join('/').replace(/\/{1,}/g, '/')
72+
73+
export function extractRootObjects(code: string) {
8274
const results = []
8375
let i = 0
8476

@@ -183,24 +175,38 @@ export const fromTypes =
183175
*
184176
* The path must export an Elysia instance
185177
*/
186-
targetFilePath: string,
178+
targetFilePath = 'src/index.ts',
187179
{
188180
tsconfigPath = 'tsconfig.json',
189181
instanceName,
190182
projectRoot = process.cwd(),
191183
overrideOutputPath,
192184
debug = false,
193185
compilerOptions,
194-
tmpRoot = join(tmpdir(), '.ElysiaAutoOpenAPI'),
186+
tmpRoot,
195187
silent = false
196188
}: OpenAPIGeneratorOptions = {}
197189
) =>
198190
() => {
199-
try {
200-
// targetFilePath is an actual dts reference
201-
if (targetFilePath.trim().startsWith('{'))
202-
return declarationToJSONSchema(targetFilePath)
191+
// targetFilePath is an actual dts reference
192+
if (targetFilePath.trim().startsWith('{'))
193+
return declarationToJSONSchema(targetFilePath)
194+
195+
if (
196+
typeof process === 'undefined' ||
197+
typeof process.getBuiltinModule !== 'function'
198+
)
199+
throw new Error(
200+
'[@elysiajs/openapi/gen] `fromTypes` from file path is only available in Node.js/Bun environment or environments'
201+
)
202+
203+
const fs = process.getBuiltinModule('fs')
204+
if (!fs)
205+
throw new Error(
206+
'[@elysiajs/openapi/gen] `fromTypes` require `fs` module which is not available in this environment'
207+
)
203208

209+
try {
204210
if (
205211
!targetFilePath.endsWith('.ts') &&
206212
!targetFilePath.endsWith('.tsx')
@@ -214,27 +220,38 @@ export const fromTypes =
214220
? targetFilePath
215221
: join(projectRoot, targetFilePath)
216222

217-
if (!existsSync(src))
223+
if (!fs.existsSync(src))
218224
throw new Error(
219225
`Couldn't find "${targetFilePath}" from ${projectRoot}`
220226
)
221227

222228
let targetFile: string
223229

230+
if (!tmpRoot) {
231+
const os = process.getBuiltinModule('os')
232+
233+
tmpRoot = join(
234+
os && typeof os.tmpdir === 'function'
235+
? os.tmpdir()
236+
: projectRoot,
237+
'.ElysiaAutoOpenAPI'
238+
)
239+
}
240+
224241
// Since it's already a declaration file
225242
// We can just read it directly
226243
if (targetFilePath.endsWith('.d.ts')) targetFile = targetFilePath
227244
else {
228-
if (existsSync(tmpRoot))
229-
rmSync(tmpRoot, { recursive: true, force: true })
245+
if (fs.existsSync(tmpRoot))
246+
fs.rmSync(tmpRoot, { recursive: true, force: true })
230247

231-
mkdirSync(tmpRoot, { recursive: true })
248+
fs.mkdirSync(tmpRoot, { recursive: true })
232249

233250
const tsconfig = tsconfigPath.startsWith('/')
234251
? tsconfigPath
235252
: join(projectRoot, tsconfigPath)
236253

237-
let extendsRef = existsSync(tsconfig)
254+
let extendsRef = fs.existsSync(tsconfig)
238255
? `"extends": "${join(projectRoot, 'tsconfig.json')}",`
239256
: ''
240257

@@ -250,7 +267,7 @@ export const fromTypes =
250267
distDir = distDir.replace(/\\/g, '/')
251268
}
252269

253-
writeFileSync(
270+
fs.writeFileSync(
254271
join(tmpRoot, 'tsconfig.json'),
255272
`{
256273
${extendsRef}
@@ -273,6 +290,17 @@ export const fromTypes =
273290
}`
274291
)
275292

293+
const child_process = process.getBuiltinModule('child_process')
294+
if (!child_process)
295+
throw new Error(
296+
'[@elysiajs/openapi/gen] `fromTypes` declaration generation require `child_process` module which is not available in this environment'
297+
)
298+
const { spawnSync } = child_process
299+
if (typeof spawnSync !== 'function')
300+
throw new Error(
301+
'[@elysiajs/openapi/gen] `fromTypes` declaration generation require child_process.spawnSync which is not available in this environment'
302+
)
303+
276304
spawnSync(`tsc`, {
277305
shell: true,
278306
cwd: tmpRoot,
@@ -298,7 +326,7 @@ export const fromTypes =
298326
fileName.slice(fileName.indexOf('/') + 1)
299327
)
300328

301-
let existed = existsSync(targetFile)
329+
let existed = fs.existsSync(targetFile)
302330

303331
if (!existed && !overrideOutputPath) {
304332
targetFile = join(
@@ -308,21 +336,22 @@ export const fromTypes =
308336
fileName
309337
)
310338

311-
existed = existsSync(targetFile)
339+
existed = fs.existsSync(targetFile)
312340
}
313341

314342
if (!existed) {
315-
rmSync(join(tmpRoot, 'tsconfig.json'))
343+
fs.rmSync(join(tmpRoot, 'tsconfig.json'))
316344

317345
console.warn(
318346
'[@elysiajs/openapi/gen] Failed to generate OpenAPI schema'
319347
)
320348
console.warn("Couldn't find generated declaration file")
321349

322-
if (existsSync(join(tmpRoot, 'dist'))) {
323-
const tempFiles = readdirSync(join(tmpRoot, 'dist'), {
324-
recursive: true
325-
})
350+
if (fs.existsSync(join(tmpRoot, 'dist'))) {
351+
const tempFiles = fs
352+
.readdirSync(join(tmpRoot, 'dist'), {
353+
recursive: true
354+
})
326355
.filter((x) => x.toString().endsWith('.d.ts'))
327356
.map((x) => `- ${x}`)
328357
.join('\n')
@@ -344,11 +373,11 @@ export const fromTypes =
344373
}
345374
}
346375

347-
const declaration = readFileSync(targetFile, 'utf8')
376+
const declaration = fs.readFileSync(targetFile, 'utf8')
348377

349378
// Check just in case of race-condition
350-
if (!debug && existsSync(tmpRoot))
351-
rmSync(tmpRoot, { recursive: true, force: true })
379+
if (!debug && fs.existsSync(tmpRoot))
380+
fs.rmSync(tmpRoot, { recursive: true, force: true })
352381

353382
let instance = declaration.match(
354383
instanceName
@@ -381,7 +410,7 @@ export const fromTypes =
381410

382411
return
383412
} finally {
384-
if (!debug && existsSync(tmpRoot))
385-
rmSync(tmpRoot, { recursive: true, force: true })
413+
if (!debug && tmpRoot && fs.existsSync(tmpRoot))
414+
fs.rmSync(tmpRoot, { recursive: true, force: true })
386415
}
387416
}

src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,7 @@ export const openapi = <
131131
return app
132132
}
133133

134+
export { fromTypes } from './gen'
134135
export { toOpenAPISchema, withHeaders } from './openapi'
135136
export type { ElysiaOpenAPIConfig }
136137

0 commit comments

Comments
 (0)