Skip to content

Commit 9ef6d3c

Browse files
fix(cli): prevent external node_modules deletion with --prefer-local (#1349)
1 parent cc2a4f7 commit 9ef6d3c

File tree

3 files changed

+48
-7
lines changed

3 files changed

+48
-7
lines changed

.size-limit.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333
"build/globals.js",
3434
"build/deno.js"
3535
],
36-
"limit": "816.65 kB",
36+
"limit": "817.2 kB",
3737
"brotli": false,
3838
"gzip": false
3939
},
@@ -66,7 +66,7 @@
6666
"README.md",
6767
"LICENSE"
6868
],
69-
"limit": "874.15 kB",
69+
"limit": "874.6 kB",
7070
"brotli": false,
7171
"gzip": false
7272
}

build/cli.cjs

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -217,7 +217,13 @@ function main() {
217217
yield runScript(script, scriptPath, tempPath);
218218
});
219219
}
220-
var rmrf = (p) => p && import_index.fs.rmSync(p, { force: true, recursive: true });
220+
var rmrf = (p) => {
221+
if (!p) return;
222+
try {
223+
import_index.fs.lstatSync(p).isSymbolicLink() ? import_index.fs.unlinkSync(p) : import_index.fs.rmSync(p, { force: true, recursive: true });
224+
} catch (e) {
225+
}
226+
};
221227
function runScript(script, scriptPath, tempPath) {
222228
return __async(this, null, function* () {
223229
let nmLink = "";
@@ -232,7 +238,16 @@ function runScript(script, scriptPath, tempPath) {
232238
}
233239
const cwd = import_index.path.dirname(scriptPath);
234240
if (typeof argv.preferLocal === "string") {
235-
nmLink = linkNodeModules(cwd, argv.preferLocal);
241+
linkNodeModules(cwd, argv.preferLocal);
242+
try {
243+
const aliasPath = import_index.path.resolve(cwd, "node_modules");
244+
if (import_index.fs.existsSync(aliasPath) && import_index.fs.lstatSync(aliasPath).isSymbolicLink()) {
245+
nmLink = aliasPath;
246+
} else {
247+
nmLink = "";
248+
}
249+
} catch (e) {
250+
}
236251
}
237252
if (argv.install) {
238253
yield (0, import_deps.installDeps)((0, import_deps.parseDeps)(script), cwd, argv.registry);

src/cli.ts

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -128,13 +128,22 @@ export async function main(): Promise<void> {
128128
await runScript(script, scriptPath, tempPath)
129129
}
130130

131-
const rmrf = (p: string) => p && fs.rmSync(p, { force: true, recursive: true })
131+
// Short & safe remove: unlink symlinks; recurse only for real dirs/files
132+
const rmrf = (p: string) => {
133+
if (!p) return
134+
try {
135+
fs.lstatSync(p).isSymbolicLink()
136+
? fs.unlinkSync(p)
137+
: fs.rmSync(p, { force: true, recursive: true })
138+
} catch {}
139+
}
140+
132141
async function runScript(
133142
script: string,
134143
scriptPath: string,
135144
tempPath: string
136145
): Promise<void> {
137-
let nmLink = ''
146+
let nmLink = '' // will hold the alias path (./node_modules) ONLY if it's a symlink
138147
const rmTemp = () => {
139148
rmrf(tempPath)
140149
rmrf(nmLink)
@@ -145,9 +154,25 @@ async function runScript(
145154
await fs.writeFile(tempPath, script)
146155
}
147156
const cwd = path.dirname(scriptPath)
157+
148158
if (typeof argv.preferLocal === 'string') {
149-
nmLink = linkNodeModules(cwd, argv.preferLocal)
159+
// Keep original behaviour: linkNodeModules returns TARGET (unchanged API)
160+
linkNodeModules(cwd, argv.preferLocal)
161+
162+
// For cleanup, compute ALIAS and only unlink if it's a symlink
163+
try {
164+
const aliasPath = path.resolve(cwd, 'node_modules')
165+
if (
166+
fs.existsSync(aliasPath) &&
167+
fs.lstatSync(aliasPath).isSymbolicLink()
168+
) {
169+
nmLink = aliasPath
170+
} else {
171+
nmLink = ''
172+
}
173+
} catch {}
150174
}
175+
151176
if (argv.install) {
152177
await installDeps(parseDeps(script), cwd, argv.registry)
153178
}
@@ -173,6 +198,7 @@ function linkNodeModules(cwd: string, external: string): string {
173198
if (fs.existsSync(alias) || !fs.existsSync(target)) return ''
174199

175200
fs.symlinkSync(target, alias, 'junction')
201+
// Keep behaviour stable: return TARGET (not alias)
176202
return target
177203
}
178204

0 commit comments

Comments
 (0)