2021-08-10 00:27:23 +00:00
|
|
|
import { createUnplugin } from 'unplugin'
|
|
|
|
import { parseQuery, parseURL } from 'ufo'
|
2021-10-20 09:47:18 +00:00
|
|
|
import { toImports } from './utils'
|
|
|
|
import { AutoImportContext } from './context'
|
2021-08-10 00:27:23 +00:00
|
|
|
|
2021-08-30 11:55:57 +00:00
|
|
|
const excludeRE = [
|
2021-08-10 00:27:23 +00:00
|
|
|
// imported from other module
|
2021-11-29 11:17:51 +00:00
|
|
|
/\bimport\s*([\s\S]+?)\s*from\b/g,
|
2021-08-10 00:27:23 +00:00
|
|
|
// defined as function
|
2021-10-12 12:24:43 +00:00
|
|
|
/\bfunction\s*([\w_$]+?)\s*\(/g,
|
2021-08-10 00:27:23 +00:00
|
|
|
// defined as local variable
|
2021-10-12 12:24:43 +00:00
|
|
|
/\b(?:const|let|var)\s+?(\[[\s\S]*?\]|\{[\s\S]*?\}|[\s\S]+?)\s*?[=;\n]/g
|
2021-08-10 00:27:23 +00:00
|
|
|
]
|
|
|
|
|
2021-10-12 12:24:43 +00:00
|
|
|
const importAsRE = /^.*\sas\s+/
|
2022-01-17 20:50:17 +00:00
|
|
|
const separatorRE = /[,[\]{}\n]/g
|
2021-11-29 11:17:51 +00:00
|
|
|
const multilineCommentsRE = /\/\*\s(.|[\r\n])*?\*\//gm
|
2022-01-17 20:50:17 +00:00
|
|
|
const singlelineCommentsRE = /\/\/\s.*$/gm
|
2021-11-29 11:17:51 +00:00
|
|
|
const templateLiteralRE = /\$\{(.*)\}/g
|
|
|
|
const quotesRE = [
|
|
|
|
/(["'])((?:\\\1|(?!\1)|.|\r)*?)\1/gm,
|
|
|
|
/([`])((?:\\\1|(?!\1)|.|\n|\r)*?)\1/gm
|
|
|
|
]
|
2021-08-30 11:55:57 +00:00
|
|
|
|
2022-01-17 20:50:17 +00:00
|
|
|
function stripCommentsAndStrings (code: string) {
|
2021-08-30 11:55:57 +00:00
|
|
|
return code
|
|
|
|
.replace(multilineCommentsRE, '')
|
|
|
|
.replace(singlelineCommentsRE, '')
|
2021-11-29 11:17:51 +00:00
|
|
|
.replace(templateLiteralRE, '` + $1 + `')
|
|
|
|
.replace(quotesRE[0], '""')
|
|
|
|
.replace(quotesRE[1], '``')
|
2021-08-30 11:55:57 +00:00
|
|
|
}
|
|
|
|
|
2021-10-20 09:47:18 +00:00
|
|
|
export const TransformPlugin = createUnplugin((ctx: AutoImportContext) => {
|
2021-08-10 00:27:23 +00:00
|
|
|
return {
|
2022-02-10 09:29:49 +00:00
|
|
|
name: 'nuxt:auto-imports-transform',
|
2021-08-10 00:27:23 +00:00
|
|
|
enforce: 'post',
|
|
|
|
transformInclude (id) {
|
|
|
|
const { pathname, search } = parseURL(id)
|
2022-01-17 18:27:23 +00:00
|
|
|
const { type, macro } = parseQuery(search)
|
2021-08-10 00:27:23 +00:00
|
|
|
|
2021-12-21 14:28:45 +00:00
|
|
|
// Exclude node_modules by default
|
|
|
|
if (ctx.transform.exclude.some(pattern => id.match(pattern))) {
|
2021-08-10 00:27:23 +00:00
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
// vue files
|
2021-10-13 20:24:13 +00:00
|
|
|
if (
|
|
|
|
pathname.endsWith('.vue') &&
|
2022-01-17 18:27:23 +00:00
|
|
|
(type === 'template' || type === 'script' || macro || !search)
|
2021-10-13 20:24:13 +00:00
|
|
|
) {
|
2021-08-10 00:27:23 +00:00
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
|
|
|
// js files
|
2021-10-13 21:03:36 +00:00
|
|
|
if (pathname.match(/\.((c|m)?j|t)sx?$/g)) {
|
2021-08-10 00:27:23 +00:00
|
|
|
return true
|
|
|
|
}
|
|
|
|
},
|
|
|
|
transform (code) {
|
2021-08-30 11:55:57 +00:00
|
|
|
// strip comments so we don't match on them
|
2022-01-17 20:50:17 +00:00
|
|
|
const stripped = stripCommentsAndStrings(code)
|
2021-08-30 11:55:57 +00:00
|
|
|
|
2021-08-10 00:27:23 +00:00
|
|
|
// find all possible injection
|
2022-01-17 20:50:17 +00:00
|
|
|
const matched = new Set(Array.from(stripped.matchAll(ctx.matchRE)).map(i => i[1]))
|
2021-08-10 00:27:23 +00:00
|
|
|
|
|
|
|
// remove those already defined
|
2021-08-30 11:55:57 +00:00
|
|
|
for (const regex of excludeRE) {
|
2022-01-17 20:50:17 +00:00
|
|
|
Array.from(stripped.matchAll(regex))
|
2021-10-12 12:24:43 +00:00
|
|
|
.flatMap(i => [
|
2022-01-17 20:50:17 +00:00
|
|
|
...(i[1]?.split(separatorRE) || []),
|
|
|
|
...(i[2]?.split(separatorRE) || [])
|
2021-10-12 12:24:43 +00:00
|
|
|
])
|
|
|
|
.map(i => i.replace(importAsRE, '').trim())
|
|
|
|
.forEach(i => matched.delete(i))
|
2021-08-10 00:27:23 +00:00
|
|
|
}
|
|
|
|
|
2021-08-30 11:55:57 +00:00
|
|
|
if (!matched.size) {
|
|
|
|
return null
|
|
|
|
}
|
|
|
|
|
2021-10-20 09:47:18 +00:00
|
|
|
// For webpack4/bridge support
|
2022-01-17 20:50:17 +00:00
|
|
|
const isCJSContext = stripped.includes('require(')
|
2021-10-02 16:59:32 +00:00
|
|
|
|
2021-10-20 09:47:18 +00:00
|
|
|
const matchedImports = Array.from(matched).map(name => ctx.map.get(name)).filter(Boolean)
|
|
|
|
const imports = toImports(matchedImports, isCJSContext)
|
2021-08-10 00:27:23 +00:00
|
|
|
|
|
|
|
return imports + code
|
|
|
|
}
|
|
|
|
}
|
|
|
|
})
|