clear_node_modules 1.4.2 → 1.4.3
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 +1 -1
- package/src/lib.js +122 -45
package/package.json
CHANGED
package/src/lib.js
CHANGED
|
@@ -6,16 +6,34 @@ const { promisify } = require("util");
|
|
|
6
6
|
|
|
7
7
|
const rimrafAsync = promisify(rimraf);
|
|
8
8
|
|
|
9
|
+
// 格式化文件大小
|
|
10
|
+
function formatSize(bytes) {
|
|
11
|
+
if (bytes < 1024) return bytes + " B";
|
|
12
|
+
if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + " KB";
|
|
13
|
+
if (bytes < 1024 * 1024 * 1024) return (bytes / 1024 / 1024).toFixed(1) + " MB";
|
|
14
|
+
return (bytes / 1024 / 1024 / 1024).toFixed(2) + " GB";
|
|
15
|
+
}
|
|
16
|
+
|
|
9
17
|
function getDirSize(dir) {
|
|
10
18
|
let total = 0;
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
const
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
19
|
+
try {
|
|
20
|
+
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
21
|
+
for (const entry of entries) {
|
|
22
|
+
const fullPath = path.join(dir, entry.name);
|
|
23
|
+
try {
|
|
24
|
+
if (entry.isSymbolicLink()) {
|
|
25
|
+
continue;
|
|
26
|
+
} else if (entry.isDirectory()) {
|
|
27
|
+
total += getDirSize(fullPath);
|
|
28
|
+
} else if (entry.isFile()) {
|
|
29
|
+
total += fs.statSync(fullPath).size;
|
|
30
|
+
}
|
|
31
|
+
} catch (e) {
|
|
32
|
+
continue;
|
|
33
|
+
}
|
|
18
34
|
}
|
|
35
|
+
} catch (e) {
|
|
36
|
+
// 目录不可读
|
|
19
37
|
}
|
|
20
38
|
return total;
|
|
21
39
|
}
|
|
@@ -25,61 +43,111 @@ function wrap(LIMIT_SIZE, NODE_MODULES) {
|
|
|
25
43
|
const tasks = [];
|
|
26
44
|
let totalCount = 0;
|
|
27
45
|
let doneCount = 0;
|
|
46
|
+
let totalFreed = 0;
|
|
47
|
+
let failedCount = 0;
|
|
28
48
|
|
|
29
|
-
//
|
|
49
|
+
// 扫描阶段
|
|
50
|
+
const scanSpinner = ora("🔍 Scanning for node_modules...").start();
|
|
51
|
+
|
|
30
52
|
function scan(pathToScan) {
|
|
31
|
-
|
|
32
|
-
return;
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
53
|
+
try {
|
|
54
|
+
if (!fs.existsSync(pathToScan)) return;
|
|
55
|
+
const stat = fs.lstatSync(pathToScan);
|
|
56
|
+
if (!stat.isDirectory() || stat.isSymbolicLink()) return;
|
|
57
|
+
|
|
58
|
+
const entries = fs.readdirSync(pathToScan, { withFileTypes: true });
|
|
59
|
+
for (const entry of entries) {
|
|
60
|
+
const subPath = path.join(pathToScan, entry.name);
|
|
61
|
+
try {
|
|
62
|
+
if (entry.isSymbolicLink()) continue;
|
|
63
|
+
if (entry.name === NODE_MODULES && entry.isDirectory()) {
|
|
64
|
+
totalCount++;
|
|
65
|
+
} else if (entry.isDirectory()) {
|
|
66
|
+
scan(subPath);
|
|
67
|
+
}
|
|
68
|
+
} catch (e) {
|
|
69
|
+
continue;
|
|
70
|
+
}
|
|
40
71
|
}
|
|
72
|
+
} catch (e) {
|
|
73
|
+
// 忽略
|
|
41
74
|
}
|
|
42
75
|
}
|
|
43
76
|
|
|
44
77
|
scan(dirPath);
|
|
78
|
+
|
|
79
|
+
if (totalCount === 0) {
|
|
80
|
+
scanSpinner.info("No node_modules found.");
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
scanSpinner.succeed(`Found ${totalCount} node_modules folder(s)`);
|
|
85
|
+
console.log("");
|
|
45
86
|
|
|
46
87
|
async function recurse(currentPath) {
|
|
47
|
-
|
|
48
|
-
!fs.existsSync(currentPath)
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
return;
|
|
88
|
+
try {
|
|
89
|
+
if (!fs.existsSync(currentPath)) return;
|
|
90
|
+
const stat = fs.lstatSync(currentPath);
|
|
91
|
+
if (!stat.isDirectory() || stat.isSymbolicLink()) return;
|
|
52
92
|
|
|
53
|
-
|
|
54
|
-
|
|
93
|
+
const entries = fs.readdirSync(currentPath, { withFileTypes: true });
|
|
94
|
+
if (entries.length === 0) return;
|
|
55
95
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
96
|
+
for (const entry of entries) {
|
|
97
|
+
const subPath = path.join(currentPath, entry.name);
|
|
98
|
+
try {
|
|
99
|
+
if (entry.isSymbolicLink()) continue;
|
|
100
|
+
|
|
101
|
+
if (entry.name === NODE_MODULES && entry.isDirectory()) {
|
|
102
|
+
const dirSize = getDirSize(subPath);
|
|
103
|
+
const sizeMB = dirSize / 1024 / 1024;
|
|
104
|
+
|
|
105
|
+
if (sizeMB < LIMIT_SIZE) {
|
|
106
|
+
doneCount++;
|
|
107
|
+
console.log(` ⏭️ [${doneCount}/${totalCount}] Skipped (${formatSize(dirSize)}) ${subPath}`);
|
|
108
|
+
continue;
|
|
109
|
+
}
|
|
61
110
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
111
|
+
const spinner = ora({
|
|
112
|
+
text: `[${++doneCount}/${totalCount}] Removing ${formatSize(dirSize)} - ${subPath}`,
|
|
113
|
+
prefixText: " "
|
|
114
|
+
}).start();
|
|
115
|
+
|
|
116
|
+
const task = rimrafAsync(subPath)
|
|
117
|
+
.then(() => {
|
|
118
|
+
totalFreed += dirSize;
|
|
119
|
+
spinner.succeed(`[${doneCount}/${totalCount}] ✓ Freed ${formatSize(dirSize)} - ${subPath}`);
|
|
120
|
+
})
|
|
121
|
+
.catch((err) => {
|
|
122
|
+
failedCount++;
|
|
123
|
+
spinner.fail(`[${doneCount}/${totalCount}] ✗ Failed - ${subPath}: ${err.message}`);
|
|
124
|
+
});
|
|
125
|
+
tasks.push(task);
|
|
126
|
+
} else if (entry.isDirectory()) {
|
|
127
|
+
await recurse(subPath);
|
|
128
|
+
}
|
|
129
|
+
} catch (e) {
|
|
130
|
+
continue;
|
|
131
|
+
}
|
|
77
132
|
}
|
|
133
|
+
} catch (e) {
|
|
134
|
+
// 忽略
|
|
78
135
|
}
|
|
79
136
|
}
|
|
80
137
|
|
|
81
138
|
await recurse(dirPath);
|
|
82
139
|
await Promise.all(tasks);
|
|
140
|
+
|
|
141
|
+
// 汇总信息
|
|
142
|
+
console.log("");
|
|
143
|
+
console.log("─".repeat(50));
|
|
144
|
+
console.log(` ✨ Completed!`);
|
|
145
|
+
console.log(` 📁 Processed: ${totalCount} folder(s)`);
|
|
146
|
+
console.log(` 💾 Freed: ${formatSize(totalFreed)}`);
|
|
147
|
+
if (failedCount > 0) {
|
|
148
|
+
console.log(` ⚠️ Failed: ${failedCount}`);
|
|
149
|
+
}
|
|
150
|
+
console.log("─".repeat(50));
|
|
83
151
|
};
|
|
84
152
|
}
|
|
85
153
|
|
|
@@ -89,9 +157,18 @@ async function clearFunc(
|
|
|
89
157
|
NODE_MODULES = "node_modules"
|
|
90
158
|
) {
|
|
91
159
|
console.log("");
|
|
160
|
+
console.log("🧹 Clear Node Modules");
|
|
161
|
+
console.log("─".repeat(50));
|
|
162
|
+
console.log(` 📂 Target: ${path.resolve(disDir)}`);
|
|
163
|
+
if (LIMIT_SIZE > 0) {
|
|
164
|
+
console.log(` 📏 Min size: ${LIMIT_SIZE} MB`);
|
|
165
|
+
}
|
|
166
|
+
console.log("─".repeat(50));
|
|
167
|
+
console.log("");
|
|
168
|
+
|
|
92
169
|
const clearDir = wrap(LIMIT_SIZE, NODE_MODULES);
|
|
93
170
|
await clearDir(path.resolve(disDir));
|
|
94
|
-
console.log("
|
|
171
|
+
console.log("");
|
|
95
172
|
}
|
|
96
173
|
|
|
97
174
|
module.exports = clearFunc;
|