@cloudwerk/vite-plugin 0.8.0 → 0.8.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.js +103 -0
  2. package/package.json +2 -2
package/dist/index.js CHANGED
@@ -1767,8 +1767,111 @@ function stripServerExports(code) {
1767
1767
  const replacement = removal.replacement ?? "";
1768
1768
  result = result.slice(0, start) + replacement + result.slice(end);
1769
1769
  }
1770
+ result = removeUnusedImports(result);
1770
1771
  return { code: result, stripped };
1771
1772
  }
1773
+ function removeUnusedImports(code) {
1774
+ const ast = parseSync2(code, {
1775
+ syntax: "typescript",
1776
+ tsx: true,
1777
+ comments: true
1778
+ });
1779
+ const offset = ast.span.start;
1780
+ const imports = [];
1781
+ for (const node of ast.body) {
1782
+ if (node.type !== "ImportDeclaration") continue;
1783
+ if (node.specifiers.length === 0) continue;
1784
+ const specifiers = [];
1785
+ for (const spec of node.specifiers) {
1786
+ if (spec.type === "ImportSpecifier") {
1787
+ specifiers.push({ localName: spec.local.value });
1788
+ } else if (spec.type === "ImportDefaultSpecifier") {
1789
+ specifiers.push({ localName: spec.local.value });
1790
+ } else if (spec.type === "ImportNamespaceSpecifier") {
1791
+ specifiers.push({ localName: spec.local.value });
1792
+ }
1793
+ }
1794
+ if (specifiers.length > 0) {
1795
+ imports.push({
1796
+ node,
1797
+ start: node.span.start,
1798
+ end: node.span.end,
1799
+ specifiers
1800
+ });
1801
+ }
1802
+ }
1803
+ if (imports.length === 0) return code;
1804
+ const importRanges = imports.map((i) => ({ start: i.start - offset, end: i.end - offset }));
1805
+ let remaining = "";
1806
+ let pos = 0;
1807
+ for (const range of importRanges.sort((a, b) => a.start - b.start)) {
1808
+ remaining += code.slice(pos, range.start);
1809
+ pos = range.end;
1810
+ }
1811
+ remaining += code.slice(pos);
1812
+ const removals = [];
1813
+ for (const imp of imports) {
1814
+ const unusedSpecs = [];
1815
+ const usedSpecs = [];
1816
+ for (const spec of imp.specifiers) {
1817
+ const regex = new RegExp(`\\b${escapeRegExp(spec.localName)}\\b`);
1818
+ if (regex.test(remaining)) {
1819
+ usedSpecs.push(spec);
1820
+ } else {
1821
+ unusedSpecs.push(spec.localName);
1822
+ }
1823
+ }
1824
+ if (unusedSpecs.length === 0) continue;
1825
+ if (usedSpecs.length === 0) {
1826
+ removals.push({ start: imp.start, end: imp.end });
1827
+ } else {
1828
+ const importNode = imp.node;
1829
+ const source = code.slice(
1830
+ importNode.source.span.start - offset,
1831
+ importNode.source.span.end - offset
1832
+ );
1833
+ const typeOnly = importNode.typeOnly ? "type " : "";
1834
+ const keptNamed = [];
1835
+ let keptDefault = null;
1836
+ let keptNamespace = null;
1837
+ for (const spec of importNode.specifiers) {
1838
+ const localName = spec.local.value;
1839
+ if (!usedSpecs.some((u) => u.localName === localName)) continue;
1840
+ if (spec.type === "ImportDefaultSpecifier") {
1841
+ keptDefault = localName;
1842
+ } else if (spec.type === "ImportNamespaceSpecifier") {
1843
+ keptNamespace = localName;
1844
+ } else if (spec.type === "ImportSpecifier") {
1845
+ const imported = spec.imported;
1846
+ if (imported && imported.type === "Identifier" && imported.value !== localName) {
1847
+ keptNamed.push(`${imported.value} as ${localName}`);
1848
+ } else {
1849
+ keptNamed.push(localName);
1850
+ }
1851
+ }
1852
+ }
1853
+ const parts = [];
1854
+ if (keptDefault) parts.push(keptDefault);
1855
+ if (keptNamespace) parts.push(`* as ${keptNamespace}`);
1856
+ if (keptNamed.length > 0) parts.push(`{ ${keptNamed.join(", ")} }`);
1857
+ const replacement = `import ${typeOnly}${parts.join(", ")} from ${source}`;
1858
+ removals.push({ start: imp.start, end: imp.end, replacement });
1859
+ }
1860
+ }
1861
+ if (removals.length === 0) return code;
1862
+ let result = code;
1863
+ removals.sort((a, b) => b.start - a.start);
1864
+ for (const removal of removals) {
1865
+ const start = removal.start - offset;
1866
+ const end = removal.end - offset;
1867
+ const replacement = removal.replacement ?? "";
1868
+ result = result.slice(0, start) + replacement + result.slice(end);
1869
+ }
1870
+ return result;
1871
+ }
1872
+ function escapeRegExp(s) {
1873
+ return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
1874
+ }
1772
1875
 
1773
1876
  // src/wrangler-watcher.ts
1774
1877
  import * as fs from "fs";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cloudwerk/vite-plugin",
3
- "version": "0.8.0",
3
+ "version": "0.8.1",
4
4
  "description": "Vite plugin for Cloudwerk file-based routing with virtual entry generation",
5
5
  "repository": {
6
6
  "type": "git",
@@ -23,7 +23,7 @@
23
23
  "@cloudwerk/ui": "^0.15.6"
24
24
  },
25
25
  "peerDependencies": {
26
- "vite": "^5.0.0 || ^6.0.0",
26
+ "vite": "^5.0.0 || ^6.0.0 || ^7.0.0",
27
27
  "@hono/vite-dev-server": ">=0.18.0",
28
28
  "hono": "^4.0.0"
29
29
  },