chunk-GR6VF5HE.js 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431
  1. import {
  2. presets
  3. } from "./chunk-S4VTQKPB.js";
  4. // src/core/unplugin.ts
  5. import { minimatch } from "minimatch";
  6. import { slash as slash2 } from "@antfu/utils";
  7. import { createUnplugin } from "unplugin";
  8. // src/core/ctx.ts
  9. import { dirname, isAbsolute, join, relative, resolve } from "path";
  10. import { existsSync, promises as fs } from "fs";
  11. import process from "process";
  12. import { slash, throttle, toArray as toArray2 } from "@antfu/utils";
  13. import { createFilter } from "@rollup/pluginutils";
  14. import { isPackageExists } from "local-pkg";
  15. import { createUnimport, resolvePreset, scanExports } from "unimport";
  16. import fg from "fast-glob";
  17. import { vueTemplateAddon } from "unimport/addons";
  18. import MagicString from "magic-string";
  19. // src/core/eslintrc.ts
  20. function generateESLintConfigs(imports, eslintrc, globals = {}) {
  21. const eslintConfigs = { globals };
  22. imports.map((i) => {
  23. var _a;
  24. return (_a = i.as) != null ? _a : i.name;
  25. }).filter(Boolean).sort().forEach((name) => {
  26. eslintConfigs.globals[name] = eslintrc.globalsPropValue;
  27. });
  28. const jsonBody = JSON.stringify(eslintConfigs, null, 2);
  29. return jsonBody;
  30. }
  31. // src/core/biomelintrc.ts
  32. function generateBiomeLintConfigs(imports) {
  33. const names = imports.map((i) => {
  34. var _a;
  35. return (_a = i.as) != null ? _a : i.name;
  36. }).filter(Boolean).sort();
  37. const config = { javascript: { globals: names } };
  38. const jsonBody = JSON.stringify(config, null, 2);
  39. return jsonBody;
  40. }
  41. // src/core/resolvers.ts
  42. import { toArray } from "@antfu/utils";
  43. function normalizeImport(info, name) {
  44. if (typeof info === "string") {
  45. return {
  46. name: "default",
  47. as: name,
  48. from: info
  49. };
  50. }
  51. if ("path" in info) {
  52. return {
  53. from: info.path,
  54. as: info.name,
  55. name: info.importName,
  56. sideEffects: info.sideEffects
  57. };
  58. }
  59. return {
  60. name,
  61. as: name,
  62. ...info
  63. };
  64. }
  65. async function firstMatchedResolver(resolvers, fullname) {
  66. let name = fullname;
  67. for (const resolver of resolvers) {
  68. if (typeof resolver === "object" && resolver.type === "directive") {
  69. if (name.startsWith("v"))
  70. name = name.slice(1);
  71. else
  72. continue;
  73. }
  74. const resolved = await (typeof resolver === "function" ? resolver(name) : resolver.resolve(name));
  75. if (resolved)
  76. return normalizeImport(resolved, fullname);
  77. }
  78. }
  79. function resolversAddon(resolvers) {
  80. return {
  81. async matchImports(names, matched) {
  82. if (!resolvers.length)
  83. return;
  84. const dynamic = [];
  85. const sideEffects = [];
  86. await Promise.all([...names].map(async (name) => {
  87. const matchedImport = matched.find((i) => i.as === name);
  88. if (matchedImport) {
  89. if ("sideEffects" in matchedImport)
  90. sideEffects.push(...toArray(matchedImport.sideEffects).map((i) => normalizeImport(i, "")));
  91. return;
  92. }
  93. const resolved = await firstMatchedResolver(resolvers, name);
  94. if (resolved)
  95. dynamic.push(resolved);
  96. if (resolved == null ? void 0 : resolved.sideEffects)
  97. sideEffects.push(...toArray(resolved == null ? void 0 : resolved.sideEffects).map((i) => normalizeImport(i, "")));
  98. }));
  99. if (dynamic.length) {
  100. this.dynamicImports.push(...dynamic);
  101. this.invalidate();
  102. }
  103. if (dynamic.length || sideEffects.length)
  104. return [...matched, ...dynamic, ...sideEffects];
  105. }
  106. };
  107. }
  108. // src/core/ctx.ts
  109. function resolveGlobsExclude(root, glob) {
  110. const excludeReg = /^!/;
  111. return `${excludeReg.test(glob) ? "!" : ""}${resolve(root, glob.replace(excludeReg, ""))}`;
  112. }
  113. async function scanDirExports(dirs, root) {
  114. const result = await fg(dirs, {
  115. absolute: true,
  116. cwd: root,
  117. onlyFiles: true,
  118. followSymbolicLinks: true
  119. });
  120. const files = Array.from(new Set(result.flat())).map(slash);
  121. return (await Promise.all(files.map((i) => scanExports(i, false)))).flat();
  122. }
  123. function createContext(options = {}, root = process.cwd()) {
  124. var _a, _b, _c;
  125. root = slash(root);
  126. const {
  127. dts: preferDTS = isPackageExists("typescript")
  128. } = options;
  129. const dirs = (_a = options.dirs) == null ? void 0 : _a.concat(options.dirs.map((dir) => join(dir, "*.{tsx,jsx,ts,js,mjs,cjs,mts,cts}"))).map((dir) => slash(resolveGlobsExclude(root, dir)));
  130. const eslintrc = options.eslintrc || {};
  131. eslintrc.enabled = eslintrc.enabled === void 0 ? false : eslintrc.enabled;
  132. eslintrc.filepath = eslintrc.filepath || "./.eslintrc-auto-import.json";
  133. eslintrc.globalsPropValue = eslintrc.globalsPropValue === void 0 ? true : eslintrc.globalsPropValue;
  134. const biomelintrc = options.biomelintrc || {};
  135. biomelintrc.enabled = biomelintrc.enabled !== void 0;
  136. biomelintrc.filepath = biomelintrc.filepath || "./.biomelintrc-auto-import.json";
  137. const resolvers = options.resolvers ? [options.resolvers].flat(2) : [];
  138. const injectAtEnd = options.injectAtEnd !== false;
  139. const unimport = createUnimport({
  140. imports: [],
  141. presets: (_c = (_b = options.packagePresets) == null ? void 0 : _b.map((p) => typeof p === "string" ? { package: p } : p)) != null ? _c : [],
  142. injectAtEnd,
  143. parser: options.parser,
  144. addons: [
  145. ...options.vueTemplate ? [vueTemplateAddon()] : [],
  146. resolversAddon(resolvers),
  147. {
  148. declaration(dts2) {
  149. return `${`
  150. /* eslint-disable */
  151. /* prettier-ignore */
  152. // @ts-nocheck
  153. // noinspection JSUnusedGlobalSymbols
  154. // Generated by unplugin-auto-import
  155. ${dts2}`.trim()}
  156. `;
  157. }
  158. }
  159. ]
  160. });
  161. const importsPromise = flattenImports(options.imports).then((imports) => {
  162. var _a2, _b2;
  163. if (!imports.length && !resolvers.length && !(dirs == null ? void 0 : dirs.length))
  164. console.warn("[auto-import] plugin installed but no imports has defined, see https://github.com/antfu/unplugin-auto-import#configurations for configurations");
  165. const compare = (left, right) => {
  166. return right instanceof RegExp ? right.test(left) : right === left;
  167. };
  168. (_a2 = options.ignore) == null ? void 0 : _a2.forEach((name) => {
  169. const i = imports.find((i2) => compare(i2.as, name));
  170. if (i)
  171. i.disabled = true;
  172. });
  173. (_b2 = options.ignoreDts) == null ? void 0 : _b2.forEach((name) => {
  174. const i = imports.find((i2) => compare(i2.as, name));
  175. if (i)
  176. i.dtsDisabled = true;
  177. });
  178. return unimport.getInternalContext().replaceImports(imports);
  179. });
  180. const filter = createFilter(
  181. options.include || [/\.[jt]sx?$/, /\.astro$/, /\.vue$/, /\.vue\?vue/, /\.svelte$/],
  182. options.exclude || [/[\\/]node_modules[\\/]/, /[\\/]\.git[\\/]/]
  183. );
  184. const dts = preferDTS === false ? false : preferDTS === true ? resolve(root, "auto-imports.d.ts") : resolve(root, preferDTS);
  185. const multilineCommentsRE = /\/\*.*?\*\//gs;
  186. const singlelineCommentsRE = /\/\/.*$/gm;
  187. const dtsReg = /declare\s+global\s*\{(.*?)[\n\r]\}/s;
  188. const componentCustomPropertiesReg = /interface\s+ComponentCustomProperties\s*\{(.*?)[\n\r]\}/gs;
  189. function parseDTS(dts2) {
  190. var _a2;
  191. dts2 = dts2.replace(multilineCommentsRE, "").replace(singlelineCommentsRE, "");
  192. const code = (_a2 = dts2.match(dtsReg)) == null ? void 0 : _a2[0];
  193. if (!code)
  194. return;
  195. return Object.fromEntries(Array.from(code.matchAll(/['"]?(const\s*[^\s'"]+)['"]?\s*:\s*(.+?)[,;\r\n]/g)).map((i) => [i[1], i[2]]));
  196. }
  197. async function generateDTS(file) {
  198. await importsPromise;
  199. const dir = dirname(file);
  200. const originalContent = existsSync(file) ? await fs.readFile(file, "utf-8") : "";
  201. const originalDTS = parseDTS(originalContent);
  202. let currentContent = await unimport.generateTypeDeclarations({
  203. resolvePath: (i) => {
  204. if (i.from.startsWith(".") || isAbsolute(i.from)) {
  205. const related = slash(relative(dir, i.from).replace(/\.ts(x)?$/, ""));
  206. return !related.startsWith(".") ? `./${related}` : related;
  207. }
  208. return i.from;
  209. }
  210. });
  211. const currentDTS = parseDTS(currentContent);
  212. if (options.vueTemplate) {
  213. currentContent = currentContent.replace(
  214. componentCustomPropertiesReg,
  215. ($1) => `interface GlobalComponents {}
  216. ${$1}`
  217. );
  218. }
  219. if (originalDTS) {
  220. Object.keys(currentDTS).forEach((key) => {
  221. originalDTS[key] = currentDTS[key];
  222. });
  223. const dtsList = Object.keys(originalDTS).sort().map((k) => ` ${k}: ${originalDTS[k]}`);
  224. return currentContent.replace(dtsReg, () => `declare global {
  225. ${dtsList.join("\n")}
  226. }`);
  227. }
  228. return currentContent;
  229. }
  230. async function parseESLint() {
  231. if (!eslintrc.filepath)
  232. return {};
  233. if (eslintrc.filepath.match(/\.[cm]?[jt]sx?$/))
  234. return {};
  235. const configStr = existsSync(eslintrc.filepath) ? await fs.readFile(eslintrc.filepath, "utf-8") : "";
  236. const config = JSON.parse(configStr || '{ "globals": {} }');
  237. return config.globals;
  238. }
  239. async function generateESLint() {
  240. return generateESLintConfigs(await unimport.getImports(), eslintrc, await parseESLint());
  241. }
  242. async function generateBiomeLint() {
  243. return generateBiomeLintConfigs(await unimport.getImports());
  244. }
  245. const writeConfigFilesThrottled = throttle(500, writeConfigFiles, { noLeading: false });
  246. async function writeFile(filePath, content = "") {
  247. await fs.mkdir(dirname(filePath), { recursive: true });
  248. return await fs.writeFile(filePath, content, "utf-8");
  249. }
  250. let lastDTS;
  251. let lastESLint;
  252. let lastBiomeLint;
  253. async function writeConfigFiles() {
  254. const promises = [];
  255. if (dts) {
  256. promises.push(
  257. generateDTS(dts).then((content) => {
  258. if (content !== lastDTS) {
  259. lastDTS = content;
  260. return writeFile(dts, content);
  261. }
  262. })
  263. );
  264. }
  265. if (eslintrc.enabled && eslintrc.filepath) {
  266. const filepath = eslintrc.filepath;
  267. promises.push(
  268. generateESLint().then(async (content) => {
  269. if (filepath.endsWith(".cjs"))
  270. content = `module.exports = ${content}`;
  271. else if (filepath.endsWith(".mjs") || filepath.endsWith(".js"))
  272. content = `export default ${content}`;
  273. content = `${content}
  274. `;
  275. if (content.trim() !== (lastESLint == null ? void 0 : lastESLint.trim())) {
  276. lastESLint = content;
  277. return writeFile(eslintrc.filepath, content);
  278. }
  279. })
  280. );
  281. }
  282. if (biomelintrc.enabled) {
  283. promises.push(
  284. generateBiomeLint().then((content) => {
  285. if (content !== lastBiomeLint) {
  286. lastBiomeLint = content;
  287. return writeFile(biomelintrc.filepath, content);
  288. }
  289. })
  290. );
  291. }
  292. return Promise.all(promises);
  293. }
  294. async function scanDirs() {
  295. if (dirs == null ? void 0 : dirs.length) {
  296. await unimport.modifyDynamicImports(async (imports) => {
  297. const exports_ = await scanDirExports(dirs, root);
  298. exports_.forEach((i) => i.__source = "dir");
  299. return modifyDefaultExportsAlias([
  300. ...imports.filter((i) => i.__source !== "dir"),
  301. ...exports_
  302. ], options);
  303. });
  304. }
  305. writeConfigFilesThrottled();
  306. }
  307. async function transform(code, id) {
  308. await importsPromise;
  309. const s = new MagicString(code);
  310. await unimport.injectImports(s, id);
  311. if (!s.hasChanged())
  312. return;
  313. writeConfigFilesThrottled();
  314. return {
  315. code: s.toString(),
  316. map: s.generateMap({ source: id, includeContent: true, hires: true })
  317. };
  318. }
  319. return {
  320. root,
  321. dirs,
  322. filter,
  323. scanDirs,
  324. writeConfigFiles,
  325. writeConfigFilesThrottled,
  326. transform,
  327. generateDTS,
  328. generateESLint,
  329. unimport
  330. };
  331. }
  332. async function flattenImports(map) {
  333. const promises = await Promise.all(toArray2(map).map(async (definition) => {
  334. if (typeof definition === "string") {
  335. if (!presets[definition])
  336. throw new Error(`[auto-import] preset ${definition} not found`);
  337. const preset = presets[definition];
  338. definition = typeof preset === "function" ? preset() : preset;
  339. }
  340. if ("from" in definition && "imports" in definition) {
  341. return await resolvePreset(definition);
  342. } else {
  343. const resolved = [];
  344. for (const mod of Object.keys(definition)) {
  345. for (const id of definition[mod]) {
  346. const meta = {
  347. from: mod
  348. };
  349. if (Array.isArray(id)) {
  350. meta.name = id[0];
  351. meta.as = id[1];
  352. } else {
  353. meta.name = id;
  354. meta.as = id;
  355. }
  356. resolved.push(meta);
  357. }
  358. }
  359. return resolved;
  360. }
  361. }));
  362. return promises.flat();
  363. }
  364. function modifyDefaultExportsAlias(imports, options) {
  365. if (options.defaultExportByFilename) {
  366. imports.forEach((i) => {
  367. var _a, _b, _c;
  368. if (i.name === "default")
  369. i.as = (_c = (_b = (_a = i.from.split("/").pop()) == null ? void 0 : _a.split(".")) == null ? void 0 : _b.shift()) != null ? _c : i.as;
  370. });
  371. }
  372. return imports;
  373. }
  374. // src/core/unplugin.ts
  375. var unplugin_default = createUnplugin((options) => {
  376. let ctx = createContext(options);
  377. return {
  378. name: "unplugin-auto-import",
  379. enforce: "post",
  380. transformInclude(id) {
  381. return ctx.filter(id);
  382. },
  383. async transform(code, id) {
  384. return ctx.transform(code, id);
  385. },
  386. async buildStart() {
  387. await ctx.scanDirs();
  388. },
  389. async buildEnd() {
  390. await ctx.writeConfigFiles();
  391. },
  392. vite: {
  393. async config(config) {
  394. var _a;
  395. if (!options.viteOptimizeDeps)
  396. return;
  397. const exclude = ((_a = config.optimizeDeps) == null ? void 0 : _a.exclude) || [];
  398. const imports = new Set((await ctx.unimport.getImports()).map((i) => i.from).filter((i) => i.match(/^[a-z@]/) && !exclude.includes(i)));
  399. if (!imports.size)
  400. return;
  401. return {
  402. optimizeDeps: {
  403. include: [...imports]
  404. }
  405. };
  406. },
  407. async handleHotUpdate({ file }) {
  408. var _a;
  409. if ((_a = ctx.dirs) == null ? void 0 : _a.some((glob) => minimatch(slash2(file), slash2(glob))))
  410. await ctx.scanDirs();
  411. },
  412. async configResolved(config) {
  413. if (ctx.root !== config.root) {
  414. ctx = createContext(options, config.root);
  415. await ctx.scanDirs();
  416. }
  417. }
  418. }
  419. };
  420. });
  421. export {
  422. unplugin_default
  423. };