Skip to content

Commit 9ae7af1

Browse files
committed
feat: use oxc to generate dts
1 parent 695d4d9 commit 9ae7af1

File tree

5 files changed

+168
-214
lines changed

5 files changed

+168
-214
lines changed

README.md

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,13 @@
88
[![npm downloads][npm-downloads-src]][npm-downloads-href]
99
<!-- [![Codecov][codecov-src]][codecov-href] -->
1010

11-
This Bun plugin generates dts files for your TypeScript project.
11+
This Bun plugin generates dts files for your TypeScript projects.
1212

1313
## Features
1414

15-
- Automatic dts generation based on your entrypoints
16-
- Honors & inherits your `tsconfig.json` settings
15+
- Automatic & fast dts generation
16+
- Powered by oxc-transform & isolatedDeclarations
1717
- Monorepo support
18-
- Dependency-free _(aside from TS & Bun)_
1918

2019
## Usage
2120

@@ -39,19 +38,16 @@ await Bun.build({
3938

4039
plugins: [
4140
dts({
42-
cwd: import.meta.dir, // optional
43-
rootDir: `${import.meta.dir}/src`, // optional
44-
outdir: 'dist/types', // optional
41+
cwd: process.cwd(), // optional
42+
root: `./src`, // optional, default: './src'
43+
outdir: './dist/types', // optional, default: './dist'
4544
}),
4645
],
4746
})
4847

4948
console.log('Build complete ✅')
5049
```
5150

52-
> [!NOTE]
53-
> Please note, this plugin honors your `tsconfig.json` `compilerOptions.outDir` setting. If you want to override this, you can do so by setting the `outdir`, `rootDir`, and `cwd` option in the build object.
54-
5551
## Testing
5652

5753
```bash
@@ -93,6 +89,7 @@ We would like to extend our thanks to the following sponsors for funding Stacks
9389

9490
Many thanks to the following core technologies & people who have contributed to this package:
9591

