Skip to content

Commit 116cac0

Browse files
committed
chore: wip
1 parent 69afa2d commit 116cac0

File tree

2 files changed

+187
-1
lines changed

2 files changed

+187
-1
lines changed

storage/framework/core/cli/build.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
import { dts } from 'bun-plugin-dts-auto'
21
import { intro, outro } from '../build/src'
2+
import { dts } from './dts'
33

44
const { startTime } = await intro({
55
dir: import.meta.dir,

storage/framework/core/cli/dts.ts

Lines changed: 186 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,186 @@
1+
import fs from 'node:fs'
2+
import p from 'node:path'
3+
import process from 'node:process'
4+
import type { BunPlugin } from 'bun'
5+
import ts from 'typescript'
6+
7+
export interface TsOptions {
8+
rootDir: string
9+
base: string
10+
declaration: boolean
11+
emitDeclarationOnly: boolean
12+
noEmit: boolean
13+
declarationMap?: boolean
14+
outDir?: ts.CompilerOptions['outDir']
15+
[index: string]: any
16+
}
17+
18+
export interface DtsOptions {
19+
/**
20+
* The base directory of the source files. If not provided, it
21+
* will use the current working directory of the process.
22+
* @default process.cwd()
23+
*/
24+
base?: string
25+
26+
/**
27+
* The TypeScript compiler options. If not provided, it will use
28+
* the `tsconfig.json` file in the current working directory.
29+
*/
30+
compiler?: ts.CompilerOptions
31+
32+
/**
33+
* The path to the `tsconfig.json` file. If not provided, it will
34+
* use the `tsconfig.json` file in the current working directory.
35+
*/
36+
tsconfigPath?: string
37+
38+
/**
39+
* The current working directory. If not provided, it will
40+
* use the current working directory of the process.
41+
*/
42+
cwd?: string
43+
44+
/**
45+
* The root directory of the source files. Please note,
46+
* it is relative to the current working directory.
47+
* @default 'src'
48+
*/
49+
root?: string
50+
51+
/**
52+
* The output directory of the declaration files. Please note,
53+
* it is relative to the current working directory.
54+
* @default 'dist/types'
55+
*/
56+
outdir?: ts.CompilerOptions['outDir']
57+
58+
/**
59+
* The files to include. If not provided, it will include all files in the
60+
* `tsconfig.json` file, or the Bun build entry points if provided.
61+
*/
62+
include?: string[]
63+
}
64+
65+
/**
66+
* Generate declaration files for the TypeScript source files.
67+
* @param entryPoints The entry points of the TypeScript source files.
68+
* @param options The options for generating the declaration files.
69+
*/
70+
export async function generate(entryPoints: string | string[], options?: DtsOptions): Promise<void> {
71+
const path = p.resolve(options?.tsconfigPath ?? 'tsconfig.json')
72+
const root = (options?.root ?? 'src').replace(/^\.\//, '')
73+
74+
try {
75+
const configFile = ts.readConfigFile(path, ts.sys.readFile)
76+
if (configFile.error) {
77+
throw new Error(`Failed to read tsconfig: ${configFile.error.messageText}`)
78+
}
79+
80+
const cwd = options?.cwd ?? process.cwd()
81+
const base = options?.base ?? cwd
82+
const rootDir = p.resolve(cwd, root)
83+
84+
const parsedCommandLine = ts.parseJsonConfigFileContent(configFile.config, ts.sys, cwd)
85+
if (parsedCommandLine.errors.length) {
86+
throw new Error(`Failed to parse tsconfig: ${parsedCommandLine.errors.map((e) => e.messageText).join(', ')}`)
87+
}
88+
89+
const outDir = p.resolve(cwd, options?.outdir || parsedCommandLine.options.outDir || 'dist')
90+
91+
const compilerOptions: ts.CompilerOptions = {
92+
...parsedCommandLine.options,
93+
...options?.compiler,
94+
declaration: true,
95+
emitDeclarationOnly: true,
96+
noEmit: false,
97+
declarationMap: true,
98+
outDir: outDir,
99+
rootDir: rootDir,
100+
incremental: false, // Disable incremental compilation
101+
}
102+
103+
const filteredEntryPoints = (Array.isArray(entryPoints) ? entryPoints : [entryPoints]).filter((entryPoint) => {
104+
const relativePath = p.relative(rootDir, entryPoint)
105+
return !relativePath.startsWith('..') && !p.isAbsolute(relativePath)
106+
})
107+
108+
if (filteredEntryPoints.length === 0) {
109+
console.warn('No valid entry points found within the src directory.')
110+
return
111+
}
112+
113+
const host = ts.createCompilerHost(compilerOptions)
114+
115+
const customHost: ts.CompilerHost = {
116+
...host,
117+
getSourceFile: (fileName, languageVersion, onError, shouldCreateNewSourceFile) => {
118+
if (!fileName.startsWith(rootDir)) {
119+
return undefined
120+
}
121+
return host.getSourceFile(fileName, languageVersion, onError, shouldCreateNewSourceFile)
122+
},
123+
}
124+
125+
const program = ts.createProgram({
126+
rootNames: filteredEntryPoints,
127+
options: compilerOptions,
128+
host: customHost,
129+
})
130+
131+
const emitResult = program.emit(undefined, (fileName, data) => {
132+
if ((fileName.endsWith('.d.ts') || fileName.endsWith('.d.ts.map')) && fileName.startsWith(rootDir)) {
133+
const outputPath = p.join(outDir, p.relative(rootDir, fileName))
134+
const dir = p.dirname(outputPath)
135+
if (!fs.existsSync(dir)) {
136+
fs.mkdirSync(dir, { recursive: true })
137+
}
138+
fs.writeFileSync(outputPath, data)
139+
}
140+
})
141+
142+
const allDiagnostics = ts.getPreEmitDiagnostics(program).concat(emitResult.diagnostics)
143+
144+
if (allDiagnostics.length) {
145+
const formatHost: ts.FormatDiagnosticsHost = {
146+
getCanonicalFileName: (path) => path,
147+
getCurrentDirectory: ts.sys.getCurrentDirectory,
148+
getNewLine: () => ts.sys.newLine,
149+
}
150+
const message = ts.formatDiagnosticsWithColorAndContext(allDiagnostics, formatHost)
151+
console.error(message)
152+
}
153+
154+
if (emitResult.emitSkipped) {
155+
throw new Error('TypeScript compilation failed')
156+
}
157+
} catch (error) {
158+
console.error('Error generating types:', error)
159+
throw error
160+
}
161+
}
162+
163+
/**
164+
* A Bun plugin to generate declaration files for the TypeScript source files.
165+
* @param options The options for generating the declaration files.
166+
*/
167+
export function dts(options?: DtsOptions): BunPlugin {
168+
return {
169+
name: 'bun-plugin-dts-auto',
170+
171+
async setup(build) {
172+
const entrypoints = [...build.config.entrypoints].sort()
173+
const root = options?.root ?? build.config.root ?? 'src'
174+
175+
await generate(entrypoints, {
176+
root,
177+
include: entrypoints,
178+
outdir: options?.outdir || build.config.outdir,
179+
cwd: options?.cwd || process.cwd(),
180+
...options,
181+
})
182+
},
183+
}
184+
}
185+
186+
export default dts

0 commit comments

Comments
 (0)