binary-collections 2.0.12 → 2.0.13
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/binaries/binary-executor.cjs +89 -13
- package/binaries/clean-nodemodule.cjs +89 -13
- package/binaries/clean-nodemodules.cjs +89 -13
- package/binaries/dev.cjs +89 -13
- package/binaries/empty.cjs +89 -13
- package/binaries/git-reduce-size.cjs +89 -13
- package/binaries/javakill.cjs +89 -13
- package/binaries/kill-process.cjs +89 -13
- package/binaries/nodekill.cjs +89 -13
- package/binaries/prod.cjs +89 -13
- package/binaries/py.cjs +89 -13
- package/binaries/rmfind.cjs +89 -13
- package/binaries/rmx.cjs +89 -13
- package/binaries/submodule-token.cjs +89 -13
- package/binaries/test-cjs.cjs +89 -13
- package/binaries/test-esm.cjs +89 -13
- package/binaries/yarn-clean.cjs +89 -13
- package/binaries/yc +22 -1
- package/binaries/yc.cjs +89 -13
- package/binaries/ycw +256 -0
- package/binaries/ycw.cjs +254 -0
- package/docs-src/binary-collections.md +34 -0
- package/docs-src/changelog.md +26 -0
- package/docs-src/clean-github-actions-caches.md +115 -0
- package/docs-src/copy-move-file.md +59 -0
- package/docs-src/del-gradle.md +17 -0
- package/docs-src/del-ps.md +28 -0
- package/docs-src/downloader.md +62 -0
- package/docs-src/env-helpers.md +29 -0
- package/docs-src/find-node-modules.md +17 -0
- package/docs-src/free-chatgpt.md +26 -0
- package/docs-src/git-diff.md +33 -0
- package/docs-src/git-fix.md +34 -0
- package/docs-src/git-purge.md +17 -0
- package/docs-src/git-reduce-size.md +17 -0
- package/docs-src/git-undo.md +21 -0
- package/docs-src/kill-night-crows.md +26 -0
- package/docs-src/node-cache-cleaner.md +182 -0
- package/docs-src/node-executor.md +50 -0
- package/docs-src/node-package-packer.md +48 -0
- package/docs-src/npm-run-series.md +43 -0
- package/docs-src/package-resolutions-updater.md +22 -0
- package/docs-src/php-cs-fixer-staged.md +19 -0
- package/docs-src/print-directory-tree.md +35 -0
- package/docs-src/print-tarball-tree.md +55 -0
- package/docs-src/py.md +19 -0
- package/docs-src/remove-module.md +32 -0
- package/docs-src/rmfind-rmx.md +21 -0
- package/docs-src/rmpath.md +38 -0
- package/docs-src/run-by-checksum.md +87 -0
- package/docs-src/submodule-install.md +31 -0
- package/docs-src/submodule-remove.md +22 -0
- package/docs-src/submodule-token.md +17 -0
- package/docs-src/test-runners.md +21 -0
- package/docs-src/yarn-install.md +31 -0
- package/docs-src/yarn-reinstall.md +27 -0
- package/lib/binary-collections/config.cjs +1 -1
- package/lib/binary-collections/config.mjs +1 -1
- package/lib/binary-collections/findScript.cjs +35 -10
- package/lib/binary-collections/findScript.mjs +2 -2
- package/lib/binary-collections/listScript.cjs +35 -10
- package/lib/binary-collections/listScript.mjs +2 -2
- package/lib/binary-collections.cjs +45 -25
- package/lib/binary-collections.mjs +11 -11
- package/lib/changelog.cjs +7 -12
- package/lib/changelog.mjs +2 -2
- package/lib/{chunk-SPTECFE5.mjs → chunk-2MN4VPV2.mjs} +86 -20
- package/lib/{chunk-V2IBPCEV.mjs → chunk-6C7KTYGZ.mjs} +3 -1
- package/lib/{chunk-5RTXZVCW.mjs → chunk-6RK5UCTP.mjs} +5 -10
- package/lib/{chunk-FB2WKVJD.mjs → chunk-CD3HF3LK.mjs} +67 -35
- package/lib/{chunk-6PU7BAHB.mjs → chunk-FLYSZFLW.mjs} +1 -1
- package/lib/chunk-KLKAIFKI.mjs +40 -0
- package/lib/chunk-LVSPEFU2.mjs +86 -0
- package/lib/{chunk-2LSRSEXF.mjs → chunk-MGPYPKIE.mjs} +2 -2
- package/lib/{chunk-ZOWVMII3.mjs → chunk-NQXUYO67.mjs} +35 -10
- package/lib/{chunk-C6D2TTYU.mjs → chunk-OBXLTXFJ.mjs} +4 -2
- package/lib/chunk-QD4T255Z.mjs +40 -0
- package/lib/{chunk-XPJGCDOD.mjs → chunk-QII2EKCS.mjs} +14 -2
- package/lib/chunk-RDGDLSPD.mjs +76 -0
- package/lib/{chunk-NCZPTKDV.mjs → chunk-RDN6HF5Z.mjs} +1 -1
- package/lib/chunk-RJKTSUAX.mjs +123 -0
- package/lib/{chunk-66KDU4TX.mjs → chunk-TBWXE7ST.mjs} +36 -61
- package/lib/{chunk-M3YIYRHT.mjs → chunk-UY5VUEA3.mjs} +1 -1
- package/lib/chunk-WSHVPGNM.mjs +44 -0
- package/lib/{chunk-G5UUEWUO.mjs → chunk-X2B3X7D4.mjs} +1 -1
- package/lib/clean-github-actions-caches-cli.cjs +255 -213
- package/lib/clean-github-actions-caches-cli.mjs +25 -7
- package/lib/clean-github-actions-caches.cjs +231 -35
- package/lib/clean-github-actions-caches.d.cts +39 -1
- package/lib/clean-github-actions-caches.mjs +2 -1
- package/lib/cross-env/command.cjs +2 -2
- package/lib/cross-env/command.js +2 -2
- package/lib/cross-env/command.mjs +2 -2
- package/lib/cross-env/index.cjs +2 -2
- package/lib/cross-env/index.mjs +3 -3
- package/lib/cross-env/variable.mjs +2 -2
- package/lib/del-gradle.cjs +6 -11
- package/lib/del-gradle.mjs +1 -1
- package/lib/del-node-modules.cjs +185 -3
- package/lib/del-node-modules.js +3 -3
- package/lib/del-node-modules.mjs +6 -3
- package/lib/{del-ps.cjs → del-ps-cli.cjs} +36 -41
- package/lib/del-ps-cli.mjs +44 -0
- package/lib/del-yarn-caches.cjs +6 -11
- package/lib/del-yarn-caches.mjs +1 -1
- package/lib/downloader-cli.cjs +256 -0
- package/lib/downloader-cli.d.cts +2 -0
- package/lib/downloader-cli.mjs +90 -0
- package/lib/file/copy-cli.cjs +183 -2
- package/lib/file/copy-cli.mjs +6 -2
- package/lib/file/move-cli.cjs +183 -2
- package/lib/file/move-cli.mjs +6 -2
- package/lib/find-node-modules-cli.cjs +1 -1
- package/lib/find-node-modules-cli.mjs +1 -1
- package/lib/find-node-modules.cjs +1 -1
- package/lib/find-node-modules.mjs +1 -1
- package/lib/free-chatgpt.cjs +6 -11
- package/lib/free-chatgpt.mjs +1 -1
- package/lib/git/user-config.cjs +7 -12
- package/lib/git/user-config.mjs +2 -2
- package/lib/git-diff-cli.cjs +91 -30
- package/lib/git-diff-cli.mjs +3 -3
- package/lib/git-diff.cjs +91 -30
- package/lib/git-diff.js +85 -28
- package/lib/git-diff.mjs +3 -3
- package/lib/git-fix.cjs +7 -12
- package/lib/git-fix.mjs +2 -2
- package/lib/git-purge.cjs +7 -12
- package/lib/git-purge.mjs +2 -2
- package/lib/index.cjs +1 -1
- package/lib/index.mjs +1 -1
- package/lib/node-cache-cleaner-cli.cjs +185 -2
- package/lib/node-cache-cleaner-cli.js +2 -5
- package/lib/node-cache-cleaner-cli.mjs +8 -4
- package/lib/node-executor.cjs +183 -2
- package/lib/node-executor.mjs +5 -2
- package/lib/node-package-packer/build-readme.cjs +150 -0
- package/lib/node-package-packer/build-readme.d.mts +10 -0
- package/lib/node-package-packer/build-readme.mjs +10 -0
- package/lib/node-package-packer/build-tarball.cjs +495 -0
- package/lib/node-package-packer/build-tarball.d.mts +33 -0
- package/lib/node-package-packer/build-tarball.mjs +175 -0
- package/lib/node-package-packer-cli.cjs +525 -0
- package/lib/node-package-packer-cli.d.mts +1 -0
- package/lib/node-package-packer-cli.mjs +34 -0
- package/lib/npm-run-series.cjs +7 -12
- package/lib/npm-run-series.mjs +2 -2
- package/lib/package-resolutions-updater-cli.cjs +73 -76
- package/lib/package-resolutions-updater-cli.mjs +4 -3
- package/lib/package-resolutions-updater.cjs +71 -74
- package/lib/package-resolutions-updater.d.mts +34 -0
- package/lib/package-resolutions-updater.mjs +3 -2
- package/lib/php-cs-fixer-staged.cjs +1 -1
- package/lib/php-cs-fixer-staged.mjs +1 -1
- package/lib/print-directory-tree.cjs +16 -18
- package/lib/print-directory-tree.mjs +11 -8
- package/lib/print-tarball-tree.cjs +262 -0
- package/lib/print-tarball-tree.d.mts +1 -0
- package/lib/print-tarball-tree.mjs +68 -0
- package/lib/ps/index.cjs +10 -10
- package/lib/ps/index.mjs +4 -4
- package/lib/ps/table-parser.d.ts +3 -4
- package/lib/ps/table-parser.js +9 -16
- package/lib/remove-module.cjs +17 -22
- package/lib/remove-module.mjs +2 -2
- package/lib/rm-node-module-cli.cjs +171 -4
- package/lib/rm-node-module-cli.mjs +7 -4
- package/lib/rmpath-cli.cjs +285 -0
- package/lib/rmpath-cli.d.mts +1 -0
- package/lib/rmpath-cli.mjs +23 -0
- package/lib/rmpath.cjs +6 -217
- package/lib/rmpath.mjs +5 -101
- package/lib/run-by-checksum/cache.cjs +69 -0
- package/lib/run-by-checksum/cache.d.ts +19 -0
- package/lib/run-by-checksum/cache.js +50 -0
- package/lib/run-by-checksum/cache.mjs +12 -0
- package/lib/run-by-checksum/hash.cjs +72 -0
- package/lib/run-by-checksum/hash.d.ts +14 -0
- package/lib/run-by-checksum/hash.js +85 -0
- package/lib/{ps/isWin.mjs → run-by-checksum/hash.mjs} +5 -5
- package/lib/run-by-checksum/run.cjs +169 -0
- package/lib/run-by-checksum/run.d.ts +22 -0
- package/lib/run-by-checksum/run.js +93 -0
- package/lib/run-by-checksum/run.mjs +10 -0
- package/lib/run-by-checksum-cli.cjs +382 -0
- package/lib/run-by-checksum-cli.d.ts +2 -0
- package/lib/run-by-checksum-cli.js +43 -0
- package/lib/run-by-checksum-cli.mjs +56 -0
- package/lib/submodule-install.cjs +8 -13
- package/lib/submodule-install.mjs +3 -3
- package/lib/submodule-remove-cli.cjs +169 -2
- package/lib/submodule-remove-cli.js +2 -2
- package/lib/submodule-remove-cli.mjs +5 -2
- package/lib/utils/fetchResponse.cjs +24 -0
- package/lib/utils/fetchResponse.d.cts +25 -0
- package/lib/utils/fetchResponse.mjs +6 -0
- package/lib/utils/index.cjs +5 -10
- package/lib/utils/index.d.cts +2 -9
- package/lib/utils/index.mjs +1 -1
- package/lib/utils/isWindows.mjs +3 -1
- package/lib/utils/runBash.cjs +1 -1
- package/lib/utils/runBash.mjs +1 -1
- package/lib/yarn-per-branch-lock-installer.cjs +202 -11
- package/lib/yarn-per-branch-lock-installer.mjs +24 -11
- package/lib/yarn-reinstall.cjs +6 -11
- package/lib/yarn-reinstall.mjs +1 -1
- package/package.json +35 -10
- package/readme.html +2 -2
- package/readme.md +5 -5
- package/releases/readme.md +6 -3
- package/tmp/test-repo-runChecksum/test-complex-glob/README.md +1 -0
- package/tmp/test-repo-runChecksum/test-mixed-args/README.md +1 -0
- package/.opencode/package.json +0 -5
- package/lib/chunk-6S4NXESK.mjs +0 -26
- package/lib/del-ps.js +0 -32
- package/lib/del-ps.mjs +0 -43
- package/lib/ps/isWin.cjs +0 -26
- package/lib/ps/isWin.d.ts +0 -2
- package/lib/ps/isWin.js +0 -4
- package/test/package.json +0 -20
- package/test-project/package.json +0 -22
- package/test-project/workspaces/workspace-a/package.json +0 -135
- package/test-project/workspaces/workspace-a/test/demo/package.json +0 -25
- package/test-project/workspaces/workspace-b/package.json +0 -139
- package/test-project/workspaces/workspace-b/test/sample-project/package.json +0 -7
- package/test-project/workspaces/workspace-b/themes/hexo-theme-flowbite/package.json +0 -96
- package/tmp/rm-node-modules-test-project/package.json +0 -17
- package/tmp/rm-node-modules-test-project/packages/workspace-a/package.json +0 -16
- package/tmp/rm-node-modules-test-project/packages/workspace-b/package.json +0 -16
- package/tmp/test-repo/package.json +0 -17
- /package/lib/{del-ps.d.ts → del-ps-cli.d.mts} +0 -0
package/binaries/yarn-clean.cjs
CHANGED
|
@@ -12,9 +12,11 @@
|
|
|
12
12
|
* - fs:
|
|
13
13
|
* Used to check whether files exist.
|
|
14
14
|
*/
|
|
15
|
-
const { spawnSync } = require(
|
|
16
|
-
const path = require(
|
|
17
|
-
const fs = require(
|
|
15
|
+
const { spawnSync } = require('child_process');
|
|
16
|
+
const path = require('path');
|
|
17
|
+
const fs = require('fs');
|
|
18
|
+
const which = require('which');
|
|
19
|
+
const { isWindows } = require('../src/utils/isWindows.js');
|
|
18
20
|
|
|
19
21
|
/**
|
|
20
22
|
* __dirname
|
|
@@ -49,7 +51,7 @@ const base = path.basename(__filename, path.extname(__filename));
|
|
|
49
51
|
* .sh
|
|
50
52
|
* executable file without extension
|
|
51
53
|
*/
|
|
52
|
-
const candidates = process.platform ===
|
|
54
|
+
const candidates = process.platform === 'win32' ? ['.cmd', '.bat', '.ps1', '.vbs'] : ['.sh', ''];
|
|
53
55
|
|
|
54
56
|
/**
|
|
55
57
|
* Search for the first matching script
|
|
@@ -72,13 +74,32 @@ let found = null;
|
|
|
72
74
|
|
|
73
75
|
for (const ext of candidates) {
|
|
74
76
|
const script = path.join(binDir, base + ext);
|
|
75
|
-
|
|
76
|
-
|
|
77
|
+
const exists = fs.existsSync(script);
|
|
78
|
+
// console.log(`Checking for ${script}: ${exists ? 'found' : 'not found'}`);
|
|
79
|
+
if (exists) {
|
|
77
80
|
found = script;
|
|
78
81
|
break;
|
|
79
82
|
}
|
|
80
83
|
}
|
|
81
84
|
|
|
85
|
+
/**
|
|
86
|
+
* If no matching script was found,
|
|
87
|
+
* try check if `bash` is available and if so, check for a .sh script.
|
|
88
|
+
*/
|
|
89
|
+
if (!found) {
|
|
90
|
+
try {
|
|
91
|
+
spawnSync('bash', ['--version'], { stdio: 'ignore' });
|
|
92
|
+
const bashScript = [path.join(binDir, base), path.join(binDir, base + '.sh')].find((script) =>
|
|
93
|
+
fs.existsSync(script)
|
|
94
|
+
);
|
|
95
|
+
if (bashScript) {
|
|
96
|
+
found = bashScript;
|
|
97
|
+
}
|
|
98
|
+
} catch {
|
|
99
|
+
// bash is not available, do nothing
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
82
103
|
/**
|
|
83
104
|
* If no matching script was found,
|
|
84
105
|
* print an error and exit with failure code 1.
|
|
@@ -92,8 +113,9 @@ if (!found) {
|
|
|
92
113
|
* Detect special script types
|
|
93
114
|
* that require a shell/interpreter.
|
|
94
115
|
*/
|
|
95
|
-
const isPs1 = found.endsWith(
|
|
96
|
-
const isCmd = found.endsWith(
|
|
116
|
+
const isPs1 = found.endsWith('.ps1');
|
|
117
|
+
const isCmd = found.endsWith('.cmd');
|
|
118
|
+
const isUnixShell = found.endsWith('.sh') || path.extname(found) === '';
|
|
97
119
|
|
|
98
120
|
/**
|
|
99
121
|
* cmd
|
|
@@ -124,9 +146,9 @@ let cmd, args;
|
|
|
124
146
|
* Forward all user-provided command-line arguments.
|
|
125
147
|
*/
|
|
126
148
|
if (isPs1) {
|
|
127
|
-
cmd =
|
|
149
|
+
cmd = 'powershell.exe';
|
|
128
150
|
|
|
129
|
-
args = [
|
|
151
|
+
args = ['-NoProfile', '-ExecutionPolicy', 'Bypass', '-File', found, ...process.argv.slice(2)];
|
|
130
152
|
|
|
131
153
|
/**
|
|
132
154
|
* CMD batch files:
|
|
@@ -137,9 +159,9 @@ if (isPs1) {
|
|
|
137
159
|
* "execute command and terminate"
|
|
138
160
|
*/
|
|
139
161
|
} else if (isCmd) {
|
|
140
|
-
cmd =
|
|
162
|
+
cmd = 'cmd.exe';
|
|
141
163
|
|
|
142
|
-
args = [
|
|
164
|
+
args = ['/c', found, ...process.argv.slice(2)];
|
|
143
165
|
|
|
144
166
|
/**
|
|
145
167
|
* Other scripts:
|
|
@@ -150,11 +172,65 @@ if (isPs1) {
|
|
|
150
172
|
*
|
|
151
173
|
* These can be executed directly.
|
|
152
174
|
*/
|
|
175
|
+
} else if (isUnixShell) {
|
|
176
|
+
// Capture shebang scripts (no extension) and .sh scripts
|
|
177
|
+
const shebang = fs.readFileSync(found, 'utf8').split('\n')[0].trim();
|
|
178
|
+
const interpreter = shebang.startsWith('#!')
|
|
179
|
+
? shebang
|
|
180
|
+
.slice(2)
|
|
181
|
+
.trim()
|
|
182
|
+
.replace(/^\/usr\/bin\/env\s+/, '')
|
|
183
|
+
.replace(/^\/bin\/env\s+/, '')
|
|
184
|
+
.replace(/^\/usr\/bin\//, '')
|
|
185
|
+
.replace(/^\/bin\//, '')
|
|
186
|
+
: null;
|
|
187
|
+
|
|
188
|
+
if (interpreter) {
|
|
189
|
+
const resolvedOrNull = which.sync(interpreter, { nothrow: true });
|
|
190
|
+
if (!resolvedOrNull) {
|
|
191
|
+
if (['bash', 'sh'].includes(interpreter) && isWindows()) {
|
|
192
|
+
const locationsToCheck = [
|
|
193
|
+
'C:\\Program Files\\Git\\usr\\bin',
|
|
194
|
+
'C:\\Program Files\\Git\\bin',
|
|
195
|
+
'C:\\Program Files (x86)\\Git\\usr\\bin',
|
|
196
|
+
'C:\\msys64\\usr\\bin',
|
|
197
|
+
'C:\\msys64\\bin',
|
|
198
|
+
'C:\\cygwin64\\bin',
|
|
199
|
+
'C:\\cygwin\\bin',
|
|
200
|
+
'C:\\MinGW\\bin',
|
|
201
|
+
'C:\\MinGW\\msys\\1.0\\bin'
|
|
202
|
+
];
|
|
203
|
+
for (const location of locationsToCheck) {
|
|
204
|
+
const potentialPath = path.join(location, 'bash.exe');
|
|
205
|
+
if (fs.existsSync(potentialPath)) {
|
|
206
|
+
cmd = potentialPath;
|
|
207
|
+
args = [found, ...process.argv.slice(2)];
|
|
208
|
+
break;
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
} else {
|
|
213
|
+
cmd = resolvedOrNull || interpreter;
|
|
214
|
+
args = [found, ...process.argv.slice(2)];
|
|
215
|
+
}
|
|
216
|
+
} else {
|
|
217
|
+
cmd = found;
|
|
218
|
+
args = process.argv.slice(2);
|
|
219
|
+
}
|
|
153
220
|
} else {
|
|
154
221
|
cmd = found;
|
|
155
222
|
args = process.argv.slice(2);
|
|
156
223
|
}
|
|
157
224
|
|
|
225
|
+
console.log(
|
|
226
|
+
`Executing: ${path.isAbsolute(cmd) ? path.relative(process.cwd(), cmd) : cmd} ${args
|
|
227
|
+
.map((f) => {
|
|
228
|
+
if (path.isAbsolute(f)) return path.relative(process.cwd(), f);
|
|
229
|
+
return f;
|
|
230
|
+
})
|
|
231
|
+
.join(' ')}`
|
|
232
|
+
);
|
|
233
|
+
|
|
158
234
|
/**
|
|
159
235
|
* Execute the selected script synchronously.
|
|
160
236
|
*
|
|
@@ -165,7 +241,7 @@ if (isPs1) {
|
|
|
165
241
|
* spawnSync waits until the child process exits.
|
|
166
242
|
*/
|
|
167
243
|
const result = spawnSync(cmd, args, {
|
|
168
|
-
stdio:
|
|
244
|
+
stdio: 'inherit'
|
|
169
245
|
});
|
|
170
246
|
|
|
171
247
|
/**
|
package/binaries/yc
CHANGED
|
@@ -4,6 +4,27 @@ set -u
|
|
|
4
4
|
cwd="$(pwd)"
|
|
5
5
|
max_jobs=4
|
|
6
6
|
|
|
7
|
+
usage() {
|
|
8
|
+
cat <<EOF
|
|
9
|
+
Usage: $(basename "$0") [options]
|
|
10
|
+
|
|
11
|
+
Options:
|
|
12
|
+
-h, --help Show this help message
|
|
13
|
+
-c, --concurrent <num> Maximum parallel jobs (default: 4)
|
|
14
|
+
|
|
15
|
+
Description:
|
|
16
|
+
Clean node_modules directories grouped by letter (a-z) in parallel.
|
|
17
|
+
EOF
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
while [[ $# -gt 0 ]]; do
|
|
21
|
+
case "$1" in
|
|
22
|
+
-h|--help) usage; exit 0 ;;
|
|
23
|
+
-c|--concurrent) max_jobs="$2"; shift 2 ;;
|
|
24
|
+
*) shift ;;
|
|
25
|
+
esac
|
|
26
|
+
done
|
|
27
|
+
|
|
7
28
|
# colors
|
|
8
29
|
GREEN='\033[0;32m'
|
|
9
30
|
RED='\033[0;31m'
|
|
@@ -38,7 +59,7 @@ log() {
|
|
|
38
59
|
INFO) color="$BLUE" ;;
|
|
39
60
|
esac
|
|
40
61
|
|
|
41
|
-
echo -e "${
|
|
62
|
+
echo -e "[${GRAY}$(timestamp)${NC}] [${color}${level}${NC}] $*"
|
|
42
63
|
}
|
|
43
64
|
|
|
44
65
|
cleanup_letter() {
|
package/binaries/yc.cjs
CHANGED
|
@@ -12,9 +12,11 @@
|
|
|
12
12
|
* - fs:
|
|
13
13
|
* Used to check whether files exist.
|
|
14
14
|
*/
|
|
15
|
-
const { spawnSync } = require(
|
|
16
|
-
const path = require(
|
|
17
|
-
const fs = require(
|
|
15
|
+
const { spawnSync } = require('child_process');
|
|
16
|
+
const path = require('path');
|
|
17
|
+
const fs = require('fs');
|
|
18
|
+
const which = require('which');
|
|
19
|
+
const { isWindows } = require('../src/utils/isWindows.js');
|
|
18
20
|
|
|
19
21
|
/**
|
|
20
22
|
* __dirname
|
|
@@ -49,7 +51,7 @@ const base = path.basename(__filename, path.extname(__filename));
|
|
|
49
51
|
* .sh
|
|
50
52
|
* executable file without extension
|
|
51
53
|
*/
|
|
52
|
-
const candidates = process.platform ===
|
|
54
|
+
const candidates = process.platform === 'win32' ? ['.cmd', '.bat', '.ps1', '.vbs'] : ['.sh', ''];
|
|
53
55
|
|
|
54
56
|
/**
|
|
55
57
|
* Search for the first matching script
|
|
@@ -72,13 +74,32 @@ let found = null;
|
|
|
72
74
|
|
|
73
75
|
for (const ext of candidates) {
|
|
74
76
|
const script = path.join(binDir, base + ext);
|
|
75
|
-
|
|
76
|
-
|
|
77
|
+
const exists = fs.existsSync(script);
|
|
78
|
+
// console.log(`Checking for ${script}: ${exists ? 'found' : 'not found'}`);
|
|
79
|
+
if (exists) {
|
|
77
80
|
found = script;
|
|
78
81
|
break;
|
|
79
82
|
}
|
|
80
83
|
}
|
|
81
84
|
|
|
85
|
+
/**
|
|
86
|
+
* If no matching script was found,
|
|
87
|
+
* try check if `bash` is available and if so, check for a .sh script.
|
|
88
|
+
*/
|
|
89
|
+
if (!found) {
|
|
90
|
+
try {
|
|
91
|
+
spawnSync('bash', ['--version'], { stdio: 'ignore' });
|
|
92
|
+
const bashScript = [path.join(binDir, base), path.join(binDir, base + '.sh')].find((script) =>
|
|
93
|
+
fs.existsSync(script)
|
|
94
|
+
);
|
|
95
|
+
if (bashScript) {
|
|
96
|
+
found = bashScript;
|
|
97
|
+
}
|
|
98
|
+
} catch {
|
|
99
|
+
// bash is not available, do nothing
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
82
103
|
/**
|
|
83
104
|
* If no matching script was found,
|
|
84
105
|
* print an error and exit with failure code 1.
|
|
@@ -92,8 +113,9 @@ if (!found) {
|
|
|
92
113
|
* Detect special script types
|
|
93
114
|
* that require a shell/interpreter.
|
|
94
115
|
*/
|
|
95
|
-
const isPs1 = found.endsWith(
|
|
96
|
-
const isCmd = found.endsWith(
|
|
116
|
+
const isPs1 = found.endsWith('.ps1');
|
|
117
|
+
const isCmd = found.endsWith('.cmd');
|
|
118
|
+
const isUnixShell = found.endsWith('.sh') || path.extname(found) === '';
|
|
97
119
|
|
|
98
120
|
/**
|
|
99
121
|
* cmd
|
|
@@ -124,9 +146,9 @@ let cmd, args;
|
|
|
124
146
|
* Forward all user-provided command-line arguments.
|
|
125
147
|
*/
|
|
126
148
|
if (isPs1) {
|
|
127
|
-
cmd =
|
|
149
|
+
cmd = 'powershell.exe';
|
|
128
150
|
|
|
129
|
-
args = [
|
|
151
|
+
args = ['-NoProfile', '-ExecutionPolicy', 'Bypass', '-File', found, ...process.argv.slice(2)];
|
|
130
152
|
|
|
131
153
|
/**
|
|
132
154
|
* CMD batch files:
|
|
@@ -137,9 +159,9 @@ if (isPs1) {
|
|
|
137
159
|
* "execute command and terminate"
|
|
138
160
|
*/
|
|
139
161
|
} else if (isCmd) {
|
|
140
|
-
cmd =
|
|
162
|
+
cmd = 'cmd.exe';
|
|
141
163
|
|
|
142
|
-
args = [
|
|
164
|
+
args = ['/c', found, ...process.argv.slice(2)];
|
|
143
165
|
|
|
144
166
|
/**
|
|
145
167
|
* Other scripts:
|
|
@@ -150,11 +172,65 @@ if (isPs1) {
|
|
|
150
172
|
*
|
|
151
173
|
* These can be executed directly.
|
|
152
174
|
*/
|
|
175
|
+
} else if (isUnixShell) {
|
|
176
|
+
// Capture shebang scripts (no extension) and .sh scripts
|
|
177
|
+
const shebang = fs.readFileSync(found, 'utf8').split('\n')[0].trim();
|
|
178
|
+
const interpreter = shebang.startsWith('#!')
|
|
179
|
+
? shebang
|
|
180
|
+
.slice(2)
|
|
181
|
+
.trim()
|
|
182
|
+
.replace(/^\/usr\/bin\/env\s+/, '')
|
|
183
|
+
.replace(/^\/bin\/env\s+/, '')
|
|
184
|
+
.replace(/^\/usr\/bin\//, '')
|
|
185
|
+
.replace(/^\/bin\//, '')
|
|
186
|
+
: null;
|
|
187
|
+
|
|
188
|
+
if (interpreter) {
|
|
189
|
+
const resolvedOrNull = which.sync(interpreter, { nothrow: true });
|
|
190
|
+
if (!resolvedOrNull) {
|
|
191
|
+
if (['bash', 'sh'].includes(interpreter) && isWindows()) {
|
|
192
|
+
const locationsToCheck = [
|
|
193
|
+
'C:\\Program Files\\Git\\usr\\bin',
|
|
194
|
+
'C:\\Program Files\\Git\\bin',
|
|
195
|
+
'C:\\Program Files (x86)\\Git\\usr\\bin',
|
|
196
|
+
'C:\\msys64\\usr\\bin',
|
|
197
|
+
'C:\\msys64\\bin',
|
|
198
|
+
'C:\\cygwin64\\bin',
|
|
199
|
+
'C:\\cygwin\\bin',
|
|
200
|
+
'C:\\MinGW\\bin',
|
|
201
|
+
'C:\\MinGW\\msys\\1.0\\bin'
|
|
202
|
+
];
|
|
203
|
+
for (const location of locationsToCheck) {
|
|
204
|
+
const potentialPath = path.join(location, 'bash.exe');
|
|
205
|
+
if (fs.existsSync(potentialPath)) {
|
|
206
|
+
cmd = potentialPath;
|
|
207
|
+
args = [found, ...process.argv.slice(2)];
|
|
208
|
+
break;
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
} else {
|
|
213
|
+
cmd = resolvedOrNull || interpreter;
|
|
214
|
+
args = [found, ...process.argv.slice(2)];
|
|
215
|
+
}
|
|
216
|
+
} else {
|
|
217
|
+
cmd = found;
|
|
218
|
+
args = process.argv.slice(2);
|
|
219
|
+
}
|
|
153
220
|
} else {
|
|
154
221
|
cmd = found;
|
|
155
222
|
args = process.argv.slice(2);
|
|
156
223
|
}
|
|
157
224
|
|
|
225
|
+
console.log(
|
|
226
|
+
`Executing: ${path.isAbsolute(cmd) ? path.relative(process.cwd(), cmd) : cmd} ${args
|
|
227
|
+
.map((f) => {
|
|
228
|
+
if (path.isAbsolute(f)) return path.relative(process.cwd(), f);
|
|
229
|
+
return f;
|
|
230
|
+
})
|
|
231
|
+
.join(' ')}`
|
|
232
|
+
);
|
|
233
|
+
|
|
158
234
|
/**
|
|
159
235
|
* Execute the selected script synchronously.
|
|
160
236
|
*
|
|
@@ -165,7 +241,7 @@ if (isPs1) {
|
|
|
165
241
|
* spawnSync waits until the child process exits.
|
|
166
242
|
*/
|
|
167
243
|
const result = spawnSync(cmd, args, {
|
|
168
|
-
stdio:
|
|
244
|
+
stdio: 'inherit'
|
|
169
245
|
});
|
|
170
246
|
|
|
171
247
|
/**
|
package/binaries/ycw
ADDED
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
set -u
|
|
3
|
+
|
|
4
|
+
cwd="$(pwd)"
|
|
5
|
+
max_jobs=4
|
|
6
|
+
|
|
7
|
+
usage() {
|
|
8
|
+
cat <<'EOF'
|
|
9
|
+
Usage: ycw [options]
|
|
10
|
+
|
|
11
|
+
Clean node_modules directories across a Yarn monorepo (workspaces-aware).
|
|
12
|
+
|
|
13
|
+
This tool:
|
|
14
|
+
- Automatically detects monorepo root via package.json "workspaces"
|
|
15
|
+
- Expands workspace globs (e.g. packages/*)
|
|
16
|
+
- Removes node_modules in root + all workspace packages
|
|
17
|
+
- Runs partial cleanup in parallel for speed
|
|
18
|
+
|
|
19
|
+
Options:
|
|
20
|
+
-h, --help Show this help message and exit
|
|
21
|
+
-c, --concurrent <num> Maximum parallel jobs (default: 4)
|
|
22
|
+
|
|
23
|
+
Behavior:
|
|
24
|
+
• Root is detected by scanning upward for package.json with "workspaces"
|
|
25
|
+
• Workspace patterns are read from package.json (no jq required)
|
|
26
|
+
• node_modules folders are removed in two phases:
|
|
27
|
+
1. Partial cleanup (letter-based parallel deletion)
|
|
28
|
+
2. Final full removal of remaining node_modules directories
|
|
29
|
+
|
|
30
|
+
Notes:
|
|
31
|
+
- Designed for Yarn workspaces monorepos
|
|
32
|
+
- Safe fallback: if no root is detected, current directory is used
|
|
33
|
+
- Uses rm -rf (destructive operation)
|
|
34
|
+
|
|
35
|
+
Example:
|
|
36
|
+
ycw
|
|
37
|
+
ycw --help
|
|
38
|
+
ycw -c 8
|
|
39
|
+
|
|
40
|
+
EOF
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
while [[ $# -gt 0 ]]; do
|
|
44
|
+
case "$1" in
|
|
45
|
+
-h|--help) usage; exit 0 ;;
|
|
46
|
+
-c|--concurrent) max_jobs="$2"; shift 2 ;;
|
|
47
|
+
*) shift ;;
|
|
48
|
+
esac
|
|
49
|
+
done
|
|
50
|
+
|
|
51
|
+
# colors
|
|
52
|
+
GREEN='\033[0;32m'
|
|
53
|
+
RED='\033[0;31m'
|
|
54
|
+
GRAY='\033[0;90m'
|
|
55
|
+
BLUE='\033[0;34m'
|
|
56
|
+
NC='\033[0m'
|
|
57
|
+
|
|
58
|
+
timestamp() {
|
|
59
|
+
date "+%Y-%m-%d %H:%M:%S"
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
relative_path() {
|
|
63
|
+
local path="$1"
|
|
64
|
+
path="${path#"$cwd"/}"
|
|
65
|
+
[[ "$path" == "$cwd" ]] && path="."
|
|
66
|
+
echo "$path"
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
log() {
|
|
70
|
+
local level="$1"
|
|
71
|
+
shift
|
|
72
|
+
|
|
73
|
+
local color="$NC"
|
|
74
|
+
case "$level" in
|
|
75
|
+
OK) color="$GREEN" ;;
|
|
76
|
+
FAIL) color="$RED" ;;
|
|
77
|
+
SKIP) color="$GRAY" ;;
|
|
78
|
+
INFO) color="$BLUE" ;;
|
|
79
|
+
esac
|
|
80
|
+
|
|
81
|
+
echo -e "[${GRAY}$(timestamp)${NC}] [${color}${level}${NC}] $*"
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
# -----------------------------------
|
|
85
|
+
# find project root (NO GIT)
|
|
86
|
+
# -----------------------------------
|
|
87
|
+
find_root() {
|
|
88
|
+
local dir="$cwd"
|
|
89
|
+
|
|
90
|
+
while [[ "$dir" != "/" ]]; do
|
|
91
|
+
if [[ -f "$dir/package.json" ]] && grep -q '"workspaces"' "$dir/package.json" 2>/dev/null; then
|
|
92
|
+
echo "$dir"
|
|
93
|
+
return 0
|
|
94
|
+
fi
|
|
95
|
+
dir="$(dirname "$dir")"
|
|
96
|
+
done
|
|
97
|
+
|
|
98
|
+
echo "$cwd"
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
ROOT="$(find_root)"
|
|
102
|
+
cwd="$ROOT"
|
|
103
|
+
|
|
104
|
+
log INFO "Using root: $(relative_path "$ROOT")"
|
|
105
|
+
|
|
106
|
+
# -----------------------------------
|
|
107
|
+
# parse workspaces from package.json
|
|
108
|
+
# -----------------------------------
|
|
109
|
+
get_workspaces() {
|
|
110
|
+
local pkg="$ROOT/package.json"
|
|
111
|
+
|
|
112
|
+
# naive JSON parsing (no jq required)
|
|
113
|
+
# supports:
|
|
114
|
+
# "workspaces": ["packages/*"] OR { "packages": [] }
|
|
115
|
+
|
|
116
|
+
grep -oP '"workspaces"\s*:\s*\K\[[^\]]+\]' "$pkg" 2>/dev/null |
|
|
117
|
+
tr -d '[]"' |
|
|
118
|
+
tr ',' '\n' |
|
|
119
|
+
sed 's/^[[:space:]]*//;s/[[:space:]]*$//'
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
# -----------------------------------
|
|
123
|
+
# expand glob patterns safely
|
|
124
|
+
# -----------------------------------
|
|
125
|
+
expand_glob() {
|
|
126
|
+
local pattern="$1"
|
|
127
|
+
|
|
128
|
+
for dir in $pattern; do
|
|
129
|
+
[[ -d "$dir" ]] && echo "$ROOT/$dir"
|
|
130
|
+
done
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
# -----------------------------------
|
|
134
|
+
# collect node_modules targets
|
|
135
|
+
# -----------------------------------
|
|
136
|
+
declare -a NODE_MODULES_TARGETS
|
|
137
|
+
|
|
138
|
+
# root
|
|
139
|
+
NODE_MODULES_TARGETS+=("$ROOT/node_modules")
|
|
140
|
+
|
|
141
|
+
# workspaces
|
|
142
|
+
while IFS= read -r pattern; do
|
|
143
|
+
[[ -z "$pattern" ]] && continue
|
|
144
|
+
|
|
145
|
+
while IFS= read -r ws; do
|
|
146
|
+
NODE_MODULES_TARGETS+=("$ws/node_modules")
|
|
147
|
+
done < <(expand_glob "$pattern")
|
|
148
|
+
|
|
149
|
+
done < <(get_workspaces)
|
|
150
|
+
|
|
151
|
+
# -----------------------------------
|
|
152
|
+
# deduplicate
|
|
153
|
+
# -----------------------------------
|
|
154
|
+
declare -A seen
|
|
155
|
+
declare -a unique
|
|
156
|
+
|
|
157
|
+
for t in "${NODE_MODULES_TARGETS[@]}"; do
|
|
158
|
+
[[ -z "$t" ]] && continue
|
|
159
|
+
[[ -n "${seen[$t]:-}" ]] && continue
|
|
160
|
+
seen["$t"]=1
|
|
161
|
+
unique+=("$t")
|
|
162
|
+
done
|
|
163
|
+
|
|
164
|
+
NODE_MODULES_TARGETS=("${unique[@]}")
|
|
165
|
+
|
|
166
|
+
# -----------------------------------
|
|
167
|
+
# cleanup function
|
|
168
|
+
# -----------------------------------
|
|
169
|
+
cleanup_letter() {
|
|
170
|
+
local base="$1"
|
|
171
|
+
local letter="$2"
|
|
172
|
+
|
|
173
|
+
[[ -d "$base" ]] || return 0
|
|
174
|
+
|
|
175
|
+
shopt -s nullglob
|
|
176
|
+
|
|
177
|
+
local targets=(
|
|
178
|
+
"${base}/${letter}"*
|
|
179
|
+
"${base}/@types/${letter}"*
|
|
180
|
+
"${base}/@${letter}"*
|
|
181
|
+
)
|
|
182
|
+
|
|
183
|
+
local removed_any=0
|
|
184
|
+
|
|
185
|
+
for path in "${targets[@]}"; do
|
|
186
|
+
[[ -e "$path" ]] || continue
|
|
187
|
+
|
|
188
|
+
local rel
|
|
189
|
+
rel="$(relative_path "$path")"
|
|
190
|
+
|
|
191
|
+
if rm -rf "$path"; then
|
|
192
|
+
log OK "$rel"
|
|
193
|
+
removed_any=1
|
|
194
|
+
else
|
|
195
|
+
log FAIL "$rel"
|
|
196
|
+
fi
|
|
197
|
+
done
|
|
198
|
+
|
|
199
|
+
if (( removed_any == 0 )); then
|
|
200
|
+
log SKIP "$(relative_path "$base") '${letter}'"
|
|
201
|
+
fi
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
# export for parallel
|
|
205
|
+
export -f cleanup_letter
|
|
206
|
+
export -f log
|
|
207
|
+
export -f timestamp
|
|
208
|
+
export -f relative_path
|
|
209
|
+
export cwd GREEN RED GRAY BLUE NC ROOT
|
|
210
|
+
|
|
211
|
+
log INFO "Detected ${#NODE_MODULES_TARGETS[@]} node_modules directories"
|
|
212
|
+
|
|
213
|
+
for t in "${NODE_MODULES_TARGETS[@]}"; do
|
|
214
|
+
log INFO "$(relative_path "$t")"
|
|
215
|
+
done
|
|
216
|
+
|
|
217
|
+
# -----------------------------------
|
|
218
|
+
# parallel deletion
|
|
219
|
+
# -----------------------------------
|
|
220
|
+
running=0
|
|
221
|
+
|
|
222
|
+
for base in "${NODE_MODULES_TARGETS[@]}"; do
|
|
223
|
+
for letter in $(printf "%s\n" {a..z} | shuf); do
|
|
224
|
+
|
|
225
|
+
cleanup_letter "$base" "$letter" &
|
|
226
|
+
|
|
227
|
+
((running++))
|
|
228
|
+
|
|
229
|
+
if (( running >= max_jobs )); then
|
|
230
|
+
wait -n
|
|
231
|
+
((running--))
|
|
232
|
+
fi
|
|
233
|
+
|
|
234
|
+
done
|
|
235
|
+
done
|
|
236
|
+
|
|
237
|
+
wait
|
|
238
|
+
|
|
239
|
+
# -----------------------------------
|
|
240
|
+
# final cleanup
|
|
241
|
+
# -----------------------------------
|
|
242
|
+
log INFO "Removing remaining node_modules directories"
|
|
243
|
+
|
|
244
|
+
for target in "${NODE_MODULES_TARGETS[@]}"; do
|
|
245
|
+
[[ -e "$target" ]] || continue
|
|
246
|
+
|
|
247
|
+
rel="$(relative_path "$target")"
|
|
248
|
+
|
|
249
|
+
if rm -rf "$target"; then
|
|
250
|
+
log OK "$rel"
|
|
251
|
+
else
|
|
252
|
+
log FAIL "$rel"
|
|
253
|
+
fi
|
|
254
|
+
done
|
|
255
|
+
|
|
256
|
+
log INFO "Done"
|