clear_node_modules 1.4.2 → 1.5.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/package.json +3 -3
- package/src/lib.js +104 -58
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "clear_node_modules",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.5.0",
|
|
4
4
|
"description": "Recursively remove node_modules folders from current directory and subdirectories",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"bin": {
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
},
|
|
32
32
|
"homepage": "https://github.com/mooniitt/clear_node_modules#readme",
|
|
33
33
|
"dependencies": {
|
|
34
|
-
"ora": "^
|
|
35
|
-
"rimraf": "^
|
|
34
|
+
"ora": "^5.4.1",
|
|
35
|
+
"rimraf": "^5.0.0"
|
|
36
36
|
}
|
|
37
37
|
}
|
package/src/lib.js
CHANGED
|
@@ -1,85 +1,122 @@
|
|
|
1
1
|
const fs = require("fs");
|
|
2
2
|
const path = require("path");
|
|
3
|
-
const rimraf = require("rimraf");
|
|
3
|
+
const { rimraf } = require("rimraf");
|
|
4
4
|
const ora = require("ora");
|
|
5
|
-
const { promisify } = require("util");
|
|
6
5
|
|
|
7
|
-
|
|
6
|
+
// 格式化文件大小
|
|
7
|
+
function formatSize(bytes) {
|
|
8
|
+
if (bytes < 1024) return bytes + " B";
|
|
9
|
+
if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + " KB";
|
|
10
|
+
if (bytes < 1024 * 1024 * 1024) return (bytes / 1024 / 1024).toFixed(1) + " MB";
|
|
11
|
+
return (bytes / 1024 / 1024 / 1024).toFixed(2) + " GB";
|
|
12
|
+
}
|
|
8
13
|
|
|
9
14
|
function getDirSize(dir) {
|
|
10
15
|
let total = 0;
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
const
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
16
|
+
try {
|
|
17
|
+
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
18
|
+
for (const entry of entries) {
|
|
19
|
+
const fullPath = path.join(dir, entry.name);
|
|
20
|
+
try {
|
|
21
|
+
if (entry.isSymbolicLink()) {
|
|
22
|
+
continue;
|
|
23
|
+
} else if (entry.isDirectory()) {
|
|
24
|
+
total += getDirSize(fullPath);
|
|
25
|
+
} else if (entry.isFile()) {
|
|
26
|
+
total += fs.statSync(fullPath).size;
|
|
27
|
+
}
|
|
28
|
+
} catch (e) {
|
|
29
|
+
continue;
|
|
30
|
+
}
|
|
18
31
|
}
|
|
32
|
+
} catch (e) {
|
|
33
|
+
// 目录不可读
|
|
19
34
|
}
|
|
20
35
|
return total;
|
|
21
36
|
}
|
|
22
37
|
|
|
23
38
|
function wrap(LIMIT_SIZE, NODE_MODULES) {
|
|
24
39
|
return async function clearDir(dirPath) {
|
|
25
|
-
const
|
|
26
|
-
let
|
|
27
|
-
let
|
|
40
|
+
const foldersToDelete = [];
|
|
41
|
+
let totalFreed = 0;
|
|
42
|
+
let skippedCount = 0;
|
|
28
43
|
|
|
29
|
-
//
|
|
44
|
+
// 扫描阶段
|
|
45
|
+
const scanSpinner = ora("🔍 Scanning for node_modules...").start();
|
|
46
|
+
|
|
30
47
|
function scan(pathToScan) {
|
|
31
|
-
|
|
32
|
-
return;
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
48
|
+
try {
|
|
49
|
+
if (!fs.existsSync(pathToScan)) return;
|
|
50
|
+
const stat = fs.lstatSync(pathToScan);
|
|
51
|
+
if (!stat.isDirectory() || stat.isSymbolicLink()) return;
|
|
52
|
+
|
|
53
|
+
const entries = fs.readdirSync(pathToScan, { withFileTypes: true });
|
|
54
|
+
for (const entry of entries) {
|
|
55
|
+
const subPath = path.join(pathToScan, entry.name);
|
|
56
|
+
try {
|
|
57
|
+
if (entry.isSymbolicLink()) continue;
|
|
58
|
+
if (entry.name === NODE_MODULES && entry.isDirectory()) {
|
|
59
|
+
const size = getDirSize(subPath);
|
|
60
|
+
foldersToDelete.push({ path: subPath, size });
|
|
61
|
+
} else if (entry.isDirectory()) {
|
|
62
|
+
scan(subPath);
|
|
63
|
+
}
|
|
64
|
+
} catch (e) {
|
|
65
|
+
continue;
|
|
66
|
+
}
|
|
40
67
|
}
|
|
68
|
+
} catch (e) {
|
|
69
|
+
// 忽略
|
|
41
70
|
}
|
|
42
71
|
}
|
|
43
72
|
|
|
44
73
|
scan(dirPath);
|
|
74
|
+
|
|
75
|
+
if (foldersToDelete.length === 0) {
|
|
76
|
+
scanSpinner.info("No node_modules found.");
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
scanSpinner.succeed(`Found ${foldersToDelete.length} node_modules folder(s)`);
|
|
81
|
+
console.log("");
|
|
45
82
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
if (entry === NODE_MODULES && fs.statSync(subPath).isDirectory()) {
|
|
59
|
-
const dirSize = getDirSize(subPath);
|
|
60
|
-
if (dirSize / 1024 / 1024 < LIMIT_SIZE) continue;
|
|
83
|
+
// 串行删除,避免进度混乱
|
|
84
|
+
const total = foldersToDelete.length;
|
|
85
|
+
for (let i = 0; i < foldersToDelete.length; i++) {
|
|
86
|
+
const { path: folderPath, size } = foldersToDelete[i];
|
|
87
|
+
const sizeMB = size / 1024 / 1024;
|
|
88
|
+
const progress = `[${i + 1}/${total}]`;
|
|
89
|
+
|
|
90
|
+
if (sizeMB < LIMIT_SIZE) {
|
|
91
|
+
skippedCount++;
|
|
92
|
+
console.log(` ⏭️ ${progress} Skipped (${formatSize(size)}) ${folderPath}`);
|
|
93
|
+
continue;
|
|
94
|
+
}
|
|
61
95
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
);
|
|
74
|
-
tasks.push(task);
|
|
75
|
-
} else if (fs.statSync(subPath).isDirectory()) {
|
|
76
|
-
await recurse(subPath);
|
|
77
|
-
}
|
|
96
|
+
const spinner = ora({
|
|
97
|
+
text: `${progress} Removing ${formatSize(size)} - ${folderPath}`,
|
|
98
|
+
prefixText: " "
|
|
99
|
+
}).start();
|
|
100
|
+
|
|
101
|
+
try {
|
|
102
|
+
await rimraf(folderPath);
|
|
103
|
+
totalFreed += size;
|
|
104
|
+
spinner.succeed(`${progress} Freed ${formatSize(size)} - ${folderPath}`);
|
|
105
|
+
} catch (err) {
|
|
106
|
+
spinner.fail(`${progress} Failed - ${folderPath}: ${err.message}`);
|
|
78
107
|
}
|
|
79
108
|
}
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
109
|
+
|
|
110
|
+
// 汇总信息
|
|
111
|
+
console.log("");
|
|
112
|
+
console.log("─".repeat(50));
|
|
113
|
+
console.log(` ✨ Completed!`);
|
|
114
|
+
console.log(` 📁 Total: ${total} folder(s)`);
|
|
115
|
+
if (skippedCount > 0) {
|
|
116
|
+
console.log(` ⏭️ Skipped: ${skippedCount}`);
|
|
117
|
+
}
|
|
118
|
+
console.log(` 💾 Freed: ${formatSize(totalFreed)}`);
|
|
119
|
+
console.log("─".repeat(50));
|
|
83
120
|
};
|
|
84
121
|
}
|
|
85
122
|
|
|
@@ -89,9 +126,18 @@ async function clearFunc(
|
|
|
89
126
|
NODE_MODULES = "node_modules"
|
|
90
127
|
) {
|
|
91
128
|
console.log("");
|
|
129
|
+
console.log("🧹 Clear Node Modules");
|
|
130
|
+
console.log("─".repeat(50));
|
|
131
|
+
console.log(` 📂 Target: ${path.resolve(disDir)}`);
|
|
132
|
+
if (LIMIT_SIZE > 0) {
|
|
133
|
+
console.log(` 📏 Min size: ${LIMIT_SIZE} MB`);
|
|
134
|
+
}
|
|
135
|
+
console.log("─".repeat(50));
|
|
136
|
+
console.log("");
|
|
137
|
+
|
|
92
138
|
const clearDir = wrap(LIMIT_SIZE, NODE_MODULES);
|
|
93
139
|
await clearDir(path.resolve(disDir));
|
|
94
|
-
console.log("
|
|
140
|
+
console.log("");
|
|
95
141
|
}
|
|
96
142
|
|
|
97
143
|
module.exports = clearFunc;
|