pruny 1.3.0 → 1.5.0

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 +85 -4
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -9394,6 +9394,21 @@ async function scanUnusedExports(config) {
9394
9394
  for (const [file, exports] of exportMap.entries()) {
9395
9395
  for (const exp of exports) {
9396
9396
  let isUsed = false;
9397
+ let usedInternally = false;
9398
+ const fileContent = totalContents.get(file);
9399
+ if (fileContent) {
9400
+ const lines = fileContent.split(`
9401
+ `);
9402
+ for (let i = 0;i < lines.length; i++) {
9403
+ if (i === exp.line - 1)
9404
+ continue;
9405
+ const referenceRegex = new RegExp(`\\b${exp.name}\\b`);
9406
+ if (referenceRegex.test(lines[i])) {
9407
+ usedInternally = true;
9408
+ break;
9409
+ }
9410
+ }
9411
+ }
9397
9412
  for (const [otherFile, content] of totalContents.entries()) {
9398
9413
  if (file === otherFile)
9399
9414
  continue;
@@ -9404,7 +9419,7 @@ async function scanUnusedExports(config) {
9404
9419
  }
9405
9420
  }
9406
9421
  if (!isUsed) {
9407
- unusedExports.push(exp);
9422
+ unusedExports.push({ ...exp, usedInternally });
9408
9423
  }
9409
9424
  }
9410
9425
  }
@@ -9742,7 +9757,7 @@ function findConfigFile(dir) {
9742
9757
  }
9743
9758
 
9744
9759
  // src/fixer.ts
9745
- import { readFileSync as readFileSync6, writeFileSync } from "node:fs";
9760
+ import { readFileSync as readFileSync6, writeFileSync, unlinkSync } from "node:fs";
9746
9761
  import { join as join6 } from "node:path";
9747
9762
  function removeExportFromLine(rootDir, exp) {
9748
9763
  const fullPath = join6(rootDir, exp.file);
@@ -9751,6 +9766,20 @@ function removeExportFromLine(rootDir, exp) {
9751
9766
  const lines = content.split(`
9752
9767
  `);
9753
9768
  const lineIndex = exp.line - 1;
9769
+ if (!exp.usedInternally) {
9770
+ const deletedLines = deleteDeclaration(lines, lineIndex);
9771
+ if (deletedLines > 0) {
9772
+ const newContent = lines.join(`
9773
+ `);
9774
+ if (isFileEmpty(newContent)) {
9775
+ unlinkSync(fullPath);
9776
+ return true;
9777
+ }
9778
+ writeFileSync(fullPath, newContent, "utf-8");
9779
+ return true;
9780
+ }
9781
+ return false;
9782
+ }
9754
9783
  const originalLine = lines[lineIndex];
9755
9784
  const exportPrefixRegex = /^(export\s+(?:async\s+)?)/;
9756
9785
  if (exportPrefixRegex.test(originalLine.trim())) {
@@ -9766,13 +9795,61 @@ function removeExportFromLine(rootDir, exp) {
9766
9795
  return false;
9767
9796
  }
9768
9797
  }
9798
+ function deleteDeclaration(lines, startLine) {
9799
+ if (startLine >= lines.length)
9800
+ return 0;
9801
+ let endLine = startLine;
9802
+ let braceCount = 0;
9803
+ let foundClosing = false;
9804
+ for (let i = startLine;i < lines.length; i++) {
9805
+ const line = lines[i];
9806
+ const openBraces = (line.match(/{/g) || []).length;
9807
+ const closeBraces = (line.match(/}/g) || []).length;
9808
+ braceCount += openBraces - closeBraces;
9809
+ if (braceCount === 0) {
9810
+ if (line.includes(";") || line.includes("};")) {
9811
+ endLine = i;
9812
+ foundClosing = true;
9813
+ break;
9814
+ }
9815
+ if (i > startLine && line.trim() === "}") {
9816
+ endLine = i;
9817
+ foundClosing = true;
9818
+ break;
9819
+ }
9820
+ }
9821
+ }
9822
+ if (!foundClosing && braceCount === 0) {
9823
+ endLine = startLine;
9824
+ }
9825
+ const linesToDelete = endLine - startLine + 1;
9826
+ lines.splice(startLine, linesToDelete);
9827
+ return linesToDelete;
9828
+ }
9829
+ function isFileEmpty(content) {
9830
+ const lines = content.split(`
9831
+ `);
9832
+ for (const line of lines) {
9833
+ const trimmed = line.trim();
9834
+ if (!trimmed)
9835
+ continue;
9836
+ if (trimmed.startsWith("//") || trimmed.startsWith("/*") || trimmed.startsWith("*"))
9837
+ continue;
9838
+ if (trimmed.startsWith("import ") || trimmed.startsWith("export "))
9839
+ continue;
9840
+ if (trimmed === '"use client";' || trimmed === '"use server";' || trimmed === "'use client';" || trimmed === "'use server';")
9841
+ continue;
9842
+ return false;
9843
+ }
9844
+ return true;
9845
+ }
9769
9846
 
9770
9847
  // src/init.ts
9771
- import { writeFileSync as writeFileSync2, existsSync as existsSync5 } from "node:fs";
9848
+ import { writeFileSync as writeFileSync2, existsSync as existsSync6 } from "node:fs";
9772
9849
  import { join as join7 } from "node:path";
9773
9850
  function init(cwd = process.cwd()) {
9774
9851
  const configPath = join7(cwd, "pruny.config.json");
9775
- if (existsSync5(configPath)) {
9852
+ if (existsSync6(configPath)) {
9776
9853
  console.log(source_default.yellow("⚠️ pruny.config.json already exists. Skipping."));
9777
9854
  return;
9778
9855
  }
@@ -9792,6 +9869,7 @@ program2.command("init").description("Create a default pruny.config.json file").
9792
9869
  init();
9793
9870
  });
9794
9871
  program2.action(async (options) => {
9872
+ const startTime = Date.now();
9795
9873
  const config = loadConfig({
9796
9874
  dir: options.dir,
9797
9875
  config: options.config,
@@ -10025,5 +10103,8 @@ program2.action(async (options) => {
10025
10103
  console.error(source_default.red("Error scanning:"), _err);
10026
10104
  process.exit(1);
10027
10105
  }
10106
+ const elapsed = ((Date.now() - startTime) / 1000).toFixed(2);
10107
+ console.log(source_default.dim(`
10108
+ ⏱️ Completed in ${elapsed}s`));
10028
10109
  });
10029
10110
  program2.parse();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pruny",
3
- "version": "1.3.0",
3
+ "version": "1.5.0",
4
4
  "description": "Find and remove unused Next.js API routes & Nest.js Controllers",
5
5
  "type": "module",
6
6
  "files": [