4a4e1f4dcb47b43538322983ccf38394f9cd467d46e3767647f3debf47012e3c1c681a194118bdc78c1ad92b21974ded2b4b2ca02f93d150080fba6dd7e623 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287
  1. import {
  2. __spreadValues,
  3. presets
  4. } from "./chunk-RW3PVGYV.js";
  5. // src/core/unplugin.ts
  6. import { createUnplugin } from "unplugin";
  7. // src/core/ctx.ts
  8. import { dirname, isAbsolute, relative, resolve } from "path";
  9. import { promises as fs } from "fs";
  10. import { slash, throttle, toArray as toArray2 } from "@antfu/utils";
  11. import { createFilter } from "@rollup/pluginutils";
  12. import { isPackageExists } from "local-pkg";
  13. import { vueTemplateAddon } from "unimport/addons";
  14. import { createUnimport, scanDirExports } from "unimport";
  15. import MagicString from "magic-string";
  16. // src/core/eslintrc.ts
  17. function generateESLintConfigs(imports, eslintrc) {
  18. const eslintConfigs = { globals: {} };
  19. imports.map((i) => {
  20. var _a;
  21. return (_a = i.as) != null ? _a : i.name;
  22. }).filter(Boolean).sort().forEach((name) => {
  23. eslintConfigs.globals[name] = eslintrc.globalsPropValue || true;
  24. });
  25. const jsonBody = JSON.stringify(eslintConfigs, null, 2);
  26. return jsonBody;
  27. }
  28. // src/core/resolvers.ts
  29. import { toArray } from "@antfu/utils";
  30. function normalizeImport(info, name) {
  31. if (typeof info === "string") {
  32. return {
  33. name: "default",
  34. as: name,
  35. from: info
  36. };
  37. }
  38. if ("path" in info) {
  39. return {
  40. from: info.path,
  41. as: info.name,
  42. name: info.importName,
  43. sideEffects: info.sideEffects
  44. };
  45. }
  46. return __spreadValues({
  47. name,
  48. as: name
  49. }, info);
  50. }
  51. async function firstMatchedResolver(resolvers, fullname) {
  52. let name = fullname;
  53. for (const resolver of resolvers) {
  54. if (typeof resolver === "object" && resolver.type === "directive") {
  55. if (name.startsWith("v"))
  56. name = name.slice(1);
  57. else
  58. continue;
  59. }
  60. const resolved = await (typeof resolver === "function" ? resolver(name) : resolver.resolve(name));
  61. if (resolved)
  62. return normalizeImport(resolved, fullname);
  63. }
  64. }
  65. function resolversAddon(resolvers) {
  66. return {
  67. async matchImports(names, matched) {
  68. if (!resolvers.length)
  69. return;
  70. const dynamic = [];
  71. const sideEffects = [];
  72. await Promise.all([...names].map(async (name) => {
  73. const matchedImport = matched.find((i) => i.as === name);
  74. if (matchedImport) {
  75. if ("sideEffects" in matchedImport)
  76. sideEffects.push(...toArray(matchedImport.sideEffects).map((i) => normalizeImport(i, "")));
  77. return;
  78. }
  79. const resolved = await firstMatchedResolver(resolvers, name);
  80. if (resolved)
  81. dynamic.push(resolved);
  82. if (resolved == null ? void 0 : resolved.sideEffects)
  83. sideEffects.push(...toArray(resolved == null ? void 0 : resolved.sideEffects).map((i) => normalizeImport(i, "")));
  84. }));
  85. if (dynamic.length) {
  86. this.dynamicImports.push(...dynamic);
  87. this.invalidate();
  88. }
  89. if (dynamic.length || sideEffects.length)
  90. return [...matched, ...dynamic, ...sideEffects];
  91. }
  92. };
  93. }
  94. // src/core/ctx.ts
  95. function createContext(options = {}, root = process.cwd()) {
  96. var _a, _b;
  97. const imports = flattenImports(options.imports, options.presetOverriding);
  98. (_a = options.ignore) == null ? void 0 : _a.forEach((name) => {
  99. const i = imports.find((i2) => i2.as === name);
  100. if (i)
  101. i.disabled = true;
  102. });
  103. const {
  104. dts: preferDTS = isPackageExists("typescript")
  105. } = options;
  106. const dirs = (_b = options.dirs) == null ? void 0 : _b.map((dir) => resolve(root, dir));
  107. const eslintrc = options.eslintrc || {};
  108. eslintrc.enabled = eslintrc.enabled === void 0 ? false : eslintrc.enabled;
  109. eslintrc.filepath = eslintrc.filepath || "./.eslintrc-auto-import.json";
  110. eslintrc.globalsPropValue = eslintrc.globalsPropValue === void 0 ? true : eslintrc.globalsPropValue;
  111. const resolvers = options.resolvers ? [options.resolvers].flat(2) : [];
  112. const unimport = createUnimport({
  113. imports,
  114. presets: [],
  115. addons: [
  116. ...options.vueTemplate ? [vueTemplateAddon()] : [],
  117. resolversAddon(resolvers),
  118. {
  119. declaration(dts2) {
  120. if (!dts2.endsWith("\n"))
  121. dts2 += "\n";
  122. return `// Generated by 'unplugin-auto-import'
  123. ${dts2}`;
  124. }
  125. }
  126. ]
  127. });
  128. const filter = createFilter(
  129. options.include || [/\.[jt]sx?$/, /\.vue$/, /\.vue\?vue/, /\.svelte$/],
  130. options.exclude || [/[\\/]node_modules[\\/]/, /[\\/]\.git[\\/]/]
  131. );
  132. const dts = preferDTS === false ? false : preferDTS === true ? resolve(root, "auto-imports.d.ts") : resolve(root, preferDTS);
  133. function generateDTS(file) {
  134. const dir = dirname(file);
  135. return unimport.generateTypeDeclarations({
  136. resolvePath: (i) => {
  137. if (i.from.startsWith(".") || isAbsolute(i.from)) {
  138. const related = slash(relative(dir, i.from).replace(/\.ts$/, ""));
  139. return !related.startsWith(".") ? `./${related}` : related;
  140. }
  141. return i.from;
  142. }
  143. });
  144. }
  145. async function generateESLint() {
  146. return generateESLintConfigs(await unimport.getImports(), eslintrc);
  147. }
  148. const writeConfigFilesThrottled = throttle(500, writeConfigFiles, { noLeading: false });
  149. let lastDTS;
  150. let lastESLint;
  151. async function writeConfigFiles() {
  152. const promises = [];
  153. if (dts) {
  154. promises.push(
  155. generateDTS(dts).then((content) => {
  156. if (content !== lastDTS) {
  157. lastDTS = content;
  158. return fs.writeFile(dts, content, "utf-8");
  159. }
  160. })
  161. );
  162. }
  163. if (eslintrc.enabled && eslintrc.filepath) {
  164. promises.push(
  165. generateESLint().then((content) => {
  166. if (content !== lastESLint) {
  167. lastESLint = content;
  168. return fs.writeFile(eslintrc.filepath, content, "utf-8");
  169. }
  170. })
  171. );
  172. }
  173. return Promise.all(promises);
  174. }
  175. async function scanDirs() {
  176. if (dirs == null ? void 0 : dirs.length) {
  177. await unimport.modifyDynamicImports(async (imports2) => {
  178. const exports = await scanDirExports(dirs);
  179. exports.forEach((i) => i.__source = "dir");
  180. return [
  181. ...imports2.filter((i) => i.__source !== "dir"),
  182. ...exports
  183. ];
  184. });
  185. }
  186. writeConfigFilesThrottled();
  187. }
  188. async function transform(code, id) {
  189. const s = new MagicString(code);
  190. await unimport.injectImports(s, id);
  191. if (!s.hasChanged())
  192. return;
  193. writeConfigFilesThrottled();
  194. return {
  195. code: s.toString(),
  196. map: s.generateMap({ source: id, includeContent: true })
  197. };
  198. }
  199. if (!imports.length && !resolvers.length)
  200. console.warn("[auto-import] plugin installed but no imports has defined, see https://github.com/antfu/unplugin-auto-import#configurations for configurations");
  201. return {
  202. root,
  203. dirs,
  204. filter,
  205. scanDirs,
  206. writeConfigFiles,
  207. writeConfigFilesThrottled,
  208. transform,
  209. generateDTS,
  210. generateESLint
  211. };
  212. }
  213. function flattenImports(map, overriding = false) {
  214. const flat = {};
  215. toArray2(map).forEach((definition) => {
  216. if (typeof definition === "string") {
  217. if (!presets[definition])
  218. throw new Error(`[auto-import] preset ${definition} not found`);
  219. const preset = presets[definition];
  220. definition = typeof preset === "function" ? preset() : preset;
  221. }
  222. for (const mod of Object.keys(definition)) {
  223. for (const id of definition[mod]) {
  224. const meta = {
  225. from: mod
  226. };
  227. let name;
  228. if (Array.isArray(id)) {
  229. name = id[1];
  230. meta.name = id[0];
  231. meta.as = id[1];
  232. } else {
  233. name = id;
  234. meta.name = id;
  235. meta.as = id;
  236. }
  237. if (flat[name] && !overriding)
  238. throw new Error(`[auto-import] identifier ${name} already defined with ${flat[name].from}`);
  239. flat[name] = meta;
  240. }
  241. }
  242. });
  243. return Object.values(flat);
  244. }
  245. // src/core/unplugin.ts
  246. var unplugin_default = createUnplugin((options) => {
  247. let ctx = createContext(options);
  248. return {
  249. name: "unplugin-auto-import",
  250. enforce: "post",
  251. transformInclude(id) {
  252. return ctx.filter(id);
  253. },
  254. async transform(code, id) {
  255. return ctx.transform(code, id);
  256. },
  257. async buildStart() {
  258. await ctx.scanDirs();
  259. },
  260. async buildEnd() {
  261. await ctx.writeConfigFiles();
  262. },
  263. vite: {
  264. async handleHotUpdate({ file }) {
  265. var _a;
  266. if ((_a = ctx.dirs) == null ? void 0 : _a.some((dir) => file.startsWith(dir)))
  267. await ctx.scanDirs();
  268. },
  269. async configResolved(config) {
  270. if (ctx.root !== config.root) {
  271. ctx = createContext(options, config.root);
  272. await ctx.scanDirs();
  273. }
  274. }
  275. }
  276. };
  277. });
  278. export {
  279. unplugin_default
  280. };