Skip to content

Commit 5e55eff

Browse files
authored
fix(fs): expandGlob/expandGlobSync - match non-glob path segments containing escaped glob chars (#6788)
1 parent b8959a5 commit 5e55eff

File tree

2 files changed

+52
-2
lines changed

2 files changed

+52
-2
lines changed

fs/expand_glob.ts

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -303,7 +303,7 @@ export async function* expandGlob(
303303
let fixedRoot = isGlobAbsolute ? winRoot ?? "/" : absRoot;
304304
while (segments.length > 0 && !isGlob(segments[0]!)) {
305305
const seg = segments.shift()!;
306-
fixedRoot = joinGlobs([fixedRoot, seg], globOptions);
306+
fixedRoot = joinGlobs([fixedRoot, unescapeGlobSegment(seg)], globOptions);
307307
}
308308

309309
let fixedRootInfo: WalkEntry;
@@ -460,7 +460,7 @@ export function* expandGlobSync(
460460
let fixedRoot = isGlobAbsolute ? winRoot ?? "/" : absRoot;
461461
while (segments.length > 0 && !isGlob(segments[0]!)) {
462462
const seg = segments.shift()!;
463-
fixedRoot = joinGlobs([fixedRoot, seg], globOptions);
463+
fixedRoot = joinGlobs([fixedRoot, unescapeGlobSegment(seg)], globOptions);
464464
}
465465

466466
let fixedRootInfo: WalkEntry;
@@ -532,3 +532,29 @@ export function* expandGlobSync(
532532
}
533533
yield* currentMatches;
534534
}
535+
536+
const globEscapeChar = Deno.build.os === "windows" ? "`" : `\\`;
537+
const globMetachars = "*?{}[]()|+@!";
538+
function unescapeGlobSegment(segment: string): string {
539+
let result = "";
540+
let lastIndex = 0;
541+
for (let i = 0; i < segment.length; i++) {
542+
const char = segment[i];
543+
if (char === globEscapeChar) {
544+
const nextChar = segment[i + 1];
545+
if (nextChar && globMetachars.includes(nextChar)) {
546+
// append the slice before the escape char, then the metachar
547+
result += segment.slice(lastIndex, i) + nextChar;
548+
i++; // skip next char since we already processed it
549+
lastIndex = i + 1;
550+
}
551+
}
552+
}
553+
// no escaped, return the original segment
554+
if (lastIndex === 0) {
555+
return segment;
556+
}
557+
// append any remaining characters
558+
result += segment.slice(lastIndex);
559+
return result;
560+
}

fs/expand_glob_test.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -448,3 +448,27 @@ Deno.test(
448448
);
449449
},
450450
);
451+
452+
const escapeChar = Deno.build.os === "windows" ? "`" : "\\";
453+
454+
Deno.test("expandGlob() finds directory with escaped brackets", async function () {
455+
assertEquals(
456+
await expandGlobArray(`a${escapeChar}[b${escapeChar}]c`, EG_OPTIONS),
457+
["a[b]c"],
458+
);
459+
assertEquals(
460+
await expandGlobArray(`a${escapeChar}[b${escapeChar}]c/fo[o]`, EG_OPTIONS),
461+
[join("a[b]c", "foo")],
462+
);
463+
});
464+
465+
Deno.test("expandGlobSync() finds directory with escaped brackets", function () {
466+
assertEquals(
467+
expandGlobSyncArray(`a${escapeChar}[b${escapeChar}]c`, EG_OPTIONS),
468+
["a[b]c"],
469+
);
470+
assertEquals(
471+
expandGlobSyncArray(`a${escapeChar}[b${escapeChar}]c/fo[o]`, EG_OPTIONS),
472+
[join("a[b]c", "foo")],
473+
);
474+
});

0 commit comments

Comments
 (0)