Skip to content

Commit f55cf5c

Browse files
committed
🎉 feat(type generator): accept .d.ts to prevent type generation in production
1 parent 2f149ff commit f55cf5c

File tree

5 files changed

+220
-102
lines changed

5 files changed

+220
-102
lines changed

CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,10 @@
1+
# 1.3.10 - 5 Sep 2025
2+
Feature:
3+
- type generator: accept `.d.ts` to prevent type generation in production
4+
5+
Bug fix:
6+
- type generator: loose path generated file mapping
7+
18
# 1.3.9 - 4 Sep 2025
29
Bug fix:
310
- type generator: loose path generated file mapping

example/gen.d.ts

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
import { Elysia } from 'elysia';
2+
export declare const app: Elysia<"", {
3+
decorator: {};
4+
store: {};
5+
derive: {};
6+
resolve: {};
7+
}, {
8+
typebox: {};
9+
error: {};
10+
}, {
11+
schema: {};
12+
standaloneSchema: {};
13+
macro: {};
14+
macroFn: {};
15+
parser: {};
16+
}, {
17+
get: {
18+
body: unknown;
19+
params: {};
20+
query: unknown;
21+
headers: unknown;
22+
response: {
23+
200: {
24+
test: "hello";
25+
} | undefined;
26+
readonly 204: unknown;
27+
422: {
28+
type: "validation";
29+
on: string;
30+
summary?: string;
31+
message?: string;
32+
found?: unknown;
33+
property?: string;
34+
expected?: string;
35+
};
36+
};
37+
};
38+
} & {
39+
json: {
40+
post: {
41+
body: {
42+
hello: string;
43+
};
44+
params: {};
45+
query: unknown;
46+
headers: unknown;
47+
response: {
48+
200: {
49+
hello: string;
50+
};
51+
418: "I'm a teapot";
52+
422: {
53+
type: "validation";
54+
on: string;
55+
summary?: string; message?: string;
56+
found?: unknown;
57+
property?: string;
58+
expected?: string;
59+
};
60+
};
61+
};
62+
};
63+
} & {
64+
id: {
65+
":id": {
66+
name: {
67+
":name": {
68+
get: {
69+
body: unknown;
70+
params: {
71+
name: string;
72+
id: string;
73+
};
74+
query: unknown;
75+
headers: unknown;
76+
response: {
77+
200: {
78+
name: string;
79+
id: string;
80+
};
81+
422: {
82+
type: "validation";
83+
on: string;
84+
summary?: string;
85+
message?: string;
86+
found?: unknown;
87+
property?: string;
88+
expected?: string;
89+
};
90+
};
91+
};
92+
};
93+
};
94+
};
95+
};
96+
}, {
97+
derive: {};
98+
resolve: {};
99+
schema: {};
100+
standaloneSchema: {};
101+
}, {
102+
derive: {};
103+
resolve: {};
104+
schema: {};
105+
standaloneSchema: {};
106+
}>;

example/gen.ts

Lines changed: 12 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,8 @@ import { fromTypes } from '../src/gen'
55
export const app = new Elysia()
66
.use(
77
openapi({
8-
references: fromTypes('gen.ts', {
9-
projectRoot: import.meta.dirname,
10-
overrideOutputPath: 'example/gen.d.ts'
11-
// debug: true
8+
references: fromTypes('example/gen.d.ts', {
9+
debug: true
1210
})
1311
})
1412
)
@@ -32,14 +30,14 @@ export const app = new Elysia()
3230
}
3331
}
3432
)
35-
// .post(
36-
// '/json',
37-
// ({ body, status }) => (Math.random() > 0.5 ? status(418) : body),
38-
// {
39-
// body: t.Object({
40-
// hello: t.String()
41-
// })
42-
// }
43-
// )
44-
// .get('/id/:id/name/:name', ({ params }) => params)
33+
.post(
34+
'/json',
35+
({ body, status }) => (Math.random() > 0.5 ? status(418) : body),
36+
{
37+
body: t.Object({
38+
hello: t.String()
39+
})
40+
}
41+
)
42+
.get('/id/:id/name/:name', ({ params }) => params)
4543
.listen(3000)

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.3.9",
3+
"version": "1.3.10",
44
"description": "Plugin for Elysia to auto-generate API documentation",
55
"author": {
66
"name": "saltyAom",

src/gen/index.ts

Lines changed: 94 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -105,101 +105,108 @@ export const fromTypes =
105105
`Couldn't find "${targetFilePath}" from ${projectRoot}`
106106
)
107107

