diff options
-rw-r--r-- | std/node/global.d.ts | 2 | ||||
-rw-r--r-- | std/node/global.ts | 2 | ||||
-rw-r--r-- | std/node/process.ts | 282 | ||||
-rw-r--r-- | std/node/process_exit_test.ts | 19 | ||||
-rw-r--r-- | std/node/process_test.ts | 71 |
5 files changed, 273 insertions, 103 deletions
diff --git a/std/node/global.d.ts b/std/node/global.d.ts index 707073e2e..94baf03b7 100644 --- a/std/node/global.d.ts +++ b/std/node/global.d.ts @@ -1,5 +1,5 @@ // Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. -import { process as processModule } from "./process.ts"; +import processModule from "./process.ts"; import { Buffer as bufferModule } from "./buffer.ts"; import timers from "./timers.ts"; diff --git a/std/node/global.ts b/std/node/global.ts index a07a892e5..550f6ddf9 100644 --- a/std/node/global.ts +++ b/std/node/global.ts @@ -1,6 +1,6 @@ // Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. /// <reference path="./global.d.ts" /> -import { process as processModule } from "./process.ts"; +import processModule from "./process.ts"; import { Buffer as bufferModule } from "./buffer.ts"; import timers from "./timers.ts"; diff --git a/std/node/process.ts b/std/node/process.ts index 5d6791fc4..419eb8cec 100644 --- a/std/node/process.ts +++ b/std/node/process.ts @@ -1,32 +1,109 @@ // Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. import { notImplemented } from "./_utils.ts"; +import EventEmitter from "./events.ts"; +import { fromFileUrl } from "../path/mod.ts"; + +const notImplementedEvents = [ + "beforeExit", + "disconnect", + "message", + "multipleResolves", + "rejectionHandled", + "SIGBREAK", + "SIGBUS", + "SIGFPE", + "SIGHUP", + "SIGILL", + "SIGINT", + "SIGSEGV", + "SIGTERM", + "SIGWINCH", + "uncaughtException", + "uncaughtExceptionMonitor", + "unhandledRejection", + "warning", +]; /** https://nodejs.org/api/process.html#process_process_arch */ export const arch = Deno.build.arch; +function getArguments() { + return [Deno.execPath(), fromFileUrl(Deno.mainModule), ...Deno.args]; +} + +//deno-lint-ignore ban-ts-comment +//@ts-ignore +const _argv: { + [Deno.customInspect]: () => string; + [key: number]: string; +} = []; + +Object.defineProperty(_argv, Deno.customInspect, { + enumerable: false, + configurable: false, + get: function () { + return getArguments(); + }, +}); + +/** + * https://nodejs.org/api/process.html#process_process_argv + * Read permissions are required in order to get the executable route + * */ +export const argv: Record<string, string> = new Proxy(_argv, { + get(target, prop) { + if (prop === Deno.customInspect) { + return target[Deno.customInspect]; + } + return getArguments()[prop as number]; + }, + ownKeys() { + return Reflect.ownKeys(getArguments()); + }, +}); + /** https://nodejs.org/api/process.html#process_process_chdir_directory */ export const chdir = Deno.chdir; /** https://nodejs.org/api/process.html#process_process_cwd */ export const cwd = Deno.cwd; -/** https://nodejs.org/api/process.html#process_process_exit_code */ -export const exit = Deno.exit; +//deno-lint-ignore ban-ts-comment +//@ts-ignore +const _env: { + [Deno.customInspect]: () => string; +} = {}; -/** https://nodejs.org/api/process.html#process_process_pid */ -export const pid = Deno.pid; - -/** https://nodejs.org/api/process.html#process_process_platform */ -export const platform = Deno.build.os === "windows" ? "win32" : Deno.build.os; +Object.defineProperty(_env, Deno.customInspect, { + enumerable: false, + configurable: false, + get: function () { + return Deno.env.toObject(); + }, +}); -/** https://nodejs.org/api/process.html#process_process_version */ -export const version = `v${Deno.version.deno}`; +/** + * https://nodejs.org/api/process.html#process_process_env + * Requires env permissions + * */ +export const env: Record<string, string> = new Proxy(_env, { + get(target, prop) { + if (prop === Deno.customInspect) { + return target[Deno.customInspect]; + } + return Deno.env.get(String(prop)); + }, + ownKeys() { + return Reflect.ownKeys(Deno.env.toObject()); + }, + set(_target, prop, value) { + Deno.env.set(String(prop), String(value)); + return value; + }, +}); -/** https://nodejs.org/api/process.html#process_process_versions */ -export const versions = { - node: Deno.version.deno, - ...Deno.version, -}; +/** https://nodejs.org/api/process.html#process_process_exit_code */ +export const exit = Deno.exit; /** https://nodejs.org/api/process.html#process_process_nexttick_callback_args */ export function nextTick(this: unknown, cb: () => void): void; @@ -47,17 +124,103 @@ export function nextTick<T extends Array<unknown>>( } } -/** https://nodejs.org/api/process.html#process_process */ -// @deprecated `import { process } from 'process'` for backwards compatibility with old deno versions -export const process = { - arch, - chdir, - cwd, - exit, - pid, - platform, - version, - versions, +/** https://nodejs.org/api/process.html#process_process_pid */ +export const pid = Deno.pid; + +/** https://nodejs.org/api/process.html#process_process_platform */ +export const platform = Deno.build.os === "windows" ? "win32" : Deno.build.os; + +/** https://nodejs.org/api/process.html#process_process_version */ +export const version = `v${Deno.version.deno}`; + +/** https://nodejs.org/api/process.html#process_process_versions */ +export const versions = { + node: Deno.version.deno, + ...Deno.version, +}; + +class Process extends EventEmitter { + constructor() { + super(); + + //This causes the exit event to be binded to the unload event + window.addEventListener("unload", () => { + //TODO(Soremwar) + //Get the exit code from the unload event + super.emit("exit", 0); + }); + } + + /** https://nodejs.org/api/process.html#process_process_arch */ + arch = arch; + + /** + * https://nodejs.org/api/process.html#process_process_argv + * Read permissions are required in order to get the executable route + * */ + argv = argv; + + /** https://nodejs.org/api/process.html#process_process_chdir_directory */ + chdir = chdir; + + /** https://nodejs.org/api/process.html#process_process_cwd */ + cwd = cwd; + + /** https://nodejs.org/api/process.html#process_process_exit_code */ + exit = exit; + + /** + * https://nodejs.org/api/process.html#process_process_env + * Requires env permissions + * */ + env = env; + + /** https://nodejs.org/api/process.html#process_process_nexttick_callback_args */ + nextTick = nextTick; + + /** https://nodejs.org/api/process.html#process_process_events */ + //deno-lint-ignore ban-types + on(event: typeof notImplementedEvents[number], listener: Function): never; + on(event: "exit", listener: (code: number) => void): this; + //deno-lint-ignore no-explicit-any + on(event: string, listener: (...args: any[]) => void): this { + if (notImplementedEvents.includes(event)) { + notImplemented(); + } + + super.on(event, listener); + + return this; + } + + /** https://nodejs.org/api/process.html#process_process_pid */ + pid = pid; + + /** https://nodejs.org/api/process.html#process_process_platform */ + platform = platform; + + removeAllListeners(_event: string): never { + notImplemented(); + } + + removeListener( + event: typeof notImplementedEvents[number], + //deno-lint-ignore ban-types + listener: Function, + ): never; + removeListener(event: "exit", listener: (code: number) => void): this; + //deno-lint-ignore no-explicit-any + removeListener(event: string, listener: (...args: any[]) => void): this { + if (notImplementedEvents.includes(event)) { + notImplemented(); + } + + super.removeListener("exit", listener); + + return this; + } + + /** https://nodejs.org/api/process.html#process_process_stderr */ get stderr() { return { fd: Deno.stderr.rid, @@ -79,7 +242,9 @@ export const process = { notImplemented(); }, }; - }, + } + + /** https://nodejs.org/api/process.html#process_process_stdin */ get stdin() { return { fd: Deno.stdin.rid, @@ -96,7 +261,9 @@ export const process = { notImplemented(); }, }; - }, + } + + /** https://nodejs.org/api/process.html#process_process_stdout */ get stdout() { return { fd: Deno.stdout.rid, @@ -118,49 +285,17 @@ export const process = { notImplemented(); }, }; - }, - - /** https://nodejs.org/api/process.html#process_process_events */ - // on is not exported by node, it is only available within process: - // node --input-type=module -e "import { on } from 'process'; console.log(on)" - // deno-lint-ignore ban-types - on(_event: string, _callback: Function): void { - // TODO(rsp): to be implemented - notImplemented(); - }, - - /** https://nodejs.org/api/process.html#process_process_argv */ - get argv(): string[] { - // Getter delegates --allow-env and --allow-read until request - // Getter also allows the export Proxy instance to function as intended - return [Deno.execPath(), ...Deno.args]; - }, - - /** https://nodejs.org/api/process.html#process_process_env */ - get env(): { [index: string]: string } { - // Getter delegates --allow-env and --allow-read until request - // Getter also allows the export Proxy instance to function as intended - return Deno.env.toObject(); - }, - nextTick, -}; + } -/** - * https://nodejs.org/api/process.html#process_process_argv - * @example `import { argv } from './std/node/process.ts'; console.log(argv)` - */ -// Proxy delegates --allow-env and --allow-read to request time, even for exports -export const argv = new Proxy(process.argv, {}); + /** https://nodejs.org/api/process.html#process_process_version */ + version = version; -/** - * https://nodejs.org/api/process.html#process_process_env - * @example `import { env } from './std/node/process.ts'; console.log(env)` - */ -// Proxy delegates --allow-env and --allow-read to request time, even for exports -export const env = new Proxy(process.env, {}); + /** https://nodejs.org/api/process.html#process_process_versions */ + versions = versions; +} -// import process from './std/node/process.ts' -export default process; +/** https://nodejs.org/api/process.html#process_process */ +const process = new Process(); Object.defineProperty(process, Symbol.toStringTag, { enumerable: false, @@ -168,3 +303,16 @@ Object.defineProperty(process, Symbol.toStringTag, { configurable: false, value: "process", }); + +export const removeListener = process.removeListener; +export const removeAllListeners = process.removeAllListeners; +export const stderr = process.stderr; +export const stdin = process.stdin; +export const stdout = process.stdout; + +export default process; + +//TODO(Soremwar) +//Remove on 1.0 +//Kept for backwars compatibility with std +export { process }; diff --git a/std/node/process_exit_test.ts b/std/node/process_exit_test.ts new file mode 100644 index 000000000..54c8bcc01 --- /dev/null +++ b/std/node/process_exit_test.ts @@ -0,0 +1,19 @@ +import "./global.ts"; + +//deno-lint-ignore no-undef +process.on("exit", () => { + console.log(1); +}); + +function unexpected() { + console.log(null); +} +//deno-lint-ignore no-undef +process.on("exit", unexpected); +//deno-lint-ignore no-undef +process.removeListener("exit", unexpected); + +//deno-lint-ignore no-undef +process.on("exit", () => { + console.log(2); +}); diff --git a/std/node/process_test.ts b/std/node/process_test.ts index 9b2c050a7..22cebf260 100644 --- a/std/node/process_test.ts +++ b/std/node/process_test.ts @@ -1,37 +1,12 @@ // deno-lint-ignore-file no-undef // Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. +import "./global.ts"; import { assert, assertEquals, assertThrows } from "../testing/asserts.ts"; +import { stripColor } from "../fmt/colors.ts"; import * as path from "../path/mod.ts"; -import * as all from "./process.ts"; -import { argv, env } from "./process.ts"; import { delay } from "../async/delay.ts"; -import "./global.ts"; - -// NOTE: Deno.execPath() (and thus process.argv) currently requires --allow-env -// (Also Deno.env.toObject() (and process.env) requires --allow-env but it's more obvious) - -Deno.test({ - name: "process exports are as they should be", - fn() { - // * should be the same as process, default, and globalThis.process - // without the export aliases, and with properties that are not standalone - const allKeys = new Set<string>(Object.keys(all)); - // without { process } for deno b/c - allKeys.delete("process"); - // without esm default - allKeys.delete("default"); - // with on, stdin, stderr, and stdout, which is not exported via * - allKeys.add("on"); - allKeys.add("stdin"); - allKeys.add("stderr"); - allKeys.add("stdout"); - const allStr = Array.from(allKeys).sort().join(" "); - assertEquals(Object.keys(all.default).sort().join(" "), allStr); - assertEquals(Object.keys(all.process).sort().join(" "), allStr); - assertEquals(Object.keys(process).sort().join(" "), allStr); - }, -}); +import { env } from "./process.ts"; Deno.test({ name: "process.cwd and process.chdir success", @@ -103,7 +78,7 @@ Deno.test({ Deno.test({ name: "process.on", - fn() { + async fn() { assertEquals(typeof process.on, "function"); assertThrows( () => { @@ -112,6 +87,33 @@ Deno.test({ Error, "implemented", ); + + let triggered = false; + process.on("exit", () => { + triggered = true; + }); + process.emit("exit"); + assert(triggered); + + const cwd = path.dirname(path.fromFileUrl(import.meta.url)); + + const p = Deno.run({ + cmd: [ + Deno.execPath(), + "run", + "./process_exit_test.ts", + ], + cwd, + stdout: "piped", + }); + + const decoder = new TextDecoder(); + const rawOutput = await p.output(); + assertEquals( + stripColor(decoder.decode(rawOutput).trim()), + "1\n2", + ); + p.close(); }, }); @@ -119,12 +121,14 @@ Deno.test({ name: "process.argv", fn() { assert(Array.isArray(process.argv)); - assert(Array.isArray(argv)); assert( process.argv[0].match(/[^/\\]*deno[^/\\]*$/), "deno included in the file name of argv[0]", ); - // we cannot test for anything else (we see test runner arguments here) + assertEquals( + process.argv[1], + path.fromFileUrl(Deno.mainModule), + ); }, }); @@ -136,9 +140,8 @@ Deno.test({ assertEquals(typeof (process.env.HELLO), "string"); assertEquals(process.env.HELLO, "WORLD"); - // TODO(caspervonb) test the globals in a different setting (they're broken) - // assertEquals(typeof env.HELLO, "string"); - // assertEquals(env.HELLO, "WORLD"); + assertEquals(typeof env.HELLO, "string"); + assertEquals(env.HELLO, "WORLD"); }, }); |