summaryrefslogtreecommitdiff
path: root/cli/node
diff options
context:
space:
mode:
authorBartek IwaƄczuk <biwanczuk@gmail.com>2022-08-29 20:19:54 +0200
committerGitHub <noreply@github.com>2022-08-29 20:19:54 +0200
commitb62ef4d37bc1207abb2daed5e2568eb581f07aa2 (patch)
tree0e2e188a199d1ef2b7fdced66154021eb7eca6e5 /cli/node
parenta938aaf36fde1ecf25fdbff323690c98c99a1ecc (diff)
refactor(cli): Remove cli/node dependency on cli/compat (#15654)
Diffstat (limited to 'cli/node')
-rw-r--r--cli/node/errors.rs141
-rw-r--r--cli/node/mod.rs225
2 files changed, 358 insertions, 8 deletions
diff --git a/cli/node/errors.rs b/cli/node/errors.rs
new file mode 100644
index 000000000..d7d1bbd05
--- /dev/null
+++ b/cli/node/errors.rs
@@ -0,0 +1,141 @@
+// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
+
+use deno_core::error::generic_error;
+use deno_core::error::type_error;
+use deno_core::error::AnyError;
+use deno_core::url::Url;
+
+pub fn err_invalid_module_specifier(
+ request: &str,
+ reason: &str,
+ maybe_base: Option<String>,
+) -> AnyError {
+ let mut msg = format!(
+ "[ERR_INVALID_MODULE_SPECIFIER] Invalid module \"{}\" {}",
+ request, reason
+ );
+
+ if let Some(base) = maybe_base {
+ msg = format!("{} imported from {}", msg, base);
+ }
+
+ type_error(msg)
+}
+
+pub fn err_invalid_package_config(
+ path: &str,
+ maybe_base: Option<String>,
+ maybe_message: Option<String>,
+) -> AnyError {
+ let mut msg = format!(
+ "[ERR_INVALID_PACKAGE_CONFIG] Invalid package config {}",
+ path
+ );
+
+ if let Some(base) = maybe_base {
+ msg = format!("{} while importing {}", msg, base);
+ }
+
+ if let Some(message) = maybe_message {
+ msg = format!("{}. {}", msg, message);
+ }
+
+ generic_error(msg)
+}
+
+pub fn err_module_not_found(path: &str, base: &str, typ: &str) -> AnyError {
+ generic_error(format!(
+ "[ERR_MODULE_NOT_FOUND] Cannot find {} \"{}\" imported from \"{}\"",
+ typ, path, base
+ ))
+}
+
+pub fn err_unsupported_dir_import(path: &str, base: &str) -> AnyError {
+ generic_error(format!("[ERR_UNSUPPORTED_DIR_IMPORT] Directory import '{}' is not supported resolving ES modules imported from {}", path, base))
+}
+
+pub fn err_unsupported_esm_url_scheme(url: &Url) -> AnyError {
+ let mut msg =
+ "[ERR_UNSUPPORTED_ESM_URL_SCHEME] Only file and data URLS are supported by the default ESM loader"
+ .to_string();
+
+ if cfg!(window) && url.scheme().len() == 2 {
+ msg = format!(
+ "{}. On Windows, absolute path must be valid file:// URLs",
+ msg
+ );
+ }
+
+ msg = format!("{}. Received protocol '{}'", msg, url.scheme());
+ generic_error(msg)
+}
+
+pub fn err_invalid_package_target(
+ pkg_path: String,
+ key: String,
+ target: String,
+ is_import: bool,
+ maybe_base: Option<String>,
+) -> AnyError {
+ let rel_error = !is_import && !target.is_empty() && !target.starts_with("./");
+ let mut msg = "[ERR_INVALID_PACKAGE_TARGET]".to_string();
+
+ if key == "." {
+ assert!(!is_import);
+ msg = format!("{} Invalid \"exports\" main target {} defined in the package config {}package.json", msg, target, pkg_path)
+ } else {
+ let ie = if is_import { "imports" } else { "exports" };
+ msg = format!("{} Invalid \"{}\" target {} defined for '{}' in the package config {}package.json", msg, ie, target, key, pkg_path)
+ };
+
+ if let Some(base) = maybe_base {
+ msg = format!("{} imported from {}", msg, base);
+ };
+ if rel_error {
+ msg = format!("{}; target must start with \"./\"", msg);
+ }
+
+ generic_error(msg)
+}
+
+pub fn err_package_path_not_exported(
+ pkg_path: String,
+ subpath: String,
+ maybe_base: Option<String>,
+) -> AnyError {
+ let mut msg = "[ERR_PACKAGE_PATH_NOT_EXPORTED]".to_string();
+
+ if subpath == "." {
+ msg = format!(
+ "{} No \"exports\" main defined in {}package.json",
+ msg, pkg_path
+ );
+ } else {
+ msg = format!("{} Package subpath \'{}\' is not defined by \"exports\" in {}package.json", msg, subpath, pkg_path);
+ };
+
+ if let Some(base) = maybe_base {
+ msg = format!("{} imported from {}", msg, base);
+ }
+
+ generic_error(msg)
+}
+
+pub fn err_package_import_not_defined(
+ specifier: &str,
+ package_path: Option<String>,
+ base: &str,
+) -> AnyError {
+ let mut msg = format!(
+ "[ERR_PACKAGE_IMPORT_NOT_DEFINED] Package import specifier \"{}\" is not defined in",
+ specifier
+ );
+
+ if let Some(package_path) = package_path {
+ msg = format!("{} in package {}package.json", msg, package_path);
+ }
+
+ msg = format!("{} imported from {}", msg, base);
+
+ type_error(msg)
+}
diff --git a/cli/node/mod.rs b/cli/node/mod.rs
index c19179d0c..71046b4b7 100644
--- a/cli/node/mod.rs
+++ b/cli/node/mod.rs
@@ -4,6 +4,7 @@ use std::collections::HashSet;
use std::path::Path;
use std::path::PathBuf;
+use crate::deno_std::CURRENT_STD_URL;
use deno_ast::MediaType;
use deno_ast::ModuleSpecifier;
use deno_core::anyhow::bail;
@@ -27,7 +28,6 @@ use once_cell::sync::Lazy;
use path_clean::PathClean;
use regex::Regex;
-use crate::compat;
use crate::file_fetcher::FileFetcher;
use crate::npm::GlobalNpmPackageResolver;
use crate::npm::NpmPackageReference;
@@ -35,9 +35,218 @@ use crate::npm::NpmPackageReq;
use crate::npm::NpmPackageResolver;
mod analyze;
+pub mod errors;
pub use analyze::esm_code_with_node_globals;
+pub struct NodeModulePolyfill {
+ /// Name of the module like "assert" or "timers/promises"
+ pub name: &'static str,
+
+ /// Specifier relative to the root of `deno_std` repo, like "node/asser.ts"
+ pub specifier: &'static str,
+}
+
+pub(crate) static SUPPORTED_MODULES: &[NodeModulePolyfill] = &[
+ NodeModulePolyfill {
+ name: "assert",
+ specifier: "node/assert.ts",
+ },
+ NodeModulePolyfill {
+ name: "assert/strict",
+ specifier: "node/assert/strict.ts",
+ },
+ NodeModulePolyfill {
+ name: "async_hooks",
+ specifier: "node/async_hooks.ts",
+ },
+ NodeModulePolyfill {
+ name: "buffer",
+ specifier: "node/buffer.ts",
+ },
+ NodeModulePolyfill {
+ name: "child_process",
+ specifier: "node/child_process.ts",
+ },
+ NodeModulePolyfill {
+ name: "cluster",
+ specifier: "node/cluster.ts",
+ },
+ NodeModulePolyfill {
+ name: "console",
+ specifier: "node/console.ts",
+ },
+ NodeModulePolyfill {
+ name: "constants",
+ specifier: "node/constants.ts",
+ },
+ NodeModulePolyfill {
+ name: "crypto",
+ specifier: "node/crypto.ts",
+ },
+ NodeModulePolyfill {
+ name: "dgram",
+ specifier: "node/dgram.ts",
+ },
+ NodeModulePolyfill {
+ name: "dns",
+ specifier: "node/dns.ts",
+ },
+ NodeModulePolyfill {
+ name: "domain",
+ specifier: "node/domain.ts",
+ },
+ NodeModulePolyfill {
+ name: "events",
+ specifier: "node/events.ts",
+ },
+ NodeModulePolyfill {
+ name: "fs",
+ specifier: "node/fs.ts",
+ },
+ NodeModulePolyfill {
+ name: "fs/promises",
+ specifier: "node/fs/promises.ts",
+ },
+ NodeModulePolyfill {
+ name: "http",
+ specifier: "node/http.ts",
+ },
+ NodeModulePolyfill {
+ name: "https",
+ specifier: "node/https.ts",
+ },
+ NodeModulePolyfill {
+ name: "module",
+ specifier: "node/module.ts",
+ },
+ NodeModulePolyfill {
+ name: "net",
+ specifier: "node/net.ts",
+ },
+ NodeModulePolyfill {
+ name: "os",
+ specifier: "node/os.ts",
+ },
+ NodeModulePolyfill {
+ name: "path",
+ specifier: "node/path.ts",
+ },
+ NodeModulePolyfill {
+ name: "path/posix",
+ specifier: "node/path/posix.ts",
+ },
+ NodeModulePolyfill {
+ name: "path/win32",
+ specifier: "node/path/win32.ts",
+ },
+ NodeModulePolyfill {
+ name: "perf_hooks",
+ specifier: "node/perf_hooks.ts",
+ },
+ NodeModulePolyfill {
+ name: "process",
+ specifier: "node/process.ts",
+ },
+ NodeModulePolyfill {
+ name: "querystring",
+ specifier: "node/querystring.ts",
+ },
+ NodeModulePolyfill {
+ name: "readline",
+ specifier: "node/readline.ts",
+ },
+ NodeModulePolyfill {
+ name: "stream",
+ specifier: "node/stream.ts",
+ },
+ NodeModulePolyfill {
+ name: "stream/promises",
+ specifier: "node/stream/promises.mjs",
+ },
+ NodeModulePolyfill {
+ name: "stream/web",
+ specifier: "node/stream/web.ts",
+ },
+ NodeModulePolyfill {
+ name: "string_decoder",
+ specifier: "node/string_decoder.ts",
+ },
+ NodeModulePolyfill {
+ name: "sys",
+ specifier: "node/sys.ts",
+ },
+ NodeModulePolyfill {
+ name: "timers",
+ specifier: "node/timers.ts",
+ },
+ NodeModulePolyfill {
+ name: "timers/promises",
+ specifier: "node/timers/promises.ts",
+ },
+ NodeModulePolyfill {
+ name: "tls",
+ specifier: "node/tls.ts",
+ },
+ NodeModulePolyfill {
+ name: "tty",
+ specifier: "node/tty.ts",
+ },
+ NodeModulePolyfill {
+ name: "url",
+ specifier: "node/url.ts",
+ },
+ NodeModulePolyfill {
+ name: "util",
+ specifier: "node/util.ts",
+ },
+ NodeModulePolyfill {
+ name: "util/types",
+ specifier: "node/util/types.ts",
+ },
+ NodeModulePolyfill {
+ name: "v8",
+ specifier: "node/v8.ts",
+ },
+ NodeModulePolyfill {
+ name: "vm",
+ specifier: "node/vm.ts",
+ },
+ NodeModulePolyfill {
+ name: "worker_threads",
+ specifier: "node/worker_threads.ts",
+ },
+ NodeModulePolyfill {
+ name: "zlib",
+ specifier: "node/zlib.ts",
+ },
+];
+
+pub(crate) static NODE_COMPAT_URL: Lazy<Url> = Lazy::new(|| {
+ if let Ok(url_str) = std::env::var("DENO_NODE_COMPAT_URL") {
+ let url = Url::parse(&url_str).expect(
+ "Malformed DENO_NODE_COMPAT_URL value, make sure it's a file URL ending with a slash"
+ );
+ return url;
+ }
+
+ CURRENT_STD_URL.clone()
+});
+
+pub static MODULE_ALL_URL: Lazy<Url> =
+ Lazy::new(|| NODE_COMPAT_URL.join("node/module_all.ts").unwrap());
+
+pub fn try_resolve_builtin_module(specifier: &str) -> Option<Url> {
+ for module in SUPPORTED_MODULES {
+ if module.name == specifier {
+ let module_url = NODE_COMPAT_URL.join(module.specifier).unwrap();
+ return Some(module_url);
+ }
+ }
+
+ None
+}
+
static RESERVED_WORDS: Lazy<HashSet<&str>> = Lazy::new(|| {
HashSet::from([
"break",
@@ -96,7 +305,7 @@ pub async fn initialize_runtime(
const moduleAll = await import(moduleAllUrl);
Deno[Deno.internal].node.initialize(moduleAll.default);
}})('{}');"#,
- compat::MODULE_ALL_URL.as_str(),
+ MODULE_ALL_URL.as_str(),
);
let value =
@@ -142,7 +351,7 @@ pub fn node_resolve(
Url::parse("node:module").unwrap(),
)));
}
- if let Some(resolved) = compat::try_resolve_builtin_module(specifier) {
+ if let Some(resolved) = try_resolve_builtin_module(specifier) {
return Ok(Some(ResolveResponse::Esm(resolved)));
}
@@ -165,7 +374,7 @@ pub fn node_resolve(
)));
}
- if let Some(resolved) = compat::try_resolve_builtin_module(&specifier) {
+ if let Some(resolved) = try_resolve_builtin_module(&specifier) {
return Ok(Some(ResolveResponse::Esm(resolved)));
} else {
return Err(generic_error(format!("Unknown module {}", specifier)));
@@ -173,7 +382,7 @@ pub fn node_resolve(
}
if protocol != "file" && protocol != "data" {
- return Err(compat::errors::err_unsupported_esm_url_scheme(&url));
+ return Err(errors::err_unsupported_esm_url_scheme(&url));
}
// todo(THIS PR): I think this is handled upstream so can be removed?
@@ -410,7 +619,7 @@ fn finalize_resolution(
let encoded_sep_re = Regex::new(r"%2F|%2C").unwrap();
if encoded_sep_re.is_match(resolved.path()) {
- return Err(compat::errors::err_invalid_module_specifier(
+ return Err(errors::err_invalid_module_specifier(
resolved.path(),
"must not include encoded \"/\" or \"\\\\\" characters",
Some(to_file_path_string(base)),
@@ -437,12 +646,12 @@ fn finalize_resolution(
(false, false)
};
if is_dir {
- return Err(compat::errors::err_unsupported_dir_import(
+ return Err(errors::err_unsupported_dir_import(
resolved.as_str(),
base.as_str(),
));
} else if !is_file {
- return Err(compat::errors::err_module_not_found(
+ return Err(errors::err_module_not_found(
resolved.as_str(),
base.as_str(),
"module",