Skip to content

Commit a66fca1

Browse files
process: fix Windows cmd exec UTF-8 output
1 parent a73e517 commit a66fca1

File tree

2 files changed

+13
-4
lines changed

2 files changed

+13
-4
lines changed

src/process/exec.ts

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -100,16 +100,19 @@ export function shouldSpawnWithShell(params: {
100100
export async function runExec(
101101
command: string,
102102
args: string[],
103-
opts: number | { timeoutMs?: number; maxBuffer?: number; cwd?: string } = 10_000,
103+
opts:
104+
| number
105+
| { timeoutMs?: number; maxBuffer?: number; cwd?: string; encoding?: BufferEncoding } = 10_000,
104106
): Promise<{ stdout: string; stderr: string }> {
107+
const encoding = typeof opts === "number" ? "utf8" : (opts.encoding ?? "utf8");
105108
const options =
106109
typeof opts === "number"
107-
? { timeout: opts, encoding: "utf8" as const }
110+
? { timeout: opts, encoding }
108111
: {
109112
timeout: opts.timeoutMs,
110113
maxBuffer: opts.maxBuffer,
111114
cwd: opts.cwd,
112-
encoding: "utf8" as const,
115+
encoding,
113116
};
114117
try {
115118
const argv = [command, ...args];
@@ -129,10 +132,15 @@ export async function runExec(
129132
execArgs = args;
130133
}
131134
const useCmdWrapper = isWindowsBatchCommand(execCommand);
135+
const cmdCommandLine = buildCmdExeCommandLine(execCommand, execArgs);
136+
const wrappedCommandLine =
137+
process.platform === "win32" && useCmdWrapper && encoding.toLowerCase() === "utf8"
138+
? `chcp 65001>nul && ${cmdCommandLine}`
139+
: cmdCommandLine;
132140
const { stdout, stderr } = useCmdWrapper
133141
? await execFileAsync(
134142
process.env.ComSpec ?? "cmd.exe",
135-
["/d", "/s", "/c", buildCmdExeCommandLine(execCommand, execArgs)],
143+
["/d", "/s", "/c", wrappedCommandLine],
136144
{ ...options, windowsVerbatimArguments: true },
137145
)
138146
: await execFileAsync(execCommand, execArgs, options);

src/process/exec.windows.test.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,7 @@ describe("windows command wrapper behavior", () => {
113113
await runExec("pnpm", ["--version"], 1000);
114114
const captured = execFileMock.mock.calls[0] as ExecCall | undefined;
115115
expectCmdWrappedInvocation({ captured, expectedComSpec });
116+
expect(captured?.[1][3]).toContain("chcp 65001>nul &&");
116117
} finally {
117118
platformSpy.mockRestore();
118119
}

0 commit comments

Comments
 (0)