summaryrefslogtreecommitdiff
path: root/ext
diff options
context:
space:
mode:
Diffstat (limited to 'ext')
-rw-r--r--ext/node/global.rs6
-rw-r--r--ext/node/lib.rs24
-rw-r--r--ext/node/polyfills/02_init.js4
-rw-r--r--ext/node/polyfills/process.ts266
-rw-r--r--ext/node/resolution.rs7
5 files changed, 209 insertions, 98 deletions
diff --git a/ext/node/global.rs b/ext/node/global.rs
index 78e009971..52c1b6bb9 100644
--- a/ext/node/global.rs
+++ b/ext/node/global.rs
@@ -1,5 +1,6 @@
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
+use std::mem::MaybeUninit;
use std::rc::Rc;
use deno_core::v8;
@@ -266,13 +267,14 @@ fn current_mode(scope: &mut v8::HandleScope) -> Mode {
let Some(v8_string) = v8::StackTrace::current_script_name_or_source_url(scope) else {
return Mode::Deno;
};
- let string = v8_string.to_rust_string_lossy(scope);
let op_state = deno_core::JsRuntime::op_state_from(scope);
let op_state = op_state.borrow();
let Some(node_resolver) = op_state.try_borrow::<Rc<NodeResolver>>() else {
return Mode::Deno;
};
- if node_resolver.in_npm_package_with_cache(string) {
+ let mut buffer = [MaybeUninit::uninit(); 2048];
+ let str = v8_string.to_rust_cow_lossy(scope, &mut buffer);
+ if node_resolver.in_npm_package_with_cache(str) {
Mode::Node
} else {
Mode::Deno
diff --git a/ext/node/lib.rs b/ext/node/lib.rs
index e2643a84f..c7d617666 100644
--- a/ext/node/lib.rs
+++ b/ext/node/lib.rs
@@ -8,7 +8,6 @@ use std::rc::Rc;
use deno_core::error::AnyError;
use deno_core::located_script_name;
use deno_core::op;
-use deno_core::serde_json;
use deno_core::serde_v8;
use deno_core::url::Url;
#[allow(unused_imports)]
@@ -558,29 +557,6 @@ deno_core::extension!(deno_node,
},
);
-pub fn initialize_runtime(
- js_runtime: &mut JsRuntime,
- uses_local_node_modules_dir: bool,
- maybe_binary_command_name: Option<&str>,
-) -> Result<(), AnyError> {
- let argv0 = if let Some(binary_command_name) = maybe_binary_command_name {
- serde_json::to_string(binary_command_name)?
- } else {
- "undefined".to_string()
- };
- let source_code = format!(
- r#"(function loadBuiltinNodeModules(usesLocalNodeModulesDir, argv0) {{
- Deno[Deno.internal].node.initialize(
- usesLocalNodeModulesDir,
- argv0
- );
- }})({uses_local_node_modules_dir}, {argv0});"#,
- );
-
- js_runtime.execute_script(located_script_name!(), source_code.into())?;
- Ok(())
-}
-
pub fn load_cjs_module(
js_runtime: &mut JsRuntime,
module: &str,
diff --git a/ext/node/polyfills/02_init.js b/ext/node/polyfills/02_init.js
index d73d5d822..e3061c95d 100644
--- a/ext/node/polyfills/02_init.js
+++ b/ext/node/polyfills/02_init.js
@@ -7,6 +7,10 @@ const requireImpl = internals.requireImpl;
import { nodeGlobals } from "ext:deno_node/00_globals.js";
import "node:module";
+globalThis.nodeBootstrap = function (usesLocalNodeModulesDir, argv0) {
+ initialize(usesLocalNodeModulesDir, argv0);
+};
+
let initialized = false;
function initialize(
diff --git a/ext/node/polyfills/process.ts b/ext/node/polyfills/process.ts
index 4c375760d..c7c22b562 100644
--- a/ext/node/polyfills/process.ts
+++ b/ext/node/polyfills/process.ts
@@ -33,6 +33,8 @@ export { _nextTick as nextTick, chdir, cwd, env, version, versions };
import {
createWritableStdioStream,
initStdin,
+ Readable,
+ Writable,
} from "ext:deno_node/_process/streams.mjs";
import {
enableNextTick,
@@ -52,15 +54,42 @@ export let platform = "";
// TODO(kt3k): This should be set at start up time
export let pid = 0;
-// TODO(kt3k): Give better types to stdio objects
-// deno-lint-ignore no-explicit-any
-let stderr = null as any;
-// deno-lint-ignore no-explicit-any
-let stdin = null as any;
-// deno-lint-ignore no-explicit-any
-let stdout = null as any;
+// We want streams to be as lazy as possible, but we cannot export a getter in a module. To
+// work around this we make these proxies that eagerly instantiate the underlying object on
+// first access of any property/method.
+function makeLazyStream<T>(objectFactory: () => T): T {
+ return new Proxy({}, {
+ get: function (_, prop, receiver) {
+ // deno-lint-ignore no-explicit-any
+ return Reflect.get(objectFactory() as any, prop, receiver);
+ },
+ has: function (_, prop) {
+ // deno-lint-ignore no-explicit-any
+ return Reflect.has(objectFactory() as any, prop);
+ },
+ ownKeys: function (_) {
+ // deno-lint-ignore no-explicit-any
+ return Reflect.ownKeys(objectFactory() as any);
+ },
+ set: function (_, prop, value, receiver) {
+ // deno-lint-ignore no-explicit-any
+ return Reflect.set(objectFactory() as any, prop, value, receiver);
+ },
+ getPrototypeOf: function (_) {
+ // deno-lint-ignore no-explicit-any
+ return Reflect.getPrototypeOf(objectFactory() as any);
+ },
+ getOwnPropertyDescriptor(_, prop) {
+ // deno-lint-ignore no-explicit-any
+ return Reflect.getOwnPropertyDescriptor(objectFactory() as any, prop);
+ },
+ }) as T;
+}
+
+export let stderr = makeLazyStream(getStderr);
+export let stdin = makeLazyStream(getStdin);
+export let stdout = makeLazyStream(getStdout);
-export { stderr, stdin, stdout };
import { getBinding } from "ext:deno_node/internal_binding/mod.ts";
import * as constants from "ext:deno_node/internal_binding/constants.ts";
import * as uv from "ext:deno_node/internal_binding/uv.ts";
@@ -605,13 +634,19 @@ class Process extends EventEmitter {
memoryUsage = memoryUsage;
/** https://nodejs.org/api/process.html#process_process_stderr */
- stderr = stderr;
+ get stderr(): Writable {
+ return getStderr();
+ }
/** https://nodejs.org/api/process.html#process_process_stdin */
- stdin = stdin;
+ get stdin(): Readable {
+ return getStdin();
+ }
/** https://nodejs.org/api/process.html#process_process_stdout */
- stdout = stdout;
+ get stdout(): Writable {
+ return getStdout();
+ }
/** https://nodejs.org/api/process.html#process_process_version */
version = version;
@@ -704,6 +739,115 @@ addReadOnlyProcessAlias("throwDeprecation", "--throw-deprecation");
export const removeListener = process.removeListener;
export const removeAllListeners = process.removeAllListeners;
+let unhandledRejectionListenerCount = 0;
+let uncaughtExceptionListenerCount = 0;
+let beforeExitListenerCount = 0;
+let exitListenerCount = 0;
+
+process.on("newListener", (event: string) => {
+ switch (event) {
+ case "unhandledRejection":
+ unhandledRejectionListenerCount++;
+ break;
+ case "uncaughtException":
+ uncaughtExceptionListenerCount++;
+ break;
+ case "beforeExit":
+ beforeExitListenerCount++;
+ break;
+ case "exit":
+ exitListenerCount++;
+ break;
+ default:
+ return;
+ }
+ synchronizeListeners();
+});
+
+process.on("removeListener", (event: string) => {
+ switch (event) {
+ case "unhandledRejection":
+ unhandledRejectionListenerCount--;
+ break;
+ case "uncaughtException":
+ uncaughtExceptionListenerCount--;
+ break;
+ case "beforeExit":
+ beforeExitListenerCount--;
+ break;
+ case "exit":
+ exitListenerCount--;
+ break;
+ default:
+ return;
+ }
+ synchronizeListeners();
+});
+
+function processOnError(event: ErrorEvent) {
+ if (process.listenerCount("uncaughtException") > 0) {
+ event.preventDefault();
+ }
+
+ uncaughtExceptionHandler(event.error, "uncaughtException");
+}
+
+function processOnBeforeUnload(event: Event) {
+ process.emit("beforeExit", process.exitCode || 0);
+ processTicksAndRejections();
+ if (core.eventLoopHasMoreWork()) {
+ event.preventDefault();
+ }
+}
+
+function processOnUnload() {
+ if (!process._exiting) {
+ process._exiting = true;
+ process.emit("exit", process.exitCode || 0);
+ }
+}
+
+function synchronizeListeners() {
+ // Install special "unhandledrejection" handler, that will be called
+ // last.
+ if (
+ unhandledRejectionListenerCount > 0 || uncaughtExceptionListenerCount > 0
+ ) {
+ internals.nodeProcessUnhandledRejectionCallback = (event) => {
+ if (process.listenerCount("unhandledRejection") === 0) {
+ // The Node.js default behavior is to raise an uncaught exception if
+ // an unhandled rejection occurs and there are no unhandledRejection
+ // listeners.
+
+ event.preventDefault();
+ uncaughtExceptionHandler(event.reason, "unhandledRejection");
+ return;
+ }
+
+ event.preventDefault();
+ process.emit("unhandledRejection", event.reason, event.promise);
+ };
+ } else {
+ internals.nodeProcessUnhandledRejectionCallback = undefined;
+ }
+
+ if (uncaughtExceptionListenerCount > 0) {
+ globalThis.addEventListener("error", processOnError);
+ } else {
+ globalThis.removeEventListener("error", processOnError);
+ }
+ if (beforeExitListenerCount > 0) {
+ globalThis.addEventListener("beforeunload", processOnBeforeUnload);
+ } else {
+ globalThis.removeEventListener("beforeunload", processOnBeforeUnload);
+ }
+ if (exitListenerCount > 0) {
+ globalThis.addEventListener("unload", processOnUnload);
+ } else {
+ globalThis.removeEventListener("unload", processOnUnload);
+ }
+}
+
// Should be called only once, in `runtime/js/99_main.js` when the runtime is
// bootstrapped.
internals.__bootstrapNodeProcess = function (
@@ -748,68 +892,52 @@ internals.__bootstrapNodeProcess = function (
core.setMacrotaskCallback(runNextTicks);
enableNextTick();
- // Install special "unhandledrejection" handler, that will be called
- // last.
- internals.nodeProcessUnhandledRejectionCallback = (event) => {
- if (process.listenerCount("unhandledRejection") === 0) {
- // The Node.js default behavior is to raise an uncaught exception if
- // an unhandled rejection occurs and there are no unhandledRejection
- // listeners.
- if (process.listenerCount("uncaughtException") === 0) {
- throw event.reason;
- }
-
- event.preventDefault();
- uncaughtExceptionHandler(event.reason, "unhandledRejection");
- return;
- }
-
- event.preventDefault();
- process.emit("unhandledRejection", event.reason, event.promise);
- };
-
- globalThis.addEventListener("error", (event) => {
- if (process.listenerCount("uncaughtException") > 0) {
- event.preventDefault();
- }
-
- uncaughtExceptionHandler(event.error, "uncaughtException");
- });
-
- globalThis.addEventListener("beforeunload", (e) => {
- process.emit("beforeExit", process.exitCode || 0);
- processTicksAndRejections();
- if (core.eventLoopHasMoreWork()) {
- e.preventDefault();
- }
- });
-
- globalThis.addEventListener("unload", () => {
- if (!process._exiting) {
- process._exiting = true;
- process.emit("exit", process.exitCode || 0);
- }
- });
-
- // Initializes stdin
- stdin = process.stdin = initStdin();
-
- /** https://nodejs.org/api/process.html#process_process_stderr */
- stderr = process.stderr = createWritableStdioStream(
- io.stderr,
- "stderr",
- );
-
- /** https://nodejs.org/api/process.html#process_process_stdout */
- stdout = process.stdout = createWritableStdioStream(
- io.stdout,
- "stdout",
- );
-
process.setStartTime(Date.now());
// @ts-ignore Remove setStartTime and #startTime is not modifiable
delete process.setStartTime;
delete internals.__bootstrapNodeProcess;
};
+// deno-lint-ignore no-explicit-any
+let stderr_ = null as any;
+// deno-lint-ignore no-explicit-any
+let stdin_ = null as any;
+// deno-lint-ignore no-explicit-any
+let stdout_ = null as any;
+
+function getStdin(): Readable {
+ if (!stdin_) {
+ stdin_ = initStdin();
+ stdin = stdin_;
+ Object.defineProperty(process, "stdin", { get: () => stdin_ });
+ }
+ return stdin_;
+}
+
+/** https://nodejs.org/api/process.html#process_process_stdout */
+function getStdout(): Writable {
+ if (!stdout_) {
+ stdout_ = createWritableStdioStream(
+ io.stdout,
+ "stdout",
+ );
+ stdout = stdout_;
+ Object.defineProperty(process, "stdout", { get: () => stdout_ });
+ }
+ return stdout_;
+}
+
+/** https://nodejs.org/api/process.html#process_process_stderr */
+function getStderr(): Writable {
+ if (!stderr_) {
+ stderr_ = createWritableStdioStream(
+ io.stderr,
+ "stderr",
+ );
+ stderr = stderr_;
+ Object.defineProperty(process, "stderr", { get: () => stderr_ });
+ }
+ return stderr_;
+}
+
export default process;
diff --git a/ext/node/resolution.rs b/ext/node/resolution.rs
index 4c43fcbad..20501b0f1 100644
--- a/ext/node/resolution.rs
+++ b/ext/node/resolution.rs
@@ -1,5 +1,6 @@
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
+use std::borrow::Cow;
use std::collections::HashMap;
use std::path::Path;
use std::path::PathBuf;
@@ -128,10 +129,10 @@ impl NodeResolver {
self.npm_resolver.in_npm_package(specifier)
}
- pub fn in_npm_package_with_cache(&self, specifier: String) -> bool {
+ pub fn in_npm_package_with_cache(&self, specifier: Cow<str>) -> bool {
let mut cache = self.in_npm_package_cache.lock();
- if let Some(result) = cache.get(&specifier) {
+ if let Some(result) = cache.get(specifier.as_ref()) {
return *result;
}
@@ -141,7 +142,7 @@ impl NodeResolver {
} else {
false
};
- cache.insert(specifier, result);
+ cache.insert(specifier.into_owned(), result);
result
}