unimport.d104e189.cjs 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575
  1. 'use strict';
  2. const node_path = require('node:path');
  3. const process = require('node:process');
  4. const pathe = require('pathe');
  5. const scule = require('scule');
  6. const MagicString = require('magic-string');
  7. const mlly = require('mlly');
  8. const stripLiteral = require('strip-literal');
  9. function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e.default : e; }
  10. const process__default = /*#__PURE__*/_interopDefaultCompat(process);
  11. const MagicString__default = /*#__PURE__*/_interopDefaultCompat(MagicString);
  12. const excludeRE = [
  13. // imported/exported from other module
  14. /\b(import|export)\b([\w$*{},\s]+?)\bfrom\s*["']/g,
  15. // defined as function
  16. /\bfunction\s*([\w$]+)\s*\(/g,
  17. // defined as class
  18. /\bclass\s*([\w$]+)\s*\{/g,
  19. // defined as local variable
  20. // eslint-disable-next-line regexp/no-super-linear-backtracking
  21. /\b(?:const|let|var)\s+?(\[.*?\]|\{.*?\}|.+?)\s*?[=;\n]/gs
  22. ];
  23. const importAsRE = /^.*\sas\s+/;
  24. const separatorRE = /[,[\]{}\n]|\b(?:import|export)\b/g;
  25. const matchRE = /(^|\.\.\.|(?:\bcase|\?)\s+|[^\w$/)]|\bextends\s+)([\w$]+)\s*(?=[.()[\]}:;?+\-*&|`<>,\n]|\b(?:instanceof|in)\b|$|(?<=extends\s+\w+)\s+\{)/g;
  26. const regexRE = /\/\S*?(?<!\\)(?<!\[[^\]]*)\/[gimsuy]*/g;
  27. function stripCommentsAndStrings(code, options) {
  28. return stripLiteral.stripLiteral(code, options).replace(regexRE, 'new RegExp("")');
  29. }
  30. function defineUnimportPreset(preset) {
  31. return preset;
  32. }
  33. const safePropertyName = /^[a-z$_][\w$]*$/i;
  34. function stringifyWith(withValues) {
  35. let withDefs = "";
  36. for (let entries = Object.entries(withValues), l = entries.length, i = 0; i < l; i++) {
  37. const [prop, value] = entries[i];
  38. withDefs += safePropertyName.test(prop) ? prop : JSON.stringify(prop);
  39. withDefs += `: ${JSON.stringify(String(value))}`;
  40. if (i + 1 !== l)
  41. withDefs += ", ";
  42. }
  43. return `{ ${withDefs} }`;
  44. }
  45. function stringifyImports(imports, isCJS = false) {
  46. const map = toImportModuleMap(imports);
  47. return Object.entries(map).flatMap(([name, importSet]) => {
  48. const entries = [];
  49. const imports2 = Array.from(importSet).filter((i) => {
  50. if (!i.name || i.as === "") {
  51. let importStr;
  52. if (isCJS) {
  53. importStr = `require('${name}');`;
  54. } else {
  55. importStr = `import '${name}'`;
  56. if (i.with)
  57. importStr += ` with ${stringifyWith(i.with)}`;
  58. importStr += ";";
  59. }
  60. entries.push(importStr);
  61. return false;
  62. } else if (i.name === "default" || i.name === "=") {
  63. let importStr;
  64. if (isCJS) {
  65. importStr = i.name === "=" ? `const ${i.as} = require('${name}');` : `const { default: ${i.as} } = require('${name}');`;
  66. } else {
  67. importStr = `import ${i.as} from '${name}'`;
  68. if (i.with)
  69. importStr += ` with ${stringifyWith(i.with)}`;
  70. importStr += ";";
  71. }
  72. entries.push(importStr);
  73. return false;
  74. } else if (i.name === "*") {
  75. let importStr;
  76. if (isCJS) {
  77. importStr = `const ${i.as} = require('${name}');`;
  78. } else {
  79. importStr = `import * as ${i.as} from '${name}'`;
  80. if (i.with)
  81. importStr += ` with ${stringifyWith(i.with)}`;
  82. importStr += ";";
  83. }
  84. entries.push(importStr);
  85. return false;
  86. } else if (!isCJS && i.with) {
  87. entries.push(`import { ${stringifyImportAlias(i)} } from '${name}' with ${stringifyWith(i.with)};`);
  88. return false;
  89. }
  90. return true;
  91. });
  92. if (imports2.length) {
  93. const importsAs = imports2.map((i) => stringifyImportAlias(i, isCJS));
  94. entries.push(
  95. isCJS ? `const { ${importsAs.join(", ")} } = require('${name}');` : `import { ${importsAs.join(", ")} } from '${name}';`
  96. );
  97. }
  98. return entries;
  99. }).join("\n");
  100. }
  101. function dedupeImports(imports, warn) {
  102. const map = /* @__PURE__ */ new Map();
  103. const indexToRemove = /* @__PURE__ */ new Set();
  104. imports.filter((i) => !i.disabled).forEach((i, idx) => {
  105. if (i.declarationType === "enum" || i.declarationType === "class")
  106. return;
  107. const name = i.as ?? i.name;
  108. if (!map.has(name)) {
  109. map.set(name, idx);
  110. return;
  111. }
  112. const other = imports[map.get(name)];
  113. if (other.from === i.from) {
  114. indexToRemove.add(idx);
  115. return;
  116. }
  117. const diff = (other.priority || 1) - (i.priority || 1);
  118. if (diff === 0)
  119. warn(`Duplicated imports "${name}", the one from "${other.from}" has been ignored and "${i.from}" is used`);
  120. if (diff <= 0) {
  121. indexToRemove.add(map.get(name));
  122. map.set(name, idx);
  123. } else {
  124. indexToRemove.add(idx);
  125. }
  126. });
  127. return imports.filter((_, idx) => !indexToRemove.has(idx));
  128. }
  129. function toExports(imports, fileDir, includeType = false) {
  130. const map = toImportModuleMap(imports, includeType);
  131. return Object.entries(map).flatMap(([name, imports2]) => {
  132. if (isFilePath(name))
  133. name = name.replace(/\.[a-z]+$/i, "");
  134. if (fileDir && pathe.isAbsolute(name)) {
  135. name = pathe.relative(fileDir, name);
  136. if (!name.match(/^[./]/))
  137. name = `./${name}`;
  138. }
  139. const entries = [];
  140. const filtered = Array.from(imports2).filter((i) => {
  141. if (i.name === "*") {
  142. entries.push(`export * as ${i.as} from '${name}';`);
  143. return false;
  144. }
  145. return true;
  146. });
  147. if (filtered.length)
  148. entries.push(`export { ${filtered.map((i) => stringifyImportAlias(i, false)).join(", ")} } from '${name}';`);
  149. return entries;
  150. }).join("\n");
  151. }
  152. function stripFileExtension(path) {
  153. return path.replace(/\.[a-z]+$/i, "");
  154. }
  155. function toTypeDeclarationItems(imports, options) {
  156. return imports.map((i) => {
  157. const from = options?.resolvePath?.(i) || stripFileExtension(i.typeFrom || i.from);
  158. let typeDef = "";
  159. if (i.with)
  160. typeDef += `import('${from}', { with: ${stringifyWith(i.with)} })`;
  161. else
  162. typeDef += `import('${from}')`;
  163. if (i.name !== "*" && i.name !== "=")
  164. typeDef += `['${i.name}']`;
  165. return `const ${i.as}: typeof ${typeDef}`;
  166. }).sort();
  167. }
  168. function toTypeDeclarationFile(imports, options) {
  169. const items = toTypeDeclarationItems(imports, options);
  170. const {
  171. exportHelper = true
  172. } = options || {};
  173. let declaration = "";
  174. if (exportHelper)
  175. declaration += "export {}\n";
  176. declaration += `declare global {
  177. ${items.map((i) => ` ${i}`).join("\n")}
  178. }`;
  179. return declaration;
  180. }
  181. function makeTypeModulesMap(imports, resolvePath) {
  182. const modulesMap = /* @__PURE__ */ new Map();
  183. const resolveImportFrom = typeof resolvePath === "function" ? (i) => {
  184. return resolvePath(i) || stripFileExtension(i.typeFrom || i.from);
  185. } : (i) => stripFileExtension(i.typeFrom || i.from);
  186. for (const import_ of imports) {
  187. const from = resolveImportFrom(import_);
  188. let module = modulesMap.get(from);
  189. if (!module) {
  190. module = { typeImports: /* @__PURE__ */ new Set(), starTypeImport: void 0 };
  191. modulesMap.set(from, module);
  192. }
  193. if (import_.name === "*") {
  194. if (import_.as)
  195. module.starTypeImport = import_;
  196. } else {
  197. module.typeImports.add(import_);
  198. }
  199. }
  200. return modulesMap;
  201. }
  202. function toTypeReExports(imports, options) {
  203. const importsMap = makeTypeModulesMap(imports, options?.resolvePath);
  204. const code = Array.from(importsMap).flatMap(([from, module]) => {
  205. from = from.replace(/\.d\.([cm]?)ts$/i, ".$1js");
  206. const { starTypeImport, typeImports } = module;
  207. const strings = [];
  208. if (typeImports.size) {
  209. const typeImportNames = Array.from(typeImports).map(({ name, as }) => {
  210. if (as && as !== name)
  211. return `${name} as ${as}`;
  212. return name;
  213. });
  214. strings.push(
  215. "// @ts-ignore",
  216. `export type { ${typeImportNames.join(", ")} } from '${from}'`
  217. );
  218. }
  219. if (starTypeImport) {
  220. strings.push(
  221. "// @ts-ignore",
  222. `export type * as ${starTypeImport.as} from '${from}'`
  223. );
  224. }
  225. if (strings.length) {
  226. strings.push(
  227. // This is a workaround for a TypeScript issue where type-only re-exports are not properly initialized.
  228. `import('${from}')`
  229. );
  230. }
  231. return strings;
  232. });
  233. return `// for type re-export
  234. declare global {
  235. ${code.map((i) => ` ${i}`).join("\n")}
  236. }`;
  237. }
  238. function stringifyImportAlias(item, isCJS = false) {
  239. return item.as === void 0 || item.name === item.as ? item.name : isCJS ? `${item.name}: ${item.as}` : `${item.name} as ${item.as}`;
  240. }
  241. function toImportModuleMap(imports, includeType = false) {
  242. const map = {};
  243. for (const _import of imports) {
  244. if (_import.type && !includeType)
  245. continue;
  246. if (!map[_import.from])
  247. map[_import.from] = /* @__PURE__ */ new Set();
  248. map[_import.from].add(_import);
  249. }
  250. return map;
  251. }
  252. function getString(code) {
  253. if (typeof code === "string")
  254. return code;
  255. return code.toString();
  256. }
  257. function getMagicString(code) {
  258. if (typeof code === "string")
  259. return new MagicString__default(code);
  260. return code;
  261. }
  262. function addImportToCode(code, imports, isCJS = false, mergeExisting = false, injectAtLast = false, firstOccurrence = Number.POSITIVE_INFINITY, onResolved, onStringified) {
  263. let newImports = [];
  264. const s = getMagicString(code);
  265. let _staticImports;
  266. const strippedCode = stripCommentsAndStrings(s.original);
  267. function findStaticImportsLazy() {
  268. if (!_staticImports) {
  269. _staticImports = mlly.findStaticImports(s.original).filter((i) => Boolean(strippedCode.slice(i.start, i.end).trim())).map((i) => mlly.parseStaticImport(i));
  270. }
  271. return _staticImports;
  272. }
  273. function hasShebang() {
  274. const shebangRegex = /^#!.+/;
  275. return shebangRegex.test(s.original);
  276. }
  277. if (mergeExisting && !isCJS) {
  278. const existingImports = findStaticImportsLazy();
  279. const map = /* @__PURE__ */ new Map();
  280. imports.forEach((i) => {
  281. const target = existingImports.find((e) => e.specifier === i.from && e.imports.startsWith("{"));
  282. if (!target)
  283. return newImports.push(i);
  284. if (!map.has(target))
  285. map.set(target, []);
  286. map.get(target).push(i);
  287. });
  288. for (const [target, items] of map.entries()) {
  289. const strings = items.map((i) => `${stringifyImportAlias(i)}, `);
  290. const importLength = target.code.match(/^\s*import\s*\{/)?.[0]?.length;
  291. if (importLength)
  292. s.appendLeft(target.start + importLength, ` ${strings.join("").trim()}`);
  293. }
  294. } else {
  295. newImports = imports;
  296. }
  297. newImports = onResolved?.(newImports) ?? newImports;
  298. let newEntries = stringifyImports(newImports, isCJS);
  299. newEntries = onStringified?.(newEntries, newImports) ?? newEntries;
  300. if (newEntries) {
  301. const insertionIndex = injectAtLast ? findStaticImportsLazy().reverse().find((i) => i.end <= firstOccurrence)?.end ?? 0 : 0;
  302. if (insertionIndex > 0)
  303. s.appendRight(insertionIndex, `
  304. ${newEntries}
  305. `);
  306. else if (hasShebang())
  307. s.appendLeft(s.original.indexOf("\n") + 1, `
  308. ${newEntries}
  309. `);
  310. else
  311. s.prepend(`${newEntries}
  312. `);
  313. }
  314. return {
  315. s,
  316. get code() {
  317. return s.toString();
  318. }
  319. };
  320. }
  321. function normalizeImports(imports) {
  322. for (const _import of imports)
  323. _import.as = _import.as ?? _import.name;
  324. return imports;
  325. }
  326. function resolveIdAbsolute(id, parentId) {
  327. return mlly.resolvePathSync(id, {
  328. url: parentId
  329. });
  330. }
  331. function isFilePath(path) {
  332. return path.startsWith(".") || pathe.isAbsolute(path) || path.includes("://");
  333. }
  334. const toImports = stringifyImports;
  335. const contextRE$1 = /\b_ctx\.([$\w]+)\b/g;
  336. const UNREF_KEY = "__unimport_unref_";
  337. const VUE_TEMPLATE_NAME = "unimport:vue-template";
  338. function vueTemplateAddon() {
  339. const self = {
  340. name: VUE_TEMPLATE_NAME,
  341. async transform(s, id) {
  342. if (!s.original.includes("_ctx.") || s.original.includes(UNREF_KEY))
  343. return s;
  344. const matches = Array.from(s.original.matchAll(contextRE$1));
  345. const imports = await this.getImports();
  346. let targets = [];
  347. for (const match of matches) {
  348. const name = match[1];
  349. const item = imports.find((i) => i.as === name);
  350. if (!item)
  351. continue;
  352. const start = match.index;
  353. const end = start + match[0].length;
  354. const tempName = `__unimport_${name}`;
  355. s.overwrite(start, end, `(${JSON.stringify(name)} in _ctx ? _ctx.${name} : ${UNREF_KEY}(${tempName}))`);
  356. if (!targets.find((i) => i.as === tempName)) {
  357. targets.push({
  358. ...item,
  359. as: tempName
  360. });
  361. }
  362. }
  363. if (targets.length) {
  364. targets.push({
  365. name: "unref",
  366. from: "vue",
  367. as: UNREF_KEY
  368. });
  369. for (const addon of this.addons) {
  370. if (addon === self)
  371. continue;
  372. targets = await addon.injectImportsResolved?.call(this, targets, s, id) ?? targets;
  373. }
  374. let injection = stringifyImports(targets);
  375. for (const addon of this.addons) {
  376. if (addon === self)
  377. continue;
  378. injection = await addon.injectImportsStringified?.call(this, injection, targets, s, id) ?? injection;
  379. }
  380. s.prepend(injection);
  381. }
  382. return s;
  383. },
  384. async declaration(dts, options) {
  385. const imports = await this.getImports();
  386. const items = imports.map((i) => {
  387. if (i.type || i.dtsDisabled)
  388. return "";
  389. const from = options?.resolvePath?.(i) || i.from;
  390. return `readonly ${i.as}: UnwrapRef<typeof import('${from}')${i.name !== "*" ? `['${i.name}']` : ""}>`;
  391. }).filter(Boolean).sort();
  392. const extendItems = items.map((i) => ` ${i}`).join("\n");
  393. return `${dts}
  394. // for vue template auto import
  395. import { UnwrapRef } from 'vue'
  396. declare module 'vue' {
  397. interface ComponentCustomProperties {
  398. ${extendItems}
  399. }
  400. }`;
  401. }
  402. };
  403. return self;
  404. }
  405. const contextRE = /resolveDirective as _resolveDirective/;
  406. const contextText = `${contextRE.source}, `;
  407. const directiveRE = /(?:var|const) (\w+) = _resolveDirective\("([\w.-]+)"\);?\s*/g;
  408. const VUE_DIRECTIVES_NAME = "unimport:vue-directives";
  409. function vueDirectivesAddon(options = {}) {
  410. function isDirective(importEntry) {
  411. let isDirective2 = importEntry.meta?.vueDirective === true;
  412. if (isDirective2) {
  413. return true;
  414. }
  415. isDirective2 = options.isDirective?.(normalizePath(process__default.cwd(), importEntry.from), importEntry) ?? false;
  416. if (isDirective2) {
  417. importEntry.meta ?? (importEntry.meta = {});
  418. importEntry.meta.vueDirective = true;
  419. }
  420. return isDirective2;
  421. }
  422. const self = {
  423. name: VUE_DIRECTIVES_NAME,
  424. async transform(s, id) {
  425. if (!s.original.match(contextRE))
  426. return s;
  427. const matches = Array.from(s.original.matchAll(directiveRE)).sort((a, b) => b.index - a.index);
  428. if (!matches.length)
  429. return s;
  430. let targets = [];
  431. for await (const [
  432. begin,
  433. end,
  434. importEntry
  435. ] of findDirectives(
  436. isDirective,
  437. matches,
  438. this.getImports()
  439. )) {
  440. s.overwrite(begin, end, "");
  441. targets.push(importEntry);
  442. }
  443. if (!targets.length)
  444. return s;
  445. s.replace(contextText, "");
  446. for (const addon of this.addons) {
  447. if (addon === self)
  448. continue;
  449. targets = await addon.injectImportsResolved?.call(this, targets, s, id) ?? targets;
  450. }
  451. let injection = stringifyImports(targets);
  452. for (const addon of this.addons) {
  453. if (addon === self)
  454. continue;
  455. injection = await addon.injectImportsStringified?.call(this, injection, targets, s, id) ?? injection;
  456. }
  457. s.prepend(injection);
  458. return s;
  459. },
  460. async declaration(dts, options2) {
  461. const directivesMap = await this.getImports().then((imports) => {
  462. return imports.filter(isDirective).reduce((acc, i) => {
  463. if (i.type || i.dtsDisabled)
  464. return acc;
  465. let name;
  466. if (i.name === "default" && (i.as === "default" || !i.as)) {
  467. const file = node_path.basename(i.from);
  468. const idx = file.indexOf(".");
  469. name = idx > -1 ? file.slice(0, idx) : file;
  470. } else {
  471. name = i.as ?? i.name;
  472. }
  473. name = name[0] === "v" ? scule.camelCase(name) : scule.camelCase(`v-${name}`);
  474. if (!acc.has(name)) {
  475. acc.set(name, i);
  476. }
  477. return acc;
  478. }, /* @__PURE__ */ new Map());
  479. });
  480. if (!directivesMap.size)
  481. return dts;
  482. const directives = Array.from(directivesMap.entries()).map(([name, i]) => ` ${name}: typeof import('${options2?.resolvePath?.(i) || i.from}')['${i.name}']`).sort().join("\n");
  483. return `${dts}
  484. // for vue directives auto import
  485. declare module 'vue' {
  486. interface ComponentCustomProperties {
  487. ${directives}
  488. }
  489. interface GlobalDirectives {
  490. ${directives}
  491. }
  492. }`;
  493. }
  494. };
  495. return self;
  496. }
  497. function resolvePath(cwd, path) {
  498. return path[0] === "." ? pathe.resolve(cwd, path) : path;
  499. }
  500. function normalizePath(cwd, path) {
  501. return resolvePath(cwd, path).replace(/\\/g, "/");
  502. }
  503. async function* findDirectives(isDirective, regexArray, importsPromise) {
  504. const imports = (await importsPromise).filter(isDirective);
  505. if (!imports.length)
  506. return;
  507. const symbols = regexArray.reduce((acc, regex) => {
  508. const [all, symbol, resolveDirectiveName] = regex;
  509. if (acc.has(symbol))
  510. return acc;
  511. acc.set(symbol, [
  512. regex.index,
  513. regex.index + all.length,
  514. scule.kebabCase(resolveDirectiveName)
  515. ]);
  516. return acc;
  517. }, /* @__PURE__ */ new Map());
  518. for (const [symbol, data] of symbols.entries()) {
  519. yield* findDirective(imports, symbol, data);
  520. }
  521. }
  522. function* findDirective(imports, symbol, [begin, end, importName]) {
  523. let resolvedName;
  524. for (const i of imports) {
  525. if (i.name === "default" && (i.as === "default" || !i.as)) {
  526. const file = node_path.basename(i.from);
  527. const idx = file.indexOf(".");
  528. resolvedName = scule.kebabCase(idx > -1 ? file.slice(0, idx) : file);
  529. } else {
  530. resolvedName = scule.kebabCase(i.as ?? i.name);
  531. }
  532. if (resolvedName[0] === "v") {
  533. resolvedName = resolvedName.slice(resolvedName[1] === "-" ? 2 : 1);
  534. }
  535. if (resolvedName === importName) {
  536. yield [
  537. begin,
  538. end,
  539. { ...i, name: i.name, as: symbol }
  540. ];
  541. return;
  542. }
  543. }
  544. }
  545. exports.VUE_DIRECTIVES_NAME = VUE_DIRECTIVES_NAME;
  546. exports.VUE_TEMPLATE_NAME = VUE_TEMPLATE_NAME;
  547. exports.addImportToCode = addImportToCode;
  548. exports.dedupeImports = dedupeImports;
  549. exports.defineUnimportPreset = defineUnimportPreset;
  550. exports.excludeRE = excludeRE;
  551. exports.getMagicString = getMagicString;
  552. exports.getString = getString;
  553. exports.importAsRE = importAsRE;
  554. exports.matchRE = matchRE;
  555. exports.normalizeImports = normalizeImports;
  556. exports.resolveIdAbsolute = resolveIdAbsolute;
  557. exports.separatorRE = separatorRE;
  558. exports.stringifyImports = stringifyImports;
  559. exports.stripCommentsAndStrings = stripCommentsAndStrings;
  560. exports.stripFileExtension = stripFileExtension;
  561. exports.toExports = toExports;
  562. exports.toImports = toImports;
  563. exports.toTypeDeclarationFile = toTypeDeclarationFile;
  564. exports.toTypeDeclarationItems = toTypeDeclarationItems;
  565. exports.toTypeReExports = toTypeReExports;
  566. exports.vueDirectivesAddon = vueDirectivesAddon;
  567. exports.vueTemplateAddon = vueTemplateAddon;