pruny 1.19.0 → 1.20.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.
- package/dist/index.js +73 -63
- package/dist/workers/file-processor.js +17 -2
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -9369,6 +9369,8 @@ var IGNORED_EXPORT_NAMES = new Set([
|
|
|
9369
9369
|
"OPTIONS",
|
|
9370
9370
|
"default"
|
|
9371
9371
|
]);
|
|
9372
|
+
var NEST_LIFECYCLE_METHODS = new Set(["constructor", "onModuleInit", "onApplicationBootstrap", "onModuleDestroy", "beforeApplicationShutdown", "onApplicationShutdown"]);
|
|
9373
|
+
var classMethodRegex = /^\s*(?:async\s+)?([a-zA-Z0-9_$]+)\s*\([^)]*\)\s*(?::\s*[^\{]*)?\{/gm;
|
|
9372
9374
|
async function processFilesInParallel(files, cwd, workerCount) {
|
|
9373
9375
|
const __filename2 = fileURLToPath(import.meta.url);
|
|
9374
9376
|
const __dirname2 = dirname2(__filename2);
|
|
@@ -9475,6 +9477,7 @@ async function scanUnusedExports(config) {
|
|
|
9475
9477
|
}
|
|
9476
9478
|
const content = readFileSync3(join3(cwd, file), "utf-8");
|
|
9477
9479
|
totalContents.set(file, content);
|
|
9480
|
+
const isService = file.endsWith(".service.ts") || file.endsWith(".service.tsx");
|
|
9478
9481
|
const lines = content.split(`
|
|
9479
9482
|
`);
|
|
9480
9483
|
for (let i = 0;i < lines.length; i++) {
|
|
@@ -9498,6 +9501,20 @@ async function scanUnusedExports(config) {
|
|
|
9498
9501
|
}
|
|
9499
9502
|
}
|
|
9500
9503
|
}
|
|
9504
|
+
if (isService) {
|
|
9505
|
+
classMethodRegex.lastIndex = 0;
|
|
9506
|
+
while ((match2 = classMethodRegex.exec(line)) !== null) {
|
|
9507
|
+
const name = match2[1];
|
|
9508
|
+
if (name && !NEST_LIFECYCLE_METHODS.has(name) && !IGNORED_EXPORT_NAMES.has(name)) {
|
|
9509
|
+
const existing = exportMap.get(file)?.find((e) => e.name === name);
|
|
9510
|
+
if (!existing) {
|
|
9511
|
+
if (addExport(file, name, i + 1)) {
|
|
9512
|
+
allExportsCount++;
|
|
9513
|
+
}
|
|
9514
|
+
}
|
|
9515
|
+
}
|
|
9516
|
+
}
|
|
9517
|
+
}
|
|
9501
9518
|
}
|
|
9502
9519
|
} catch {}
|
|
9503
9520
|
}
|
|
@@ -10203,13 +10220,11 @@ program2.action(async (options) => {
|
|
|
10203
10220
|
if (result.unusedFiles) {
|
|
10204
10221
|
result.unusedFiles.files = result.unusedFiles.files.filter((f) => matchesFilter(f.path));
|
|
10205
10222
|
result.unusedFiles.total = result.unusedFiles.files.length;
|
|
10206
|
-
result.unusedFiles.used = 0;
|
|
10207
10223
|
result.unusedFiles.unused = result.unusedFiles.files.length;
|
|
10208
10224
|
}
|
|
10209
10225
|
if (result.unusedExports) {
|
|
10210
10226
|
result.unusedExports.exports = result.unusedExports.exports.filter((e) => matchesFilter(e.file));
|
|
10211
10227
|
result.unusedExports.total = result.unusedExports.exports.length;
|
|
10212
|
-
result.unusedExports.used = 0;
|
|
10213
10228
|
result.unusedExports.unused = result.unusedExports.exports.length;
|
|
10214
10229
|
}
|
|
10215
10230
|
}
|
|
@@ -10261,7 +10276,7 @@ program2.action(async (options) => {
|
|
|
10261
10276
|
console.log("");
|
|
10262
10277
|
}
|
|
10263
10278
|
if (result.unusedExports && result.unusedExports.exports.length > 0) {
|
|
10264
|
-
console.log(source_default.red.bold(`\uD83D\uDD17 Unused Named Exports:
|
|
10279
|
+
console.log(source_default.red.bold(`\uD83D\uDD17 Unused Named Exports/Methods:
|
|
10265
10280
|
`));
|
|
10266
10281
|
for (const exp of result.unusedExports.exports) {
|
|
10267
10282
|
console.log(source_default.red(` ${exp.name}`));
|
|
@@ -10308,7 +10323,6 @@ program2.action(async (options) => {
|
|
|
10308
10323
|
fixedSomething = true;
|
|
10309
10324
|
} else {
|
|
10310
10325
|
console.log(source_default.yellow(` Skipped File Deletion (internally used): ${filePath}`));
|
|
10311
|
-
console.log(source_default.dim(` → This controller is imported in another file (e.g. app.module.ts).`));
|
|
10312
10326
|
const allMethodsToPrune = [];
|
|
10313
10327
|
for (const r of fileRoutes) {
|
|
10314
10328
|
for (const m of r.unusedMethods) {
|
|
@@ -10386,38 +10400,17 @@ program2.action(async (options) => {
|
|
|
10386
10400
|
console.log("");
|
|
10387
10401
|
}
|
|
10388
10402
|
if (result.unusedExports && result.unusedExports.exports.length > 0) {
|
|
10389
|
-
|
|
10390
|
-
|
|
10391
|
-
|
|
10392
|
-
|
|
10393
|
-
|
|
10394
|
-
|
|
10395
|
-
|
|
10396
|
-
|
|
10397
|
-
}
|
|
10398
|
-
let fixedCount = 0;
|
|
10399
|
-
for (const [file, exports] of exportsByFile.entries()) {
|
|
10400
|
-
const sortedExports = exports.sort((a, b) => b.line - a.line);
|
|
10401
|
-
for (const exp of sortedExports) {
|
|
10402
|
-
const fullPath = join8(config.dir, exp.file);
|
|
10403
|
-
if (!existsSync7(fullPath))
|
|
10404
|
-
continue;
|
|
10405
|
-
if (removeExportFromLine(config.dir, exp)) {
|
|
10406
|
-
console.log(source_default.green(` Fixed: ${exp.name} in ${exp.file}`));
|
|
10407
|
-
fixedCount++;
|
|
10408
|
-
fixedSomething = true;
|
|
10409
|
-
const expIdx = result.unusedExports.exports.indexOf(exp);
|
|
10410
|
-
if (expIdx !== -1) {
|
|
10411
|
-
result.unusedExports.exports.splice(expIdx, 1);
|
|
10412
|
-
result.unusedExports.unused--;
|
|
10413
|
-
}
|
|
10414
|
-
}
|
|
10415
|
-
}
|
|
10416
|
-
}
|
|
10417
|
-
if (fixedCount > 0) {
|
|
10418
|
-
console.log(source_default.green(`
|
|
10419
|
-
✅ Removed "export" from ${fixedCount} item(s).
|
|
10403
|
+
fixedSomething = await fixUnusedExports(result, config) || fixedSomething;
|
|
10404
|
+
}
|
|
10405
|
+
if (fixedSomething) {
|
|
10406
|
+
console.log(source_default.cyan.bold(`
|
|
10407
|
+
\uD83D\uDD04 Checking for cascading dead code (newly unused implementation)...`));
|
|
10408
|
+
const secondPass = await scanUnusedExports(config);
|
|
10409
|
+
if (secondPass.unused > 0) {
|
|
10410
|
+
console.log(source_default.yellow(` Found ${secondPass.unused} newly unused items/methods after pruning.
|
|
10420
10411
|
`));
|
|
10412
|
+
result.unusedExports = secondPass;
|
|
10413
|
+
await fixUnusedExports(result, config);
|
|
10421
10414
|
}
|
|
10422
10415
|
}
|
|
10423
10416
|
if (fixedSomething) {
|
|
@@ -10451,41 +10444,21 @@ program2.action(async (options) => {
|
|
|
10451
10444
|
for (const key of sortedKeys) {
|
|
10452
10445
|
const group = groupedRoutes.get(key);
|
|
10453
10446
|
const typeLabel = group.type === "nextjs" ? "Next.js" : "NestJS";
|
|
10454
|
-
const label = `${typeLabel} (${group.app})`;
|
|
10455
10447
|
summary.push({
|
|
10456
|
-
Category:
|
|
10448
|
+
Category: `${typeLabel} (${group.app})`,
|
|
10457
10449
|
Total: group.routes.length,
|
|
10458
10450
|
Used: group.routes.filter((r) => r.used).length,
|
|
10459
10451
|
Unused: group.routes.filter((r) => !r.used).length
|
|
10460
10452
|
});
|
|
10461
10453
|
}
|
|
10462
|
-
if (summary.length === 0)
|
|
10454
|
+
if (summary.length === 0)
|
|
10463
10455
|
summary.push({ Category: "API Routes", Total: result.total, Used: result.used, Unused: result.unused });
|
|
10464
|
-
|
|
10465
|
-
|
|
10466
|
-
|
|
10467
|
-
|
|
10468
|
-
|
|
10469
|
-
|
|
10470
|
-
Unused: result.publicAssets.unused
|
|
10471
|
-
});
|
|
10472
|
-
}
|
|
10473
|
-
if (result.unusedFiles) {
|
|
10474
|
-
summary.push({
|
|
10475
|
-
Category: "Source Files",
|
|
10476
|
-
Total: result.unusedFiles.total,
|
|
10477
|
-
Used: result.unusedFiles.used,
|
|
10478
|
-
Unused: result.unusedFiles.unused
|
|
10479
|
-
});
|
|
10480
|
-
}
|
|
10481
|
-
if (result.unusedExports) {
|
|
10482
|
-
summary.push({
|
|
10483
|
-
Category: "Exported Items",
|
|
10484
|
-
Total: result.unusedExports.total,
|
|
10485
|
-
Used: result.unusedExports.used,
|
|
10486
|
-
Unused: result.unusedExports.unused
|
|
10487
|
-
});
|
|
10488
|
-
}
|
|
10456
|
+
if (result.publicAssets)
|
|
10457
|
+
summary.push({ Category: "Public Assets", Total: result.publicAssets.total, Used: result.publicAssets.used, Unused: result.publicAssets.unused });
|
|
10458
|
+
if (result.unusedFiles)
|
|
10459
|
+
summary.push({ Category: "Source Files", Total: result.unusedFiles.total, Used: result.unusedFiles.used, Unused: result.unusedFiles.unused });
|
|
10460
|
+
if (result.unusedExports)
|
|
10461
|
+
summary.push({ Category: "Exported Items", Total: result.unusedExports.total, Used: result.unusedExports.used, Unused: result.unusedExports.unused });
|
|
10489
10462
|
console.table(summary);
|
|
10490
10463
|
} catch (_err) {
|
|
10491
10464
|
console.error(source_default.red("Error scanning:"), _err);
|
|
@@ -10495,4 +10468,41 @@ program2.action(async (options) => {
|
|
|
10495
10468
|
console.log(source_default.dim(`
|
|
10496
10469
|
⏱️ Completed in ${elapsed}s`));
|
|
10497
10470
|
});
|
|
10471
|
+
async function fixUnusedExports(result, config) {
|
|
10472
|
+
if (!result.unusedExports || result.unusedExports.exports.length === 0)
|
|
10473
|
+
return false;
|
|
10474
|
+
console.log(source_default.yellow.bold(`\uD83D\uDD27 Fixing unused exports/methods...
|
|
10475
|
+
`));
|
|
10476
|
+
const exportsByFile = new Map;
|
|
10477
|
+
for (const exp of result.unusedExports.exports) {
|
|
10478
|
+
if (!exportsByFile.has(exp.file))
|
|
10479
|
+
exportsByFile.set(exp.file, []);
|
|
10480
|
+
exportsByFile.get(exp.file).push(exp);
|
|
10481
|
+
}
|
|
10482
|
+
let fixedCount = 0;
|
|
10483
|
+
let fixedSomething = false;
|
|
10484
|
+
for (const [file, exports] of exportsByFile.entries()) {
|
|
10485
|
+
const sortedExports = exports.sort((a, b) => b.line - a.line);
|
|
10486
|
+
for (const exp of sortedExports) {
|
|
10487
|
+
const fullPath = join8(config.dir, exp.file);
|
|
10488
|
+
if (!existsSync7(fullPath))
|
|
10489
|
+
continue;
|
|
10490
|
+
if (removeExportFromLine(config.dir, exp)) {
|
|
10491
|
+
console.log(source_default.green(` Fixed: ${exp.name} in ${exp.file}`));
|
|
10492
|
+
fixedCount++;
|
|
10493
|
+
fixedSomething = true;
|
|
10494
|
+
const expIdx = result.unusedExports.exports.indexOf(exp);
|
|
10495
|
+
if (expIdx !== -1) {
|
|
10496
|
+
result.unusedExports.exports.splice(expIdx, 1);
|
|
10497
|
+
result.unusedExports.unused--;
|
|
10498
|
+
}
|
|
10499
|
+
}
|
|
10500
|
+
}
|
|
10501
|
+
}
|
|
10502
|
+
if (fixedCount > 0)
|
|
10503
|
+
console.log(source_default.green(`
|
|
10504
|
+
✅ Cleaned up ${fixedCount} unused item(s).
|
|
10505
|
+
`));
|
|
10506
|
+
return fixedSomething;
|
|
10507
|
+
}
|
|
10498
10508
|
program2.parse();
|
|
@@ -22,11 +22,11 @@ var IGNORED_EXPORT_NAMES = new Set([
|
|
|
22
22
|
"POST",
|
|
23
23
|
"PUT",
|
|
24
24
|
"PATCH",
|
|
25
|
-
"DELETE",
|
|
26
|
-
"HEAD",
|
|
27
25
|
"OPTIONS",
|
|
28
26
|
"default"
|
|
29
27
|
]);
|
|
28
|
+
var NEST_LIFECYCLE_METHODS = new Set(["constructor", "onModuleInit", "onApplicationBootstrap", "onModuleDestroy", "beforeApplicationShutdown", "onApplicationShutdown"]);
|
|
29
|
+
var classMethodRegex = /^\s*(?:async\s+)?([a-zA-Z0-9_$]+)\s*\([^)]*\)\s*(?::\s*[^\{]*)?\{/gm;
|
|
30
30
|
var inlineExportRegex = /^export\s+(?:async\s+)?(?:const|let|var|function|type|interface|enum|class)\s+([a-zA-Z0-9_$]+)/gm;
|
|
31
31
|
var blockExportRegex = /^export\s*\{([^}]+)\}/gm;
|
|
32
32
|
if (parentPort && workerData) {
|
|
@@ -40,6 +40,7 @@ if (parentPort && workerData) {
|
|
|
40
40
|
contents.set(file, content);
|
|
41
41
|
const lines = content.split(`
|
|
42
42
|
`);
|
|
43
|
+
const isService = file.endsWith(".service.ts") || file.endsWith(".service.tsx");
|
|
43
44
|
for (let i = 0;i < lines.length; i++) {
|
|
44
45
|
const line = lines[i];
|
|
45
46
|
inlineExportRegex.lastIndex = 0;
|
|
@@ -66,6 +67,20 @@ if (parentPort && workerData) {
|
|
|
66
67
|
}
|
|
67
68
|
}
|
|
68
69
|
}
|
|
70
|
+
if (isService) {
|
|
71
|
+
classMethodRegex.lastIndex = 0;
|
|
72
|
+
while ((match = classMethodRegex.exec(line)) !== null) {
|
|
73
|
+
const name = match[1];
|
|
74
|
+
if (name && !NEST_LIFECYCLE_METHODS.has(name) && !IGNORED_EXPORT_NAMES.has(name)) {
|
|
75
|
+
const existing = exportMap.get(file)?.find((e) => e.name === name);
|
|
76
|
+
if (!existing) {
|
|
77
|
+
if (!exportMap.has(file))
|
|
78
|
+
exportMap.set(file, []);
|
|
79
|
+
exportMap.get(file).push({ name, line: i + 1, file });
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
69
84
|
}
|
|
70
85
|
processedCount++;
|
|
71
86
|
if (processedCount % 10 === 0) {
|