92+
- [Oxc](https://oxc.rs/)
9693
- [Chris Breuer](https://github.com/chrisbbreuer)
9794
- [All Contributors](../../contributors)
9895

build.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ const result = await Bun.build({
77
entrypoints: ['src/index.ts'],
88
outdir: 'dist',
99
target: 'bun',
10-
1110
plugins: [dts()],
1211
})
1312

package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
},
1616
"keywords": [
1717
"dts",
18+
"oxc",
1819
"generation",
1920
"typescript",
2021
"types",
@@ -57,6 +58,7 @@
5758
"changelogen": "^0.5.7",
5859
"commitizen": "^4.3.1",
5960
"cz-git": "^1.9.4",
61+
"oxc-transform": "^0.30.5",
6062
"lint-staged": "^15.2.10",
6163
"simple-git-hooks": "^2.11.1",
6264
"typescript": "^5.6.2"

src/index.ts

Lines changed: 43 additions & 148 deletions
Original file line numberDiff line numberDiff line change
@@ -1,158 +1,56 @@
11
import fs from 'node:fs'
22
import p from 'node:path'
3-
import process from 'node:process'
3+
import path from 'node:path'
44
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-
}
5+
import { isolatedDeclaration } from 'oxc-transform'
176

187
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-
*/
428
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-
*/
499
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'
55-
*/
56-
outdir?: ts.CompilerOptions['outDir'] // sadly, the bundler uses `outdir` instead of `outDir` and to avoid confusion, we'll use `outdir` here
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[]
10+
outdir?: string
11+
// sourcemap?: boolean
6312
}
6413

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-
*/
7014
export async function generate(entryPoints: string | string[], options?: DtsOptions): Promise<void> {
71-
const cwd = options?.cwd ?? process.cwd()
72-
const configPath = options?.tsconfigPath ? p.resolve(cwd, options.tsconfigPath) : p.resolve(cwd, 'tsconfig.json')
73-
const root = p.resolve(cwd, (options?.root ?? 'src').replace(/^\.\//, ''))
74-
const outDir = p.resolve(cwd, options?.outdir ?? './dist')
75-
76-
// console.log('TSConfig path:', configPath)
77-
// console.log('Root directory:', root)
78-
// console.log('Output directory:', outDir)
79-
// console.log('Entry points:', entryPoints)
80-
81-
try {
82-
const configFile = ts.readConfigFile(configPath, ts.sys.readFile)
83-
if (configFile.error) {
84-
throw new Error(`Failed to read tsconfig: ${configFile.error.messageText}`)
85-
}
86-
87-
const parsedCommandLine = ts.parseJsonConfigFileContent(configFile.config, ts.sys, cwd)
88-
89-
if (parsedCommandLine.errors.length) {
90-
throw new Error(`Failed to parse tsconfig: ${parsedCommandLine.errors.map((e) => e.messageText).join(', ')}`)
91-
}
92-
93-
const compilerOptions: ts.CompilerOptions = {
94-
...parsedCommandLine.options,
95-
...options?.compiler,
96-
rootDir: root,
97-
outDir,
98-
declaration: true,
99-
emitDeclarationOnly: true,
100-
noEmit: false,
101-
skipLibCheck: true,
102-
isolatedModules: true,
103-
}
104-
105-
// console.log('Compiler Options:', JSON.stringify(compilerOptions, null, 2))
106-
107-
const host = ts.createCompilerHost(compilerOptions)
108-
109-
// Ensure entryPoints is an array and resolve to absolute paths
110-
const entryPointsArray = (Array.isArray(entryPoints) ? entryPoints : [entryPoints]).map((entry) =>
111-
p.resolve(cwd, entry),
112-
)
113-
114-
// Use only the entry points that are within the root directory
115-
const validEntryPoints = entryPointsArray.filter((entry) => entry.startsWith(root))
116-
117-
if (validEntryPoints.length === 0) {
118-
throw new Error('No valid entry points found within the specified root directory')
119-
}
15+
// console.log('Generate function called with:')
16+
// console.log('EntryPoints:', entryPoints)
17+
// console.log('Options:', options)
12018

121-
const program = ts.createProgram(validEntryPoints, compilerOptions, host)
122-
123-
const emitResult = program.emit(undefined, (fileName, data) => {
124-
if (fileName.endsWith('.d.ts') || fileName.endsWith('.d.ts.map')) {
125-
const outputPath = p.join(outDir, p.relative(root, fileName))
126-
const dir = p.dirname(outputPath)
127-
if (!fs.existsSync(dir)) {
128-
fs.mkdirSync(dir, { recursive: true })
129-
}
130-
fs.writeFileSync(outputPath, data)
131-
// console.log('Emitted:', outputPath)
132-
}
133-
})
134-
135-
const allDiagnostics = ts.getPreEmitDiagnostics(program).concat(emitResult.diagnostics)
136-
137-
if (allDiagnostics.length) {
138-
const formatHost: ts.FormatDiagnosticsHost = {
139-
getCanonicalFileName: (path) => path,
140-
getCurrentDirectory: ts.sys.getCurrentDirectory,
141-
getNewLine: () => ts.sys.newLine,
142-
}
143-
const message = ts.formatDiagnosticsWithColorAndContext(allDiagnostics, formatHost)
144-
console.error(message)
145-
}
146-
147-
if (emitResult.emitSkipped) {
148-
throw new Error('TypeScript compilation failed')
19+
const files = Array.isArray(entryPoints) ? entryPoints : [entryPoints]
20+
const cwd = options?.cwd ?? process.cwd()
21+
const root = options?.root ?? 'src'
22+
const outdir = options?.outdir ?? './dist/'
23+
24+
// console.log('Resolved options:')
25+
// console.log('CWD:', cwd)
26+
// console.log('Root:', root)
27+
// console.log('Outdir:', outdir)
28+
29+
for (const file of files) {
30+
const fullPath = path.join(cwd, file)
31+
// console.log(`Processing file: ${fullPath}`)
32+
33+
if (fs.existsSync(fullPath)) {
34+
const ts = fs.readFileSync(fullPath, 'utf-8')
35+
const dts = isolatedDeclaration(fullPath, ts, { sourcemap: false })
36+
const code = dts.code
37+
const relativePath = path.relative(path.join(cwd, root), fullPath)
38+
const outputPath = path.join(cwd, outdir, relativePath.replace(/\.ts$/, '.d.ts'))
39+
// console.log(`Writing declaration file: ${outputPath}`)
40+
write(outputPath, code)
41+
} else {
42+
console.warn(`File not found: ${fullPath}`)
14943
}
150-
} catch (error) {
151-
console.error('Error generating types:', error)
152-
throw error
15344
}
15445
}
15546

47+
function write(file: string, content: string) {
48+
const dir = path.dirname(file)
49+
fs.mkdirSync(dir, { recursive: true })
50+
fs.writeFileSync(file, content)
51+
// console.log(`File written: ${file}`)
52+
}
53+
15654
/**
15755
* A Bun plugin to generate declaration files for the TypeScript source files.
15856
* @param options The options for generating the declaration files.
@@ -164,17 +62,14 @@ export function dts(options?: DtsOptions): BunPlugin {
16462
async setup(build) {
16563
const entrypoints = [...build.config.entrypoints].sort()
16664
const root = options?.root ?? build.config.root ?? 'src'
65+
const outdir = options?.outdir ?? './dist/'
66+
const cwd = options?.cwd ?? process.cwd()
16767

16868
await generate(entrypoints, {
69+
...options,
16970
root,
170-
include: entrypoints, // Use only the entrypoints from build.ts
171-
cwd: options?.cwd || process.cwd(),
172-
tsconfigPath: options?.tsconfigPath,
173-
outdir: options?.outdir || build.config.outdir,
174-
compiler: {
175-
...options?.compiler,
176-
paths: undefined, // Remove the paths option to avoid generating extra dts files
177-
},
71+
outdir,
72+
cwd,
17873
})
17974
},
18075
}

0 commit comments

Comments
 (0)