chunk-6AAI2DNE.js 12 KB

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