pruny 1.17.1 → 1.18.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 +56 -26
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -9680,14 +9680,21 @@ function extractNestRoutes(filePath, content, globalPrefix = "api") {
9680
9680
  return routes;
9681
9681
  }
9682
9682
  function shouldIgnore(path2, ignorePatterns) {
9683
- const normalizedPath = path2.replace(/\\/g, "/").replace(/^\.\//, "");
9683
+ const cleanPath = path2.replace(/\\/g, "/").replace(/^\//, "").replace(/^\.\//, "");
9684
9684
  return ignorePatterns.some((pattern) => {
9685
- const normalizedPattern = pattern.replace(/\\/g, "/").replace(/^\.\//, "");
9686
- if (minimatch(normalizedPath, normalizedPattern))
9685
+ let cleanPattern = pattern.replace(/\\/g, "/").replace(/^\.\//, "");
9686
+ const isAbsolute = cleanPattern.startsWith("/");
9687
+ if (isAbsolute)
9688
+ cleanPattern = cleanPattern.substring(1);
9689
+ if (minimatch(cleanPath, cleanPattern))
9687
9690
  return true;
9688
- const folderPattern = normalizedPattern.endsWith("/") ? normalizedPattern : normalizedPattern + "/";
9689
- if (normalizedPath.startsWith(folderPattern))
9691
+ const folderPattern = cleanPattern.endsWith("/") ? cleanPattern : cleanPattern + "/";
9692
+ if (cleanPath.startsWith(folderPattern))
9690
9693
  return true;
9694
+ if (!isAbsolute && !cleanPattern.includes("/") && !cleanPattern.includes("*")) {
9695
+ if (cleanPath.endsWith("/" + cleanPattern) || cleanPath === cleanPattern)
9696
+ return true;
9697
+ }
9691
9698
  return false;
9692
9699
  });
9693
9700
  }
@@ -9808,7 +9815,7 @@ async function scan(config) {
9808
9815
  } catch {}
9809
9816
  }
9810
9817
  for (const route of routes) {
9811
- if (shouldIgnore(route.path, config.ignore.routes)) {
9818
+ if (shouldIgnore(route.path, config.ignore.routes) || shouldIgnore(route.filePath, config.ignore.routes)) {
9812
9819
  route.used = true;
9813
9820
  route.references.push("(ignored by config)");
9814
9821
  route.unusedMethods = [];
@@ -9930,7 +9937,7 @@ function loadConfig(options) {
9930
9937
  return prefixed.includes("/") ? `**/${prefixed}` : `**/${prefixed}`;
9931
9938
  };
9932
9939
  if (config.ignore?.routes)
9933
- mergedIgnore.routes.push(...config.ignore.routes.map(prefixPattern));
9940
+ mergedIgnore.routes.push(...config.ignore.routes);
9934
9941
  if (config.ignore?.folders)
9935
9942
  mergedIgnore.folders.push(...config.ignore.folders.map(prefixPattern));
9936
9943
  if (config.ignore?.files)
@@ -10253,47 +10260,70 @@ program2.action(async (options) => {
10253
10260
  if (unusedRoutes.length > 0) {
10254
10261
  console.log(source_default.yellow.bold(`\uD83D\uDDD1️ Deleting unused routes...
10255
10262
  `));
10256
- for (const route of unusedRoutes) {
10257
- const fullPath = join8(config.dir, route.filePath);
10263
+ const routesByFile = new Map;
10264
+ for (const r of unusedRoutes) {
10265
+ const list = routesByFile.get(r.filePath) || [];
10266
+ list.push(r);
10267
+ routesByFile.set(r.filePath, list);
10268
+ }
10269
+ for (const [filePath, fileRoutes] of routesByFile) {
10270
+ const fullPath = join8(config.dir, filePath);
10271
+ if (!existsSync7(fullPath))
10272
+ continue;
10273
+ const route = fileRoutes[0];
10258
10274
  const routeDir = dirname4(fullPath);
10259
10275
  try {
10260
- if (!existsSync7(fullPath))
10261
- continue;
10262
10276
  if (route.type === "nextjs") {
10263
- if (route.filePath.includes("app/api") || route.filePath.includes("pages/api")) {
10277
+ if (filePath.includes("app/api") || filePath.includes("pages/api")) {
10264
10278
  rmSync(routeDir, { recursive: true, force: true });
10265
10279
  console.log(source_default.red(` Deleted Folder: ${routeDir}`));
10266
10280
  } else {
10267
10281
  rmSync(fullPath, { force: true });
10268
- console.log(source_default.red(` Deleted File: ${route.filePath}`));
10282
+ console.log(source_default.red(` Deleted File: ${filePath}`));
10269
10283
  }
10284
+ fixedSomething = true;
10270
10285
  } else if (route.type === "nestjs") {
10271
- const isInternallyUnused = result.unusedFiles?.files.some((f) => f.path === route.filePath);
10272
- if (isInternallyUnused || route.filePath.includes("api/")) {
10286
+ const isInternallyUnused = result.unusedFiles?.files.some((f) => f.path === filePath);
10287
+ if (isInternallyUnused || filePath.includes("api/")) {
10273
10288
  rmSync(fullPath, { force: true });
10274
- console.log(source_default.red(` Deleted File: ${route.filePath}`));
10289
+ console.log(source_default.red(` Deleted File: ${filePath}`));
10275
10290
  fixedSomething = true;
10276
10291
  } else {
10277
- console.log(source_default.yellow(` Skipped Deletion (internally used): ${route.filePath}`));
10292
+ console.log(source_default.yellow(` Skipped File Deletion (internally used): ${filePath}`));
10278
10293
  console.log(source_default.dim(` → This controller is imported in another file (e.g. app.module.ts).`));
10279
- continue;
10294
+ const allMethodsToPrune = [];
10295
+ for (const r of fileRoutes) {
10296
+ for (const m of r.unusedMethods) {
10297
+ if (r.methodLines[m] !== undefined) {
10298
+ allMethodsToPrune.push({ method: m, line: r.methodLines[m] });
10299
+ }
10300
+ }
10301
+ }
10302
+ allMethodsToPrune.sort((a, b) => b.line - a.line);
10303
+ for (const { method, line } of allMethodsToPrune) {
10304
+ if (removeMethodFromRoute(config.dir, filePath, method, line)) {
10305
+ console.log(source_default.green(` Fixed: Removed ${method} from ${filePath}`));
10306
+ fixedSomething = true;
10307
+ }
10308
+ }
10280
10309
  }
10281
10310
  } else {
10282
10311
  rmSync(fullPath, { force: true });
10283
- console.log(source_default.red(` Deleted File: ${route.filePath}`));
10312
+ console.log(source_default.red(` Deleted File: ${filePath}`));
10284
10313
  fixedSomething = true;
10285
10314
  }
10286
- fixedSomething = true;
10287
- const idx = result.routes.indexOf(route);
10288
- if (idx !== -1)
10289
- result.routes.splice(idx, 1);
10290
- } catch (_err) {
10291
- console.log(source_default.yellow(` Failed to delete: ${route.filePath}`));
10315
+ for (const r of fileRoutes) {
10316
+ const idx = result.routes.indexOf(r);
10317
+ if (idx !== -1)
10318
+ result.routes.splice(idx, 1);
10319
+ }
10320
+ } catch (err) {
10321
+ console.log(source_default.yellow(` Failed to fix: ${filePath}`));
10292
10322
  }
10293
10323
  }
10294
10324
  console.log("");
10295
10325
  }
10296
- const partiallyRoutes = result.routes.filter((r) => r.used && r.unusedMethods.length > 0);
10326
+ const partiallyRoutes = result.routes.filter((r) => r.used && r.unusedMethods && r.unusedMethods.length > 0);
10297
10327
  if (partiallyRoutes.length > 0) {
10298
10328
  console.log(source_default.yellow.bold(`\uD83D\uDD27 Fixing partially unused routes...
10299
10329
  `));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pruny",
3
- "version": "1.17.1",
3
+ "version": "1.18.0",
4
4
  "description": "Find and remove unused Next.js API routes & Nest.js Controllers",
5
5
  "type": "module",
6
6
  "files": [