3f62c4b003800d0fa810807a7dd6f28ee81150d62ffe1d6a8689f8583cb55806c4f2f462363782d2181bc3881d23a110e7b922c014448814acce5172c8f38c 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905
  1. 'use strict';
  2. const fs = require('fs');
  3. const fg = require('fast-glob');
  4. const pathe = require('pathe');
  5. const mlly = require('mlly');
  6. const scule = require('scule');
  7. const vueTemplate = require('./unimport.4f90cbbb.cjs');
  8. const localPkg = require('local-pkg');
  9. const os = require('os');
  10. const pkgTypes = require('pkg-types');
  11. const pinia = vueTemplate.defineUnimportPreset({
  12. from: "pinia",
  13. imports: [
  14. // https://pinia.esm.dev/api/modules/pinia.html#functions
  15. "acceptHMRUpdate",
  16. "createPinia",
  17. "defineStore",
  18. "getActivePinia",
  19. "mapActions",
  20. "mapGetters",
  21. "mapState",
  22. "mapStores",
  23. "mapWritableState",
  24. "setActivePinia",
  25. "setMapStoreSuffix",
  26. "storeToRefs"
  27. ]
  28. });
  29. const preact = vueTemplate.defineUnimportPreset({
  30. from: "preact",
  31. imports: [
  32. "useState",
  33. "useCallback",
  34. "useMemo",
  35. "useEffect",
  36. "useRef",
  37. "useContext",
  38. "useReducer"
  39. ]
  40. });
  41. const quasar = vueTemplate.defineUnimportPreset({
  42. from: "quasar",
  43. imports: [
  44. // https://quasar.dev/vue-composables
  45. "useQuasar",
  46. "useDialogPluginComponent",
  47. "useFormChild",
  48. "useMeta"
  49. ]
  50. });
  51. const react = vueTemplate.defineUnimportPreset({
  52. from: "react",
  53. imports: [
  54. "useState",
  55. "useCallback",
  56. "useMemo",
  57. "useEffect",
  58. "useRef",
  59. "useContext",
  60. "useReducer"
  61. ]
  62. });
  63. const ReactRouterHooks = [
  64. "useOutletContext",
  65. "useHref",
  66. "useInRouterContext",
  67. "useLocation",
  68. "useNavigationType",
  69. "useNavigate",
  70. "useOutlet",
  71. "useParams",
  72. "useResolvedPath",
  73. "useRoutes"
  74. ];
  75. const reactRouter = vueTemplate.defineUnimportPreset({
  76. from: "react-router",
  77. imports: [
  78. ...ReactRouterHooks
  79. ]
  80. });
  81. const reactRouterDom = vueTemplate.defineUnimportPreset({
  82. from: "react-router-dom",
  83. imports: [
  84. ...ReactRouterHooks,
  85. // react-router-dom only hooks
  86. "useLinkClickHandler",
  87. "useSearchParams",
  88. // react-router-dom Component
  89. // call once in general
  90. // 'BrowserRouter',
  91. // 'HashRouter',
  92. // 'MemoryRouter',
  93. "Link",
  94. "NavLink",
  95. "Navigate",
  96. "Outlet",
  97. "Route",
  98. "Routes"
  99. ]
  100. });
  101. const svelteAnimate = vueTemplate.defineUnimportPreset({
  102. from: "svelte/animate",
  103. imports: [
  104. "flip"
  105. ]
  106. });
  107. const svelteEasing = vueTemplate.defineUnimportPreset({
  108. from: "svelte/easing",
  109. imports: [
  110. "back",
  111. "bounce",
  112. "circ",
  113. "cubic",
  114. "elastic",
  115. "expo",
  116. "quad",
  117. "quart",
  118. "quint",
  119. "sine"
  120. ].reduce((acc, e) => {
  121. acc.push(`${e}In`, `${e}Out`, `${e}InOut`);
  122. return acc;
  123. }, ["linear"])
  124. });
  125. const svelteStore = vueTemplate.defineUnimportPreset({
  126. from: "svelte/store",
  127. imports: [
  128. "writable",
  129. "readable",
  130. "derived",
  131. "get"
  132. ]
  133. });
  134. const svelteMotion = vueTemplate.defineUnimportPreset({
  135. from: "svelte/motion",
  136. imports: [
  137. "tweened",
  138. "spring"
  139. ]
  140. });
  141. const svelteTransition = vueTemplate.defineUnimportPreset({
  142. from: "svelte/transition",
  143. imports: [
  144. "fade",
  145. "blur",
  146. "fly",
  147. "slide",
  148. "scale",
  149. "draw",
  150. "crossfade"
  151. ]
  152. });
  153. const svelte = vueTemplate.defineUnimportPreset({
  154. from: "svelte",
  155. imports: [
  156. // lifecycle
  157. "onMount",
  158. "beforeUpdate",
  159. "afterUpdate",
  160. "onDestroy",
  161. // tick
  162. "tick",
  163. // context
  164. "setContext",
  165. "getContext",
  166. "hasContext",
  167. "getAllContexts",
  168. // event dispatcher
  169. "createEventDispatcher"
  170. ]
  171. });
  172. const veeValidate = vueTemplate.defineUnimportPreset({
  173. from: "vee-validate",
  174. imports: [
  175. // https://vee-validate.logaretm.com/v4/guide/composition-api/api-review
  176. // https://github.com/logaretm/vee-validate/blob/main/packages/vee-validate/src/index.ts
  177. "validate",
  178. "defineRule",
  179. "configure",
  180. "useField",
  181. "useForm",
  182. "useFieldArray",
  183. "useResetForm",
  184. "useIsFieldDirty",
  185. "useIsFieldTouched",
  186. "useIsFieldValid",
  187. "useIsSubmitting",
  188. "useValidateField",
  189. "useIsFormDirty",
  190. "useIsFormTouched",
  191. "useIsFormValid",
  192. "useValidateForm",
  193. "useSubmitCount",
  194. "useFieldValue",
  195. "useFormValues",
  196. "useFormErrors",
  197. "useFieldError",
  198. "useSubmitForm",
  199. "FormContextKey",
  200. "FieldContextKey"
  201. ]
  202. });
  203. const vitepress = vueTemplate.defineUnimportPreset({
  204. from: "vitepress",
  205. imports: [
  206. // helper methods
  207. "useData",
  208. "useRoute",
  209. "useRouter",
  210. "withBase"
  211. ]
  212. });
  213. const CommonCompositionAPI = [
  214. // lifecycle
  215. "onActivated",
  216. "onBeforeMount",
  217. "onBeforeUnmount",
  218. "onBeforeUpdate",
  219. "onErrorCaptured",
  220. "onDeactivated",
  221. "onMounted",
  222. "onServerPrefetch",
  223. "onUnmounted",
  224. "onUpdated",
  225. // setup helpers
  226. "useAttrs",
  227. "useSlots",
  228. // reactivity,
  229. "computed",
  230. "customRef",
  231. "isReadonly",
  232. "isRef",
  233. "markRaw",
  234. "reactive",
  235. "readonly",
  236. "ref",
  237. "shallowReactive",
  238. "shallowReadonly",
  239. "shallowRef",
  240. "triggerRef",
  241. "toRaw",
  242. "toRef",
  243. "toRefs",
  244. "unref",
  245. "watch",
  246. "watchEffect",
  247. // component
  248. "defineComponent",
  249. "defineAsyncComponent",
  250. "getCurrentInstance",
  251. "h",
  252. "inject",
  253. "nextTick",
  254. "provide",
  255. "useCssModule",
  256. "createApp",
  257. // effect scope
  258. "effectScope",
  259. "EffectScope",
  260. "getCurrentScope",
  261. "onScopeDispose"
  262. ];
  263. const vue = vueTemplate.defineUnimportPreset({
  264. from: "vue",
  265. imports: [
  266. ...CommonCompositionAPI,
  267. // vue3 only
  268. "onRenderTracked",
  269. "onRenderTriggered",
  270. "resolveComponent",
  271. "useCssVars"
  272. ]
  273. });
  274. const vueMacros = vueTemplate.defineUnimportPreset({
  275. from: "vue/macros",
  276. imports: [
  277. // https://vuejs.org/guide/extras/reactivity-transform.html#refs-vs-reactive-variables
  278. "$",
  279. "$$",
  280. "$ref",
  281. "$shallowRef",
  282. "$toRef",
  283. "$customRef",
  284. "$computed"
  285. ]
  286. });
  287. const vueDemi = vueTemplate.defineUnimportPreset({
  288. from: "vue-demi",
  289. imports: CommonCompositionAPI
  290. });
  291. const vueI18n = vueTemplate.defineUnimportPreset({
  292. from: "vue-i18n",
  293. imports: [
  294. "useI18n"
  295. ]
  296. });
  297. const vueRouter = vueTemplate.defineUnimportPreset({
  298. from: "vue-router",
  299. imports: [
  300. "useRouter",
  301. "useRoute"
  302. ]
  303. });
  304. const vueCompositionApi = vueTemplate.defineUnimportPreset({
  305. from: "@vue/composition-api",
  306. imports: CommonCompositionAPI
  307. });
  308. let _cache;
  309. const vueuseCore = () => {
  310. const excluded = ["toRefs", "utils"];
  311. if (!_cache) {
  312. try {
  313. const corePath = localPkg.resolveModule("@vueuse/core") || process.cwd();
  314. const path = localPkg.resolveModule("@vueuse/core/indexes.json") || localPkg.resolveModule("@vueuse/metadata/index.json") || localPkg.resolveModule("@vueuse/metadata/index.json", { paths: [corePath] });
  315. const indexesJson = JSON.parse(fs.readFileSync(path, "utf-8"));
  316. _cache = vueTemplate.defineUnimportPreset({
  317. from: "@vueuse/core",
  318. imports: indexesJson.functions.filter((i) => ["core", "shared"].includes(i.package)).map((i) => i.name).filter((i) => i && i.length >= 4 && !excluded.includes(i))
  319. });
  320. } catch (error) {
  321. console.error(error);
  322. throw new Error("[auto-import] failed to load @vueuse/core, have you installed it?");
  323. }
  324. }
  325. return _cache;
  326. };
  327. const vueuseHead = vueTemplate.defineUnimportPreset({
  328. from: "@vueuse/head",
  329. imports: [
  330. "useHead"
  331. ]
  332. });
  333. const vuex = vueTemplate.defineUnimportPreset({
  334. from: "vuex",
  335. imports: [
  336. // https://next.vuex.vuejs.org/api/#createstore
  337. "createStore",
  338. // https://github.com/vuejs/vuex/blob/4.0/types/logger.d.ts#L20
  339. "createLogger",
  340. // https://next.vuex.vuejs.org/api/#component-binding-helpers
  341. "mapState",
  342. "mapGetters",
  343. "mapActions",
  344. "mapMutations",
  345. "createNamespacedHelpers",
  346. // https://next.vuex.vuejs.org/api/#composable-functions
  347. "useStore"
  348. ]
  349. });
  350. const vitest = vueTemplate.defineUnimportPreset({
  351. from: "vitest",
  352. imports: [
  353. // suite
  354. "suite",
  355. "test",
  356. "describe",
  357. "it",
  358. // chai
  359. "chai",
  360. "expect",
  361. "assert",
  362. // utils
  363. "vitest",
  364. "vi",
  365. // hooks
  366. "beforeAll",
  367. "afterAll",
  368. "beforeEach",
  369. "afterEach"
  370. ]
  371. });
  372. const uniApp = vueTemplate.defineUnimportPreset({
  373. from: "@dcloudio/uni-app",
  374. imports: [
  375. "onAddToFavorites",
  376. "onBackPress",
  377. "onError",
  378. "onHide",
  379. "onLaunch",
  380. "onLoad",
  381. "onNavigationBarButtonTap",
  382. "onNavigationBarSearchInputChanged",
  383. "onNavigationBarSearchInputClicked",
  384. "onNavigationBarSearchInputConfirmed",
  385. "onNavigationBarSearchInputFocusChanged",
  386. "onPageNotFound",
  387. "onPageScroll",
  388. "onPullDownRefresh",
  389. "onReachBottom",
  390. "onReady",
  391. "onResize",
  392. "onShareAppMessage",
  393. "onShareTimeline",
  394. "onShow",
  395. "onTabItemTap",
  396. "onThemeChange",
  397. "onUnhandledRejection",
  398. "onUnload"
  399. ]
  400. });
  401. const solidCore = vueTemplate.defineUnimportPreset({
  402. from: "solid-js",
  403. imports: [
  404. "createSignal",
  405. "createEffect",
  406. "createMemo",
  407. "createResource",
  408. "onMount",
  409. "onCleanup",
  410. "onError",
  411. "untrack",
  412. "batch",
  413. "on",
  414. "createRoot",
  415. "mergeProps",
  416. "splitProps",
  417. "useTransition",
  418. "observable",
  419. "mapArray",
  420. "indexArray",
  421. "createContext",
  422. "useContext",
  423. "children",
  424. "lazy",
  425. "createDeferred",
  426. "createRenderEffect",
  427. "createSelector",
  428. "For",
  429. "Show",
  430. "Switch",
  431. "Match",
  432. "Index",
  433. "ErrorBoundary",
  434. "Suspense",
  435. "SuspenseList"
  436. ]
  437. });
  438. const solidStore = vueTemplate.defineUnimportPreset({
  439. from: "solid-js/store",
  440. imports: [
  441. "createStore",
  442. "produce",
  443. "reconcile",
  444. "createMutable"
  445. ]
  446. });
  447. const solidWeb = vueTemplate.defineUnimportPreset({
  448. from: "solid-js/web",
  449. imports: [
  450. "Dynamic",
  451. "hydrate",
  452. "render",
  453. "renderToString",
  454. "renderToStringAsync",
  455. "renderToStream",
  456. "isServer",
  457. "Portal"
  458. ]
  459. });
  460. const solid = vueTemplate.defineUnimportPreset({
  461. from: "solid-js",
  462. imports: [
  463. solidCore,
  464. solidStore,
  465. solidWeb
  466. ]
  467. });
  468. const solidAppRouter = vueTemplate.defineUnimportPreset({
  469. from: "solid-app-router",
  470. imports: [
  471. "Link",
  472. "NavLink",
  473. "Navigate",
  474. "Outlet",
  475. "Route",
  476. "Router",
  477. "Routes",
  478. "_mergeSearchString",
  479. "createIntegration",
  480. "hashIntegration",
  481. "normalizeIntegration",
  482. "pathIntegration",
  483. "staticIntegration",
  484. "useHref",
  485. "useIsRouting",
  486. "useLocation",
  487. "useMatch",
  488. "useNavigate",
  489. "useParams",
  490. "useResolvedPath",
  491. "useRouteData",
  492. "useRoutes",
  493. "useSearchParams"
  494. ]
  495. });
  496. const builtinPresets = {
  497. "@vue/composition-api": vueCompositionApi,
  498. "@vueuse/core": vueuseCore,
  499. "@vueuse/head": vueuseHead,
  500. pinia,
  501. preact,
  502. quasar,
  503. react,
  504. "react-router": reactRouter,
  505. "react-router-dom": reactRouterDom,
  506. svelte,
  507. "svelte/animate": svelteAnimate,
  508. "svelte/easing": svelteEasing,
  509. "svelte/motion": svelteMotion,
  510. "svelte/store": svelteStore,
  511. "svelte/transition": svelteTransition,
  512. "vee-validate": veeValidate,
  513. vitepress,
  514. "vue-demi": vueDemi,
  515. "vue-i18n": vueI18n,
  516. "vue-router": vueRouter,
  517. vue,
  518. "vue/macros": vueMacros,
  519. vuex,
  520. vitest,
  521. "uni-app": uniApp,
  522. "solid-js": solid,
  523. "solid-app-router": solidAppRouter
  524. };
  525. const CACHE_PATH = /* @__PURE__ */ pathe.join(os.tmpdir(), "unimport");
  526. let CACHE_WRITEABLE;
  527. async function resolvePackagePreset(preset) {
  528. const scanned = await extractExports(preset.package, preset.url, preset.cache);
  529. const filtered = scanned.filter((name) => {
  530. for (const item of preset.ignore || []) {
  531. if (typeof item === "string" && item === name) {
  532. return false;
  533. }
  534. if (item instanceof RegExp && item.test(name)) {
  535. return false;
  536. }
  537. if (typeof item === "function" && item(name) === false) {
  538. return false;
  539. }
  540. }
  541. return true;
  542. });
  543. return filtered.map((name) => ({
  544. from: preset.package,
  545. name
  546. }));
  547. }
  548. async function extractExports(name, url, cache = true) {
  549. const packageJsonPath = await pkgTypes.resolvePackageJSON(name, { url });
  550. const packageJson = await pkgTypes.readPackageJSON(packageJsonPath);
  551. const version = packageJson.version;
  552. const cachePath = pathe.join(CACHE_PATH, name + "@" + version, "exports.json");
  553. if (cache && CACHE_WRITEABLE === void 0) {
  554. try {
  555. CACHE_WRITEABLE = isWritable(CACHE_PATH);
  556. } catch {
  557. CACHE_WRITEABLE = false;
  558. }
  559. }
  560. const useCache = cache && version && CACHE_WRITEABLE;
  561. if (useCache && fs.existsSync(cachePath)) {
  562. return JSON.parse(await fs.promises.readFile(cachePath, "utf-8"));
  563. }
  564. const scanned = await mlly.resolveModuleExportNames(name, { url });
  565. if (useCache) {
  566. await fs.promises.mkdir(pathe.dirname(cachePath), { recursive: true });
  567. await fs.promises.writeFile(cachePath, JSON.stringify(scanned), "utf-8");
  568. }
  569. return scanned;
  570. }
  571. function isWritable(filename) {
  572. try {
  573. fs.accessSync(filename, fs.constants.W_OK);
  574. return true;
  575. } catch (e) {
  576. return false;
  577. }
  578. }
  579. const commonProps = ["from", "priority", "disabled", "meta"];
  580. async function resolvePreset(preset) {
  581. const imports = [];
  582. if ("package" in preset) {
  583. return await resolvePackagePreset(preset);
  584. }
  585. const common = {};
  586. commonProps.forEach((i) => {
  587. if (i in preset) {
  588. common[i] = preset[i];
  589. }
  590. });
  591. for (const _import of preset.imports) {
  592. if (typeof _import === "string") {
  593. imports.push({ ...common, name: _import, as: _import });
  594. } else if (Array.isArray(_import)) {
  595. imports.push({ ...common, name: _import[0], as: _import[1] || _import[0], from: _import[2] || preset.from });
  596. } else if (_import.imports) {
  597. imports.push(...await resolvePreset(_import));
  598. } else {
  599. imports.push({ ...common, ..._import });
  600. }
  601. }
  602. return imports;
  603. }
  604. async function resolveBuiltinPresets(presets) {
  605. const resolved = await Promise.all(presets.map(async (p) => {
  606. let preset = typeof p === "string" ? builtinPresets[p] : p;
  607. if (typeof preset === "function") {
  608. preset = preset();
  609. }
  610. return await resolvePreset(preset);
  611. }));
  612. return resolved.flat();
  613. }
  614. async function scanDirExports(dir, options) {
  615. const dirs = (Array.isArray(dir) ? dir : [dir]).map((d) => pathe.normalize(d));
  616. const fileFilter = options?.fileFilter || (() => true);
  617. const filePatterns = options?.filePatterns || ["*.{ts,js,mjs,cjs,mts,cts}"];
  618. const result = await Promise.all(
  619. // Do multiple glob searches to persist the order of input dirs
  620. dirs.map(
  621. async (i) => await fg(
  622. [i, ...filePatterns.map((p) => pathe.join(i, p))],
  623. {
  624. absolute: true,
  625. cwd: options?.cwd || process.cwd(),
  626. onlyFiles: true,
  627. followSymbolicLinks: true
  628. }
  629. ).then(
  630. (r) => r.map((f) => pathe.normalize(f)).sort()
  631. )
  632. )
  633. );
  634. const files = Array.from(new Set(result.flat())).filter(fileFilter);
  635. const fileExports = await Promise.all(files.map(scanExports));
  636. return fileExports.flat();
  637. }
  638. async function scanExports(filepath) {
  639. const imports = [];
  640. const code = await fs.promises.readFile(filepath, "utf-8");
  641. const exports = mlly.findExports(code);
  642. const defaultExport = exports.find((i) => i.type === "default");
  643. if (defaultExport) {
  644. let name = pathe.parse(filepath).name;
  645. if (name === "index") {
  646. name = pathe.parse(filepath.split("/").slice(0, -1).join("/")).name;
  647. }
  648. imports.push({ name: "default", as: scule.camelCase(name), from: filepath });
  649. }
  650. for (const exp of exports) {
  651. if (exp.type === "named") {
  652. for (const name of exp.names) {
  653. imports.push({ name, as: name, from: filepath });
  654. }
  655. } else if (exp.type === "declaration") {
  656. if (exp.name) {
  657. imports.push({ name: exp.name, as: exp.name, from: filepath });
  658. }
  659. }
  660. }
  661. return imports;
  662. }
  663. function createUnimport(opts) {
  664. let _combinedImports;
  665. const _map = /* @__PURE__ */ new Map();
  666. const addons = [];
  667. if (Array.isArray(opts.addons)) {
  668. addons.push(...opts.addons);
  669. } else if (opts.addons?.vueTemplate) {
  670. addons.push(vueTemplate.vueTemplateAddon());
  671. }
  672. opts.addons = addons;
  673. opts.commentsDisable = opts.commentsDisable ?? ["@unimport-disable", "@imports-disable"];
  674. opts.commentsDebug = opts.commentsDebug ?? ["@unimport-debug", "@imports-debug"];
  675. let metadata;
  676. if (opts.collectMeta) {
  677. metadata = {
  678. injectionUsage: {}
  679. };
  680. }
  681. const ctx = {
  682. staticImports: [...opts.imports || []].filter(Boolean),
  683. dynamicImports: [],
  684. async getImports() {
  685. await resolvePromise;
  686. return updateImports();
  687. },
  688. async getImportMap() {
  689. await ctx.getImports();
  690. return _map;
  691. },
  692. invalidate() {
  693. _combinedImports = void 0;
  694. },
  695. getMetadata() {
  696. return metadata;
  697. },
  698. resolveId: (id, parentId) => opts.resolveId?.(id, parentId),
  699. addons,
  700. options: opts
  701. };
  702. const resolvePromise = resolveBuiltinPresets(opts.presets || []).then((r) => {
  703. ctx.staticImports.unshift(...r);
  704. _combinedImports = void 0;
  705. updateImports();
  706. });
  707. function updateImports() {
  708. if (!_combinedImports) {
  709. const imports = vueTemplate.normalizeImports(vueTemplate.dedupeImports([...ctx.staticImports, ...ctx.dynamicImports], opts.warn || console.warn)).filter((i) => !i.disabled);
  710. _map.clear();
  711. for (const _import of imports) {
  712. _map.set(_import.as ?? _import.name, _import);
  713. }
  714. _combinedImports = imports;
  715. }
  716. return _combinedImports;
  717. }
  718. async function modifyDynamicImports(fn) {
  719. const result = await fn(ctx.dynamicImports);
  720. if (Array.isArray(result)) {
  721. ctx.dynamicImports = result;
  722. }
  723. ctx.invalidate();
  724. }
  725. function clearDynamicImports() {
  726. ctx.dynamicImports.length = 0;
  727. ctx.invalidate();
  728. }
  729. async function generateTypeDeclarations(options) {
  730. const opts2 = {
  731. resolvePath: (i) => i.from.replace(/\.ts$/, ""),
  732. ...options
  733. };
  734. let dts = vueTemplate.toTypeDeclarationFile(await ctx.getImports(), opts2);
  735. for (const addon of ctx.addons) {
  736. dts = await addon.declaration?.call(ctx, dts, opts2) ?? dts;
  737. }
  738. return dts;
  739. }
  740. return {
  741. clearDynamicImports,
  742. modifyDynamicImports,
  743. getImports: () => ctx.getImports(),
  744. detectImports: (code) => detectImports(code, ctx),
  745. injectImports: async (code, id, options) => {
  746. const result = await injectImports(code, id, ctx, options);
  747. if (metadata) {
  748. result.imports.forEach((i) => {
  749. metadata.injectionUsage[i.name] = metadata.injectionUsage[i.name] || { import: i, count: 0, moduleIds: [] };
  750. metadata.injectionUsage[i.name].count++;
  751. if (id && !metadata.injectionUsage[i.name].moduleIds.includes(id)) {
  752. metadata.injectionUsage[i.name].moduleIds.push(id);
  753. }
  754. });
  755. }
  756. return result;
  757. },
  758. toExports: async (filepath) => vueTemplate.toExports(await ctx.getImports(), filepath),
  759. parseVirtualImports: (code) => parseVirtualImports(code, ctx),
  760. generateTypeDeclarations,
  761. getMetadata: () => ctx.getMetadata()
  762. };
  763. }
  764. function parseVirtualImports(code, ctx) {
  765. if (ctx.options.virtualImports?.length) {
  766. return mlly.findStaticImports(code).filter((i) => ctx.options.virtualImports.includes(i.specifier)).map((i) => mlly.parseStaticImport(i));
  767. }
  768. return [];
  769. }
  770. async function detectImports(code, ctx, options) {
  771. const s = vueTemplate.getMagicString(code);
  772. const original = s.original;
  773. const strippedCode = vueTemplate.stripCommentsAndStrings(original);
  774. const syntax = mlly.detectSyntax(strippedCode);
  775. const isCJSContext = syntax.hasCJS && !syntax.hasESM;
  776. let matchedImports = [];
  777. const map = await ctx.getImportMap();
  778. if (options?.autoImport !== false) {
  779. const identifiers = new Set(
  780. Array.from(strippedCode.matchAll(vueTemplate.matchRE)).map((i) => {
  781. if (i[1] === ".") {
  782. return "";
  783. }
  784. const end = strippedCode[i.index + i[0].length];
  785. if (end === ":" && !["?", "case"].includes(i[1].trim())) {
  786. return "";
  787. }
  788. return i[2];
  789. }).filter(Boolean)
  790. );
  791. for (const regex of vueTemplate.excludeRE) {
  792. for (const match of strippedCode.matchAll(regex)) {
  793. const segments = [...match[1]?.split(vueTemplate.separatorRE) || [], ...match[2]?.split(vueTemplate.separatorRE) || []];
  794. for (const segment of segments) {
  795. const identifier = segment.replace(vueTemplate.importAsRE, "").trim();
  796. identifiers.delete(identifier);
  797. }
  798. }
  799. }
  800. matchedImports = Array.from(identifiers).map((name) => map.get(name)).filter((i) => i && !i.disabled);
  801. for (const addon of ctx.addons) {
  802. matchedImports = await addon.matchImports?.call(ctx, identifiers, matchedImports) || matchedImports;
  803. }
  804. }
  805. if (options?.transformVirtualImports !== false && options?.transformVirtualImoports !== false && ctx.options.virtualImports?.length) {
  806. const virtualImports = parseVirtualImports(original, ctx);
  807. virtualImports.forEach((i) => {
  808. s.remove(i.start, i.end);
  809. Object.entries(i.namedImports || {}).forEach(([name, as]) => {
  810. const original2 = map.get(name);
  811. if (!original2) {
  812. throw new Error(`[unimport] failed to find "${name}" imported from "${i.specifier}"`);
  813. }
  814. matchedImports.push({
  815. from: original2.from,
  816. name: original2.name,
  817. as
  818. });
  819. });
  820. });
  821. }
  822. return {
  823. s,
  824. strippedCode,
  825. isCJSContext,
  826. matchedImports
  827. };
  828. }
  829. async function injectImports(code, id, ctx, options) {
  830. const s = vueTemplate.getMagicString(code);
  831. if (ctx.options.commentsDisable?.some((c) => s.original.includes(c))) {
  832. return {
  833. s,
  834. get code() {
  835. return s.toString();
  836. },
  837. imports: []
  838. };
  839. }
  840. for (const addon of ctx.addons) {
  841. await addon.transform?.call(ctx, s, id);
  842. }
  843. const { isCJSContext, matchedImports } = await detectImports(s, ctx, options);
  844. const imports = await resolveImports(ctx, matchedImports, id);
  845. if (ctx.options.commentsDebug?.some((c) => s.original.includes(c))) {
  846. const log = ctx.options.debugLog || console.log;
  847. log(`[unimport] ${imports.length} imports detected in "${id}"${imports.length ? ": " + imports.map((i) => i.name).join(", ") : ""}`);
  848. }
  849. return {
  850. ...vueTemplate.addImportToCode(s, imports, isCJSContext, options?.mergeExisting),
  851. imports
  852. };
  853. }
  854. async function resolveImports(ctx, imports, id) {
  855. const resolveCache = /* @__PURE__ */ new Map();
  856. const _imports = await Promise.all(imports.map(async (i) => {
  857. if (!resolveCache.has(i.from)) {
  858. resolveCache.set(i.from, await ctx.resolveId(i.from, id) || i.from);
  859. }
  860. const from = resolveCache.get(i.from);
  861. if (i.from === id || !from || from === "." || from === id) {
  862. return;
  863. }
  864. return {
  865. ...i,
  866. from
  867. };
  868. }));
  869. return _imports.filter(Boolean);
  870. }
  871. exports.builtinPresets = builtinPresets;
  872. exports.createUnimport = createUnimport;
  873. exports.resolveBuiltinPresets = resolveBuiltinPresets;
  874. exports.resolvePreset = resolvePreset;
  875. exports.scanDirExports = scanDirExports;
  876. exports.scanExports = scanExports;