pruny 1.17.1 → 1.19.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 +86 -38
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -7649,13 +7649,20 @@ var API_METHOD_PATTERNS = [
|
|
|
7649
7649
|
{ regex: /axios\.put\s*\(\s*['"`](\/[^'"`\s)]+)['"`]/g, method: "PUT" },
|
|
7650
7650
|
{ regex: /axios\.delete\s*\(\s*['"`](\/[^'"`\s)]+)['"`]/g, method: "DELETE" },
|
|
7651
7651
|
{ regex: /axios\.patch\s*\(\s*['"`](\/[^'"`\s)]+)['"`]/g, method: "PATCH" },
|
|
7652
|
+
{ regex: /axios\.get\s*\(\s*`[^`]*?(\/[^`\s)]+)`/g, method: "GET" },
|
|
7653
|
+
{ regex: /axios\.post\s*\(\s*`[^`]*?(\/[^`\s)]+)`/g, method: "POST" },
|
|
7654
|
+
{ regex: /axios\.put\s*\(\s*`[^`]*?(\/[^`\s)]+)`/g, method: "PUT" },
|
|
7655
|
+
{ regex: /axios\.delete\s*\(\s*`[^`]*?(\/[^`\s)]+)`/g, method: "DELETE" },
|
|
7656
|
+
{ regex: /axios\.patch\s*\(\s*`[^`]*?(\/[^`\s)]+)`/g, method: "PATCH" },
|
|
7652
7657
|
{ regex: /useSWR\s*\(\s*['"`](\/[^'"`\s)]+)['"`]/g, method: "GET" },
|
|
7658
|
+
{ regex: /useSWR\s*\(\s*`[^`]*?(\/[^`\s)]+)`/g, method: "GET" },
|
|
7653
7659
|
{ regex: /fetch\s*\(\s*['"`](\/[^'"`\s)]+)['"`]/g, method: undefined },
|
|
7654
|
-
{ regex: /fetch\s*\(\s*`[^`]
|
|
7660
|
+
{ regex: /fetch\s*\(\s*`[^`]*?(\/[^`\s)]+)`/g, method: undefined },
|
|
7655
7661
|
{ regex: /['"`](\/api\/[^'"`\s]+)['"`]/g, method: undefined },
|
|
7656
|
-
{ regex:
|
|
7657
|
-
{ regex: /`[^`]
|
|
7658
|
-
{ regex: /['"`](\/[\w-]{2,}\/[
|
|
7662
|
+
{ regex: /`[^`]*?(\/api\/[^`\s]+)`/g, method: undefined },
|
|
7663
|
+
{ regex: /`[^`]*?(\/[\w-]{2,}\/[^`\s]*)`/g, method: undefined },
|
|
7664
|
+
{ regex: /['"`](\/[\w-]{2,}\/[^'"`\s]*)['"`]/g, method: undefined },
|
|
7665
|
+
{ regex: /['"`](\/api\/[^'"`\s]*)['"`]/g, method: undefined }
|
|
7659
7666
|
];
|
|
7660
7667
|
function extractApiReferences(content) {
|
|
7661
7668
|
const matches = [];
|
|
@@ -9680,14 +9687,21 @@ function extractNestRoutes(filePath, content, globalPrefix = "api") {
|
|
|
9680
9687
|
return routes;
|
|
9681
9688
|
}
|
|
9682
9689
|
function shouldIgnore(path2, ignorePatterns) {
|
|
9683
|
-
const
|
|
9690
|
+
const cleanPath = path2.replace(/\\/g, "/").replace(/^\//, "").replace(/^\.\//, "");
|
|
9684
9691
|
return ignorePatterns.some((pattern) => {
|
|
9685
|
-
|
|
9686
|
-
|
|
9692
|
+
let cleanPattern = pattern.replace(/\\/g, "/").replace(/^\.\//, "");
|
|
9693
|
+
const isAbsolute = cleanPattern.startsWith("/");
|
|
9694
|
+
if (isAbsolute)
|
|
9695
|
+
cleanPattern = cleanPattern.substring(1);
|
|
9696
|
+
if (minimatch(cleanPath, cleanPattern))
|
|
9687
9697
|
return true;
|
|
9688
|
-
const folderPattern =
|
|
9689
|
-
if (
|
|
9698
|
+
const folderPattern = cleanPattern.endsWith("/") ? cleanPattern : cleanPattern + "/";
|
|
9699
|
+
if (cleanPath.startsWith(folderPattern))
|
|
9690
9700
|
return true;
|
|
9701
|
+
if (!isAbsolute && !cleanPattern.includes("/") && !cleanPattern.includes("*")) {
|
|
9702
|
+
if (cleanPath.endsWith("/" + cleanPattern) || cleanPath === cleanPattern)
|
|
9703
|
+
return true;
|
|
9704
|
+
}
|
|
9691
9705
|
return false;
|
|
9692
9706
|
});
|
|
9693
9707
|
}
|
|
@@ -9697,21 +9711,32 @@ function normalizeNextPath(path2) {
|
|
|
9697
9711
|
function normalizeNestPath(path2) {
|
|
9698
9712
|
return path2.replace(/\/$/, "").replace(/\?.*$/, "").replace(/:[^/]+/g, "*").toLowerCase();
|
|
9699
9713
|
}
|
|
9700
|
-
function checkRouteUsage(route, references, nestGlobalPrefix = "
|
|
9714
|
+
function checkRouteUsage(route, references, nestGlobalPrefix = "") {
|
|
9701
9715
|
const normalize = route.type === "nextjs" ? normalizeNextPath : normalizeNestPath;
|
|
9702
9716
|
const normalizedRoute = normalize(route.path);
|
|
9703
|
-
const
|
|
9704
|
-
|
|
9717
|
+
const variations = new Set([normalizedRoute]);
|
|
9718
|
+
if (route.type === "nestjs") {
|
|
9719
|
+
if (nestGlobalPrefix) {
|
|
9720
|
+
const prefixToRemove = `/${nestGlobalPrefix}`.replace(/\/+/g, "/");
|
|
9721
|
+
if (route.path.startsWith(prefixToRemove)) {
|
|
9722
|
+
variations.add(normalize(route.path.substring(prefixToRemove.length)));
|
|
9723
|
+
}
|
|
9724
|
+
}
|
|
9725
|
+
if (route.path.startsWith("/api/")) {
|
|
9726
|
+
variations.add(normalize(route.path.substring(4)));
|
|
9727
|
+
} else {
|
|
9728
|
+
variations.add(normalize("/api" + route.path));
|
|
9729
|
+
}
|
|
9730
|
+
}
|
|
9705
9731
|
const usedMethods = new Set;
|
|
9706
9732
|
let used = false;
|
|
9707
9733
|
for (const ref of references) {
|
|
9708
9734
|
const normalizedFound = ref.path.replace(/\/$/, "").replace(/\?.*$/, "").replace(/\$\{[^}]+\}/g, "*").toLowerCase();
|
|
9709
9735
|
let match2 = false;
|
|
9710
|
-
|
|
9711
|
-
|
|
9712
|
-
} else if (normalizedRouteNoPrefix) {
|
|
9713
|
-
if (normalizedRouteNoPrefix === normalizedFound || normalizedFound.startsWith(normalizedRouteNoPrefix + "/") || minimatch(normalizedFound, normalizedRouteNoPrefix)) {
|
|
9736
|
+
for (const v of variations) {
|
|
9737
|
+
if (v === normalizedFound || normalizedFound.startsWith(v + "/") || minimatch(normalizedFound, v)) {
|
|
9714
9738
|
match2 = true;
|
|
9739
|
+
break;
|
|
9715
9740
|
}
|
|
9716
9741
|
}
|
|
9717
9742
|
if (match2) {
|
|
@@ -9808,7 +9833,7 @@ async function scan(config) {
|
|
|
9808
9833
|
} catch {}
|
|
9809
9834
|
}
|
|
9810
9835
|
for (const route of routes) {
|
|
9811
|
-
if (shouldIgnore(route.path, config.ignore.routes)) {
|
|
9836
|
+
if (shouldIgnore(route.path, config.ignore.routes) || shouldIgnore(route.filePath, config.ignore.routes)) {
|
|
9812
9837
|
route.used = true;
|
|
9813
9838
|
route.references.push("(ignored by config)");
|
|
9814
9839
|
route.unusedMethods = [];
|
|
@@ -9888,7 +9913,7 @@ var DEFAULT_CONFIG = {
|
|
|
9888
9913
|
]
|
|
9889
9914
|
},
|
|
9890
9915
|
extensions: [".ts", ".tsx", ".js", ".jsx"],
|
|
9891
|
-
nestGlobalPrefix: "
|
|
9916
|
+
nestGlobalPrefix: "",
|
|
9892
9917
|
extraRoutePatterns: []
|
|
9893
9918
|
};
|
|
9894
9919
|
function loadConfig(options) {
|
|
@@ -9930,7 +9955,7 @@ function loadConfig(options) {
|
|
|
9930
9955
|
return prefixed.includes("/") ? `**/${prefixed}` : `**/${prefixed}`;
|
|
9931
9956
|
};
|
|
9932
9957
|
if (config.ignore?.routes)
|
|
9933
|
-
mergedIgnore.routes.push(...config.ignore.routes
|
|
9958
|
+
mergedIgnore.routes.push(...config.ignore.routes);
|
|
9934
9959
|
if (config.ignore?.folders)
|
|
9935
9960
|
mergedIgnore.folders.push(...config.ignore.folders.map(prefixPattern));
|
|
9936
9961
|
if (config.ignore?.files)
|
|
@@ -10253,47 +10278,70 @@ program2.action(async (options) => {
|
|
|
10253
10278
|
if (unusedRoutes.length > 0) {
|
|
10254
10279
|
console.log(source_default.yellow.bold(`\uD83D\uDDD1️ Deleting unused routes...
|
|
10255
10280
|
`));
|
|
10256
|
-
|
|
10257
|
-
|
|
10281
|
+
const routesByFile = new Map;
|
|
10282
|
+
for (const r of unusedRoutes) {
|
|
10283
|
+
const list = routesByFile.get(r.filePath) || [];
|
|
10284
|
+
list.push(r);
|
|
10285
|
+
routesByFile.set(r.filePath, list);
|
|
10286
|
+
}
|
|
10287
|
+
for (const [filePath, fileRoutes] of routesByFile) {
|
|
10288
|
+
const fullPath = join8(config.dir, filePath);
|
|
10289
|
+
if (!existsSync7(fullPath))
|
|
10290
|
+
continue;
|
|
10291
|
+
const route = fileRoutes[0];
|
|
10258
10292
|
const routeDir = dirname4(fullPath);
|
|
10259
10293
|
try {
|
|
10260
|
-
if (!existsSync7(fullPath))
|
|
10261
|
-
continue;
|
|
10262
10294
|
if (route.type === "nextjs") {
|
|
10263
|
-
if (
|
|
10295
|
+
if (filePath.includes("app/api") || filePath.includes("pages/api")) {
|
|
10264
10296
|
rmSync(routeDir, { recursive: true, force: true });
|
|
10265
10297
|
console.log(source_default.red(` Deleted Folder: ${routeDir}`));
|
|
10266
10298
|
} else {
|
|
10267
10299
|
rmSync(fullPath, { force: true });
|
|
10268
|
-
console.log(source_default.red(` Deleted File: ${
|
|
10300
|
+
console.log(source_default.red(` Deleted File: ${filePath}`));
|
|
10269
10301
|
}
|
|
10302
|
+
fixedSomething = true;
|
|
10270
10303
|
} else if (route.type === "nestjs") {
|
|
10271
|
-
const isInternallyUnused = result.unusedFiles?.files.some((f) => f.path ===
|
|
10272
|
-
if (isInternallyUnused ||
|
|
10304
|
+
const isInternallyUnused = result.unusedFiles?.files.some((f) => f.path === filePath);
|
|
10305
|
+
if (isInternallyUnused || filePath.includes("api/")) {
|
|
10273
10306
|
rmSync(fullPath, { force: true });
|
|
10274
|
-
console.log(source_default.red(` Deleted File: ${
|
|
10307
|
+
console.log(source_default.red(` Deleted File: ${filePath}`));
|
|
10275
10308
|
fixedSomething = true;
|
|
10276
10309
|
} else {
|
|
10277
|
-
console.log(source_default.yellow(` Skipped Deletion (internally used): ${
|
|
10310
|
+
console.log(source_default.yellow(` Skipped File Deletion (internally used): ${filePath}`));
|
|
10278
10311
|
console.log(source_default.dim(` → This controller is imported in another file (e.g. app.module.ts).`));
|
|
10279
|
-
|
|
10312
|
+
const allMethodsToPrune = [];
|
|
10313
|
+
for (const r of fileRoutes) {
|
|
10314
|
+
for (const m of r.unusedMethods) {
|
|
10315
|
+
if (r.methodLines[m] !== undefined) {
|
|
10316
|
+
allMethodsToPrune.push({ method: m, line: r.methodLines[m] });
|
|
10317
|
+
}
|
|
10318
|
+
}
|
|
10319
|
+
}
|
|
10320
|
+
allMethodsToPrune.sort((a, b) => b.line - a.line);
|
|
10321
|
+
for (const { method, line } of allMethodsToPrune) {
|
|
10322
|
+
if (removeMethodFromRoute(config.dir, filePath, method, line)) {
|
|
10323
|
+
console.log(source_default.green(` Fixed: Removed ${method} from ${filePath}`));
|
|
10324
|
+
fixedSomething = true;
|
|
10325
|
+
}
|
|
10326
|
+
}
|
|
10280
10327
|
}
|
|
10281
10328
|
} else {
|
|
10282
10329
|
rmSync(fullPath, { force: true });
|
|
10283
|
-
console.log(source_default.red(` Deleted File: ${
|
|
10330
|
+
console.log(source_default.red(` Deleted File: ${filePath}`));
|
|
10284
10331
|
fixedSomething = true;
|
|
10285
10332
|
}
|
|
10286
|
-
|
|
10287
|
-
|
|
10288
|
-
|
|
10289
|
-
|
|
10290
|
-
|
|
10291
|
-
|
|
10333
|
+
for (const r of fileRoutes) {
|
|
10334
|
+
const idx = result.routes.indexOf(r);
|
|
10335
|
+
if (idx !== -1)
|
|
10336
|
+
result.routes.splice(idx, 1);
|
|
10337
|
+
}
|
|
10338
|
+
} catch (err) {
|
|
10339
|
+
console.log(source_default.yellow(` Failed to fix: ${filePath}`));
|
|
10292
10340
|
}
|
|
10293
10341
|
}
|
|
10294
10342
|
console.log("");
|
|
10295
10343
|
}
|
|
10296
|
-
const partiallyRoutes = result.routes.filter((r) => r.used && r.unusedMethods.length > 0);
|
|
10344
|
+
const partiallyRoutes = result.routes.filter((r) => r.used && r.unusedMethods && r.unusedMethods.length > 0);
|
|
10297
10345
|
if (partiallyRoutes.length > 0) {
|
|
10298
10346
|
console.log(source_default.yellow.bold(`\uD83D\uDD27 Fixing partially unused routes...
|
|
10299
10347
|
`));
|