diff --git a/src/cli/run_command.zig b/src/cli/run_command.zig index d0e4889ed2..c9b323f6e4 100644 --- a/src/cli/run_command.zig +++ b/src/cli/run_command.zig @@ -813,7 +813,7 @@ pub const RunCommand = struct { if (!has_copied) { bun.copy(u8, &path_buf, value.dir); dir_slice = path_buf[0..value.dir.len]; - if (!strings.endsWithChar(value.dir, std.fs.path.sep)) { + if (!strings.endsWithCharOrIsZeroLength(value.dir, std.fs.path.sep)) { dir_slice = path_buf[0 .. value.dir.len + 1]; } has_copied = true; diff --git a/src/resolver/package_json.zig b/src/resolver/package_json.zig index e87a61e879..e827e6a995 100644 --- a/src/resolver/package_json.zig +++ b/src/resolver/package_json.zig @@ -1753,7 +1753,7 @@ pub const ESModule = struct { log.addNoteFmt("Substituted \"{s}\" for \"*\" in \".{s}\" to get \".{s}\" ", .{ subpath, resolved_target, result }); } - const status: Status = if (strings.endsWithChar(result, '*') and strings.indexOfChar(result, '*').? == result.len - 1) + const status: Status = if (strings.endsWithCharOrIsZeroLength(result, '*') and strings.indexOfChar(result, '*').? == result.len - 1) .ExactEndsWithStar else .Exact; @@ -1937,7 +1937,7 @@ pub const ESModule = struct { if (match_obj.data != .map) return null; const map = match_obj.data.map; - if (!strings.endsWithChar(query, "*")) { + if (!strings.endsWithCharOrIsZeroLength(query, "*")) { var slices = map.list.slice(); const keys = slices.items(.key); const values = slices.items(.value); @@ -1949,7 +1949,7 @@ pub const ESModule = struct { } for (map.expansion_keys) |expansion| { - if (strings.endsWithChar(expansion.key, '*')) { + if (strings.endsWithCharOrIsZeroLength(expansion.key, '*')) { if (r.resolveTargetReverse(query, expansion.key, expansion.value, .pattern)) |result| { return result; } diff --git a/src/string_immutable.zig b/src/string_immutable.zig index 0014d5a3fa..331e7e33f2 100644 --- a/src/string_immutable.zig +++ b/src/string_immutable.zig @@ -713,6 +713,10 @@ pub inline fn startsWithChar(self: string, char: u8) bool { } pub inline fn endsWithChar(self: string, char: u8) bool { + return self.len > 0 and self[self.len - 1] == char; +} + +pub inline fn endsWithCharOrIsZeroLength(self: string, char: u8) bool { return self.len == 0 or self[self.len - 1] == char; } diff --git a/test/cli/init/init.test.ts b/test/cli/init/init.test.ts index 3bb69e37f6..2a6c2b1028 100644 --- a/test/cli/init/init.test.ts +++ b/test/cli/init/init.test.ts @@ -6,13 +6,52 @@ import { bunExe, bunEnv } from "harness"; test("bun init works", () => { const temp = fs.realpathSync(fs.mkdtempSync(path.join(os.tmpdir(), "bun-init-X"))); - Bun.spawnSync({ + const out = Bun.spawnSync({ cmd: [bunExe(), "init", "-y"], cwd: temp, stdio: ["ignore", "inherit", "inherit"], env: bunEnv, }); + expect(out.signal).toBe(undefined); + expect(out.exitCode).toBe(0); + + const pkg = JSON.parse(fs.readFileSync(path.join(temp, "package.json"), "utf8")); + expect(pkg).toEqual({ + "name": path.basename(temp).toLowerCase(), + "module": "index.ts", + "type": "module", + "devDependencies": { + "bun-types": "latest", + }, + "peerDependencies": { + "typescript": "^5.0.0", + }, + }); + const readme = fs.readFileSync(path.join(temp, "README.md"), "utf8"); + expect(readme).toStartWith("# " + path.basename(temp).toLowerCase() + "\n"); + expect(readme).toInclude("v" + Bun.version.replaceAll("-debug", "")); + expect(readme).toInclude("index.ts"); + + expect(fs.existsSync(path.join(temp, "index.ts"))).toBe(true); + expect(fs.existsSync(path.join(temp, ".gitignore"))).toBe(true); + expect(fs.existsSync(path.join(temp, "node_modules"))).toBe(true); + expect(fs.existsSync(path.join(temp, "tsconfig.json"))).toBe(true); +}, 30_000); + +test("bun init with piped cli", () => { + const temp = fs.realpathSync(fs.mkdtempSync(path.join(os.tmpdir(), "bun-init-X"))); + + const out = Bun.spawnSync({ + cmd: [bunExe(), "init"], + cwd: temp, + stdio: [new Blob(["\n\n\n\n\n\n\n\n\n\n\n\n"]), "inherit", "inherit"], + env: bunEnv, + }); + + expect(out.signal).toBe(undefined); + expect(out.exitCode).toBe(0); + const pkg = JSON.parse(fs.readFileSync(path.join(temp, "package.json"), "utf8")); expect(pkg).toEqual({ "name": path.basename(temp).toLowerCase(),