pruny 1.43.5 → 1.43.6

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 +60 -56
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -12563,13 +12563,13 @@ var source_default = chalk;
12563
12563
 
12564
12564
  // src/index.ts
12565
12565
  var import_prompts = __toESM(require_prompts3(), 1);
12566
- import { rmSync, existsSync as existsSync10, readdirSync, lstatSync, writeFileSync as writeFileSync3 } from "node:fs";
12567
- import { dirname as dirname6, join as join10, relative as relative5, resolve as resolve4 } from "node:path";
12566
+ import { rmSync, existsSync as existsSync11, readdirSync, lstatSync, writeFileSync as writeFileSync3 } from "node:fs";
12567
+ import { dirname as dirname6, join as join11, relative as relative5, resolve as resolve4 } from "node:path";
12568
12568
 
12569
12569
  // src/scanner.ts
12570
12570
  var import_fast_glob10 = __toESM(require_out4(), 1);
12571
- import { existsSync as existsSync7, readFileSync as readFileSync10 } from "node:fs";
12572
- import { join as join7 } from "node:path";
12571
+ import { existsSync as existsSync8, readFileSync as readFileSync10 } from "node:fs";
12572
+ import { join as join8 } from "node:path";
12573
12573
 
12574
12574
  // src/patterns.ts
12575
12575
  var EXPORTED_METHOD_PATTERN = /export\s+(?:async\s+)?(?:function|const)\s+(GET|POST|PUT|DELETE|PATCH|HEAD|OPTIONS)/g;
