Skip to content

Commit

Permalink
feat: add files option
Browse files Browse the repository at this point in the history
  • Loading branch information
chrisbbreuer committed Oct 7, 2024
1 parent ce9a9b7 commit 9987588
Show file tree
Hide file tree
Showing 4 changed files with 71 additions and 71 deletions.
12 changes: 11 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,15 +38,25 @@ await Bun.build({
plugins: [
dts({
cwd: process.cwd(), // optional
root: `./src`, // optional, default: './src'
root: './src', // optional, default: 'src'
outdir: './dist/types', // optional, default: './dist'
files: ['src/index.ts'], // optional, if not specified, all .ts files in root will be processed
}),
],
})

console.log('Build complete ✅')
```

## API

The `dts` plugin accepts an options object with the following properties:

- `cwd`: The current working directory _(optional, default: `process.cwd()`)_
- `root`: The root directory of your TypeScript files _(optional, default: `'src'`)_
- `outdir`: The output directory for generated declaration files _(optional, default: `'./dist'`)_
- `files`: An array of file paths or a single file path to process _(optional, if not specified, all `.ts` files in the root directory will be processed)_

## Testing

```bash
Expand Down
45 changes: 25 additions & 20 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,53 +8,58 @@ export async function generate(options?: DtsOptions): Promise<void> {
const cwd = options?.cwd ?? process.cwd()
const root = options?.root ?? 'src'
const outdir = options?.outdir ?? './dist/'
const files = options?.files

const glob = new Bun.Glob('**/*.ts')
const rootDir = path.join(cwd, root)

for await (const file of glob.scan({ cwd: rootDir, absolute: true })) {
// console.log(`Processing file: ${file}`)

if (fs.existsSync(file)) {
const ts = fs.readFileSync(file, 'utf-8')
const dts = isolatedDeclaration(file, ts, { sourcemap: false })
const code = dts.code
const relativePath = path.relative(rootDir, file)
const outputPath = path.join(cwd, outdir, relativePath.replace(/\.ts$/, '.d.ts'))
// console.log(`Writing declaration file: ${outputPath}`)
write(outputPath, code)
} else {
console.warn(`File not found: ${file}`)
if (files) {
const f = Array.isArray(files) ? files : [files]
for (const file of f) {
await processFile(path.join(cwd, file), rootDir, cwd, outdir)
}
} else {
const glob = new Bun.Glob('**/*.ts')
for await (const file of glob.scan({ cwd: rootDir, absolute: true })) {
await processFile(file, rootDir, cwd, outdir)
}
}
}

async function processFile(file: string, rootDir: string, cwd: string, outdir: string) {
if (fs.existsSync(file)) {
const ts = fs.readFileSync(file, 'utf-8')
const dts = isolatedDeclaration(file, ts, { sourcemap: false })
const code = dts.code
const relativePath = path.relative(rootDir, file)
const outputPath = path.join(cwd, outdir, relativePath.replace(/\.ts$/, '.d.ts'))
write(outputPath, code)
} else {
console.warn(`File not found: ${file}`)
}
}

function write(file: string, content: string) {
const dir = path.dirname(file)
fs.mkdirSync(dir, { recursive: true })
fs.writeFileSync(file, content)
// console.log(`File written: ${file}`)
}

/**
* A Bun plugin to generate declaration files for the TypeScript source files.
* @param options The options for generating the declaration files.
*/
export function dts(options?: DtsOptions): BunPlugin {
return {
name: 'bun-plugin-dts-auto',

async setup(build) {
// const entrypoints = [...build.config.entrypoints].sort()
const root = options?.root ?? build.config.root ?? './src/'
const outdir = options?.outdir ?? './dist/'
const cwd = options?.cwd ?? process.cwd()
const files = options?.files

await generate({
...options,
root,
outdir,
cwd,
files,
})
},
}
Expand Down
2 changes: 1 addition & 1 deletion src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@ export interface DtsOptions {
cwd?: string
root?: string
outdir?: string
files?: string | string[]
// sourcemap?: boolean
// entryPoints?: string | string[],
}
83 changes: 34 additions & 49 deletions test/dts-auto.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,11 @@ const outDir = path.join(tempDir, 'dist')

describe('bun-plugin-dts-auto', () => {
beforeAll(() => {
// console.log('Creating directories:')
// console.log(`tempDir: ${tempDir}`)
// console.log(`srcDir: ${srcDir}`)
// console.log(`outDir: ${outDir}`)

fs.mkdirSync(tempDir, { recursive: true })
fs.mkdirSync(srcDir, { recursive: true })
fs.mkdirSync(outDir, { recursive: true })

const sampleFile = path.join(srcDir, 'sample.ts')
// console.log(`Creating sample file: ${sampleFile}`)
fs.writeFileSync(
sampleFile,
`
Expand All @@ -37,44 +31,35 @@ describe('bun-plugin-dts-auto', () => {
})

afterAll(() => {
// console.log(`Cleaning up temporary directory: ${tempDir}`)
fs.rmSync(tempDir, { recursive: true, force: true })
})

it('should generate declaration files', async () => {
// console.log('Running: should generate declaration files')
const inputFile = 'src/sample.ts'
// console.log(`Input file: ${inputFile}`)
// console.log(`Generating with options: cwd=${tempDir}, root=src, outdir=dist`)

await generate(inputFile, {
await generate({
cwd: tempDir,
root: 'src',
outdir: 'dist',
files: inputFile,
})

const declarationFile = path.join(outDir, 'sample.d.ts')
// console.log(`Checking for declaration file: ${declarationFile}`)
// console.log(`File exists: ${fs.existsSync(declarationFile)}`)

expect(fs.existsSync(declarationFile)).toBe(true)

if (fs.existsSync(declarationFile)) {
const content = fs.readFileSync(declarationFile, 'utf-8')
// console.log('Declaration file content:')
// console.log(content)
expect(content).toContain('export interface User')
expect(content).toContain('export declare function greet(user: User): string')
}
})

it('should handle multiple entry points', async () => {
it('should handle multiple files', async () => {
const inputFiles = ['src/sample1.ts', 'src/sample2.ts', 'src/sample3.ts']

// Create sample files
inputFiles.forEach((file, index) => {
const filePath = path.join(tempDir, file)
// console.log(`Creating file: ${filePath}`)
fs.writeFileSync(
filePath,
`
Expand All @@ -84,30 +69,25 @@ describe('bun-plugin-dts-auto', () => {
)
})

// console.log('Calling generate function')
await generate(inputFiles, {
await generate({
cwd: tempDir,
root: 'src',
outdir: 'dist',
files: inputFiles,
})

// console.log('Checking generated files')
inputFiles.forEach((file) => {
const declarationFile = path.join(tempDir, 'dist', file.replace(/^src\//, '').replace('.ts', '.d.ts'))
// console.log(`Checking file: ${declarationFile}`)
// console.log(`File exists: ${fs.existsSync(declarationFile)}`)
expect(fs.existsSync(declarationFile)).toBe(true)
if (fs.existsSync(declarationFile)) {
const content = fs.readFileSync(declarationFile, 'utf-8')
// console.log(`File content:\n${content}`)
expect(content).toContain('export declare const constant')
expect(content).toContain('export type MyType')
}
})
})

it('should work as a Bun plugin', async () => {
// console.log('Running: should work as a Bun plugin')
const plugin = dts({
cwd: tempDir,
root: path.relative(tempDir, srcDir),
Expand All @@ -131,31 +111,22 @@ describe('bun-plugin-dts-auto', () => {
},
}

// console.log('Setting up plugin with mock build')
// console.log('Mock build:', JSON.stringify(mockBuild, null, 2))
await plugin.setup(mockBuild)

const declarationFile = path.join(outDir, 'sample.d.ts')
// console.log(`Checking for declaration file: ${declarationFile}`)
// console.log(`File exists: ${fs.existsSync(declarationFile)}`)

expect(fs.existsSync(declarationFile)).toBe(true)

if (fs.existsSync(declarationFile)) {
const content = fs.readFileSync(declarationFile, 'utf-8')
// console.log('Declaration file content:')
// console.log(content)
expect(content).toContain('export interface User')
expect(content).toContain('export declare function greet(user: User): string')
}
})

it('should generate declaration files with correct references', async () => {
// console.log('Running: should generate declaration files with correct references')
const sampleFile1 = path.join(srcDir, 'sample1.ts')
const sampleFile2 = path.join(srcDir, 'sample2.ts')

// console.log(`Creating sample1.ts: ${sampleFile1}`)
fs.writeFileSync(
sampleFile1,
`
Expand All @@ -166,7 +137,6 @@ describe('bun-plugin-dts-auto', () => {
`,
)

// console.log(`Creating sample2.ts: ${sampleFile2}`)
fs.writeFileSync(
sampleFile2,
`
Expand All @@ -178,38 +148,53 @@ describe('bun-plugin-dts-auto', () => {
)

const inputFiles = [path.relative(tempDir, sampleFile1), path.relative(tempDir, sampleFile2)]
// console.log(
// `Generating with options: cwd=${tempDir}, root=${path.relative(tempDir, srcDir)}, outdir=${path.relative(tempDir, outDir)}`,
// )
await generate(inputFiles, {
await generate({
cwd: tempDir,
root: path.relative(tempDir, srcDir),
outdir: path.relative(tempDir, outDir),
files: inputFiles,
})

const declarationFile1 = path.join(outDir, 'sample1.d.ts')
const declarationFile2 = path.join(outDir, 'sample2.d.ts')

// console.log(`Checking for declaration file 1: ${declarationFile1}`)
// console.log(`File 1 exists: ${fs.existsSync(declarationFile1)}`)
// console.log(`Checking for declaration file 2: ${declarationFile2}`)
// console.log(`File 2 exists: ${fs.existsSync(declarationFile2)}`)

expect(fs.existsSync(declarationFile1)).toBe(true)
expect(fs.existsSync(declarationFile2)).toBe(true)

if (fs.existsSync(declarationFile1) && fs.existsSync(declarationFile2)) {
const content1 = fs.readFileSync(declarationFile1, 'utf-8')
const content2 = fs.readFileSync(declarationFile2, 'utf-8')

// console.log('Declaration file 1 content:')
// console.log(content1)
// console.log('Declaration file 2 content:')
// console.log(content2)

expect(content1).toContain('export interface User')
expect(content2).toContain('import { User } from "./sample1"')
expect(content2).toContain('export declare function greet(user: User): string')
}
})

it('should generate declaration files for all files in root when no files are specified', async () => {
// Create additional sample files
const additionalFiles = ['src/extra1.ts', 'src/extra2.ts']
additionalFiles.forEach((file, index) => {
const filePath = path.join(tempDir, file)
fs.writeFileSync(
filePath,
`
export const extraConstant${index + 1} = ${index + 1};
export type ExtraType${index + 1} = boolean | null;
`,
)
})

await generate({
cwd: tempDir,
root: 'src',
outdir: 'dist',
})

const allFiles = [...additionalFiles, 'src/sample.ts', 'src/sample1.ts', 'src/sample2.ts', 'src/sample3.ts']
allFiles.forEach((file) => {
const declarationFile = path.join(tempDir, 'dist', file.replace(/^src\//, '').replace('.ts', '.d.ts'))
expect(fs.existsSync(declarationFile)).toBe(true)
})
})
})

0 comments on commit 9987588

Please sign in to comment.