108-
if (existsSync(tmpRoot))
109-
rmSync(tmpRoot, { recursive: true, force: true })
110-
111-
mkdirSync(tmpRoot, { recursive: true })
112-
113-
const tsconfig = tsconfigPath.startsWith('/')
114-
? tsconfigPath
115-
: join(projectRoot, tsconfigPath)
116-
117-
const extendsRef = existsSync(tsconfig)
118-
? `"extends": "${join(projectRoot, 'tsconfig.json')}",`
119-
: ''
120-
121-
writeFileSync(
122-
join(tmpRoot, 'tsconfig.json'),
123-
`{
124-
${extendsRef}
125-
"compilerOptions": {
126-
"lib": ["ESNext"],
127-
"module": "ESNext",
128-
"noEmit": false,
129-
"declaration": true,
130-
"emitDeclarationOnly": true,
131-
"moduleResolution": "bundler",
132-
"skipLibCheck": true,
133-
"skipDefaultLibCheck": true,
134-
"outDir": "./dist"
135-
},
136-
"include": ["${src}"]
137-
}`
138-
)
139-
140-
spawnSync(`tsc`, {
141-
shell: true,
142-
cwd: tmpRoot,
143-
stdio: debug ? 'inherit' : undefined
144-
})
145-
146-
const fileName = targetFilePath
147-
.replace(/.tsx$/, '.ts')
148-
.replace(/.ts$/, '.d.ts')
149-
150-
let targetFile =
151-
(overrideOutputPath
152-
? typeof overrideOutputPath === 'string'
153-
? overrideOutputPath.startsWith('/')
154-
? overrideOutputPath
155-
: join(tmpRoot, 'dist', overrideOutputPath)
156-
: overrideOutputPath(tmpRoot)
157-
: undefined) ??
158-
join(
159-
tmpRoot,
160-
'dist',
161-
// remove leading like src or something similar
162-
fileName.slice(fileName.indexOf('/') + 1)
108+
let targetFile: string
109+
110+
// Since it's already a declaration file
111+
// We can just read it directly
112+
if (targetFilePath.endsWith('.d.ts')) targetFile = targetFilePath
113+
else {
114+
if (existsSync(tmpRoot))
115+
rmSync(tmpRoot, { recursive: true, force: true })
116+
117+
mkdirSync(tmpRoot, { recursive: true })
118+
119+
const tsconfig = tsconfigPath.startsWith('/')
120+
? tsconfigPath
121+
: join(projectRoot, tsconfigPath)
122+
123+
const extendsRef = existsSync(tsconfig)
124+
? `"extends": "${join(projectRoot, 'tsconfig.json')}",`
125+
: ''
126+
127+
writeFileSync(
128+
join(tmpRoot, 'tsconfig.json'),
129+
`{
130+
${extendsRef}
131+
"compilerOptions": {
132+
"lib": ["ESNext"],
133+
"module": "ESNext",
134+
"noEmit": false,
135+
"declaration": true,
136+
"emitDeclarationOnly": true,
137+
"moduleResolution": "bundler",
138+
"skipLibCheck": true,
139+
"skipDefaultLibCheck": true,
140+
"outDir": "./dist"
141+
},
142+
"include": ["${src}"]
143+
}`
163144
)
164145

165-
let existed = existsSync(targetFile)
146+
spawnSync(`tsc`, {
147+
shell: true,
148+
cwd: tmpRoot,
149+
stdio: debug ? 'inherit' : undefined
150+
})
151+
152+
const fileName = targetFilePath
153+
.replace(/.tsx$/, '.ts')
154+
.replace(/.ts$/, '.d.ts')
155+
156+
targetFile =
157+
(overrideOutputPath
158+
? typeof overrideOutputPath === 'string'
159+
? overrideOutputPath.startsWith('/')
160+
? overrideOutputPath
161+
: join(tmpRoot, 'dist', overrideOutputPath)
162+
: overrideOutputPath(tmpRoot)
163+
: undefined) ??
164+
join(
165+
tmpRoot,
166+
'dist',
167+
// remove leading like src or something similar
168+
fileName.slice(fileName.indexOf('/') + 1)
169+
)
166170

167-
if (!existed && overrideOutputPath) {
168-
targetFile = join(
169-
tmpRoot,
170-
'dist',
171-
// use original file name as-is eg. in monorepo
172-
fileName
173-
)
171+
let existed = existsSync(targetFile)
174172

175-
existed = existsSync(targetFile)
176-
}
173+
if (!existed && !overrideOutputPath) {
174+
targetFile = join(
175+
tmpRoot,
176+
'dist',
177+
// use original file name as-is eg. in monorepo
178+
fileName
179+
)
180+
181+
existed = existsSync(targetFile)
182+
}
177183

178-
if (!existed) {
179-
rmSync(join(tmpRoot, 'tsconfig.json'))
184+
if (!existed) {
185+
rmSync(join(tmpRoot, 'tsconfig.json'))
180186

181-
console.warn(
182-
'[@elysiajs/openapi/gen] Failed to generate OpenAPI schema'
183-
)
184-
console.warn("Couldn't find generated declaration file")
185-
186-
if (existsSync(join(tmpRoot, 'dist'))) {
187-
const tempFiles = readdirSync(join(tmpRoot, 'dist'), {
188-
recursive: true
189-
})
190-
.filter((x) => x.toString().endsWith('.d.ts'))
191-
.map((x) => `- ${x}`)
192-
.join('\n')
193-
194-
if (tempFiles) {
195-
console.warn(
196-
'You can override with `overrideOutputPath` with one of the following:'
197-
)
198-
console.warn(tempFiles)
187+
console.warn(
188+
'[@elysiajs/openapi/gen] Failed to generate OpenAPI schema'
189+
)
190+
console.warn("Couldn't find generated declaration file")
191+
192+
if (existsSync(join(tmpRoot, 'dist'))) {
193+
const tempFiles = readdirSync(join(tmpRoot, 'dist'), {
194+
recursive: true
195+
})
196+
.filter((x) => x.toString().endsWith('.d.ts'))
197+
.map((x) => `- ${x}`)
198+
.join('\n')
199+
200+
if (tempFiles) {
201+
console.warn(
202+
'You can override with `overrideOutputPath` with one of the following:'
203+
)
204+
console.warn(tempFiles)
205+
}
199206
}
200-
}
201207

202-
return
208+
return
209+
}
203210
}
204211

205212
const declaration = readFileSync(targetFile, 'utf8')

0 commit comments

Comments
 (0)