From 7107c358a185e7f79dcf7df6fd0253cf6167656a Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Mon, 3 Feb 2025 16:39:04 +0530 Subject: [PATCH] fix(ext/node): set process fields on own instance (#27927) Ref https://github.com/denoland/deno/pull/27891#issuecomment-2626286689 ``` % deno eval 'console.log(Object.getOwnPropertyNames(process))' [ "_events", "_eventsCount", "_maxListeners", "versions", "stdin", "stdout", "stderr" ] % target/debug/deno eval 'console.log(Object.getOwnPropertyNames(process))' [ "_events", "_eventsCount", "_maxListeners", "release", "arch", "report", "title", "argv", "argv0", "chdir", "config", "cpuUsage", "cwd", "env", "execArgv", "exit", "abort", "reallyExit", "_exiting", "exitCode", "mainModule", "nextTick", "dlopen", "pid", "ppid", "platform", "setSourceMapsEnabled", "hrtime", "_kill", "kill", "memoryUsage", "stderr", "stdin", "stdout", "version", "versions", "emitWarning", "binding", "umask", "getgid", "getuid", "getegid", "geteuid", "getBuiltinModule", "_eval", "execPath", "uptime", "allowedNodeEnvironmentFlags", "features", "noDeprecation" ] ``` --- ext/node/polyfills/process.ts | 374 +++++++++++++++++----------------- 1 file changed, 185 insertions(+), 189 deletions(-) diff --git a/ext/node/polyfills/process.ts b/ext/node/polyfills/process.ts index 3e63b9a076d965..cbfee4f9f03987 100644 --- a/ext/node/polyfills/process.ts +++ b/ext/node/polyfills/process.ts @@ -376,8 +376,142 @@ function Process(this: any) { } Process.prototype = Object.create(EventEmitter.prototype); +/** https://nodejs.org/api/process.html#process_process_events */ +Process.prototype.on = function ( + // deno-lint-ignore no-explicit-any + this: any, + event: string, + // deno-lint-ignore no-explicit-any + listener: (...args: any[]) => void, +) { + if (notImplementedEvents.includes(event)) { + warnNotImplemented(`process.on("${event}")`); + EventEmitter.prototype.on.call(this, event, listener); + } else if (event.startsWith("SIG")) { + if (event === "SIGBREAK" && Deno.build.os !== "windows") { + // Ignores SIGBREAK if the platform is not windows. + } else if (event === "SIGTERM" && Deno.build.os === "windows") { + // Ignores SIGTERM on windows. + } else if ( + event !== "SIGBREAK" && event !== "SIGINT" && Deno.build.os === "windows" + ) { + // TODO(#26331): Ignores all signals except SIGBREAK and SIGINT on windows. + } else { + EventEmitter.prototype.on.call(this, event, listener); + Deno.addSignalListener(event as Deno.Signal, listener); + } + } else { + EventEmitter.prototype.on.call(this, event, listener); + } + + return this; +}; + +Process.prototype.off = function ( + // deno-lint-ignore no-explicit-any + this: any, + event: string, + // deno-lint-ignore no-explicit-any + listener: (...args: any[]) => void, +) { + if (notImplementedEvents.includes(event)) { + warnNotImplemented(`process.off("${event}")`); + EventEmitter.prototype.off.call(this, event, listener); + } else if (event.startsWith("SIG")) { + if (event === "SIGBREAK" && Deno.build.os !== "windows") { + // Ignores SIGBREAK if the platform is not windows. + } else if ( + event !== "SIGBREAK" && event !== "SIGINT" && Deno.build.os === "windows" + ) { + // Ignores all signals except SIGBREAK and SIGINT on windows. + } else { + EventEmitter.prototype.off.call(this, event, listener); + Deno.removeSignalListener(event as Deno.Signal, listener); + } + } else { + EventEmitter.prototype.off.call(this, event, listener); + } + + return this; +}; + +Process.prototype.emit = function ( + // deno-lint-ignore no-explicit-any + this: any, + event: string, + // deno-lint-ignore no-explicit-any + ...args: any[] +): boolean { + if (event.startsWith("SIG")) { + if (event === "SIGBREAK" && Deno.build.os !== "windows") { + // Ignores SIGBREAK if the platform is not windows. + } else { + Deno.kill(Deno.pid, event as Deno.Signal); + } + } else { + return EventEmitter.prototype.emit.call(this, event, ...args); + } + + return true; +}; + +Process.prototype.prependListener = function ( + // deno-lint-ignore no-explicit-any + this: any, + event: string, + // deno-lint-ignore no-explicit-any + listener: (...args: any[]) => void, +) { + if (notImplementedEvents.includes(event)) { + warnNotImplemented(`process.prependListener("${event}")`); + EventEmitter.prototype.prependListener.call(this, event, listener); + } else if (event.startsWith("SIG")) { + if (event === "SIGBREAK" && Deno.build.os !== "windows") { + // Ignores SIGBREAK if the platform is not windows. + } else { + EventEmitter.prototype.prependListener.call(this, event, listener); + Deno.addSignalListener(event as Deno.Signal, listener); + } + } else { + EventEmitter.prototype.prependListener.call(this, event, listener); + } + + return this; +}; + +Process.prototype.addListener = function ( + // deno-lint-ignore no-explicit-any + this: any, + event: string, + // deno-lint-ignore no-explicit-any + listener: (...args: any[]) => void, +) { + if (notImplementedEvents.includes(event)) { + warnNotImplemented(`process.addListener("${event}")`); + } + + return this.on(event, listener); +}; + +Process.prototype.removeListener = function ( + // deno-lint-ignore no-explicit-any + this: any, + event: string, // deno-lint-ignore no-explicit-any + listener: (...args: any[]) => void, +) { + if (notImplementedEvents.includes(event)) { + warnNotImplemented(`process.removeListener("${event}")`); + } + + return this.off(event, listener); +}; + +/** https://nodejs.org/api/process.html#process_process */ +// @ts-ignore TS doesn't work well with ES5 classes +const process = new Process(); + /** https://nodejs.org/api/process.html#processrelease */ -Object.defineProperty(Process.prototype, "release", { +Object.defineProperty(process, "release", { get() { return { name: "node", @@ -390,19 +524,19 @@ Object.defineProperty(Process.prototype, "release", { }); /** https://nodejs.org/api/process.html#process_process_arch */ -Object.defineProperty(Process.prototype, "arch", { +Object.defineProperty(process, "arch", { get() { return arch; }, }); -Object.defineProperty(Process.prototype, "report", { +Object.defineProperty(process, "report", { get() { return report; }, }); -Object.defineProperty(Process.prototype, "title", { +Object.defineProperty(process, "title", { get() { return "deno"; }, @@ -417,9 +551,9 @@ Object.defineProperty(Process.prototype, "title", { * https://nodejs.org/api/process.html#process_process_argv * Read permissions are required in order to get the executable route */ -Process.prototype.argv = argv; +process.argv = argv; -Object.defineProperty(Process.prototype, "argv0", { +Object.defineProperty(process, "argv0", { get() { return argv0; }, @@ -427,10 +561,10 @@ Object.defineProperty(Process.prototype, "argv0", { }); /** https://nodejs.org/api/process.html#process_process_chdir_directory */ -Process.prototype.chdir = chdir; +process.chdir = chdir; /** https://nodejs.org/api/process.html#processconfig */ -Process.prototype.config = { +process.config = { target_defaults: { default_configuration: "Release", }, @@ -440,39 +574,39 @@ Process.prototype.config = { }, }; -Process.prototype.cpuUsage = function () { +process.cpuUsage = function () { return Deno.cpuUsage(); }; /** https://nodejs.org/api/process.html#process_process_cwd */ -Process.prototype.cwd = cwd; +process.cwd = cwd; /** * https://nodejs.org/api/process.html#process_process_env * Requires env permissions */ -Process.prototype.env = env; +process.env = env; /** https://nodejs.org/api/process.html#process_process_execargv */ -Process.prototype.execArgv = execArgv; +process.execArgv = execArgv; /** https://nodejs.org/api/process.html#process_process_exit_code */ -Process.prototype.exit = exit; +process.exit = exit; /** https://nodejs.org/api/process.html#processabort */ -Process.prototype.abort = abort; +process.abort = abort; // Undocumented Node API that is used by `signal-exit` which in turn // is used by `node-tap`. It was marked for removal a couple of years // ago. See https://github.com/nodejs/node/blob/6a6b3c54022104cc110ab09044a2a0cecb8988e7/lib/internal/bootstrap/node.js#L172 -Process.prototype.reallyExit = (code: number) => { +process.reallyExit = (code: number) => { return Deno.exit(code || 0); }; -Process.prototype._exiting = _exiting; +process._exiting = _exiting; /** https://nodejs.org/api/process.html#processexitcode_1 */ -Object.defineProperty(Process.prototype, "exitCode", { +Object.defineProperty(process, "exitCode", { get() { return ProcessExitCode; }, @@ -498,170 +632,40 @@ Object.defineProperty(Process.prototype, "exitCode", { }); // Typed as any to avoid importing "module" module for types -Process.prototype.mainModule = undefined; +process.mainModule = undefined; /** https://nodejs.org/api/process.html#process_process_nexttick_callback_args */ -Process.prototype.nextTick = _nextTick; +process.nextTick = _nextTick; -Process.prototype.dlopen = dlopen; - -/** https://nodejs.org/api/process.html#process_process_events */ -Process.prototype.on = function ( - // deno-lint-ignore no-explicit-any - this: any, - event: string, - // deno-lint-ignore no-explicit-any - listener: (...args: any[]) => void, -) { - if (notImplementedEvents.includes(event)) { - warnNotImplemented(`process.on("${event}")`); - EventEmitter.prototype.on.call(this, event, listener); - } else if (event.startsWith("SIG")) { - if (event === "SIGBREAK" && Deno.build.os !== "windows") { - // Ignores SIGBREAK if the platform is not windows. - } else if (event === "SIGTERM" && Deno.build.os === "windows") { - // Ignores SIGTERM on windows. - } else if ( - event !== "SIGBREAK" && event !== "SIGINT" && Deno.build.os === "windows" - ) { - // TODO(#26331): Ignores all signals except SIGBREAK and SIGINT on windows. - } else { - EventEmitter.prototype.on.call(this, event, listener); - Deno.addSignalListener(event as Deno.Signal, listener); - } - } else { - EventEmitter.prototype.on.call(this, event, listener); - } - - return this; -}; - -Process.prototype.off = function ( - // deno-lint-ignore no-explicit-any - this: any, - event: string, - // deno-lint-ignore no-explicit-any - listener: (...args: any[]) => void, -) { - if (notImplementedEvents.includes(event)) { - warnNotImplemented(`process.off("${event}")`); - EventEmitter.prototype.off.call(this, event, listener); - } else if (event.startsWith("SIG")) { - if (event === "SIGBREAK" && Deno.build.os !== "windows") { - // Ignores SIGBREAK if the platform is not windows. - } else if ( - event !== "SIGBREAK" && event !== "SIGINT" && Deno.build.os === "windows" - ) { - // Ignores all signals except SIGBREAK and SIGINT on windows. - } else { - EventEmitter.prototype.off.call(this, event, listener); - Deno.removeSignalListener(event as Deno.Signal, listener); - } - } else { - EventEmitter.prototype.off.call(this, event, listener); - } - - return this; -}; - -Process.prototype.emit = function ( - // deno-lint-ignore no-explicit-any - this: any, - event: string, - // deno-lint-ignore no-explicit-any - ...args: any[] -): boolean { - if (event.startsWith("SIG")) { - if (event === "SIGBREAK" && Deno.build.os !== "windows") { - // Ignores SIGBREAK if the platform is not windows. - } else { - Deno.kill(Deno.pid, event as Deno.Signal); - } - } else { - return EventEmitter.prototype.emit.call(this, event, ...args); - } - - return true; -}; - -Process.prototype.prependListener = function ( - // deno-lint-ignore no-explicit-any - this: any, - event: string, - // deno-lint-ignore no-explicit-any - listener: (...args: any[]) => void, -) { - if (notImplementedEvents.includes(event)) { - warnNotImplemented(`process.prependListener("${event}")`); - EventEmitter.prototype.prependListener.call(this, event, listener); - } else if (event.startsWith("SIG")) { - if (event === "SIGBREAK" && Deno.build.os !== "windows") { - // Ignores SIGBREAK if the platform is not windows. - } else { - EventEmitter.prototype.prependListener.call(this, event, listener); - Deno.addSignalListener(event as Deno.Signal, listener); - } - } else { - EventEmitter.prototype.prependListener.call(this, event, listener); - } - - return this; -}; +process.dlopen = dlopen; /** https://nodejs.org/api/process.html#process_process_pid */ -Object.defineProperty(Process.prototype, "pid", { +Object.defineProperty(process, "pid", { get() { return pid; }, }); /** https://nodejs.org/api/process.html#processppid */ -Object.defineProperty(Process.prototype, "ppid", { +Object.defineProperty(process, "ppid", { get() { return Deno.ppid; }, }); /** https://nodejs.org/api/process.html#process_process_platform */ -Object.defineProperty(Process.prototype, "platform", { +Object.defineProperty(process, "platform", { get() { return platform; }, }); // https://nodejs.org/api/process.html#processsetsourcemapsenabledval -Process.prototype.setSourceMapsEnabled = (_val: boolean) => { +process.setSourceMapsEnabled = (_val: boolean) => { // This is a no-op in Deno. Source maps are always enabled. // TODO(@satyarohith): support disabling source maps if needed. }; -Process.prototype.addListener = function ( - // deno-lint-ignore no-explicit-any - this: any, - event: string, - // deno-lint-ignore no-explicit-any - listener: (...args: any[]) => void, -) { - if (notImplementedEvents.includes(event)) { - warnNotImplemented(`process.addListener("${event}")`); - } - - return this.on(event, listener); -}; - -Process.prototype.removeListener = function ( - // deno-lint-ignore no-explicit-any - this: any, - event: string, // deno-lint-ignore no-explicit-any - listener: (...args: any[]) => void, -) { - if (notImplementedEvents.includes(event)) { - warnNotImplemented(`process.removeListener("${event}")`); - } - - return this.off(event, listener); -}; - /** * Returns the current high-resolution real time in a [seconds, nanoseconds] * tuple. @@ -675,44 +679,44 @@ Process.prototype.removeListener = function ( * These times are relative to an arbitrary time in the past, and not related to the time of day and therefore not subject to clock drift. The primary use is for measuring performance between intervals. * https://nodejs.org/api/process.html#process_process_hrtime_time */ -Process.prototype.hrtime = hrtime; +process.hrtime = hrtime; /** * @private * * NodeJS internal, use process.kill instead */ -Process.prototype._kill = _kill; +process._kill = _kill; /** https://nodejs.org/api/process.html#processkillpid-signal */ -Process.prototype.kill = kill; +process.kill = kill; -Process.prototype.memoryUsage = memoryUsage; +process.memoryUsage = memoryUsage; /** https://nodejs.org/api/process.html#process_process_stderr */ -Process.prototype.stderr = stderr; +process.stderr = stderr; /** https://nodejs.org/api/process.html#process_process_stdin */ -Process.prototype.stdin = stdin; +process.stdin = stdin; /** https://nodejs.org/api/process.html#process_process_stdout */ -Process.prototype.stdout = stdout; +process.stdout = stdout; /** https://nodejs.org/api/process.html#process_process_version */ -Process.prototype.version = version; +process.version = version; /** https://nodejs.org/api/process.html#process_process_versions */ -Process.prototype.versions = versions; +process.versions = versions; /** https://nodejs.org/api/process.html#process_process_emitwarning_warning_options */ -Process.prototype.emitWarning = emitWarning; +process.emitWarning = emitWarning; -Process.prototype.binding = (name: BindingName) => { +process.binding = (name: BindingName) => { return getBinding(name); }; /** https://nodejs.org/api/process.html#processumaskmask */ -Process.prototype.umask = () => { +process.umask = () => { // Always return the system default umask value. // We don't use Deno.umask here because it has a race // condition bug. @@ -721,25 +725,25 @@ Process.prototype.umask = () => { }; /** This method is removed on Windows */ -Process.prototype.getgid = getgid; +process.getgid = getgid; /** This method is removed on Windows */ -Process.prototype.getuid = getuid; +process.getuid = getuid; /** This method is removed on Windows */ -Process.prototype.getegid = getegid; +process.getegid = getegid; /** This method is removed on Windows */ -Process.prototype.geteuid = geteuid; +process.geteuid = geteuid; -Process.prototype.getBuiltinModule = getBuiltinModule; +process.getBuiltinModule = getBuiltinModule; // TODO(kt3k): Implement this when we added -e option to node compat mode -Process.prototype._eval = undefined; +process._eval = undefined; /** https://nodejs.org/api/process.html#processexecpath */ -Object.defineProperty(Process.prototype, "execPath", { +Object.defineProperty(process, "execPath", { get() { return String(execPath); }, @@ -749,12 +753,12 @@ Object.defineProperty(Process.prototype, "execPath", { }); /** https://nodejs.org/api/process.html#processuptime */ -Process.prototype.uptime = () => { +process.uptime = () => { return Number((performance.now() / 1000).toFixed(9)); }; /** https://nodejs.org/api/process.html#processallowednodeenvironmentflags */ -Object.defineProperty(Process.prototype, "allowedNodeEnvironmentFlags", { +Object.defineProperty(process, "allowedNodeEnvironmentFlags", { get() { return ALLOWED_FLAGS; }, @@ -762,26 +766,18 @@ Object.defineProperty(Process.prototype, "allowedNodeEnvironmentFlags", { export const allowedNodeEnvironmentFlags = ALLOWED_FLAGS; -Process.prototype.features = { inspector: false }; +process.features = { inspector: false }; // TODO(kt3k): Get the value from --no-deprecation flag. -Process.prototype.noDeprecation = false; +process.noDeprecation = false; if (isWindows) { - delete Process.prototype.getgid; - delete Process.prototype.getuid; - delete Process.prototype.getegid; - delete Process.prototype.geteuid; + delete process.getgid; + delete process.getuid; + delete process.getegid; + delete process.geteuid; } -/** https://nodejs.org/api/process.html#process_process */ -// @ts-ignore TS doesn't work well with ES5 classes -const process = new Process(); - -/* Set owned property */ -process.versions = versions; -process.env = env; - Object.defineProperty(process, Symbol.toStringTag, { enumerable: false, writable: true,