@@ -15873,7 +15873,8 @@ async function scanUnusedServices(config) {
15873
15873
 
15874
15874
  // src/scanners/broken-links.ts
15875
15875
  var import_fast_glob9 = __toESM(require_out4(), 1);
15876
- import { readFileSync as readFileSync9 } from "node:fs";
15876
+ import { readFileSync as readFileSync9, existsSync as existsSync7 } from "node:fs";
15877
+ import { join as join7 } from "node:path";
15877
15878
  var LINK_PATTERNS = [
15878
15879
  /<Link\s+[^>]*href\s*=\s*['"`](\/[^'"`\s{}$]+)['"`]/g,
15879
15880
  /router\.(push|replace)\s*\(\s*['"`](\/[^'"`\s{}$]+)['"`]/g,
@@ -16010,13 +16011,13 @@ async function scanBrokenLinks(config) {
16010
16011
  });
16011
16012
  if (config.appSpecificScan) {
16012
16013
  const { readdirSync, lstatSync } = await import("node:fs");
16013
- const { join: join7 } = await import("node:path");
16014
- const appsDir = join7(config.appSpecificScan.rootDir, "apps");
16014
+ const { join: join8 } = await import("node:path");
16015
+ const appsDir = join8(config.appSpecificScan.rootDir, "apps");
16015
16016
  try {
16016
- const apps = readdirSync(appsDir).filter((a) => lstatSync(join7(appsDir, a)).isDirectory());
16017
+ const apps = readdirSync(appsDir).filter((a) => lstatSync(join8(appsDir, a)).isDirectory());
16017
16018
  const expoAppDirs = [];
16018
16019
  for (const app of apps) {
16019
- const appPath = join7(appsDir, app);
16020
+ const appPath = join8(appsDir, app);
16020
16021
  const frameworks = detectAppFramework(appPath);
16021
16022
  if (frameworks.includes("expo") || frameworks.includes("react-native")) {
16022
16023
  expoAppDirs.push(appPath);
@@ -16046,6 +16047,9 @@ async function scanBrokenLinks(config) {
16046
16047
  continue;
16047
16048
  allLinkPaths.add(cleaned);
16048
16049
  if (!matchesRoute(cleaned, knownRoutes, routeSegmentsList)) {
16050
+ const publicPath = join7(appDir, "public", cleaned);
16051
+ if (existsSync7(publicPath))
16052
+ continue;
16049
16053
  const ignorePatterns = [
16050
16054
  ...config.ignore.links || [],
16051
16055
  ...config.ignore.routes
@@ -16226,12 +16230,12 @@ function normalizeNestPath(path2) {
16226
16230
  return path2.replace(/\/$/, "").replace(/\?.*$/, "").replace(/\$\{[^}]+\}/g, "*").replace(/:[^/]+/g, "*").toLowerCase();
16227
16231
  }
16228
16232
  async function detectGlobalPrefix(appDir) {
16229
- const mainTsPath = join7(appDir, "src/main.ts");
16230
- const mainTsAltPath = join7(appDir, "main.ts");
16233
+ const mainTsPath = join8(appDir, "src/main.ts");
16234
+ const mainTsAltPath = join8(appDir, "main.ts");
16231
16235
  let content;
16232
- if (existsSync7(mainTsPath)) {
16236
+ if (existsSync8(mainTsPath)) {
16233
16237
  content = readFileSync10(mainTsPath, "utf-8");
16234
- } else if (existsSync7(mainTsAltPath)) {
16238
+ } else if (existsSync8(mainTsAltPath)) {
16235
16239
  content = readFileSync10(mainTsAltPath, "utf-8");
16236
16240
  } else {
16237
16241
  return "";
@@ -16290,8 +16294,8 @@ function checkRouteUsage(route, references, nestGlobalPrefix = "") {
16290
16294
  return { used, usedMethods };
16291
16295
  }
16292
16296
  function getVercelExternalPaths(dir) {
16293
- const vercelPath = join7(dir, "vercel.json");
16294
- if (!existsSync7(vercelPath)) {
16297
+ const vercelPath = join8(dir, "vercel.json");
16298
+ if (!existsSync8(vercelPath)) {
16295
16299
  return [];
16296
16300
  }
16297
16301
  try {
@@ -16322,15 +16326,15 @@ function getVercelExternalPaths(dir) {
16322
16326
  }
16323
16327
  }
16324
16328
  function getGitHubWorkflowPaths(dir) {
16325
- const workflowDir = join7(dir, ".github", "workflows");
16326
- if (!existsSync7(workflowDir))
16329
+ const workflowDir = join8(dir, ".github", "workflows");
16330
+ if (!existsSync8(workflowDir))
16327
16331
  return [];
16328
16332
  const paths = [];
16329
16333
  const apiPathPattern = /\/api\/[a-zA-Z0-9_\-/[\]]+/g;
16330
16334
  try {
16331
16335
  const files = import_fast_glob10.default.sync("*.{yml,yaml}", { cwd: workflowDir });
16332
16336
  for (const file of files) {
16333
- const content = readFileSync10(join7(workflowDir, file), "utf-8");
16337
+ const content = readFileSync10(join8(workflowDir, file), "utf-8");
16334
16338
  let match2;
16335
16339
  apiPathPattern.lastIndex = 0;
16336
16340
  while ((match2 = apiPathPattern.exec(content)) !== null) {
@@ -16349,10 +16353,10 @@ function getGitHubWorkflowPaths(dir) {
16349
16353
  function getAutoDetectedExternalRoutes(dir) {
16350
16354
  const routes = [];
16351
16355
  const packagePaths = [
16352
- join7(dir, "package.json")
16356
+ join8(dir, "package.json")
16353
16357
  ];
16354
16358
  for (const pkgPath of packagePaths) {
16355
- if (!existsSync7(pkgPath))
16359
+ if (!existsSync8(pkgPath))
16356
16360
  continue;
16357
16361
  try {
16358
16362
  const pkg = JSON.parse(readFileSync10(pkgPath, "utf-8"));
@@ -16398,7 +16402,7 @@ async function scan(config) {
16398
16402
  ignore: config.ignore.folders
16399
16403
  });
16400
16404
  const nextRoutes = nextFiles.map((file) => {
16401
- const fullPath = join7(scanCwd, file);
16405
+ const fullPath = join8(scanCwd, file);
16402
16406
  const content = readFileSync10(fullPath, "utf-8");
16403
16407
  const { methods, methodLines } = extractExportedMethods(content);
16404
16408
  return {
@@ -16418,7 +16422,7 @@ async function scan(config) {
16418
16422
  ignore: config.ignore.folders
16419
16423
  });
16420
16424
  const nestRoutes = nestFiles.flatMap((file) => {
16421
- const fullPath = join7(scanCwd, file);
16425
+ const fullPath = join8(scanCwd, file);
16422
16426
  const content = readFileSync10(fullPath, "utf-8");
16423
16427
  const relativePathFromRoot = fullPath.replace(config.appSpecificScan ? config.appSpecificScan.rootDir + "/" : cwd + "/", "");
16424
16428
  return extractNestRoutes(relativePathFromRoot, content, detectedGlobalPrefix);
@@ -16475,7 +16479,7 @@ async function scan(config) {
16475
16479
  const allReferences = [];
16476
16480
  const fileReferences = new Map;
16477
16481
  for (const file of sourceFiles) {
16478
- const filePath = join7(referenceScanCwd, file);
16482
+ const filePath = join8(referenceScanCwd, file);
16479
16483
  try {
16480
16484
  const content = readFileSync10(filePath, "utf-8");
16481
16485
  const refs = extractApiReferences(content);
@@ -16585,8 +16589,8 @@ async function scan(config) {
16585
16589
 
16586
16590
  // src/config.ts
16587
16591
  var import_fast_glob11 = __toESM(require_out4(), 1);
16588
- import { existsSync as existsSync8, readFileSync as readFileSync11 } from "node:fs";
16589
- import { join as join8, resolve as resolve3, relative as relative4, dirname as dirname5 } from "node:path";
16592
+ import { existsSync as existsSync9, readFileSync as readFileSync11 } from "node:fs";
16593
+ import { join as join9, resolve as resolve3, relative as relative4, dirname as dirname5 } from "node:path";
16590
16594
  var DEFAULT_CONFIG = {
16591
16595
  dir: "./",
16592
16596
  ignore: {
@@ -16623,7 +16627,7 @@ function loadConfig(options) {
16623
16627
  ignore: DEFAULT_CONFIG.ignore.folders,
16624
16628
  absolute: true
16625
16629
  });
16626
- if (options.config && existsSync8(options.config)) {
16630
+ if (options.config && existsSync9(options.config)) {
16627
16631
  const absConfig = resolve3(cwd, options.config);
16628
16632
  if (!configFiles.includes(absConfig)) {
16629
16633
  configFiles.push(absConfig);
@@ -16652,7 +16656,7 @@ function loadConfig(options) {
16652
16656
  const prefixPattern = (p) => {
16653
16657
  if (p.startsWith("**/") || p.startsWith("/") || !relDir)
16654
16658
  return p;
16655
- const prefixed = join8(relDir, p).replace(/\\/g, "/");
16659
+ const prefixed = join9(relDir, p).replace(/\\/g, "/");
16656
16660
  return prefixed.includes("/") ? `**/${prefixed}` : `**/${prefixed}`;
16657
16661
  };
16658
16662
  if (config.ignore?.routes)
@@ -16691,8 +16695,8 @@ function loadConfig(options) {
16691
16695
  };
16692
16696
  }
16693
16697
  function parseGitIgnore(dir) {
16694
- const gitIgnorePath = join8(dir, ".gitignore");
16695
- if (!existsSync8(gitIgnorePath))
16698
+ const gitIgnorePath = join9(dir, ".gitignore");
16699
+ if (!existsSync9(gitIgnorePath))
16696
16700
  return [];
16697
16701
  try {
16698
16702
  const content = readFileSync11(gitIgnorePath, "utf-8");
@@ -16709,8 +16713,8 @@ function parseGitIgnore(dir) {
16709
16713
  function findConfigFile(dir) {
16710
16714
  const candidates = ["pruny.config.json", ".prunyrc.json", ".prunyrc"];
16711
16715
  for (const name of candidates) {
16712
- const path2 = join8(dir, name);
16713
- if (existsSync8(path2)) {
16716
+ const path2 = join9(dir, name);
16717
+ if (existsSync9(path2)) {
16714
16718
  return path2;
16715
16719
  }
16716
16720
  }
@@ -16718,11 +16722,11 @@ function findConfigFile(dir) {
16718
16722
  }
16719
16723
 
16720
16724
  // src/init.ts
16721
- import { writeFileSync as writeFileSync2, existsSync as existsSync9 } from "node:fs";
16722
- import { join as join9 } from "node:path";
16725
+ import { writeFileSync as writeFileSync2, existsSync as existsSync10 } from "node:fs";
16726
+ import { join as join10 } from "node:path";
16723
16727
  function init(cwd = process.cwd()) {
16724
- const configPath = join9(cwd, "pruny.config.json");
16725
- if (existsSync9(configPath)) {
16728
+ const configPath = join10(cwd, "pruny.config.json");
16729
+ if (existsSync10(configPath)) {
16726
16730
  console.log(source_default.yellow("⚠️ pruny.config.json already exists. Skipping."));
16727
16731
  return;
16728
16732
  }
@@ -16750,7 +16754,7 @@ program2.action(async (options) => {
16750
16754
  config: options.config,
16751
16755
  excludePublic: !options.public
16752
16756
  });
16753
- const absoluteDir = baseConfig.dir.startsWith("/") ? baseConfig.dir : join10(process.cwd(), baseConfig.dir);
16757
+ const absoluteDir = baseConfig.dir.startsWith("/") ? baseConfig.dir : join11(process.cwd(), baseConfig.dir);
16754
16758
  baseConfig.dir = absoluteDir;
16755
16759
  if (options.verbose)
16756
16760
  console.log("");
@@ -16758,13 +16762,13 @@ program2.action(async (options) => {
16758
16762
  \uD83D\uDD0D Scanning for unused API routes...
16759
16763
  `));
16760
16764
  let monorepoRoot = absoluteDir;
16761
- let appsDir = join10(monorepoRoot, "apps");
16762
- let isMonorepo = existsSync10(appsDir) && lstatSync(appsDir).isDirectory();
16765
+ let appsDir = join11(monorepoRoot, "apps");
16766
+ let isMonorepo = existsSync11(appsDir) && lstatSync(appsDir).isDirectory();
16763
16767
  if (!isMonorepo) {
16764
16768
  let current = absoluteDir;
16765
16769
  while (current !== dirname6(current)) {
16766
- const potentialApps = join10(current, "apps");
16767
- if (existsSync10(potentialApps) && lstatSync(potentialApps).isDirectory()) {
16770
+ const potentialApps = join11(current, "apps");
16771
+ if (existsSync11(potentialApps) && lstatSync(potentialApps).isDirectory()) {
16768
16772
  monorepoRoot = current;
16769
16773
  appsDir = potentialApps;
16770
16774
  isMonorepo = true;
@@ -16782,13 +16786,13 @@ program2.action(async (options) => {
16782
16786
  const ignoredApps = options.ignoreApps ? options.ignoreApps.split(",").map((a) => a.trim()) : [];
16783
16787
  if (isMonorepo) {
16784
16788
  if (monorepoRoot !== absoluteDir) {
16785
- const appName = relative5(join10(monorepoRoot, "apps"), absoluteDir);
16789
+ const appName = relative5(join11(monorepoRoot, "apps"), absoluteDir);
16786
16790
  appsToScan.push(appName);
16787
16791
  } else {
16788
16792
  const apps = readdirSync(appsDir);
16789
16793
  const availableApps = [];
16790
16794
  for (const app of apps) {
16791
- const appPath = join10(appsDir, app);
16795
+ const appPath = join11(appsDir, app);
16792
16796
  if (lstatSync(appPath).isDirectory()) {
16793
16797
  availableApps.push(app);
16794
16798
  }
@@ -16850,7 +16854,7 @@ program2.action(async (options) => {
16850
16854
  let appDir = monorepoRoot;
16851
16855
  if (isMonorepo) {
16852
16856
  appLabel = `App: ${appName}`;
16853
- appDir = join10(monorepoRoot, "apps", appName);
16857
+ appDir = join11(monorepoRoot, "apps", appName);
16854
16858
  currentConfig.appSpecificScan = {
16855
16859
  appDir,
16856
16860
  rootDir: monorepoRoot
@@ -17311,7 +17315,7 @@ Analyzing cascading impact...`));
17311
17315
  }));
17312
17316
  dryRunReport.uniqueFiles = brokenList.length;
17313
17317
  }
17314
- const reportPath = join10(process.cwd(), "pruny-dry-run.json");
17318
+ const reportPath = join11(process.cwd(), "pruny-dry-run.json");
17315
17319
  writeFileSync3(reportPath, JSON.stringify(dryRunReport, null, 2));
17316
17320
  console.log(source_default.green(`
17317
17321
  ✅ Dry run report saved to: ${source_default.bold(reportPath)}`));
@@ -17365,7 +17369,7 @@ Analyzing cascading impact...`));
17365
17369
  if (!asset.used) {
17366
17370
  try {
17367
17371
  const fullPath = asset.path;
17368
- if (existsSync10(fullPath)) {
17372
+ if (existsSync11(fullPath)) {
17369
17373
  rmSync(fullPath, { force: true });
17370
17374
  console.log(source_default.red(` Deleted: ${asset.relativePath}`));
17371
17375
  fixedSomething = true;
@@ -17453,7 +17457,7 @@ Analyzing cascading impact...`));
17453
17457
  }
17454
17458
  const actuallyDeleted = new Set;
17455
17459
  for (const path2 of filesToUnlink) {
17456
- if (existsSync10(path2)) {
17460
+ if (existsSync11(path2)) {
17457
17461
  rmSync(path2, { recursive: true, force: true });
17458
17462
  actuallyDeleted.add(path2);
17459
17463
  console.log(source_default.red(` Deleted: ${relative5(config.dir, path2)}`));
@@ -17466,7 +17470,7 @@ Analyzing cascading impact...`));
17466
17470
  for (const [absPath, removals] of removalsByFile) {
17467
17471
  if (actuallyDeleted.has(absPath) || actuallyDeleted.has(dirname6(absPath)))
17468
17472
  continue;
17469
- if (!existsSync10(absPath))
17473
+ if (!existsSync11(absPath))
17470
17474
  continue;
17471
17475
  const sortedRemovals = removals.sort((a, b) => b.line - a.line);
17472
17476
  for (const rem of sortedRemovals) {
@@ -17496,8 +17500,8 @@ Analyzing cascading impact...`));
17496
17500
  \uD83D\uDDD1️ Deleting unused source files...`));
17497
17501
  for (const file of result.unusedFiles.files) {
17498
17502
  try {
17499
- const fullPath = join10(config.dir, file.path);
17500
- if (!existsSync10(fullPath))
17503
+ const fullPath = join11(config.dir, file.path);
17504
+ if (!existsSync11(fullPath))
17501
17505
  continue;
17502
17506
  rmSync(fullPath, { force: true });
17503
17507
  console.log(source_default.red(` Deleted: ${file.path}`));
@@ -17534,8 +17538,8 @@ Analyzing cascading impact...`));
17534
17538
  }
17535
17539
  let fixedCount = 0;
17536
17540
  for (const [file, methods] of methodsByFile.entries()) {
17537
- const fullPath = join10(config.dir, file);
17538
- if (!existsSync10(fullPath))
17541
+ const fullPath = join11(config.dir, file);
17542
+ if (!existsSync11(fullPath))
17539
17543
  continue;
17540
17544
  const sortedMethods = methods.sort((a, b) => b.line - a.line);
17541
17545
  for (const method of sortedMethods) {
@@ -17608,8 +17612,8 @@ Analyzing cascading impact...`));
17608
17612
  }
17609
17613
  let svcFixedCount = 0;
17610
17614
  for (const [file, methods] of svcByFile.entries()) {
17611
- const fullPath = join10(config.dir, file);
17612
- if (!existsSync10(fullPath))
17615
+ const fullPath = join11(config.dir, file);
17616
+ if (!existsSync11(fullPath))
17613
17617
  continue;
17614
17618
  const sortedMethods = methods.sort((a, b) => b.line - a.line);
17615
17619
  for (const method of sortedMethods) {
@@ -17654,8 +17658,8 @@ async function fixUnusedExports(result, config) {
17654
17658
  for (const [_file, exports] of exportsByFile.entries()) {
17655
17659
  const sortedExports = exports.sort((a, b) => b.line - a.line);
17656
17660
  for (const exp of sortedExports) {
17657
- const fullPath = join10(config.dir, exp.file);
17658
- if (!existsSync10(fullPath))
17661
+ const fullPath = join11(config.dir, exp.file);
17662
+ if (!existsSync11(fullPath))
17659
17663
  continue;
17660
17664
  if (removeExportFromLine(config.dir, exp)) {
17661
17665
  console.log(source_default.green(` Fixed: ${exp.name} in ${exp.file}`));
@@ -17952,7 +17956,7 @@ function printTable(summary) {
17952
17956
  function findGitRoot(startDir) {
17953
17957
  let currentDir = startDir;
17954
17958
  while (currentDir !== dirname6(currentDir)) {
17955
- if (existsSync10(join10(currentDir, ".git"))) {
17959
+ if (existsSync11(join11(currentDir, ".git"))) {
17956
17960
  return true;
17957
17961
  }
17958
17962
  currentDir = dirname6(currentDir);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pruny",
3
- "version": "1.43.5",
3
+ "version": "1.43.6",
4
4
  "description": "Find and remove unused Next.js API routes & Nest.js Controllers",
5
5
  "type": "module",
6
6
  "files": [