From f29075ae4cf435032e410d582bdfa22b031e802c Mon Sep 17 00:00:00 2001 From: David Sherret Date: Sat, 2 Dec 2023 11:03:37 -0500 Subject: [PATCH] fix(node): setting process.exitCode should change exit code of process (#21429) --- cli/tests/unit_node/process_test.ts | 53 +++++++++++++++++++++++++++-- ext/node/polyfills/process.ts | 17 +++++++-- 2 files changed, 65 insertions(+), 5 deletions(-) diff --git a/cli/tests/unit_node/process_test.ts b/cli/tests/unit_node/process_test.ts index 69af8a3ad141d7..b9290fbac266e4 100644 --- a/cli/tests/unit_node/process_test.ts +++ b/cli/tests/unit_node/process_test.ts @@ -681,9 +681,58 @@ Deno.test("process.memoryUsage.rss()", () => { }); Deno.test("process.exitCode", () => { - assert(process.exitCode === undefined); + assertEquals(process.exitCode, undefined); process.exitCode = 127; - assert(process.exitCode === 127); + assertEquals(process.exitCode, 127); + // deno-lint-ignore no-explicit-any + (process.exitCode as any) = "asdf"; + // deno-lint-ignore no-explicit-any + assertEquals(process.exitCode as any, "asdf"); + // deno-lint-ignore no-explicit-any + (process.exitCode as any) = "10"; + process.exitCode = undefined; // reset +}); + +async function exitCodeTest(codeText: string, expectedExitCode: number) { + const command = new Deno.Command(Deno.execPath(), { + args: [ + "eval", + codeText, + ], + cwd: testDir, + }); + const { code } = await command.output(); + assertEquals(code, expectedExitCode); +} + +Deno.test("process.exitCode in should change exit code", async () => { + await exitCodeTest( + "import process from 'node:process'; process.exitCode = 127;", + 127, + ); + await exitCodeTest( + "import process from 'node:process'; process.exitCode = 2.5;", + 2, + ); + await exitCodeTest( + "import process from 'node:process'; process.exitCode = '10';", + 10, + ); + await exitCodeTest( + "import process from 'node:process'; process.exitCode = '0x10';", + 16, + ); + await exitCodeTest( + "import process from 'node:process'; process.exitCode = NaN;", + 0, + ); +}); + +Deno.test("Deno.exit should override process exit", async () => { + await exitCodeTest( + "import process from 'node:process'; process.exitCode = 10; Deno.exit(12);", + 12, + ); }); Deno.test("process.config", () => { diff --git a/ext/node/polyfills/process.ts b/ext/node/polyfills/process.ts index c495a90bb162dc..575d8dfb14eefd 100644 --- a/ext/node/polyfills/process.ts +++ b/ext/node/polyfills/process.ts @@ -76,15 +76,16 @@ const notImplementedEvents = [ ]; export const argv: string[] = []; +let globalProcessExitCode: number | undefined = undefined; /** https://nodejs.org/api/process.html#process_process_exit_code */ export const exit = (code?: number | string) => { if (code || code === 0) { if (typeof code === "string") { const parsedCode = parseInt(code); - process.exitCode = isNaN(parsedCode) ? undefined : parsedCode; + globalProcessExitCode = isNaN(parsedCode) ? undefined : parsedCode; } else { - process.exitCode = code; + globalProcessExitCode = code; } } @@ -426,7 +427,17 @@ class Process extends EventEmitter { _exiting = _exiting; /** https://nodejs.org/api/process.html#processexitcode_1 */ - exitCode: undefined | number = undefined; + get exitCode() { + return globalProcessExitCode; + } + + set exitCode(code: number | undefined) { + globalProcessExitCode = code; + code = parseInt(code) || 0; + if (!isNaN(code)) { + ops.op_set_exit_code(code); + } + } // Typed as any to avoid importing "module" module for types // deno-lint-ignore no-explicit-any