next-auto-import 0.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +62 -0
- package/dist/index.cjs +352 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +199 -0
- package/dist/index.d.cts.map +1 -0
- package/dist/index.d.mts +199 -0
- package/dist/index.d.mts.map +1 -0
- package/dist/index.mjs +324 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +72 -0
- package/src/core/biomelintrc.ts +13 -0
- package/src/core/ctx.ts +287 -0
- package/src/core/eslintrc.ts +16 -0
- package/src/core/resolvers.ts +94 -0
- package/src/core/unplugin.ts +80 -0
- package/src/index.ts +30 -0
- package/src/presets/index.ts +9 -0
- package/src/presets/react-dom.ts +15 -0
- package/src/presets/react.ts +40 -0
- package/src/types.ts +242 -0
package/src/core/ctx.ts
ADDED
|
@@ -0,0 +1,287 @@
|
|
|
1
|
+
import { existsSync, promises as fs } from 'node:fs'
|
|
2
|
+
import { dirname, isAbsolute, relative, resolve } from 'node:path'
|
|
3
|
+
import process from 'node:process'
|
|
4
|
+
import { slash, toArray } from '@antfu/utils'
|
|
5
|
+
import { isPackageExists } from 'local-pkg'
|
|
6
|
+
import { createUnimport, resolvePreset } from 'unimport'
|
|
7
|
+
import { presets } from '../presets'
|
|
8
|
+
import { generateBiomeLintConfigs } from './biomelintrc'
|
|
9
|
+
import { generateESLintConfigs } from './eslintrc'
|
|
10
|
+
import { resolversAddon } from './resolvers'
|
|
11
|
+
import type { Import, InlinePreset } from 'unimport'
|
|
12
|
+
import type { BiomeLintrc, ESLintrc, Options } from '../types'
|
|
13
|
+
|
|
14
|
+
export const INCLUDE_RE_LIST = [/\.[jt]sx?$/]
|
|
15
|
+
export const EXCLUDE_RE_LIST = [/[\\/]node_modules[\\/]/, /[\\/]\.git[\\/]/]
|
|
16
|
+
|
|
17
|
+
export function createContext(options: Options = {}, root = process.cwd()) {
|
|
18
|
+
root = slash(root)
|
|
19
|
+
|
|
20
|
+
const {
|
|
21
|
+
dts: preferDTS = isPackageExists('typescript'),
|
|
22
|
+
dtsMode = 'append',
|
|
23
|
+
dtsPreserveExts = false,
|
|
24
|
+
dirsScanOptions,
|
|
25
|
+
dirs,
|
|
26
|
+
} = options
|
|
27
|
+
|
|
28
|
+
const eslintrc: ESLintrc = options.eslintrc || {}
|
|
29
|
+
eslintrc.enabled = eslintrc.enabled === undefined ? false : eslintrc.enabled
|
|
30
|
+
eslintrc.filepath = eslintrc.filepath || './.eslintrc-auto-import.json'
|
|
31
|
+
eslintrc.globalsPropValue =
|
|
32
|
+
eslintrc.globalsPropValue === undefined ? true : eslintrc.globalsPropValue
|
|
33
|
+
|
|
34
|
+
const biomelintrc: BiomeLintrc = options.biomelintrc || {}
|
|
35
|
+
biomelintrc.enabled = biomelintrc.enabled !== undefined
|
|
36
|
+
biomelintrc.filepath =
|
|
37
|
+
biomelintrc.filepath || './.biomelintrc-auto-import.json'
|
|
38
|
+
|
|
39
|
+
const dumpUnimportItems =
|
|
40
|
+
options.dumpUnimportItems === true
|
|
41
|
+
? './.unimport-items.json'
|
|
42
|
+
: (options.dumpUnimportItems ?? false)
|
|
43
|
+
|
|
44
|
+
const resolvers = options.resolvers ? [options.resolvers].flat(2) : []
|
|
45
|
+
|
|
46
|
+
// When "options.injectAtEnd" is undefined or true, it's true.
|
|
47
|
+
const injectAtEnd = options.injectAtEnd !== false
|
|
48
|
+
|
|
49
|
+
const unimport = createUnimport({
|
|
50
|
+
imports: [],
|
|
51
|
+
presets:
|
|
52
|
+
options.packagePresets?.map((p) =>
|
|
53
|
+
typeof p === 'string' ? { package: p } : p,
|
|
54
|
+
) ?? [],
|
|
55
|
+
dirsScanOptions: {
|
|
56
|
+
...dirsScanOptions,
|
|
57
|
+
cwd: root,
|
|
58
|
+
},
|
|
59
|
+
dirs,
|
|
60
|
+
injectAtEnd,
|
|
61
|
+
parser: options.parser,
|
|
62
|
+
addons: {
|
|
63
|
+
addons: [
|
|
64
|
+
resolversAddon(resolvers),
|
|
65
|
+
{
|
|
66
|
+
name: 'unplugin-auto-import:dts',
|
|
67
|
+
declaration(dts) {
|
|
68
|
+
return `${`
|
|
69
|
+
/* eslint-disable */
|
|
70
|
+
/* prettier-ignore */
|
|
71
|
+
// @ts-nocheck
|
|
72
|
+
// noinspection JSUnusedGlobalSymbols
|
|
73
|
+
// Generated by unplugin-auto-import
|
|
74
|
+
// biome-ignore lint: disable
|
|
75
|
+
${dts}`.trim()}\n`
|
|
76
|
+
},
|
|
77
|
+
},
|
|
78
|
+
],
|
|
79
|
+
},
|
|
80
|
+
})
|
|
81
|
+
|
|
82
|
+
const importsPromise = flattenImports(options.imports).then((imports) => {
|
|
83
|
+
if (!imports.length && !resolvers.length && !dirs?.length)
|
|
84
|
+
console.warn(
|
|
85
|
+
'[auto-import] plugin installed but no imports has defined, see https://github.com/antfu/unplugin-auto-import#configurations for configurations',
|
|
86
|
+
)
|
|
87
|
+
|
|
88
|
+
const compare = (
|
|
89
|
+
left: string | undefined,
|
|
90
|
+
right: NonNullable<Options['ignore'] | Options['ignoreDts']>[number],
|
|
91
|
+
) => {
|
|
92
|
+
return right instanceof RegExp ? right.test(left!) : right === left
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
options.ignore?.forEach((name) => {
|
|
96
|
+
const i = imports.find((i) => compare(i.as, name))
|
|
97
|
+
if (i) i.disabled = true
|
|
98
|
+
})
|
|
99
|
+
|
|
100
|
+
options.ignoreDts?.forEach((name) => {
|
|
101
|
+
const i = imports.find((i) => compare(i.as, name))
|
|
102
|
+
if (i) i.dtsDisabled = true
|
|
103
|
+
})
|
|
104
|
+
|
|
105
|
+
return unimport.getInternalContext().replaceImports(imports)
|
|
106
|
+
})
|
|
107
|
+
|
|
108
|
+
const dts =
|
|
109
|
+
preferDTS === false
|
|
110
|
+
? false
|
|
111
|
+
: preferDTS === true
|
|
112
|
+
? resolve(root, 'auto-imports.d.ts')
|
|
113
|
+
: resolve(root, preferDTS)
|
|
114
|
+
|
|
115
|
+
const multilineCommentsRE = /\/\*.*?\*\//gs
|
|
116
|
+
const singlelineCommentsRE = /\/\/.*$/gm
|
|
117
|
+
const dtsReg = /declare\s+global\s*\{(.*?)[\n\r]\}/s
|
|
118
|
+
function parseDTS(dts: string) {
|
|
119
|
+
dts = dts.replace(multilineCommentsRE, '').replace(singlelineCommentsRE, '')
|
|
120
|
+
|
|
121
|
+
const code = dts.match(dtsReg)?.[0]
|
|
122
|
+
if (!code) return
|
|
123
|
+
|
|
124
|
+
return Object.fromEntries(
|
|
125
|
+
Array.from(
|
|
126
|
+
code.matchAll(/['"]?(const\s*[^\s'"]+)['"]?\s*:\s*(.+?)[,;\r\n]/g),
|
|
127
|
+
).map((i) => [i[1], i[2]]),
|
|
128
|
+
)
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
async function generateDTS(file: string) {
|
|
132
|
+
await importsPromise
|
|
133
|
+
const dir = dirname(file)
|
|
134
|
+
const originalContent = existsSync(file)
|
|
135
|
+
? await fs.readFile(file, 'utf-8')
|
|
136
|
+
: ''
|
|
137
|
+
const originalDTS = parseDTS(originalContent)
|
|
138
|
+
const currentContent = await unimport.generateTypeDeclarations({
|
|
139
|
+
resolvePath: (i) => {
|
|
140
|
+
if (i.from.startsWith('.') || isAbsolute(i.from)) {
|
|
141
|
+
const related = slash(
|
|
142
|
+
dtsPreserveExts
|
|
143
|
+
? relative(dir, i.from)
|
|
144
|
+
: relative(dir, i.from).replace(/\.ts(x)?$/, ''),
|
|
145
|
+
)
|
|
146
|
+
return !related.startsWith('.') ? `./${related}` : related
|
|
147
|
+
}
|
|
148
|
+
return i.from
|
|
149
|
+
},
|
|
150
|
+
})
|
|
151
|
+
|
|
152
|
+
if (dtsMode === 'append') {
|
|
153
|
+
const currentDTS = parseDTS(currentContent)!
|
|
154
|
+
if (originalDTS) {
|
|
155
|
+
Object.assign(originalDTS, currentDTS)
|
|
156
|
+
|
|
157
|
+
const dtsList = Object.keys(originalDTS)
|
|
158
|
+
.sort()
|
|
159
|
+
.map((k) => ` ${k}: ${originalDTS[k]}`)
|
|
160
|
+
return currentContent.replace(
|
|
161
|
+
dtsReg,
|
|
162
|
+
() => `declare global {\n${dtsList.join('\n')}\n}`,
|
|
163
|
+
)
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
return currentContent
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
async function generateESLint() {
|
|
171
|
+
return generateESLintConfigs(await unimport.getImports(), eslintrc)
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
async function generateBiomeLint() {
|
|
175
|
+
return generateBiomeLintConfigs(await unimport.getImports())
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// eslint-disable-next-line unicorn/consistent-function-scoping
|
|
179
|
+
async function writeFile(filePath: string, content = '') {
|
|
180
|
+
await fs.mkdir(dirname(filePath), { recursive: true })
|
|
181
|
+
return await fs.writeFile(filePath, content, 'utf-8')
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
let lastDTS: string | undefined
|
|
185
|
+
let lastESLint: string | undefined
|
|
186
|
+
let lastBiomeLint: string | undefined
|
|
187
|
+
let lastUnimportItems: string | undefined
|
|
188
|
+
|
|
189
|
+
async function writeConfigFiles() {
|
|
190
|
+
const promises: any[] = []
|
|
191
|
+
if (dts) {
|
|
192
|
+
promises.push(
|
|
193
|
+
generateDTS(dts).then((content) => {
|
|
194
|
+
if (content !== lastDTS) {
|
|
195
|
+
lastDTS = content
|
|
196
|
+
return writeFile(dts, content)
|
|
197
|
+
}
|
|
198
|
+
}),
|
|
199
|
+
)
|
|
200
|
+
}
|
|
201
|
+
if (eslintrc.enabled && eslintrc.filepath) {
|
|
202
|
+
const filepath = eslintrc.filepath
|
|
203
|
+
promises.push(
|
|
204
|
+
generateESLint().then(async (content) => {
|
|
205
|
+
if (filepath.endsWith('.cjs')) content = `module.exports = ${content}`
|
|
206
|
+
else if (filepath.endsWith('.mjs') || filepath.endsWith('.js'))
|
|
207
|
+
content = `export default ${content}`
|
|
208
|
+
|
|
209
|
+
content = `${content}\n`
|
|
210
|
+
if (content.trim() !== lastESLint?.trim()) {
|
|
211
|
+
lastESLint = content
|
|
212
|
+
return writeFile(eslintrc.filepath!, content)
|
|
213
|
+
}
|
|
214
|
+
}),
|
|
215
|
+
)
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
if (biomelintrc.enabled) {
|
|
219
|
+
promises.push(
|
|
220
|
+
generateBiomeLint().then((content) => {
|
|
221
|
+
if (content !== lastBiomeLint) {
|
|
222
|
+
lastBiomeLint = content
|
|
223
|
+
return writeFile(biomelintrc.filepath!, content)
|
|
224
|
+
}
|
|
225
|
+
}),
|
|
226
|
+
)
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
if (dumpUnimportItems) {
|
|
230
|
+
promises.push(
|
|
231
|
+
unimport.getImports().then((items) => {
|
|
232
|
+
if (!dumpUnimportItems) return
|
|
233
|
+
const content = JSON.stringify(items, null, 2)
|
|
234
|
+
if (content !== lastUnimportItems) {
|
|
235
|
+
lastUnimportItems = content
|
|
236
|
+
return writeFile(dumpUnimportItems, content)
|
|
237
|
+
}
|
|
238
|
+
}),
|
|
239
|
+
)
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
return Promise.all(promises)
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
return {
|
|
246
|
+
writeConfigFiles,
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
export async function flattenImports(
|
|
251
|
+
map: Options['imports'],
|
|
252
|
+
): Promise<Import[]> {
|
|
253
|
+
const promises = await Promise.all(
|
|
254
|
+
toArray(map).map(async (definition) => {
|
|
255
|
+
if (typeof definition === 'string') {
|
|
256
|
+
if (!presets[definition])
|
|
257
|
+
throw new Error(`[auto-import] preset ${definition} not found`)
|
|
258
|
+
const preset = presets[definition]
|
|
259
|
+
definition = preset
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
if ('from' in definition && 'imports' in definition) {
|
|
263
|
+
return await resolvePreset(definition as InlinePreset)
|
|
264
|
+
} else {
|
|
265
|
+
const resolved: Import[] = []
|
|
266
|
+
for (const mod of Object.keys(definition)) {
|
|
267
|
+
for (const id of definition[mod]) {
|
|
268
|
+
const meta = {
|
|
269
|
+
from: mod,
|
|
270
|
+
} as Import
|
|
271
|
+
if (Array.isArray(id)) {
|
|
272
|
+
meta.name = id[0]
|
|
273
|
+
meta.as = id[1]
|
|
274
|
+
} else {
|
|
275
|
+
meta.name = id
|
|
276
|
+
meta.as = id
|
|
277
|
+
}
|
|
278
|
+
resolved.push(meta)
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
return resolved
|
|
282
|
+
}
|
|
283
|
+
}),
|
|
284
|
+
)
|
|
285
|
+
|
|
286
|
+
return promises.flat()
|
|
287
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { Import } from 'unimport'
|
|
2
|
+
import type { ESLintrc } from '../types'
|
|
3
|
+
|
|
4
|
+
export function generateESLintConfigs(imports: Import[], eslintrc: ESLintrc) {
|
|
5
|
+
const eslintConfigs: any = { globals: {} }
|
|
6
|
+
|
|
7
|
+
imports
|
|
8
|
+
.map((i) => i.as ?? i.name)
|
|
9
|
+
.filter(Boolean)
|
|
10
|
+
.sort()
|
|
11
|
+
.forEach((name) => {
|
|
12
|
+
eslintConfigs.globals[name] = eslintrc.globalsPropValue
|
|
13
|
+
})
|
|
14
|
+
const jsonBody = JSON.stringify(eslintConfigs, null, 2)
|
|
15
|
+
return jsonBody
|
|
16
|
+
}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { toArray } from '@antfu/utils'
|
|
2
|
+
import type { Addon, Import } from 'unimport'
|
|
3
|
+
import type {
|
|
4
|
+
ImportExtended,
|
|
5
|
+
ImportLegacy,
|
|
6
|
+
Resolver,
|
|
7
|
+
ResolverResult,
|
|
8
|
+
} from '../types'
|
|
9
|
+
|
|
10
|
+
export function normalizeImport(
|
|
11
|
+
info: Import | ResolverResult | ImportExtended | ImportLegacy | string,
|
|
12
|
+
name: string,
|
|
13
|
+
): ImportExtended {
|
|
14
|
+
if (typeof info === 'string') {
|
|
15
|
+
return {
|
|
16
|
+
name: 'default',
|
|
17
|
+
as: name,
|
|
18
|
+
from: info,
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
if ('path' in info) {
|
|
22
|
+
return {
|
|
23
|
+
from: info.path,
|
|
24
|
+
as: info.name,
|
|
25
|
+
name: info.importName!,
|
|
26
|
+
sideEffects: info.sideEffects,
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
return {
|
|
30
|
+
name,
|
|
31
|
+
as: name,
|
|
32
|
+
...info,
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export async function firstMatchedResolver(
|
|
37
|
+
resolvers: Resolver[],
|
|
38
|
+
fullname: string,
|
|
39
|
+
) {
|
|
40
|
+
let name = fullname
|
|
41
|
+
for (const resolver of resolvers) {
|
|
42
|
+
if (typeof resolver === 'object' && resolver.type === 'directive') {
|
|
43
|
+
if (name.startsWith('v')) name = name.slice(1)
|
|
44
|
+
else continue
|
|
45
|
+
}
|
|
46
|
+
const resolved = await (typeof resolver === 'function'
|
|
47
|
+
? resolver(name)
|
|
48
|
+
: resolver.resolve(name))
|
|
49
|
+
if (resolved) return normalizeImport(resolved, fullname)
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export function resolversAddon(resolvers: Resolver[]): Addon {
|
|
54
|
+
return {
|
|
55
|
+
name: 'unplugin-auto-import:resolvers',
|
|
56
|
+
async matchImports(names, matched) {
|
|
57
|
+
if (!resolvers.length) return
|
|
58
|
+
const dynamic: ImportExtended[] = []
|
|
59
|
+
const sideEffects: ImportExtended[] = []
|
|
60
|
+
await Promise.all(
|
|
61
|
+
[...names].map(async (name) => {
|
|
62
|
+
const matchedImport = matched.find((i) => i.as === name)
|
|
63
|
+
if (matchedImport) {
|
|
64
|
+
if ('sideEffects' in matchedImport)
|
|
65
|
+
sideEffects.push(
|
|
66
|
+
...toArray((matchedImport as ImportExtended).sideEffects).map(
|
|
67
|
+
(i) => normalizeImport(i, ''),
|
|
68
|
+
),
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
return
|
|
72
|
+
}
|
|
73
|
+
const resolved = await firstMatchedResolver(resolvers, name)
|
|
74
|
+
if (resolved) dynamic.push(resolved)
|
|
75
|
+
|
|
76
|
+
if (resolved?.sideEffects)
|
|
77
|
+
sideEffects.push(
|
|
78
|
+
...toArray(resolved?.sideEffects).map((i) =>
|
|
79
|
+
normalizeImport(i, ''),
|
|
80
|
+
),
|
|
81
|
+
)
|
|
82
|
+
}),
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
if (dynamic.length) {
|
|
86
|
+
this.dynamicImports.push(...dynamic)
|
|
87
|
+
this.invalidate()
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
if (dynamic.length || sideEffects.length)
|
|
91
|
+
return [...matched, ...dynamic, ...sideEffects]
|
|
92
|
+
},
|
|
93
|
+
}
|
|
94
|
+
}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { slash } from '@antfu/utils'
|
|
2
|
+
import { isPackageExists } from 'local-pkg'
|
|
3
|
+
import pm from 'picomatch'
|
|
4
|
+
import { createUnplugin } from 'unplugin'
|
|
5
|
+
import { createContext, EXCLUDE_RE_LIST, INCLUDE_RE_LIST } from './ctx'
|
|
6
|
+
import type { FilterPattern } from 'unplugin'
|
|
7
|
+
import type { Options } from '../types'
|
|
8
|
+
|
|
9
|
+
export default createUnplugin<Options>((options) => {
|
|
10
|
+
let ctx = createContext(options)
|
|
11
|
+
return {
|
|
12
|
+
name: 'unplugin-auto-import',
|
|
13
|
+
enforce: 'post',
|
|
14
|
+
transformInclude(id) {
|
|
15
|
+
return ctx.filter(id)
|
|
16
|
+
},
|
|
17
|
+
transform: {
|
|
18
|
+
filter: {
|
|
19
|
+
id: {
|
|
20
|
+
include: (options.include as FilterPattern) || INCLUDE_RE_LIST,
|
|
21
|
+
exclude: (options.exclude as FilterPattern) || EXCLUDE_RE_LIST,
|
|
22
|
+
},
|
|
23
|
+
},
|
|
24
|
+
async handler(code, id) {
|
|
25
|
+
return ctx.transform(code, id)
|
|
26
|
+
},
|
|
27
|
+
},
|
|
28
|
+
async buildStart() {
|
|
29
|
+
await ctx.scanDirs()
|
|
30
|
+
},
|
|
31
|
+
async buildEnd() {
|
|
32
|
+
await ctx.writeConfigFiles()
|
|
33
|
+
},
|
|
34
|
+
vite: {
|
|
35
|
+
async config(config) {
|
|
36
|
+
if (options.viteOptimizeDeps === false) return
|
|
37
|
+
|
|
38
|
+
const exclude = config.optimizeDeps?.exclude || []
|
|
39
|
+
|
|
40
|
+
const imports = new Set(
|
|
41
|
+
(await ctx.unimport.getImports())
|
|
42
|
+
.map((i) => i.from)
|
|
43
|
+
.filter(
|
|
44
|
+
(i) =>
|
|
45
|
+
i.match(/^[a-z@]/) &&
|
|
46
|
+
!exclude.includes(i) &&
|
|
47
|
+
isPackageExists(i),
|
|
48
|
+
),
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
if (!imports.size) return
|
|
52
|
+
|
|
53
|
+
return {
|
|
54
|
+
optimizeDeps: {
|
|
55
|
+
include: [...imports],
|
|
56
|
+
},
|
|
57
|
+
}
|
|
58
|
+
},
|
|
59
|
+
async handleHotUpdate({ file }) {
|
|
60
|
+
if (!ctx.dirs?.length) return
|
|
61
|
+
|
|
62
|
+
if (ctx.configFilePaths.includes(file)) return
|
|
63
|
+
|
|
64
|
+
const normalizedFilePath = slash(file)
|
|
65
|
+
|
|
66
|
+
const shouldRescan = ctx.normalizedDirPaths.some((dirPath) =>
|
|
67
|
+
pm.isMatch(normalizedFilePath, dirPath.glob),
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
if (shouldRescan) await ctx.scanDirs()
|
|
71
|
+
},
|
|
72
|
+
async configResolved(config) {
|
|
73
|
+
if (ctx.root !== config.root) {
|
|
74
|
+
ctx = createContext(options, config.root)
|
|
75
|
+
await ctx.scanDirs()
|
|
76
|
+
}
|
|
77
|
+
},
|
|
78
|
+
},
|
|
79
|
+
}
|
|
80
|
+
})
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { createContext } from './core/ctx'
|
|
2
|
+
import type { NextConfig } from 'next'
|
|
3
|
+
import type { Options } from './types'
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Creates a Next.js auto-import context
|
|
7
|
+
*/
|
|
8
|
+
export function createAutoImport(options: Options = {}) {
|
|
9
|
+
const ctx = createContext(options)
|
|
10
|
+
|
|
11
|
+
ctx.writeConfigFiles()
|
|
12
|
+
|
|
13
|
+
return (nextConfig: NextConfig = {}): NextConfig => {
|
|
14
|
+
return {
|
|
15
|
+
...nextConfig,
|
|
16
|
+
experimental: {
|
|
17
|
+
...nextConfig.experimental,
|
|
18
|
+
swcPlugins: [
|
|
19
|
+
[
|
|
20
|
+
'swc-plugin-auto-import',
|
|
21
|
+
{
|
|
22
|
+
presets: ['react'],
|
|
23
|
+
},
|
|
24
|
+
],
|
|
25
|
+
...(nextConfig.experimental?.swcPlugins ?? []),
|
|
26
|
+
],
|
|
27
|
+
},
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { ImportsMap } from '../types'
|
|
2
|
+
|
|
3
|
+
export default {
|
|
4
|
+
'react-dom': [
|
|
5
|
+
'useFormStatus',
|
|
6
|
+
'createPortal',
|
|
7
|
+
'flushSync',
|
|
8
|
+
'preconnect',
|
|
9
|
+
'prefetchDNS',
|
|
10
|
+
'preinit',
|
|
11
|
+
'preinitModule',
|
|
12
|
+
'preload',
|
|
13
|
+
'preloadModule',
|
|
14
|
+
],
|
|
15
|
+
} as const satisfies ImportsMap
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type { ImportsMap } from '../types'
|
|
2
|
+
|
|
3
|
+
export const CommonReactAPI = [
|
|
4
|
+
'useState',
|
|
5
|
+
'useCallback',
|
|
6
|
+
'useMemo',
|
|
7
|
+
'useEffect',
|
|
8
|
+
'useRef',
|
|
9
|
+
'useContext',
|
|
10
|
+
'useReducer',
|
|
11
|
+
'useImperativeHandle',
|
|
12
|
+
'useDebugValue',
|
|
13
|
+
'useDeferredValue',
|
|
14
|
+
'useLayoutEffect',
|
|
15
|
+
'useTransition',
|
|
16
|
+
'startTransition',
|
|
17
|
+
'useSyncExternalStore',
|
|
18
|
+
'useInsertionEffect',
|
|
19
|
+
'useId',
|
|
20
|
+
'lazy',
|
|
21
|
+
'memo',
|
|
22
|
+
'createRef',
|
|
23
|
+
'forwardRef',
|
|
24
|
+
] as const
|
|
25
|
+
|
|
26
|
+
export default {
|
|
27
|
+
react: [
|
|
28
|
+
...CommonReactAPI,
|
|
29
|
+
'cache',
|
|
30
|
+
'cacheSignal',
|
|
31
|
+
'createContext',
|
|
32
|
+
'use',
|
|
33
|
+
'useOptimistic',
|
|
34
|
+
'useEffectEvent',
|
|
35
|
+
'useActionState',
|
|
36
|
+
'Fragment',
|
|
37
|
+
'Suspense',
|
|
38
|
+
'Activity',
|
|
39
|
+
],
|
|
40
|
+
} as const satisfies ImportsMap
|