Skip to content

Commit 31d1992

Browse files
Claude Botclaude
andcommitted
fix(glob): preserve directory name case in glob walker
Fixes #11295 The glob walker's DirEntryAccessor was using the lowercase map key instead of the case-preserved filename stored in the Entry. This caused ENOENT errors when trying to open directories with mixed-case names like "BuildIconList" because it would try to open "buildiconlist". The fix uses entry.base() to get the original case-preserved name instead of the lowercase key used for case-insensitive lookups. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
1 parent f31db64 commit 31d1992

File tree

2 files changed

+87
-2
lines changed

2 files changed

+87
-2
lines changed

src/glob/GlobWalker.zig

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -211,8 +211,10 @@ pub const DirEntryAccessor = struct {
211211
pub inline fn next(self: *DirIter) Maybe(?IterResult) {
212212
if (self.value) |*value| {
213213
const nextval = value.next() orelse return .{ .result = null };
214-
const name = nextval.key_ptr.*;
215-
const kind = nextval.value_ptr.*.kind(&FS.instance.fs, true);
214+
const entry = nextval.value_ptr.*;
215+
// Use the original case-preserved name, not the lowercase key
216+
const name = entry.base();
217+
const kind = entry.kind(&FS.instance.fs, true);
216218
const fskind = switch (kind) {
217219
.file => std.fs.File.Kind.file,
218220
.dir => std.fs.File.Kind.directory,
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
import { expect, test } from "bun:test";
2+
import { bunEnv, bunExe, tempDir } from "harness";
3+
4+
test("issue #11295 - bun run --filter preserves directory case", async () => {
5+
// Regression test: the glob walker was using lowercase keys from the FS cache
6+
// instead of the case-preserved names, causing ENOENT when trying to open
7+
// directories with mixed-case names like "BuildIconList"
8+
using dir = tempDir("ws-case-sensitive", {
9+
"tools/BuildIconList/package.json": JSON.stringify({
10+
name: "@test/build-icon-list",
11+
version: "1.0.0",
12+
scripts: {
13+
build: "echo building BuildIconList",
14+
},
15+
}),
16+
"tools/lowercase/package.json": JSON.stringify({
17+
name: "@test/lowercase",
18+
version: "1.0.0",
19+
scripts: {
20+
build: "echo building lowercase",
21+
},
22+
}),
23+
"package.json": JSON.stringify({
24+
name: "case-test",
25+
private: true,
26+
workspaces: ["tools/*"],
27+
}),
28+
});
29+
30+
await using proc = Bun.spawn({
31+
cmd: [bunExe(), "run", "--filter", "*", "build"],
32+
cwd: String(dir),
33+
env: bunEnv,
34+
stdout: "pipe",
35+
stderr: "pipe",
36+
});
37+
38+
const [stdout, stderr, exitCode] = await Promise.all([
39+
new Response(proc.stdout).text(),
40+
new Response(proc.stderr).text(),
41+
proc.exited,
42+
]);
43+
44+
expect(stderr).not.toContain("ENOENT");
45+
expect(stdout).toContain("building BuildIconList");
46+
expect(stdout).toContain("building lowercase");
47+
expect(exitCode).toBe(0);
48+
});
49+
50+
test("issue #11295 - bun run --filter with path filter preserves case", async () => {
51+
using dir = tempDir("ws-path-filter", {
52+
"packages/MyPackage/package.json": JSON.stringify({
53+
name: "my-package",
54+
version: "1.0.0",
55+
scripts: {
56+
test: "echo testing MyPackage",
57+
},
58+
}),
59+
"package.json": JSON.stringify({
60+
name: "path-filter-test",
61+
private: true,
62+
workspaces: ["packages/*"],
63+
}),
64+
});
65+
66+
await using proc = Bun.spawn({
67+
cmd: [bunExe(), "run", "--filter", "./packages/MyPackage", "test"],
68+
cwd: String(dir),
69+
env: bunEnv,
70+
stdout: "pipe",
71+
stderr: "pipe",
72+
});
73+
74+
const [stdout, stderr, exitCode] = await Promise.all([
75+
new Response(proc.stdout).text(),
76+
new Response(proc.stderr).text(),
77+
proc.exited,
78+
]);
79+
80+
expect(stderr).not.toContain("ENOENT");
81+
expect(stdout).toContain("testing MyPackage");
82+
expect(exitCode).toBe(0);
83+
});

0 commit comments

Comments
 (0)