pruny 1.5.0 → 1.7.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 +70 -8
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -9402,8 +9402,12 @@ async function scanUnusedExports(config) {
9402
9402
  for (let i = 0;i < lines.length; i++) {
9403
9403
  if (i === exp.line - 1)
9404
9404
  continue;
9405
+ const line = lines[i];
9406
+ if (isCommentOrString(line))
9407
+ continue;
9408
+ const cleanLine = stripStringsAndComments(line);
9405
9409
  const referenceRegex = new RegExp(`\\b${exp.name}\\b`);
9406
- if (referenceRegex.test(lines[i])) {
9410
+ if (referenceRegex.test(cleanLine)) {
9407
9411
  usedInternally = true;
9408
9412
  break;
9409
9413
  }
@@ -9412,11 +9416,29 @@ async function scanUnusedExports(config) {
9412
9416
  for (const [otherFile, content] of totalContents.entries()) {
9413
9417
  if (file === otherFile)
9414
9418
  continue;
9415
- const referenceRegex = new RegExp(`\\b${exp.name}\\b`);
9416
- if (referenceRegex.test(content)) {
9419
+ const jsxPattern = new RegExp(`<${exp.name}[\\s/>]`);
9420
+ const importPattern = new RegExp(`import.*\\b${exp.name}\\b.*from`);
9421
+ const destructurePattern = new RegExp(`\\{[^}]*\\b${exp.name}\\b[^}]*\\}`);
9422
+ if (jsxPattern.test(content) || importPattern.test(content)) {
9417
9423
  isUsed = true;
9418
9424
  break;
9419
9425
  }
9426
+ if (!isUsed) {
9427
+ const lines = content.split(`
9428
+ `);
9429
+ for (const line of lines) {
9430
+ if (isCommentOrString(line))
9431
+ continue;
9432
+ const cleanLine = stripStringsAndComments(line);
9433
+ const codeUsagePattern = new RegExp(`\\b${exp.name}\\s*[({]|\\b${exp.name}\\s*\\.|\\b${exp.name}\\s*,|\\b${exp.name}\\s*;|\\b${exp.name}\\s*\\)`);
9434
+ if (codeUsagePattern.test(cleanLine)) {
9435
+ isUsed = true;
9436
+ break;
9437
+ }
9438
+ }
9439
+ }
9440
+ if (isUsed)
9441
+ break;
9420
9442
  }
9421
9443
  if (!isUsed) {
9422
9444
  unusedExports.push({ ...exp, usedInternally });
@@ -9430,6 +9452,24 @@ async function scanUnusedExports(config) {
9430
9452
  exports: unusedExports
9431
9453
  };
9432
9454
  }
9455
+ function isCommentOrString(line) {
9456
+ const trimmed = line.trim();
9457
+ if (trimmed.startsWith("//"))
9458
+ return true;
9459
+ if (trimmed.startsWith("/*") || trimmed.startsWith("*"))
9460
+ return true;
9461
+ if (trimmed.includes("{/*") || trimmed.includes("*/}"))
9462
+ return true;
9463
+ return false;
9464
+ }
9465
+ function stripStringsAndComments(line) {
9466
+ let result = line;
9467
+ result = result.replace(/\/\/.*$/g, "");
9468
+ result = result.replace(/'([^'\\]|\\.)*'/g, "''");
9469
+ result = result.replace(/"([^"\\]|\\.)*"/g, '""');
9470
+ result = result.replace(/`([^`\\]|\\.)*`/g, "``");
9471
+ return result;
9472
+ }
9433
9473
 
9434
9474
  // src/scanner.ts
9435
9475
  function extractRoutePath(filePath) {
@@ -9898,7 +9938,19 @@ program2.action(async (options) => {
9898
9938
  return "Root";
9899
9939
  };
9900
9940
  const matchesFilter = (path2) => {
9901
- return path2.toLowerCase().includes(filter2) || getAppName2(path2).toLowerCase().includes(filter2);
9941
+ const lowerPath = path2.toLowerCase();
9942
+ const appName = getAppName2(path2).toLowerCase();
9943
+ if (appName.includes(filter2))
9944
+ return true;
9945
+ const segments = lowerPath.split("/");
9946
+ for (const segment of segments) {
9947
+ if (segment === filter2)
9948
+ return true;
9949
+ const withoutExt = segment.replace(/\.[^.]+$/, "");
9950
+ if (withoutExt === filter2)
9951
+ return true;
9952
+ }
9953
+ return lowerPath.includes(filter2);
9902
9954
  };
9903
9955
  result.routes = result.routes.filter((r) => matchesFilter(r.filePath));
9904
9956
  if (result.publicAssets) {
@@ -10082,11 +10134,21 @@ program2.action(async (options) => {
10082
10134
  if (result.unusedExports && result.unusedExports.exports.length > 0) {
10083
10135
  console.log(source_default.yellow.bold(`\uD83D\uDD27 Fixing unused exports (removing "export" keyword)...
10084
10136
  `));
10085
- let fixedCount = 0;
10137
+ const exportsByFile = new Map;
10086
10138
  for (const exp of result.unusedExports.exports) {
10087
- if (removeExportFromLine(config.dir, exp)) {
10088
- console.log(source_default.green(` Fixed: ${exp.name} in ${exp.file}`));
10089
- fixedCount++;
10139
+ if (!exportsByFile.has(exp.file)) {
10140
+ exportsByFile.set(exp.file, []);
10141
+ }
10142
+ exportsByFile.get(exp.file).push(exp);
10143
+ }
10144
+ let fixedCount = 0;
10145
+ for (const [file, exports] of exportsByFile.entries()) {
10146
+ const sortedExports = exports.sort((a, b) => b.line - a.line);
10147
+ for (const exp of sortedExports) {
10148
+ if (removeExportFromLine(config.dir, exp)) {
10149
+ console.log(source_default.green(` Fixed: ${exp.name} in ${exp.file}`));
10150
+ fixedCount++;
10151
+ }
10090
10152
  }
10091
10153
  }
10092
10154
  if (fixedCount > 0) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pruny",
3
- "version": "1.5.0",
3
+ "version": "1.7.0",
4
4
  "description": "Find and remove unused Next.js API routes & Nest.js Controllers",
5
5
  "type": "module",
6
6
  "files": [