1
- import { dirname , isAbsolute , posix , relative , resolve , sep } from 'node:path'
2
- import { promises as fs } from 'node:fs'
1
+ import { dirname , isAbsolute , relative , resolve } from 'node:path'
2
+ import { existsSync , promises as fs } from 'node:fs'
3
3
import { slash , throttle , toArray } from '@antfu/utils'
4
4
import { createFilter } from '@rollup/pluginutils'
5
5
import { isPackageExists } from 'local-pkg'
@@ -9,14 +9,13 @@ import { createUnimport, resolvePreset, scanDirExports } from 'unimport'
9
9
import { vueTemplateAddon } from 'unimport/addons'
10
10
import MagicString from 'magic-string'
11
11
import { presets } from '../presets'
12
- import type { ESLintrc , ImportExtended , Options } from '../types'
12
+ import type { ESLintGlobalsPropValue , ESLintrc , ImportExtended , Options } from '../types'
13
13
import { generateESLintConfigs } from './eslintrc'
14
14
import { resolversAddon } from './resolvers'
15
15
16
16
export function createContext ( options : Options = { } , root = process . cwd ( ) ) {
17
17
const {
18
18
dts : preferDTS = isPackageExists ( 'typescript' ) ,
19
- cache : isCache = false ,
20
19
} = options
21
20
22
21
const dirs = options . dirs ?. map ( dir => resolve ( root , dir ) )
@@ -28,10 +27,6 @@ export function createContext(options: Options = {}, root = process.cwd()) {
28
27
29
28
const resolvers = options . resolvers ? [ options . resolvers ] . flat ( 2 ) : [ ]
30
29
31
- const cachePath = isCache === false
32
- ? false
33
- : resolve ( root , typeof isCache === 'string' ? isCache : 'node_modules/.cache/unplugin-auto-import.json' )
34
-
35
30
// When "options.injectAtEnd" is undefined or true, it's true.
36
31
const injectAtEnd = options . injectAtEnd !== false
37
32
@@ -79,10 +74,27 @@ ${dts}`.trim()}\n`
79
74
? resolve ( root , 'auto-imports.d.ts' )
80
75
: resolve ( root , preferDTS )
81
76
77
+ const multilineCommentsRE = / \/ \* .* ?\* \/ / gms
78
+ const singlelineCommentsRE = / \/ \/ .* $ / gm
79
+ const dtsReg = / d e c l a r e \s + g l o b a l \s * { ( .* ?) } / s
80
+ function parseDTS ( dts : string ) {
81
+ dts = dts
82
+ . replace ( multilineCommentsRE , '' )
83
+ . replace ( singlelineCommentsRE , '' )
84
+
85
+ const code = dts . match ( dtsReg ) ?. [ 0 ]
86
+ if ( ! code )
87
+ return
88
+
89
+ return Object . fromEntries ( Array . from ( code . matchAll ( / [ ' " ] ? ( c o n s t \s * [ ^ \s ' " ] + ) [ ' " ] ? \s * : \s * ( .+ ?) [ , ; \r \n ] / g) ) . map ( i => [ i [ 1 ] , i [ 2 ] ] ) )
90
+ }
91
+
82
92
async function generateDTS ( file : string ) {
83
93
await importsPromise
84
94
const dir = dirname ( file )
85
- return unimport . generateTypeDeclarations ( {
95
+ const originalContent = existsSync ( file ) ? await fs . readFile ( file , 'utf-8' ) : ''
96
+ const originalDTS = parseDTS ( originalContent )
97
+ const currentContent = await unimport . generateTypeDeclarations ( {
86
98
resolvePath : ( i ) => {
87
99
if ( i . from . startsWith ( '.' ) || isAbsolute ( i . from ) ) {
88
100
const related = slash ( relative ( dir , i . from ) . replace ( / \. t s ( x ) ? $ / , '' ) )
@@ -93,14 +105,29 @@ ${dts}`.trim()}\n`
93
105
return i . from
94
106
} ,
95
107
} )
108
+ const currentDTS = parseDTS ( currentContent ) !
109
+ if ( originalDTS ) {
110
+ Object . keys ( currentDTS ) . forEach ( ( key ) => {
111
+ originalDTS [ key ] = currentDTS [ key ]
112
+ } )
113
+ const dtsList = Object . keys ( originalDTS ) . sort ( ) . map ( k => ` ${ k } : ${ originalDTS [ k ] } ` )
114
+ return currentContent . replace ( dtsReg , `declare global {\n${ dtsList . join ( '\n' ) } \n}` )
115
+ }
116
+
117
+ return currentContent
118
+ }
119
+
120
+ async function parseESLint ( ) {
121
+ const configStr = existsSync ( eslintrc . filepath ! ) ? await fs . readFile ( eslintrc . filepath ! , 'utf-8' ) : ''
122
+ const config = JSON . parse ( configStr || '{ "globals": {} }' )
123
+ return config . globals as Record < string , ESLintGlobalsPropValue >
96
124
}
97
125
98
126
async function generateESLint ( ) {
99
- return generateESLintConfigs ( await unimport . getImports ( ) , eslintrc )
127
+ return generateESLintConfigs ( await unimport . getImports ( ) , eslintrc , await parseESLint ( ) )
100
128
}
101
129
102
130
const writeConfigFilesThrottled = throttle ( 500 , writeConfigFiles , { noLeading : false } )
103
- const writeFileThrottled = throttle ( 500 , writeFile , { noLeading : false } )
104
131
105
132
async function writeFile ( filePath : string , content = '' ) {
106
133
await fs . mkdir ( dirname ( filePath ) , { recursive : true } )
@@ -150,68 +177,12 @@ ${dts}`.trim()}\n`
150
177
writeConfigFilesThrottled ( )
151
178
}
152
179
153
- async function getCacheData ( cache : string ) {
154
- const str = ( await fs . readFile ( cache , 'utf-8' ) ) . trim ( )
155
- return JSON . parse ( str || '{}' ) as { [ key : string ] : Import [ ] }
156
- }
157
-
158
- async function generateCache ( ) : Promise < Record < string , Import [ ] > > {
159
- if ( ! cachePath )
160
- return { }
161
-
162
- let cacheData = { }
163
- try {
164
- cacheData = await getCacheData ( cachePath )
165
- await Promise . allSettled ( Object . keys ( cacheData ) . map ( async ( filePath ) => {
166
- try {
167
- const normalizeRoot = root . replaceAll ( sep , posix . sep )
168
- await fs . access ( posix . join ( normalizeRoot , filePath ) )
169
- }
170
- catch {
171
- Reflect . deleteProperty ( cacheData , filePath )
172
- }
173
- } ) )
174
- await writeFile ( cachePath , JSON . stringify ( cacheData , null , 2 ) )
175
- }
176
- catch {
177
- await writeFile ( cachePath , '{}' )
178
- }
179
-
180
- return cacheData
181
- }
182
-
183
- let isInitialCache = false
184
- const resolveCachePromise = generateCache ( )
185
- async function updateCacheImports ( id ?: string , importList ?: Import [ ] ) {
186
- if ( ! cachePath || ( isInitialCache && ! id ) )
187
- return
188
-
189
- isInitialCache = true
190
- const cacheData = await resolveCachePromise
191
- await unimport . modifyDynamicImports ( async ( imports ) => {
192
- if ( id && importList ) {
193
- const filePath = posix . normalize ( posix . relative ( root , id ) )
194
- importList = importList . filter ( i => ( i . name ?? i . as ) && i . name !== 'default' )
195
- if ( importList . length )
196
- cacheData [ filePath ] = importList
197
- else
198
- delete cacheData [ filePath ]
199
- writeFileThrottled ( cachePath , JSON . stringify ( cacheData , null , 2 ) )
200
- return imports . concat ( importList )
201
- }
202
-
203
- return imports . concat ( Object . values ( cacheData ) . reduce ( ( p , n ) => p . concat ( n ) , [ ] ) )
204
- } )
205
- }
206
-
207
180
async function transform ( code : string , id : string ) {
208
181
await importsPromise
209
182
210
183
const s = new MagicString ( code )
211
184
212
- const res = await unimport . injectImports ( s , id )
213
-
214
- await updateCacheImports ( id , res . imports )
185
+ await unimport . injectImports ( s , id )
215
186
216
187
if ( ! s . hasChanged ( ) )
217
188
return
@@ -229,7 +200,6 @@ ${dts}`.trim()}\n`
229
200
dirs,
230
201
filter,
231
202
scanDirs,
232
- updateCacheImports,
233
203
writeConfigFiles,
234
204
writeConfigFilesThrottled,
235
205
transform,
0 commit comments