From a615eb3b56545960ec9684991442dd34a8b2abfc Mon Sep 17 00:00:00 2001 From: David Sherret Date: Fri, 21 Apr 2023 21:02:46 -0400 Subject: [PATCH] refactor(node): move most of cli/node to ext/node (#18797) This is just a straight refactor and I didn't do any cleanup in ext/node. After this PR we can start to clean it up and make things private that don't need to be public anymore. --- Cargo.lock | 3 + Cargo.toml | 3 + cli/Cargo.toml | 4 +- cli/graph_util.rs | 9 +- cli/lsp/diagnostics.rs | 8 +- cli/lsp/documents.rs | 10 +- cli/lsp/language_server.rs | 22 ++- cli/module_loader.rs | 26 ++-- cli/{node/analyze.rs => node.rs} | 28 ++++ cli/npm/mod.rs | 3 +- cli/npm/resolution.rs | 2 +- cli/npm/resolvers/mod.rs | 91 +++++------- cli/ops/mod.rs | 8 +- cli/proc_state.rs | 17 +-- cli/tools/check.rs | 6 +- cli/tools/info.rs | 10 +- cli/tools/task.rs | 8 +- cli/tsc/mod.rs | 16 +- cli/worker.rs | 23 +-- ext/node/Cargo.toml | 3 + ext/node/analyze.rs | 16 +- ext/node/lib.rs | 107 +++++++++++++- ext/node/ops.rs | 26 ++-- ext/node/package_json.rs | 4 +- ext/node/polyfill.rs | 20 ++- ext/node/resolution.rs | 20 +-- cli/node/mod.rs => ext/node/resolver.rs | 185 +++++++++--------------- runtime/web_worker.rs | 4 +- runtime/worker.rs | 4 +- 29 files changed, 387 insertions(+), 299 deletions(-) rename cli/{node/analyze.rs => node.rs} (82%) rename cli/node/mod.rs => ext/node/resolver.rs (77%) diff --git a/Cargo.lock b/Cargo.lock index 3edd36c28c..ceeb2cf2a0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1132,6 +1132,9 @@ dependencies = [ "cbc", "data-encoding", "deno_core", + "deno_media_type", + "deno_npm", + "deno_semver", "digest 0.10.6", "dsa", "ecb", diff --git a/Cargo.toml b/Cargo.toml index 45f355cdfe..6b49de2311 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -52,6 +52,9 @@ napi_sym = { version = "0.29.0", path = "./cli/napi/sym" } deno_bench_util = { version = "0.93.0", path = "./bench_util" } test_util = { path = "./test_util" } deno_lockfile = "0.13.0" +deno_media_type = { version = "0.1.0", features = ["module_specifier"] } +deno_npm = "0.3.0" +deno_semver = "0.2.1" # exts deno_broadcast_channel = { version = "0.93.0", path = "./ext/broadcast_channel" } diff --git a/cli/Cargo.toml b/cli/Cargo.toml index 64ce5fce7c..96fe458ae2 100644 --- a/cli/Cargo.toml +++ b/cli/Cargo.toml @@ -47,9 +47,9 @@ deno_emit = "0.20.0" deno_graph = "=0.48.0" deno_lint = { version = "0.44.0", features = ["docs"] } deno_lockfile.workspace = true -deno_npm = "0.3.0" +deno_npm.workspace = true deno_runtime = { workspace = true, features = ["dont_create_runtime_snapshot", "include_js_files_for_snapshotting"] } -deno_semver = "0.2.1" +deno_semver.workspace = true deno_task_shell = "0.11.0" napi_sym.workspace = true diff --git a/cli/graph_util.rs b/cli/graph_util.rs index dacd3be174..d5bc6ac0d5 100644 --- a/cli/graph_util.rs +++ b/cli/graph_util.rs @@ -9,7 +9,7 @@ use crate::cache::ParsedSourceCache; use crate::colors; use crate::errors::get_error_class_name; use crate::file_fetcher::FileFetcher; -use crate::npm::NpmPackageResolver; +use crate::npm::CliNpmResolver; use crate::resolver::CliGraphResolver; use crate::tools::check; use crate::tools::check::TypeChecker; @@ -29,6 +29,7 @@ use deno_graph::ModuleGraph; use deno_graph::ModuleGraphError; use deno_graph::ResolutionError; use deno_graph::SpecifierError; +use deno_runtime::deno_node; use deno_runtime::permissions::PermissionsContainer; use import_map::ImportMapError; use std::collections::HashMap; @@ -165,7 +166,7 @@ pub fn graph_lock_or_exit(graph: &ModuleGraph, lockfile: &mut Lockfile) { pub struct ModuleGraphBuilder { options: Arc, resolver: Arc, - npm_resolver: Arc, + npm_resolver: Arc, parsed_source_cache: Arc, lockfile: Option>>, emit_cache: cache::EmitCache, @@ -178,7 +179,7 @@ impl ModuleGraphBuilder { pub fn new( options: Arc, resolver: Arc, - npm_resolver: Arc, + npm_resolver: Arc, parsed_source_cache: Arc, lockfile: Option>>, emit_cache: cache::EmitCache, @@ -377,7 +378,7 @@ pub fn get_resolution_error_bare_node_specifier( error: &ResolutionError, ) -> Option<&str> { get_resolution_error_bare_specifier(error).filter(|specifier| { - crate::node::resolve_builtin_node_module(specifier).is_ok() + deno_node::resolve_builtin_node_module(specifier).is_ok() }) } diff --git a/cli/lsp/diagnostics.rs b/cli/lsp/diagnostics.rs index 8c2126561b..965075a2d7 100644 --- a/cli/lsp/diagnostics.rs +++ b/cli/lsp/diagnostics.rs @@ -16,7 +16,6 @@ use super::tsc::TsServer; use crate::args::LintOptions; use crate::graph_util; use crate::graph_util::enhanced_resolution_error_message; -use crate::node; use crate::tools::lint::get_configured_rules; use deno_ast::MediaType; @@ -31,6 +30,7 @@ use deno_graph::Resolution; use deno_graph::ResolutionError; use deno_graph::SpecifierError; use deno_lint::rules::LintRule; +use deno_runtime::deno_node; use deno_runtime::tokio_util::create_basic_runtime; use deno_semver::npm::NpmPackageReqReference; use log::error; @@ -469,8 +469,8 @@ async fn generate_lint_diagnostics( } // ignore any npm package files - if let Some(npm_resolver) = &snapshot.maybe_npm_resolver { - if npm_resolver.in_npm_package(document.specifier()) { + if let Some(node_resolver) = &snapshot.maybe_node_resolver { + if node_resolver.in_npm_package(document.specifier()) { continue; } } @@ -926,7 +926,7 @@ fn diagnose_resolution( } } else if let Some(module_name) = specifier.as_str().strip_prefix("node:") { - if node::resolve_builtin_node_module(module_name).is_err() { + if deno_node::resolve_builtin_node_module(module_name).is_err() { diagnostics.push( DenoDiagnostic::InvalidNodeSpecifier(specifier.clone()) .to_lsp_diagnostic(&range), diff --git a/cli/lsp/documents.rs b/cli/lsp/documents.rs index 7b206406c1..fd40bb95f2 100644 --- a/cli/lsp/documents.rs +++ b/cli/lsp/documents.rs @@ -18,7 +18,6 @@ use crate::file_fetcher::map_content_type; use crate::file_fetcher::SUPPORTED_SCHEMES; use crate::lsp::logging::lsp_warn; use crate::node::CliNodeResolver; -use crate::node::NodeResolution; use crate::npm::CliNpmRegistryApi; use crate::npm::NpmResolution; use crate::npm::PackageJsonDepsInstaller; @@ -37,8 +36,11 @@ use deno_core::url; use deno_core::ModuleSpecifier; use deno_graph::GraphImport; use deno_graph::Resolution; +use deno_runtime::deno_node; +use deno_runtime::deno_node::NodeResolution; use deno_runtime::deno_node::NodeResolutionMode; use deno_runtime::deno_node::PackageJson; +use deno_runtime::deno_node::RealFs; use deno_runtime::permissions::PermissionsContainer; use deno_semver::npm::NpmPackageReq; use deno_semver::npm::NpmPackageReqReference; @@ -1069,7 +1071,7 @@ impl Documents { // we're in an npm package, so use node resolution results.push(Some(NodeResolution::into_specifier_and_media_type( node_resolver - .resolve( + .resolve::( &specifier, referrer, NodeResolutionMode::Types, @@ -1082,7 +1084,7 @@ impl Documents { } } if let Some(module_name) = specifier.strip_prefix("node:") { - if crate::node::resolve_builtin_node_module(module_name).is_ok() { + if deno_node::resolve_builtin_node_module(module_name).is_ok() { // return itself for node: specifiers because during type checking // we resolve to the ambient modules in the @types/node package // rather than deno_std/node @@ -1457,7 +1459,7 @@ fn node_resolve_npm_req_ref( maybe_node_resolver.map(|node_resolver| { NodeResolution::into_specifier_and_media_type( node_resolver - .resolve_npm_req_reference( + .resolve_npm_req_reference::( &npm_req_ref, NodeResolutionMode::Types, &mut PermissionsContainer::allow_all(), diff --git a/cli/lsp/language_server.rs b/cli/lsp/language_server.rs index 239ff8a6ef..f1b9cb4347 100644 --- a/cli/lsp/language_server.rs +++ b/cli/lsp/language_server.rs @@ -9,6 +9,7 @@ use deno_core::serde_json; use deno_core::serde_json::json; use deno_core::serde_json::Value; use deno_core::ModuleSpecifier; +use deno_runtime::deno_node::NodeResolver; use deno_runtime::deno_node::PackageJson; use deno_runtime::deno_web::BlobStore; use import_map::ImportMap; @@ -81,8 +82,8 @@ use crate::lsp::urls::LspUrlKind; use crate::node::CliNodeResolver; use crate::npm::create_npm_fs_resolver; use crate::npm::CliNpmRegistryApi; +use crate::npm::CliNpmResolver; use crate::npm::NpmCache; -use crate::npm::NpmPackageResolver; use crate::npm::NpmResolution; use crate::proc_state::ProcState; use crate::tools::fmt::format_file; @@ -103,7 +104,7 @@ pub struct StateSnapshot { pub documents: Documents, pub maybe_import_map: Option>, pub maybe_node_resolver: Option>, - pub maybe_npm_resolver: Option>, + pub maybe_npm_resolver: Option>, } #[derive(Debug)] @@ -153,7 +154,7 @@ pub struct Inner { /// Npm resolution that is stored in memory. npm_resolution: Arc, /// Resolver for npm packages. - npm_resolver: Arc, + npm_resolver: Arc, /// A collection of measurements which instrument that performance of the LSP. performance: Arc, /// A memoized version of fixable diagnostic codes retrieved from TypeScript. @@ -424,7 +425,7 @@ fn create_lsp_structs( ) -> ( Arc, Arc, - Arc, + Arc, Arc, ) { let registry_url = CliNpmRegistryApi::default_url(); @@ -457,11 +458,7 @@ fn create_lsp_structs( ( api, npm_cache, - Arc::new(NpmPackageResolver::new( - resolution.clone(), - fs_resolver, - None, - )), + Arc::new(CliNpmResolver::new(resolution.clone(), fs_resolver, None)), resolution, ) } @@ -703,19 +700,18 @@ impl Inner { self.npm_resolution.snapshot(), None, )); - let npm_resolver = Arc::new(NpmPackageResolver::new( + let npm_resolver = Arc::new(CliNpmResolver::new( npm_resolution.clone(), create_npm_fs_resolver( self.npm_cache.clone(), &ProgressBar::new(ProgressBarStyle::TextOnly), self.npm_api.base_url().clone(), - npm_resolution.clone(), + npm_resolution, None, ), None, )); - let node_resolver = - Arc::new(CliNodeResolver::new(npm_resolution, npm_resolver.clone())); + let node_resolver = Arc::new(NodeResolver::new(npm_resolver.clone())); Arc::new(StateSnapshot { assets: self.assets.snapshot(), cache_metadata: self.cache_metadata.clone(), diff --git a/cli/module_loader.rs b/cli/module_loader.rs index 07fad6ffc6..c4ef0ed7e9 100644 --- a/cli/module_loader.rs +++ b/cli/module_loader.rs @@ -11,10 +11,8 @@ use crate::graph_util::graph_valid_with_cli_options; use crate::graph_util::ModuleGraphBuilder; use crate::graph_util::ModuleGraphContainer; use crate::node; -use crate::node::CliCjsEsmCodeAnalyzer; +use crate::node::CliNodeCodeTranslator; use crate::node::CliNodeResolver; -use crate::node::NodeResolution; -use crate::npm::CliRequireNpmResolver; use crate::proc_state::CjsResolutionStore; use crate::proc_state::FileWatcherReporter; use crate::proc_state::ProcState; @@ -50,7 +48,8 @@ use deno_graph::JsonModule; use deno_graph::Module; use deno_graph::Resolution; use deno_lockfile::Lockfile; -use deno_runtime::deno_node::analyze::NodeCodeTranslator; +use deno_runtime::deno_node; +use deno_runtime::deno_node::NodeResolution; use deno_runtime::deno_node::NodeResolutionMode; use deno_runtime::deno_node::RealFs; use deno_runtime::permissions::PermissionsContainer; @@ -244,8 +243,7 @@ pub struct CliModuleLoader { emitter: Arc, graph_container: Arc, module_load_preparer: Arc, - node_code_translator: - Arc>, + node_code_translator: Arc, node_resolver: Arc, parsed_source_cache: Arc, resolver: Arc, @@ -430,7 +428,7 @@ impl CliModuleLoader { fn handle_node_resolve_result( &self, - result: Result, AnyError>, + result: Result, AnyError>, ) -> Result { let response = match result? { Some(response) => response, @@ -440,7 +438,7 @@ impl CliModuleLoader { // remember that this was a common js resolution self.cjs_resolutions.insert(specifier.clone()); } else if let NodeResolution::BuiltIn(specifier) = &response { - return node::resolve_builtin_node_module(specifier); + return deno_node::resolve_builtin_node_module(specifier); } Ok(response.into_url()) } @@ -468,7 +466,7 @@ impl ModuleLoader for CliModuleLoader { if self.node_resolver.in_npm_package(referrer) { // we're in an npm package, so use node resolution return self - .handle_node_resolve_result(self.node_resolver.resolve( + .handle_node_resolve_result(self.node_resolver.resolve::( specifier, referrer, NodeResolutionMode::Execution, @@ -494,7 +492,7 @@ impl ModuleLoader for CliModuleLoader { return match graph.get(specifier) { Some(Module::Npm(module)) => self .handle_node_resolve_result( - self.node_resolver.resolve_npm_reference( + self.node_resolver.resolve_npm_reference::( &module.nv_reference, NodeResolutionMode::Execution, &mut permissions, @@ -504,7 +502,7 @@ impl ModuleLoader for CliModuleLoader { format!("Could not resolve '{}'.", module.nv_reference) }), Some(Module::Node(module)) => { - node::resolve_builtin_node_module(&module.module_name) + deno_node::resolve_builtin_node_module(&module.module_name) } Some(Module::Esm(module)) => Ok(module.specifier.clone()), Some(Module::Json(module)) => Ok(module.specifier.clone()), @@ -526,7 +524,7 @@ impl ModuleLoader for CliModuleLoader { // Built-in Node modules if let Some(module_name) = specifier.strip_prefix("node:") { - return node::resolve_builtin_node_module(module_name); + return deno_node::resolve_builtin_node_module(module_name); } // FIXME(bartlomieju): this is a hacky way to provide compatibility with REPL @@ -556,9 +554,9 @@ impl ModuleLoader for CliModuleLoader { { return self .handle_node_resolve_result( - self.node_resolver.resolve_npm_req_reference( + self.node_resolver.resolve_npm_req_reference::( &reference, - deno_runtime::deno_node::NodeResolutionMode::Execution, + NodeResolutionMode::Execution, &mut permissions, ), ) diff --git a/cli/node/analyze.rs b/cli/node.rs similarity index 82% rename from cli/node/analyze.rs rename to cli/node.rs index 27818639ef..3ec9500e88 100644 --- a/cli/node/analyze.rs +++ b/cli/node.rs @@ -1,6 +1,7 @@ // Copyright 2018-2023 the Deno authors. All rights reserved. MIT license. use std::collections::HashSet; +use std::sync::Arc; use deno_ast::swc::common::SyntaxContext; use deno_ast::view::Node; @@ -13,8 +14,35 @@ use deno_ast::SourceRanged; use deno_core::error::AnyError; use deno_runtime::deno_node::analyze::CjsAnalysis as ExtNodeCjsAnalysis; use deno_runtime::deno_node::analyze::CjsEsmCodeAnalyzer; +use deno_runtime::deno_node::analyze::NodeCodeTranslator; +use deno_runtime::deno_node::NodeResolver; use crate::cache::NodeAnalysisCache; +use crate::npm::CliNpmResolver; +use crate::util::fs::canonicalize_path_maybe_not_exists; + +pub type CliNodeCodeTranslator = + NodeCodeTranslator>; +pub type CliNodeResolver = NodeResolver>; + +/// Resolves a specifier that is pointing into a node_modules folder. +/// +/// Note: This should be called whenever getting the specifier from +/// a Module::External(module) reference because that module might +/// not be fully resolved at the time deno_graph is analyzing it +/// because the node_modules folder might not exist at that time. +pub fn resolve_specifier_into_node_modules( + specifier: &ModuleSpecifier, +) -> ModuleSpecifier { + specifier + .to_file_path() + .ok() + // this path might not exist at the time the graph is being created + // because the node_modules folder might not yet exist + .and_then(|path| canonicalize_path_maybe_not_exists(&path).ok()) + .and_then(|path| ModuleSpecifier::from_file_path(path).ok()) + .unwrap_or_else(|| specifier.clone()) +} pub struct CliCjsEsmCodeAnalyzer { cache: NodeAnalysisCache, diff --git a/cli/npm/mod.rs b/cli/npm/mod.rs index 8f6ac77bc6..488f8eae6a 100644 --- a/cli/npm/mod.rs +++ b/cli/npm/mod.rs @@ -13,6 +13,5 @@ pub use installer::PackageJsonDepsInstaller; pub use registry::CliNpmRegistryApi; pub use resolution::NpmResolution; pub use resolvers::create_npm_fs_resolver; -pub use resolvers::CliRequireNpmResolver; -pub use resolvers::NpmPackageResolver; +pub use resolvers::CliNpmResolver; pub use resolvers::NpmProcessState; diff --git a/cli/npm/resolution.rs b/cli/npm/resolution.rs index 26fc356ffb..1b191b2455 100644 --- a/cli/npm/resolution.rs +++ b/cli/npm/resolution.rs @@ -154,7 +154,7 @@ impl NpmResolution { Ok(()) } - pub fn pkg_req_ref_to_nv_ref( + pub fn resolve_nv_ref_from_pkg_req_ref( &self, req_ref: &NpmPackageReqReference, ) -> Result { diff --git a/cli/npm/resolvers/mod.rs b/cli/npm/resolvers/mod.rs index f693d3d23a..8b871beaf7 100644 --- a/cli/npm/resolvers/mod.rs +++ b/cli/npm/resolvers/mod.rs @@ -20,10 +20,12 @@ use deno_npm::resolution::SerializedNpmResolutionSnapshot; use deno_npm::NpmPackageId; use deno_runtime::deno_node::NodePermissions; use deno_runtime::deno_node::NodeResolutionMode; +use deno_runtime::deno_node::NpmResolver; use deno_runtime::deno_node::PathClean; -use deno_runtime::deno_node::RequireNpmResolver; use deno_semver::npm::NpmPackageNv; +use deno_semver::npm::NpmPackageNvReference; use deno_semver::npm::NpmPackageReq; +use deno_semver::npm::NpmPackageReqReference; use global::GlobalNpmPackageResolver; use serde::Deserialize; use serde::Serialize; @@ -45,13 +47,13 @@ pub struct NpmProcessState { } /// Brings together the npm resolution with the file system. -pub struct NpmPackageResolver { +pub struct CliNpmResolver { fs_resolver: Arc, resolution: Arc, maybe_lockfile: Option>>, } -impl std::fmt::Debug for NpmPackageResolver { +impl std::fmt::Debug for CliNpmResolver { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_struct("NpmPackageResolver") .field("fs_resolver", &"") @@ -61,7 +63,7 @@ impl std::fmt::Debug for NpmPackageResolver { } } -impl NpmPackageResolver { +impl CliNpmResolver { pub fn new( resolution: Arc, fs_resolver: Arc, @@ -85,15 +87,6 @@ impl NpmPackageResolver { self.resolution.resolve_pkg_id_from_pkg_req(req) } - /// Resolves an npm package folder path from a Deno module. - pub fn resolve_package_folder_from_deno_module( - &self, - pkg_nv: &NpmPackageNv, - ) -> Result { - let pkg_id = self.resolution.resolve_pkg_id_from_deno_module(pkg_nv)?; - self.resolve_pkg_folder_from_deno_module_at_pkg_id(&pkg_id) - } - fn resolve_pkg_folder_from_deno_module_at_pkg_id( &self, pkg_id: &NpmPackageId, @@ -108,20 +101,6 @@ impl NpmPackageResolver { Ok(path) } - /// Resolves an npm package folder path from an npm package referrer. - pub fn resolve_package_folder_from_package( - &self, - name: &str, - referrer: &ModuleSpecifier, - mode: NodeResolutionMode, - ) -> Result { - let path = self - .fs_resolver - .resolve_package_folder_from_package(name, referrer, mode)?; - log::debug!("Resolved {} from {} to {}", name, referrer, path.display()); - Ok(path) - } - /// Resolve the root folder of the package the provided specifier is in. /// /// This will error when the provided specifier is not in an npm package. @@ -228,26 +207,20 @@ impl NpmPackageResolver { self.fs_resolver.cache_packages().await?; Ok(()) } - - pub fn as_require_npm_resolver(self: &Arc) -> CliRequireNpmResolver { - CliRequireNpmResolver(self.clone()) - } } -#[derive(Debug)] -pub struct CliRequireNpmResolver(Arc); - -impl RequireNpmResolver for CliRequireNpmResolver { +impl NpmResolver for CliNpmResolver { fn resolve_package_folder_from_package( &self, - specifier: &str, - referrer: &std::path::Path, + name: &str, + referrer: &ModuleSpecifier, mode: NodeResolutionMode, ) -> Result { - let referrer = path_to_specifier(referrer)?; - self - .0 - .resolve_package_folder_from_package(specifier, &referrer, mode) + let path = self + .fs_resolver + .resolve_package_folder_from_package(name, referrer, mode)?; + log::debug!("Resolved {} from {} to {}", name, referrer, path.display()); + Ok(path) } fn resolve_package_folder_from_path( @@ -255,18 +228,34 @@ impl RequireNpmResolver for CliRequireNpmResolver { path: &Path, ) -> Result { let specifier = path_to_specifier(path)?; - self.0.resolve_package_folder_from_specifier(&specifier) + self.resolve_package_folder_from_specifier(&specifier) } - fn in_npm_package(&self, path: &Path) -> bool { - let specifier = - match ModuleSpecifier::from_file_path(path.to_path_buf().clean()) { - Ok(p) => p, - Err(_) => return false, - }; + fn resolve_package_folder_from_deno_module( + &self, + pkg_nv: &NpmPackageNv, + ) -> Result { + let pkg_id = self.resolution.resolve_pkg_id_from_deno_module(pkg_nv)?; + self.resolve_pkg_folder_from_deno_module_at_pkg_id(&pkg_id) + } + + fn resolve_pkg_id_from_pkg_req( + &self, + req: &NpmPackageReq, + ) -> Result { + self.resolution.resolve_pkg_id_from_pkg_req(req) + } + + fn resolve_nv_ref_from_pkg_req_ref( + &self, + req_ref: &NpmPackageReqReference, + ) -> Result { + self.resolution.resolve_nv_ref_from_pkg_req_ref(req_ref) + } + + fn in_npm_package(&self, specifier: &ModuleSpecifier) -> bool { self - .0 - .resolve_package_folder_from_specifier(&specifier) + .resolve_package_folder_from_specifier(specifier) .is_ok() } @@ -275,7 +264,7 @@ impl RequireNpmResolver for CliRequireNpmResolver { permissions: &mut dyn NodePermissions, path: &Path, ) -> Result<(), AnyError> { - self.0.fs_resolver.ensure_read_permission(permissions, path) + self.fs_resolver.ensure_read_permission(permissions, path) } } diff --git a/cli/ops/mod.rs b/cli/ops/mod.rs index 9adc944cee..d39f19270a 100644 --- a/cli/ops/mod.rs +++ b/cli/ops/mod.rs @@ -2,7 +2,7 @@ use std::sync::Arc; -use crate::npm::NpmPackageResolver; +use crate::npm::CliNpmResolver; use deno_core::error::AnyError; use deno_core::op; use deno_core::Extension; @@ -11,14 +11,14 @@ use deno_core::OpState; pub mod bench; pub mod testing; -pub fn cli_exts(npm_resolver: Arc) -> Vec { +pub fn cli_exts(npm_resolver: Arc) -> Vec { vec![deno_cli::init_ops(npm_resolver)] } deno_core::extension!(deno_cli, ops = [op_npm_process_state], options = { - npm_resolver: Arc, + npm_resolver: Arc, }, state = |state, options| { state.put(options.npm_resolver); @@ -30,6 +30,6 @@ deno_core::extension!(deno_cli, #[op] fn op_npm_process_state(state: &mut OpState) -> Result { - let npm_resolver = state.borrow_mut::>(); + let npm_resolver = state.borrow_mut::>(); Ok(npm_resolver.get_npm_process_state()) } diff --git a/cli/proc_state.rs b/cli/proc_state.rs index bfe45bc861..6b7e9b1f28 100644 --- a/cli/proc_state.rs +++ b/cli/proc_state.rs @@ -18,12 +18,12 @@ use crate::graph_util::ModuleGraphContainer; use crate::http_util::HttpClient; use crate::module_loader::ModuleLoadPreparer; use crate::node::CliCjsEsmCodeAnalyzer; +use crate::node::CliNodeCodeTranslator; use crate::node::CliNodeResolver; use crate::npm::create_npm_fs_resolver; use crate::npm::CliNpmRegistryApi; -use crate::npm::CliRequireNpmResolver; +use crate::npm::CliNpmResolver; use crate::npm::NpmCache; -use crate::npm::NpmPackageResolver; use crate::npm::NpmResolution; use crate::npm::PackageJsonDepsInstaller; use crate::resolver::CliGraphResolver; @@ -39,6 +39,7 @@ use deno_core::SharedArrayBufferStore; use deno_runtime::deno_broadcast_channel::InMemoryBroadcastChannel; use deno_runtime::deno_node::analyze::NodeCodeTranslator; +use deno_runtime::deno_node::NodeResolver; use deno_runtime::deno_tls::rustls::RootCertStore; use deno_runtime::deno_web::BlobStore; use deno_runtime::inspector_server::InspectorServer; @@ -77,12 +78,11 @@ pub struct Inner { maybe_file_watcher_reporter: Option, pub module_graph_builder: Arc, pub module_load_preparer: Arc, - pub node_code_translator: - Arc>, + pub node_code_translator: Arc, pub node_resolver: Arc, pub npm_api: Arc, pub npm_cache: Arc, - pub npm_resolver: Arc, + pub npm_resolver: Arc, pub npm_resolution: Arc, pub package_json_deps_installer: Arc, pub cjs_resolutions: Arc, @@ -252,7 +252,7 @@ impl ProcState { npm_resolution.clone(), cli_options.node_modules_dir_path(), ); - let npm_resolver = Arc::new(NpmPackageResolver::new( + let npm_resolver = Arc::new(CliNpmResolver::new( npm_resolution.clone(), npm_fs_resolver, lockfile.as_ref().cloned(), @@ -310,12 +310,9 @@ impl ProcState { let cjs_esm_analyzer = CliCjsEsmCodeAnalyzer::new(node_analysis_cache); let node_code_translator = Arc::new(NodeCodeTranslator::new( cjs_esm_analyzer, - npm_resolver.as_require_npm_resolver(), - )); - let node_resolver = Arc::new(CliNodeResolver::new( - npm_resolution.clone(), npm_resolver.clone(), )); + let node_resolver = Arc::new(NodeResolver::new(npm_resolver.clone())); let type_checker = Arc::new(TypeChecker::new( dir.clone(), caches.clone(), diff --git a/cli/tools/check.rs b/cli/tools/check.rs index c7f4042233..36bc25d6a8 100644 --- a/cli/tools/check.rs +++ b/cli/tools/check.rs @@ -22,7 +22,7 @@ use crate::cache::DenoDir; use crate::cache::FastInsecureHasher; use crate::cache::TypeCheckCache; use crate::node::CliNodeResolver; -use crate::npm::NpmPackageResolver; +use crate::npm::CliNpmResolver; use crate::tsc; use crate::version; @@ -43,7 +43,7 @@ pub struct TypeChecker { caches: Arc, cli_options: Arc, node_resolver: Arc, - npm_resolver: Arc, + npm_resolver: Arc, } impl TypeChecker { @@ -52,7 +52,7 @@ impl TypeChecker { caches: Arc, cli_options: Arc, node_resolver: Arc, - npm_resolver: Arc, + npm_resolver: Arc, ) -> Self { Self { deno_dir, diff --git a/cli/tools/info.rs b/cli/tools/info.rs index 69faa10fbc..a59f8a4c84 100644 --- a/cli/tools/info.rs +++ b/cli/tools/info.rs @@ -28,7 +28,7 @@ use crate::args::Flags; use crate::args::InfoFlags; use crate::display; use crate::graph_util::graph_lock_or_exit; -use crate::npm::NpmPackageResolver; +use crate::npm::CliNpmResolver; use crate::proc_state::ProcState; use crate::util::checksum; @@ -141,7 +141,7 @@ fn print_cache_info( fn add_npm_packages_to_json( json: &mut serde_json::Value, - npm_resolver: &NpmPackageResolver, + npm_resolver: &CliNpmResolver, ) { // ideally deno_graph could handle this, but for now we just modify the json here let snapshot = npm_resolver.snapshot(); @@ -318,7 +318,7 @@ struct NpmInfo { impl NpmInfo { pub fn build<'a>( graph: &'a ModuleGraph, - npm_resolver: &'a NpmPackageResolver, + npm_resolver: &'a CliNpmResolver, npm_snapshot: &'a NpmResolutionSnapshot, ) -> Self { let mut info = NpmInfo::default(); @@ -344,7 +344,7 @@ impl NpmInfo { fn fill_package_info<'a>( &mut self, package: &NpmResolutionPackage, - npm_resolver: &'a NpmPackageResolver, + npm_resolver: &'a CliNpmResolver, npm_snapshot: &'a NpmResolutionSnapshot, ) { self @@ -380,7 +380,7 @@ struct GraphDisplayContext<'a> { impl<'a> GraphDisplayContext<'a> { pub fn write( graph: &'a ModuleGraph, - npm_resolver: &'a NpmPackageResolver, + npm_resolver: &'a CliNpmResolver, writer: &mut TWrite, ) -> fmt::Result { let npm_snapshot = npm_resolver.snapshot(); diff --git a/cli/tools/task.rs b/cli/tools/task.rs index c64e2a77cd..898cdd8d90 100644 --- a/cli/tools/task.rs +++ b/cli/tools/task.rs @@ -5,7 +5,7 @@ use crate::args::Flags; use crate::args::TaskFlags; use crate::colors; use crate::node::CliNodeResolver; -use crate::npm::NpmPackageResolver; +use crate::npm::CliNpmResolver; use crate::proc_state::ProcState; use crate::util::fs::canonicalize_path; use deno_core::anyhow::bail; @@ -13,6 +13,7 @@ use deno_core::anyhow::Context; use deno_core::error::AnyError; use deno_core::futures; use deno_core::futures::future::LocalBoxFuture; +use deno_runtime::deno_node::RealFs; use deno_semver::npm::NpmPackageNv; use deno_task_shell::ExecuteResult; use deno_task_shell::ShellCommand; @@ -234,13 +235,14 @@ impl ShellCommand for NpmPackageBinCommand { } fn resolve_npm_commands( - npm_resolver: &NpmPackageResolver, + npm_resolver: &CliNpmResolver, node_resolver: &CliNodeResolver, ) -> Result>, AnyError> { let mut result = HashMap::new(); let snapshot = npm_resolver.snapshot(); for id in snapshot.top_level_packages() { - let bin_commands = node_resolver.resolve_binary_commands(&id.nv)?; + let bin_commands = + node_resolver.resolve_binary_commands::(&id.nv)?; for bin_command in bin_commands { result.insert( bin_command.to_string(), diff --git a/cli/tsc/mod.rs b/cli/tsc/mod.rs index 57a4a1be83..0d956b661f 100644 --- a/cli/tsc/mod.rs +++ b/cli/tsc/mod.rs @@ -5,7 +5,6 @@ use crate::args::TypeCheckMode; use crate::cache::FastInsecureHasher; use crate::node; use crate::node::CliNodeResolver; -use crate::node::NodeResolution; use crate::util::checksum; use crate::util::path::mapped_specifier_for_tsc; @@ -33,7 +32,10 @@ use deno_core::Snapshot; use deno_graph::Module; use deno_graph::ModuleGraph; use deno_graph::ResolutionResolved; +use deno_runtime::deno_node; +use deno_runtime::deno_node::NodeResolution; use deno_runtime::deno_node::NodeResolutionMode; +use deno_runtime::deno_node::RealFs; use deno_runtime::permissions::PermissionsContainer; use deno_semver::npm::NpmPackageReqReference; use lsp_types::Url; @@ -537,7 +539,7 @@ fn op_resolve( }; for specifier in args.specifiers { if let Some(module_name) = specifier.strip_prefix("node:") { - if crate::node::resolve_builtin_node_module(module_name).is_ok() { + if deno_node::resolve_builtin_node_module(module_name).is_ok() { // return itself for node: specifiers because during type checking // we resolve to the ambient modules in the @types/node package // rather than deno_std/node @@ -635,7 +637,7 @@ fn resolve_graph_specifier_types( } Some(Module::Npm(module)) => { if let Some(node_resolver) = &state.maybe_node_resolver { - let maybe_resolution = node_resolver.resolve_npm_reference( + let maybe_resolution = node_resolver.resolve_npm_reference::( &module.nv_reference, NodeResolutionMode::Types, &mut PermissionsContainer::allow_all(), @@ -653,7 +655,9 @@ fn resolve_graph_specifier_types( let specifier = node::resolve_specifier_into_node_modules(&module.specifier); NodeResolution::into_specifier_and_media_type( - node_resolver.url_to_node_resolution(specifier).ok(), + node_resolver + .url_to_node_resolution::(specifier) + .ok(), ) })) } @@ -674,7 +678,7 @@ fn resolve_non_graph_specifier_types( // we're in an npm package, so use node resolution Ok(Some(NodeResolution::into_specifier_and_media_type( node_resolver - .resolve( + .resolve::( specifier, referrer, NodeResolutionMode::Types, @@ -688,7 +692,7 @@ fn resolve_non_graph_specifier_types( // we don't need this special code here. // This could occur when resolving npm:@types/node when it is // injected and not part of the graph - let maybe_resolution = node_resolver.resolve_npm_req_reference( + let maybe_resolution = node_resolver.resolve_npm_req_reference::( &npm_ref, NodeResolutionMode::Types, &mut PermissionsContainer::allow_all(), diff --git a/cli/worker.rs b/cli/worker.rs index 7ee8fc8021..c73e4edbed 100644 --- a/cli/worker.rs +++ b/cli/worker.rs @@ -13,6 +13,8 @@ use deno_core::Extension; use deno_core::ModuleId; use deno_runtime::colors; use deno_runtime::deno_node; +use deno_runtime::deno_node::NodeResolution; +use deno_runtime::deno_node::RealFs; use deno_runtime::fmt_errors::format_js_error; use deno_runtime::ops::worker_host::CreateWebWorkerCb; use deno_runtime::ops::worker_host::WorkerEventCb; @@ -27,7 +29,6 @@ use deno_semver::npm::NpmPackageReqReference; use crate::args::DenoSubcommand; use crate::errors; use crate::module_loader::CliModuleLoader; -use crate::node; use crate::ops; use crate::proc_state::ProcState; use crate::tools; @@ -258,16 +259,16 @@ pub async fn create_custom_worker( ps.npm_resolver .add_package_reqs(vec![package_ref.req.clone()]) .await?; - let node_resolution = - ps.node_resolver.resolve_binary_export(&package_ref)?; - let is_main_cjs = - matches!(node_resolution, node::NodeResolution::CommonJs(_)); + let node_resolution = ps + .node_resolver + .resolve_binary_export::(&package_ref)?; + let is_main_cjs = matches!(node_resolution, NodeResolution::CommonJs(_)); (node_resolution.into_url(), is_main_cjs) } else if ps.options.is_npm_main() { - let node_resolution = - ps.node_resolver.url_to_node_resolution(main_module)?; - let is_main_cjs = - matches!(node_resolution, node::NodeResolution::CommonJs(_)); + let node_resolution = ps + .node_resolver + .url_to_node_resolution::(main_module)?; + let is_main_cjs = matches!(node_resolution, NodeResolution::CommonJs(_)); (node_resolution.into_url(), is_main_cjs) } else { (main_module, false) @@ -344,7 +345,7 @@ pub async fn create_custom_worker( should_break_on_first_statement: ps.options.inspect_brk().is_some(), should_wait_for_inspector_session: ps.options.inspect_wait().is_some(), module_loader, - npm_resolver: Some(Rc::new(ps.npm_resolver.as_require_npm_resolver())), + npm_resolver: Some(Rc::new(ps.npm_resolver.clone())), get_error_class_fn: Some(&errors::get_error_class_name), cache_storage_dir, origin_storage_dir, @@ -467,7 +468,7 @@ fn create_web_worker_callback( format_js_error_fn: Some(Arc::new(format_js_error)), source_map_getter: Some(Box::new(module_loader.clone())), module_loader, - npm_resolver: Some(Rc::new(ps.npm_resolver.as_require_npm_resolver())), + npm_resolver: Some(Rc::new(ps.npm_resolver.clone())), worker_type: args.worker_type, maybe_inspector_server, get_error_class_fn: Some(&errors::get_error_class_name), diff --git a/ext/node/Cargo.toml b/ext/node/Cargo.toml index 0d647e4f02..576e62d559 100644 --- a/ext/node/Cargo.toml +++ b/ext/node/Cargo.toml @@ -18,6 +18,9 @@ aes.workspace = true cbc.workspace = true data-encoding = "2.3.3" deno_core.workspace = true +deno_media_type.workspace = true +deno_npm.workspace = true +deno_semver.workspace = true digest = { version = "0.10.5", features = ["core-api", "std"] } dsa = "0.6.1" ecb.workspace = true diff --git a/ext/node/analyze.rs b/ext/node/analyze.rs index 03bf41995c..a206f4425a 100644 --- a/ext/node/analyze.rs +++ b/ext/node/analyze.rs @@ -17,9 +17,9 @@ use crate::NodeFs; use crate::NodeModuleKind; use crate::NodePermissions; use crate::NodeResolutionMode; +use crate::NpmResolver; use crate::PackageJson; use crate::PathClean; -use crate::RequireNpmResolver; use crate::NODE_GLOBAL_THIS_NAME; static NODE_GLOBALS: &[&str] = &[ @@ -66,20 +66,18 @@ pub trait CjsEsmCodeAnalyzer { pub struct NodeCodeTranslator< TCjsEsmCodeAnalyzer: CjsEsmCodeAnalyzer, - TRequireNpmResolver: RequireNpmResolver, + TNpmResolver: NpmResolver, > { cjs_esm_code_analyzer: TCjsEsmCodeAnalyzer, - npm_resolver: TRequireNpmResolver, + npm_resolver: TNpmResolver, } -impl< - TCjsEsmCodeAnalyzer: CjsEsmCodeAnalyzer, - TRequireNpmResolver: RequireNpmResolver, - > NodeCodeTranslator +impl + NodeCodeTranslator { pub fn new( cjs_esm_code_analyzer: TCjsEsmCodeAnalyzer, - npm_resolver: TRequireNpmResolver, + npm_resolver: TNpmResolver, ) -> Self { Self { cjs_esm_code_analyzer, @@ -242,7 +240,7 @@ impl< // todo(dsherret): use not_found error on not found here let module_dir = self.npm_resolver.resolve_package_folder_from_package( package_specifier.as_str(), - &referrer_path, + referrer, mode, )?; diff --git a/ext/node/lib.rs b/ext/node/lib.rs index a521e161c9..38772d0fc7 100644 --- a/ext/node/lib.rs +++ b/ext/node/lib.rs @@ -5,12 +5,20 @@ use deno_core::located_script_name; use deno_core::op; use deno_core::serde_json; use deno_core::JsRuntime; +use deno_core::ModuleSpecifier; +use deno_npm::resolution::PackageReqNotFoundError; +use deno_npm::NpmPackageId; +use deno_semver::npm::NpmPackageNv; +use deno_semver::npm::NpmPackageNvReference; +use deno_semver::npm::NpmPackageReq; +use deno_semver::npm::NpmPackageReqReference; use once_cell::sync::Lazy; use std::collections::HashSet; use std::io; use std::path::Path; use std::path::PathBuf; use std::rc::Rc; +use std::sync::Arc; pub mod analyze; mod crypto; @@ -21,14 +29,15 @@ mod package_json; mod path; mod polyfill; mod resolution; +mod resolver; mod v8; mod winerror; mod zlib; pub use package_json::PackageJson; pub use path::PathClean; -pub use polyfill::find_builtin_node_module; pub use polyfill::is_builtin_node_module; +pub use polyfill::resolve_builtin_node_module; pub use polyfill::NodeModulePolyfill; pub use polyfill::SUPPORTED_BUILTIN_NODE_MODULES; pub use resolution::get_closest_package_json; @@ -41,6 +50,8 @@ pub use resolution::path_to_declaration_path; pub use resolution::NodeModuleKind; pub use resolution::NodeResolutionMode; pub use resolution::DEFAULT_CONDITIONS; +pub use resolver::NodeResolution; +pub use resolver::NodeResolver; pub trait NodeEnv { type P: NodePermissions; @@ -51,6 +62,14 @@ pub trait NodePermissions { fn check_read(&mut self, path: &Path) -> Result<(), AnyError>; } +pub(crate) struct AllowAllNodePermissions; + +impl NodePermissions for AllowAllNodePermissions { + fn check_read(&mut self, _path: &Path) -> Result<(), AnyError> { + Ok(()) + } +} + #[derive(Default, Clone)] pub struct NodeFsMetadata { pub is_file: bool, @@ -114,20 +133,47 @@ impl NodeFs for RealFs { } } -pub trait RequireNpmResolver { +pub trait NpmResolver { + /// Resolves an npm package folder path from an npm package referrer. fn resolve_package_folder_from_package( &self, specifier: &str, - referrer: &Path, + referrer: &ModuleSpecifier, mode: NodeResolutionMode, ) -> Result; + /// Resolves the npm package folder path from the specified path. fn resolve_package_folder_from_path( &self, path: &Path, ) -> Result; - fn in_npm_package(&self, path: &Path) -> bool; + /// Resolves an npm package folder path from a Deno module. + fn resolve_package_folder_from_deno_module( + &self, + pkg_nv: &NpmPackageNv, + ) -> Result; + + fn resolve_pkg_id_from_pkg_req( + &self, + req: &NpmPackageReq, + ) -> Result; + + fn resolve_nv_ref_from_pkg_req_ref( + &self, + req_ref: &NpmPackageReqReference, + ) -> Result; + + fn in_npm_package(&self, specifier: &ModuleSpecifier) -> bool; + + fn in_npm_package_at_path(&self, path: &Path) -> bool { + let specifier = + match ModuleSpecifier::from_file_path(path.to_path_buf().clean()) { + Ok(p) => p, + Err(_) => return false, + }; + self.in_npm_package(&specifier) + } fn ensure_read_permission( &self, @@ -136,6 +182,57 @@ pub trait RequireNpmResolver { ) -> Result<(), AnyError>; } +impl NpmResolver for Arc { + fn resolve_package_folder_from_package( + &self, + specifier: &str, + referrer: &ModuleSpecifier, + mode: NodeResolutionMode, + ) -> Result { + (**self).resolve_package_folder_from_package(specifier, referrer, mode) + } + + fn resolve_package_folder_from_path( + &self, + path: &Path, + ) -> Result { + (**self).resolve_package_folder_from_path(path) + } + + fn resolve_package_folder_from_deno_module( + &self, + pkg_nv: &NpmPackageNv, + ) -> Result { + (**self).resolve_package_folder_from_deno_module(pkg_nv) + } + + fn resolve_pkg_id_from_pkg_req( + &self, + req: &NpmPackageReq, + ) -> Result { + (**self).resolve_pkg_id_from_pkg_req(req) + } + + fn resolve_nv_ref_from_pkg_req_ref( + &self, + req_ref: &NpmPackageReqReference, + ) -> Result { + (**self).resolve_nv_ref_from_pkg_req_ref(req_ref) + } + + fn in_npm_package(&self, specifier: &ModuleSpecifier) -> bool { + (**self).in_npm_package(specifier) + } + + fn ensure_read_permission( + &self, + permissions: &mut dyn NodePermissions, + path: &Path, + ) -> Result<(), AnyError> { + (**self).ensure_read_permission(permissions, path) + } +} + pub static NODE_GLOBAL_THIS_NAME: Lazy = Lazy::new(|| { let now = std::time::SystemTime::now(); let seconds = now @@ -490,7 +587,7 @@ deno_core::extension!(deno_node, "zlib.ts", ], options = { - maybe_npm_resolver: Option>, + maybe_npm_resolver: Option>, }, state = |state, options| { if let Some(npm_resolver) = options.maybe_npm_resolver { diff --git a/ext/node/ops.rs b/ext/node/ops.rs index 3db23b5eaf..662168acc2 100644 --- a/ext/node/ops.rs +++ b/ext/node/ops.rs @@ -7,6 +7,7 @@ use deno_core::normalize_path; use deno_core::op; use deno_core::url::Url; use deno_core::JsRuntimeInspector; +use deno_core::ModuleSpecifier; use deno_core::OpState; use std::cell::RefCell; use std::path::Path; @@ -20,8 +21,8 @@ use super::resolution; use super::NodeModuleKind; use super::NodePermissions; use super::NodeResolutionMode; +use super::NpmResolver; use super::PackageJson; -use super::RequireNpmResolver; fn ensure_read_permission

( state: &mut OpState, @@ -31,7 +32,7 @@ where P: NodePermissions + 'static, { let resolver = { - let resolver = state.borrow::>(); + let resolver = state.borrow::>(); resolver.clone() }; let permissions = state.borrow_mut::

(); @@ -191,11 +192,11 @@ fn op_require_resolve_deno_dir( request: String, parent_filename: String, ) -> Option { - let resolver = state.borrow::>(); + let resolver = state.borrow::>(); resolver .resolve_package_folder_from_package( &request, - &PathBuf::from(parent_filename), + &ModuleSpecifier::from_file_path(parent_filename).unwrap(), NodeResolutionMode::Execution, ) .ok() @@ -204,8 +205,8 @@ fn op_require_resolve_deno_dir( #[op] fn op_require_is_deno_dir_package(state: &mut OpState, path: String) -> bool { - let resolver = state.borrow::>(); - resolver.in_npm_package(&PathBuf::from(path)) + let resolver = state.borrow::>(); + resolver.in_npm_package_at_path(&PathBuf::from(path)) } #[op] @@ -375,7 +376,7 @@ where return Ok(None); } - let resolver = state.borrow::>().clone(); + let resolver = state.borrow::>().clone(); let permissions = state.borrow_mut::(); let pkg = resolution::get_package_scope_config::( &Url::from_file_path(parent_path.unwrap()).unwrap(), @@ -462,10 +463,11 @@ fn op_require_resolve_exports( where Env: NodeEnv + 'static, { - let resolver = state.borrow::>().clone(); + let resolver = state.borrow::>().clone(); let permissions = state.borrow_mut::(); - let pkg_path = if resolver.in_npm_package(&PathBuf::from(&modules_path)) + let pkg_path = if resolver + .in_npm_package_at_path(&PathBuf::from(&modules_path)) && !uses_local_node_modules_dir { modules_path @@ -515,7 +517,7 @@ where state, PathBuf::from(&filename).parent().unwrap(), )?; - let resolver = state.borrow::>().clone(); + let resolver = state.borrow::>().clone(); let permissions = state.borrow_mut::(); resolution::get_closest_package_json::( &Url::from_file_path(filename).unwrap(), @@ -532,7 +534,7 @@ fn op_require_read_package_scope( where Env: NodeEnv + 'static, { - let resolver = state.borrow::>().clone(); + let resolver = state.borrow::>().clone(); let permissions = state.borrow_mut::(); let package_json_path = PathBuf::from(package_json_path); PackageJson::load::(&*resolver, permissions, package_json_path).ok() @@ -549,7 +551,7 @@ where { let parent_path = PathBuf::from(&parent_filename); ensure_read_permission::(state, &parent_path)?; - let resolver = state.borrow::>().clone(); + let resolver = state.borrow::>().clone(); let permissions = state.borrow_mut::(); let pkg = PackageJson::load::( &*resolver, diff --git a/ext/node/package_json.rs b/ext/node/package_json.rs index 60f50ad787..08f78681ae 100644 --- a/ext/node/package_json.rs +++ b/ext/node/package_json.rs @@ -4,7 +4,7 @@ use crate::NodeFs; use crate::NodeModuleKind; use crate::NodePermissions; -use super::RequireNpmResolver; +use super::NpmResolver; use deno_core::anyhow; use deno_core::anyhow::bail; @@ -63,7 +63,7 @@ impl PackageJson { } pub fn load( - resolver: &dyn RequireNpmResolver, + resolver: &dyn NpmResolver, permissions: &mut dyn NodePermissions, path: PathBuf, ) -> Result { diff --git a/ext/node/polyfill.rs b/ext/node/polyfill.rs index 1fbb4afa3d..b334d2d341 100644 --- a/ext/node/polyfill.rs +++ b/ext/node/polyfill.rs @@ -1,8 +1,22 @@ // Copyright 2018-2023 the Deno authors. All rights reserved. MIT license. -pub fn find_builtin_node_module( - module_name: &str, -) -> Option<&NodeModulePolyfill> { +use deno_core::error::generic_error; +use deno_core::error::AnyError; +use deno_core::url::Url; +use deno_core::ModuleSpecifier; + +// TODO(bartlomieju): seems super wasteful to parse the specifier each time +pub fn resolve_builtin_node_module(module_name: &str) -> Result { + if let Some(module) = find_builtin_node_module(module_name) { + return Ok(ModuleSpecifier::parse(module.specifier).unwrap()); + } + + Err(generic_error(format!( + "Unknown built-in \"node:\" module: {module_name}" + ))) +} + +fn find_builtin_node_module(module_name: &str) -> Option<&NodeModulePolyfill> { SUPPORTED_BUILTIN_NODE_MODULES .iter() .find(|m| m.name == module_name) diff --git a/ext/node/resolution.rs b/ext/node/resolution.rs index 1422ba6b02..d324f4b4b9 100644 --- a/ext/node/resolution.rs +++ b/ext/node/resolution.rs @@ -16,7 +16,7 @@ use crate::package_json::PackageJson; use crate::path::PathClean; use crate::NodeFs; use crate::NodePermissions; -use crate::RequireNpmResolver; +use crate::NpmResolver; pub static DEFAULT_CONDITIONS: &[&str] = &["deno", "node", "import"]; pub static REQUIRE_CONDITIONS: &[&str] = &["require", "node"]; @@ -190,7 +190,7 @@ pub fn package_imports_resolve( referrer_kind: NodeModuleKind, conditions: &[&str], mode: NodeResolutionMode, - npm_resolver: &dyn RequireNpmResolver, + npm_resolver: &dyn NpmResolver, permissions: &mut dyn NodePermissions, ) -> Result { if name == "#" || name.starts_with("#/") || name.ends_with('/') { @@ -328,7 +328,7 @@ fn resolve_package_target_string( internal: bool, conditions: &[&str], mode: NodeResolutionMode, - npm_resolver: &dyn RequireNpmResolver, + npm_resolver: &dyn NpmResolver, permissions: &mut dyn NodePermissions, ) -> Result { if !subpath.is_empty() && !pattern && !target.ends_with('/') { @@ -438,7 +438,7 @@ fn resolve_package_target( internal: bool, conditions: &[&str], mode: NodeResolutionMode, - npm_resolver: &dyn RequireNpmResolver, + npm_resolver: &dyn NpmResolver, permissions: &mut dyn NodePermissions, ) -> Result, AnyError> { if let Some(target) = target.as_str() { @@ -576,7 +576,7 @@ pub fn package_exports_resolve( referrer_kind: NodeModuleKind, conditions: &[&str], mode: NodeResolutionMode, - npm_resolver: &dyn RequireNpmResolver, + npm_resolver: &dyn NpmResolver, permissions: &mut dyn NodePermissions, ) -> Result { if package_exports.contains_key(&package_subpath) @@ -733,7 +733,7 @@ pub fn package_resolve( referrer_kind: NodeModuleKind, conditions: &[&str], mode: NodeResolutionMode, - npm_resolver: &dyn RequireNpmResolver, + npm_resolver: &dyn NpmResolver, permissions: &mut dyn NodePermissions, ) -> Result, AnyError> { let (package_name, package_subpath, _is_scoped) = @@ -763,7 +763,7 @@ pub fn package_resolve( let package_dir_path = npm_resolver.resolve_package_folder_from_package( &package_name, - &referrer.to_file_path().unwrap(), + referrer, mode, )?; let package_json_path = package_dir_path.join("package.json"); @@ -815,7 +815,7 @@ pub fn package_resolve( pub fn get_package_scope_config( referrer: &ModuleSpecifier, - npm_resolver: &dyn RequireNpmResolver, + npm_resolver: &dyn NpmResolver, permissions: &mut dyn NodePermissions, ) -> Result { let root_folder = npm_resolver @@ -826,7 +826,7 @@ pub fn get_package_scope_config( pub fn get_closest_package_json( url: &ModuleSpecifier, - npm_resolver: &dyn RequireNpmResolver, + npm_resolver: &dyn NpmResolver, permissions: &mut dyn NodePermissions, ) -> Result { let package_json_path = @@ -836,7 +836,7 @@ pub fn get_closest_package_json( fn get_closest_package_json_path( url: &ModuleSpecifier, - npm_resolver: &dyn RequireNpmResolver, + npm_resolver: &dyn NpmResolver, ) -> Result { let file_path = url.to_file_path().unwrap(); let mut current_dir = file_path.parent().unwrap(); diff --git a/cli/node/mod.rs b/ext/node/resolver.rs similarity index 77% rename from cli/node/mod.rs rename to ext/node/resolver.rs index eb584879e8..41e1cf4d4d 100644 --- a/cli/node/mod.rs +++ b/ext/node/resolver.rs @@ -2,45 +2,34 @@ use std::path::Path; use std::path::PathBuf; -use std::sync::Arc; -use deno_ast::MediaType; -use deno_ast::ModuleSpecifier; use deno_core::anyhow::bail; use deno_core::anyhow::Context; use deno_core::error::generic_error; use deno_core::error::AnyError; use deno_core::serde_json::Value; use deno_core::url::Url; -use deno_runtime::deno_node; -use deno_runtime::deno_node::errors; -use deno_runtime::deno_node::find_builtin_node_module; -use deno_runtime::deno_node::get_closest_package_json; -use deno_runtime::deno_node::legacy_main_resolve; -use deno_runtime::deno_node::package_exports_resolve; -use deno_runtime::deno_node::package_imports_resolve; -use deno_runtime::deno_node::package_resolve; -use deno_runtime::deno_node::path_to_declaration_path; -use deno_runtime::deno_node::NodeModuleKind; -use deno_runtime::deno_node::NodePermissions; -use deno_runtime::deno_node::NodeResolutionMode; -use deno_runtime::deno_node::PackageJson; -use deno_runtime::deno_node::RealFs; -use deno_runtime::deno_node::RequireNpmResolver; -use deno_runtime::deno_node::DEFAULT_CONDITIONS; -use deno_runtime::permissions::PermissionsContainer; +use deno_core::ModuleSpecifier; +use deno_media_type::MediaType; use deno_semver::npm::NpmPackageNv; use deno_semver::npm::NpmPackageNvReference; use deno_semver::npm::NpmPackageReqReference; -use crate::npm::CliRequireNpmResolver; -use crate::npm::NpmPackageResolver; -use crate::npm::NpmResolution; -use crate::util::fs::canonicalize_path_maybe_not_exists; - -mod analyze; - -pub use analyze::CliCjsEsmCodeAnalyzer; +use crate::errors; +use crate::get_closest_package_json; +use crate::legacy_main_resolve; +use crate::package_exports_resolve; +use crate::package_imports_resolve; +use crate::package_resolve; +use crate::path_to_declaration_path; +use crate::AllowAllNodePermissions; +use crate::NodeFs; +use crate::NodeModuleKind; +use crate::NodePermissions; +use crate::NodeResolutionMode; +use crate::NpmResolver; +use crate::PackageJson; +use crate::DEFAULT_CONDITIONS; #[derive(Debug)] pub enum NodeResolution { @@ -101,33 +90,15 @@ impl NodeResolution { } } -// TODO(bartlomieju): seems super wasteful to parse specified each time -pub fn resolve_builtin_node_module(module_name: &str) -> Result { - if let Some(module) = find_builtin_node_module(module_name) { - return Ok(ModuleSpecifier::parse(module.specifier).unwrap()); - } - - Err(generic_error(format!( - "Unknown built-in \"node:\" module: {module_name}" - ))) -} - #[derive(Debug)] -pub struct CliNodeResolver { - npm_resolution: Arc, - npm_resolver: Arc, - require_npm_resolver: CliRequireNpmResolver, +pub struct NodeResolver { + npm_resolver: TRequireNpmResolver, } -impl CliNodeResolver { - pub fn new( - npm_resolution: Arc, - npm_package_resolver: Arc, - ) -> Self { +impl NodeResolver { + pub fn new(require_npm_resolver: TRequireNpmResolver) -> Self { Self { - npm_resolution, - require_npm_resolver: npm_package_resolver.as_require_npm_resolver(), - npm_resolver: npm_package_resolver, + npm_resolver: require_npm_resolver, } } @@ -137,7 +108,7 @@ impl CliNodeResolver { /// This function is an implementation of `defaultResolve` in /// `lib/internal/modules/esm/resolve.js` from Node. - pub fn resolve( + pub fn resolve( &self, specifier: &str, referrer: &ModuleSpecifier, @@ -147,7 +118,7 @@ impl CliNodeResolver { // Note: if we are here, then the referrer is an esm module // TODO(bartlomieju): skipped "policy" part as we don't plan to support it - if deno_node::is_builtin_node_module(specifier) { + if crate::is_builtin_node_module(specifier) { return Ok(Some(NodeResolution::BuiltIn(specifier.to_string()))); } @@ -162,7 +133,7 @@ impl CliNodeResolver { let split_specifier = url.as_str().split(':'); let specifier = split_specifier.skip(1).collect::(); - if deno_node::is_builtin_node_module(&specifier) { + if crate::is_builtin_node_module(&specifier) { return Ok(Some(NodeResolution::BuiltIn(specifier))); } } @@ -178,7 +149,7 @@ impl CliNodeResolver { } } - let url = self.module_resolve( + let url = self.module_resolve::( specifier, referrer, DEFAULT_CONDITIONS, @@ -196,7 +167,7 @@ impl CliNodeResolver { // todo(16370): the module kind is not correct here. I think we need // typescript to tell us if the referrer is esm or cjs let path = - match path_to_declaration_path::(path, NodeModuleKind::Esm) { + match path_to_declaration_path::(path, NodeModuleKind::Esm) { Some(path) => path, None => return Ok(None), }; @@ -204,13 +175,13 @@ impl CliNodeResolver { } }; - let resolve_response = self.url_to_node_resolution(url)?; + let resolve_response = self.url_to_node_resolution::(url)?; // TODO(bartlomieju): skipped checking errors for commonJS resolution and // "preserveSymlinksMain"/"preserveSymlinks" options. Ok(Some(resolve_response)) } - fn module_resolve( + fn module_resolve( &self, specifier: &str, referrer: &ModuleSpecifier, @@ -226,7 +197,7 @@ impl CliNodeResolver { // todo(dsherret): the node module kind is not correct and we // should use the value provided by typescript instead let declaration_path = - path_to_declaration_path::(file_path, NodeModuleKind::Esm); + path_to_declaration_path::(file_path, NodeModuleKind::Esm); declaration_path.map(|declaration_path| { ModuleSpecifier::from_file_path(declaration_path).unwrap() }) @@ -235,13 +206,13 @@ impl CliNodeResolver { } } else if specifier.starts_with('#') { Some( - package_imports_resolve::( + package_imports_resolve::( specifier, referrer, NodeModuleKind::Esm, conditions, mode, - &self.require_npm_resolver, + &self.npm_resolver, permissions, ) .map(|p| ModuleSpecifier::from_file_path(p).unwrap())?, @@ -249,34 +220,36 @@ impl CliNodeResolver { } else if let Ok(resolved) = Url::parse(specifier) { Some(resolved) } else { - package_resolve::( + package_resolve::( specifier, referrer, NodeModuleKind::Esm, conditions, mode, - &self.require_npm_resolver, + &self.npm_resolver, permissions, )? .map(|p| ModuleSpecifier::from_file_path(p).unwrap()) }; Ok(match url { - Some(url) => Some(finalize_resolution(url, referrer)?), + Some(url) => Some(finalize_resolution::(url, referrer)?), None => None, }) } - pub fn resolve_npm_req_reference( + pub fn resolve_npm_req_reference( &self, reference: &NpmPackageReqReference, mode: NodeResolutionMode, permissions: &mut dyn NodePermissions, ) -> Result, AnyError> { - let reference = self.npm_resolution.pkg_req_ref_to_nv_ref(reference)?; - self.resolve_npm_reference(&reference, mode, permissions) + let reference = self + .npm_resolver + .resolve_nv_ref_from_pkg_req_ref(reference)?; + self.resolve_npm_reference::(&reference, mode, permissions) } - pub fn resolve_npm_reference( + pub fn resolve_npm_reference( &self, reference: &NpmPackageNvReference, mode: NodeResolutionMode, @@ -286,7 +259,7 @@ impl CliNodeResolver { .npm_resolver .resolve_package_folder_from_deno_module(&reference.nv)?; let node_module_kind = NodeModuleKind::Esm; - let maybe_resolved_path = package_config_resolve( + let maybe_resolved_path = package_config_resolve::( &reference .sub_path .as_ref() @@ -296,7 +269,7 @@ impl CliNodeResolver { node_module_kind, DEFAULT_CONDITIONS, mode, - &self.require_npm_resolver, + &self.npm_resolver, permissions, ) .with_context(|| { @@ -309,23 +282,20 @@ impl CliNodeResolver { let resolved_path = match mode { NodeResolutionMode::Execution => resolved_path, NodeResolutionMode::Types => { - match path_to_declaration_path::( - resolved_path, - node_module_kind, - ) { + match path_to_declaration_path::(resolved_path, node_module_kind) { Some(path) => path, None => return Ok(None), } } }; let url = ModuleSpecifier::from_file_path(resolved_path).unwrap(); - let resolve_response = self.url_to_node_resolution(url)?; + let resolve_response = self.url_to_node_resolution::(url)?; // TODO(bartlomieju): skipped checking errors for commonJS resolution and // "preserveSymlinksMain"/"preserveSymlinks" options. Ok(Some(resolve_response)) } - pub fn resolve_binary_commands( + pub fn resolve_binary_commands( &self, pkg_nv: &NpmPackageNv, ) -> Result, AnyError> { @@ -333,9 +303,9 @@ impl CliNodeResolver { .npm_resolver .resolve_package_folder_from_deno_module(pkg_nv)?; let package_json_path = package_folder.join("package.json"); - let package_json = PackageJson::load::( - &self.require_npm_resolver, - &mut PermissionsContainer::allow_all(), + let package_json = PackageJson::load::( + &self.npm_resolver, + &mut AllowAllNodePermissions, package_json_path, )?; @@ -348,12 +318,12 @@ impl CliNodeResolver { }) } - pub fn resolve_binary_export( + pub fn resolve_binary_export( &self, pkg_ref: &NpmPackageReqReference, ) -> Result { let pkg_nv = self - .npm_resolution + .npm_resolver .resolve_pkg_id_from_pkg_req(&pkg_ref.req)? .nv; let bin_name = pkg_ref.sub_path.as_deref(); @@ -361,9 +331,9 @@ impl CliNodeResolver { .npm_resolver .resolve_package_folder_from_deno_module(&pkg_nv)?; let package_json_path = package_folder.join("package.json"); - let package_json = PackageJson::load::( - &self.require_npm_resolver, - &mut PermissionsContainer::allow_all(), + let package_json = PackageJson::load::( + &self.npm_resolver, + &mut AllowAllNodePermissions, package_json_path, )?; let bin = match &package_json.bin { @@ -377,13 +347,13 @@ impl CliNodeResolver { let url = ModuleSpecifier::from_file_path(package_folder.join(bin_entry)).unwrap(); - let resolve_response = self.url_to_node_resolution(url)?; + let resolve_response = self.url_to_node_resolution::(url)?; // TODO(bartlomieju): skipped checking errors for commonJS resolution and // "preserveSymlinksMain"/"preserveSymlinks" options. Ok(resolve_response) } - pub fn url_to_node_resolution( + pub fn url_to_node_resolution( &self, url: ModuleSpecifier, ) -> Result { @@ -391,10 +361,10 @@ impl CliNodeResolver { if url_str.starts_with("http") { Ok(NodeResolution::Esm(url)) } else if url_str.ends_with(".js") || url_str.ends_with(".d.ts") { - let package_config = get_closest_package_json::( + let package_config = get_closest_package_json::( &url, - &self.require_npm_resolver, - &mut PermissionsContainer::allow_all(), + &self.npm_resolver, + &mut AllowAllNodePermissions, )?; if package_config.typ == "module" { Ok(NodeResolution::Esm(url)) @@ -413,25 +383,6 @@ impl CliNodeResolver { } } -/// Resolves a specifier that is pointing into a node_modules folder. -/// -/// Note: This should be called whenever getting the specifier from -/// a Module::External(module) reference because that module might -/// not be fully resolved at the time deno_graph is analyzing it -/// because the node_modules folder might not exist at that time. -pub fn resolve_specifier_into_node_modules( - specifier: &ModuleSpecifier, -) -> ModuleSpecifier { - specifier - .to_file_path() - .ok() - // this path might not exist at the time the graph is being created - // because the node_modules folder might not yet exist - .and_then(|path| canonicalize_path_maybe_not_exists(&path).ok()) - .and_then(|path| ModuleSpecifier::from_file_path(path).ok()) - .unwrap_or_else(|| specifier.clone()) -} - fn resolve_bin_entry_value<'a>( pkg_nv: &NpmPackageNv, bin_name: Option<&str>, @@ -488,24 +439,24 @@ fn resolve_bin_entry_value<'a>( } } -fn package_config_resolve( +fn package_config_resolve( package_subpath: &str, package_dir: &Path, referrer_kind: NodeModuleKind, conditions: &[&str], mode: NodeResolutionMode, - npm_resolver: &dyn RequireNpmResolver, + npm_resolver: &dyn NpmResolver, permissions: &mut dyn NodePermissions, ) -> Result, AnyError> { let package_json_path = package_dir.join("package.json"); let referrer = ModuleSpecifier::from_directory_path(package_dir).unwrap(); - let package_config = PackageJson::load::( + let package_config = PackageJson::load::( npm_resolver, permissions, package_json_path.clone(), )?; if let Some(exports) = &package_config.exports { - let result = package_exports_resolve::( + let result = package_exports_resolve::( &package_json_path, package_subpath.to_string(), exports, @@ -521,7 +472,7 @@ fn package_config_resolve( Err(exports_err) => { if mode.is_types() && package_subpath == "." { if let Ok(Some(path)) = - legacy_main_resolve::(&package_config, referrer_kind, mode) + legacy_main_resolve::(&package_config, referrer_kind, mode) { return Ok(Some(path)); } else { @@ -533,13 +484,13 @@ fn package_config_resolve( } } if package_subpath == "." { - return legacy_main_resolve::(&package_config, referrer_kind, mode); + return legacy_main_resolve::(&package_config, referrer_kind, mode); } Ok(Some(package_dir.join(package_subpath))) } -fn finalize_resolution( +fn finalize_resolution( resolved: ModuleSpecifier, base: &ModuleSpecifier, ) -> Result { @@ -567,8 +518,8 @@ fn finalize_resolution( p_str.to_string() }; - let (is_dir, is_file) = if let Ok(stats) = std::fs::metadata(p) { - (stats.is_dir(), stats.is_file()) + let (is_dir, is_file) = if let Ok(stats) = Fs::metadata(p) { + (stats.is_dir, stats.is_file) } else { (false, false) }; diff --git a/runtime/web_worker.rs b/runtime/web_worker.rs index 0d743cfc62..06540a9bbf 100644 --- a/runtime/web_worker.rs +++ b/runtime/web_worker.rs @@ -37,7 +37,7 @@ use deno_core::SourceMapGetter; use deno_fs::StdFs; use deno_io::Stdio; use deno_kv::sqlite::SqliteDbHandler; -use deno_node::RequireNpmResolver; +use deno_node::NpmResolver; use deno_tls::rustls::RootCertStore; use deno_web::create_entangled_message_port; use deno_web::BlobStore; @@ -333,7 +333,7 @@ pub struct WebWorkerOptions { pub root_cert_store: Option, pub seed: Option, pub module_loader: Rc, - pub npm_resolver: Option>, + pub npm_resolver: Option>, pub create_web_worker_cb: Arc, pub preload_module_cb: Arc, pub pre_execute_module_cb: Arc, diff --git a/runtime/worker.rs b/runtime/worker.rs index 14abd12b55..5cd60604d2 100644 --- a/runtime/worker.rs +++ b/runtime/worker.rs @@ -33,7 +33,7 @@ use deno_core::SourceMapGetter; use deno_fs::StdFs; use deno_io::Stdio; use deno_kv::sqlite::SqliteDbHandler; -use deno_node::RequireNpmResolver; +use deno_node::NpmResolver; use deno_tls::rustls::RootCertStore; use deno_web::BlobStore; use log::debug; @@ -94,7 +94,7 @@ pub struct WorkerOptions { /// If not provided runtime will error if code being /// executed tries to load modules. pub module_loader: Rc, - pub npm_resolver: Option>, + pub npm_resolver: Option>, // Callbacks invoked when creating new instance of WebWorker pub create_web_worker_cb: Arc, pub web_worker_preload_module_cb: Arc,