1
1
import type { Loader , PluginBuilder } from 'bun'
2
2
import type { AutoImportsOptions , AutoImportsPlugin , ESLintOptions } from './types'
3
+ import { Glob } from 'bun'
3
4
import { generateESLintGlobals } from './eslint'
4
5
5
6
function getLoader ( path : string ) : string {
@@ -14,18 +15,94 @@ function getLoader(path: string): string {
14
15
15
16
export const GENERATED_COMMENT = '// Generated by bun-plugin-auto-imports\n'
16
17
18
+ async function scanDirExports ( dir : string ) : Promise < string [ ] > {
19
+ const exports : Set < string > = new Set ( )
20
+
21
+ // Create glob for TypeScript/JavaScript files
22
+ const glob = new Glob ( '**/*.{ts,tsx,js,jsx}' )
23
+
24
+ // Scan the directory for matching files
25
+ for await ( const file of glob . scan ( {
26
+ cwd : dir ,
27
+ absolute : true ,
28
+ onlyFiles : true ,
29
+ followSymlinks : false ,
30
+ } ) ) {
31
+ // Skip definition files and node_modules
32
+ if ( file . includes ( 'node_modules' ) || file . endsWith ( '.d.ts' ) ) {
33
+ continue
34
+ }
35
+
36
+ const content = await Bun . file ( file ) . text ( )
37
+
38
+ // Match export declarations
39
+ const exportMatches = [
40
+ // Named exports
41
+ ...content . matchAll ( / e x p o r t \s + (?: c o n s t | l e t | v a r | f u n c t i o n | c l a s s | t y p e | i n t e r f a c e ) \s + ( [ a - z A - Z _ $ ] [ \w $ ] * ) / g) ,
42
+ // Export statements
43
+ ...content . matchAll ( / e x p o r t \s + \{ ( [ ^ } ] + ) \} / g) ,
44
+ // Default exports
45
+ ...content . matchAll ( / e x p o r t \s + d e f a u l t \s + (?: (?: f u n c t i o n | c l a s s ) \s * ) ? ( [ a - z A - Z _ $ ] [ \w $ ] * ) / g) ,
46
+ ]
47
+
48
+ for ( const match of exportMatches ) {
49
+ if ( match [ 1 ] ) {
50
+ // Handle multiple exports in a single statement
51
+ const names = match [ 1 ] . split ( ',' ) . map ( name =>
52
+ name . trim ( )
53
+ . replace ( / \s + a s \s + (?: \S .* ) ? $ / , '' ) // Remove "as" aliases
54
+ . replace ( / ^ .* (?: [ \n \r \u2028 \u2029 ] \s * | [ \t \v \f \xA0 \u1680 \u2000 - \u200A \u202F \u205F \u3000 \uFEFF ] ) a s \s + / , '' ) , // Handle "originalName as exportName"
55
+ )
56
+ names . forEach ( name => exports . add ( name ) )
57
+ }
58
+ }
59
+ }
60
+
61
+ return Array . from ( exports )
62
+ }
63
+
17
64
export function autoImports ( options : Partial < AutoImportsOptions > ) : AutoImportsPlugin {
18
65
return {
19
66
name : 'bun-plugin-auto-imports' ,
20
67
21
68
async setup ( builder : PluginBuilder ) : Promise < void > {
69
+ // console.log('Auto-imports plugin setup', options)
22
70
const { createUnimport } = await import ( 'unimport' )
23
- const { injectImports, generateTypeDeclarations } = createUnimport ( {
71
+
72
+ // Scan directories for exports
73
+ const dirExports : Record < string , string [ ] > = { }
74
+ if ( options . dirs ) {
75
+ for ( const dir of options . dirs ) {
76
+ const dirPath = typeof dir === 'string' ? dir : ( 'path' in dir ? dir . path : dir )
77
+ // console.log('Scanning directory:', dirPath)
78
+ dirExports [ dirPath ] = await scanDirExports ( dirPath )
79
+ // console.log('Found exports:', dirExports[dirPath])
80
+ }
81
+ }
82
+
83
+ // Convert scanned exports to unimport format
84
+ const scannedImports = Object . entries ( dirExports ) . flatMap ( ( [ dir , exports ] ) =>
85
+ exports . map ( name => ( {
86
+ from : dir ,
87
+ name,
88
+ as : name ,
89
+ } ) ) ,
90
+ )
91
+
92
+ const unimport = createUnimport ( {
24
93
...options ,
94
+ imports : [
95
+ ...( options . imports || [ ] ) ,
96
+ ...scannedImports ,
97
+ ] ,
25
98
dts : undefined ,
26
99
} as AutoImportsOptions )
27
100
28
- const dtsContent = await generateTypeDeclarations ( )
101
+ const { injectImports } = unimport
102
+
103
+ // Generate types declarations
104
+ const dtsContent = await unimport . generateTypeDeclarations ( )
105
+
29
106
// Add generated comment to d.ts file
30
107
await Bun . write (
31
108
options . dts ?? './auto-imports.d.ts' ,
@@ -40,7 +117,7 @@ export function autoImports(options: Partial<AutoImportsOptions>): AutoImportsPl
40
117
}
41
118
42
119
const eslintContent = generateESLintGlobals ( dtsContent , eslintOptions )
43
- await Bun . write ( eslintOptions . filepath ?? './auto-imports.d.ts ' , eslintContent )
120
+ await Bun . write ( eslintOptions . filepath ?? './.eslint- auto-import.json ' , eslintContent )
44
121
}
45
122
46
123
builder . onLoad ( { filter : / .* / } , async ( args ) => {
0 commit comments