mirror of
https://github.com/denoland/deno.git
synced 2024-11-21 15:04:11 -05:00
refactor: decouple node resolution from deno_core (#24724)
This commit is contained in:
parent
0cf7f268a7
commit
3bf147fe28
45 changed files with 939 additions and 518 deletions
22
Cargo.lock
generated
22
Cargo.lock
generated
|
@ -1167,6 +1167,7 @@ dependencies = [
|
|||
"monch",
|
||||
"napi_sym",
|
||||
"nix 0.26.2",
|
||||
"node_resolver",
|
||||
"notify",
|
||||
"once_cell",
|
||||
"open",
|
||||
|
@ -1767,6 +1768,7 @@ dependencies = [
|
|||
"libz-sys",
|
||||
"md-5",
|
||||
"md4",
|
||||
"node_resolver",
|
||||
"num-bigint",
|
||||
"num-bigint-dig",
|
||||
"num-integer",
|
||||
|
@ -1908,6 +1910,7 @@ dependencies = [
|
|||
"log",
|
||||
"netif",
|
||||
"nix 0.26.2",
|
||||
"node_resolver",
|
||||
"notify",
|
||||
"ntapi",
|
||||
"once_cell",
|
||||
|
@ -4341,6 +4344,25 @@ dependencies = [
|
|||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "node_resolver"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
"deno_media_type",
|
||||
"deno_package_json",
|
||||
"futures",
|
||||
"lazy-regex",
|
||||
"once_cell",
|
||||
"path-clean",
|
||||
"regex",
|
||||
"serde_json",
|
||||
"thiserror",
|
||||
"tokio",
|
||||
"url",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nom"
|
||||
version = "5.1.3"
|
||||
|
|
|
@ -21,6 +21,7 @@ members = [
|
|||
"ext/napi",
|
||||
"ext/net",
|
||||
"ext/node",
|
||||
"ext/node_resolver",
|
||||
"ext/url",
|
||||
"ext/web",
|
||||
"ext/webgpu",
|
||||
|
@ -83,6 +84,7 @@ deno_webgpu = { version = "0.129.0", path = "./ext/webgpu" }
|
|||
deno_webidl = { version = "0.162.0", path = "./ext/webidl" }
|
||||
deno_websocket = { version = "0.167.0", path = "./ext/websocket" }
|
||||
deno_webstorage = { version = "0.157.0", path = "./ext/webstorage" }
|
||||
node_resolver = { version = "0.1.0", path = "./ext/node_resolver" }
|
||||
|
||||
aes = "=0.8.3"
|
||||
anyhow = "1.0.57"
|
||||
|
|
|
@ -80,6 +80,7 @@ deno_task_shell = "=0.17.0"
|
|||
deno_terminal.workspace = true
|
||||
eszip = "=0.72.2"
|
||||
napi_sym.workspace = true
|
||||
node_resolver.workspace = true
|
||||
|
||||
async-trait.workspace = true
|
||||
base32.workspace = true
|
||||
|
|
|
@ -820,9 +820,7 @@ impl CliOptions {
|
|||
WorkspaceDiscoverOptions {
|
||||
fs: Default::default(), // use real fs
|
||||
deno_json_cache: None,
|
||||
pkg_json_cache: Some(
|
||||
&deno_runtime::deno_node::PackageJsonThreadLocalCache,
|
||||
),
|
||||
pkg_json_cache: Some(&node_resolver::PackageJsonThreadLocalCache),
|
||||
workspace_cache: None,
|
||||
config_parse_options,
|
||||
additional_config_file_names,
|
||||
|
|
|
@ -62,13 +62,14 @@ use deno_core::futures::FutureExt;
|
|||
use deno_core::FeatureChecker;
|
||||
|
||||
use deno_runtime::deno_fs;
|
||||
use deno_runtime::deno_node::analyze::NodeCodeTranslator;
|
||||
use deno_runtime::deno_node::DenoFsNodeResolverEnv;
|
||||
use deno_runtime::deno_node::NodeResolver;
|
||||
use deno_runtime::deno_tls::rustls::RootCertStore;
|
||||
use deno_runtime::deno_tls::RootCertStoreProvider;
|
||||
use deno_runtime::deno_web::BlobStore;
|
||||
use deno_runtime::inspector_server::InspectorServer;
|
||||
use log::warn;
|
||||
use node_resolver::analyze::NodeCodeTranslator;
|
||||
use once_cell::sync::OnceCell;
|
||||
use std::future::Future;
|
||||
use std::sync::Arc;
|
||||
|
@ -553,7 +554,7 @@ impl CliFactory {
|
|||
.get_or_try_init_async(
|
||||
async {
|
||||
Ok(Arc::new(NodeResolver::new(
|
||||
self.fs().clone(),
|
||||
DenoFsNodeResolverEnv::new(self.fs().clone()),
|
||||
self.npm_resolver().await?.clone().into_npm_resolver(),
|
||||
)))
|
||||
}
|
||||
|
@ -577,7 +578,7 @@ impl CliFactory {
|
|||
|
||||
Ok(Arc::new(NodeCodeTranslator::new(
|
||||
cjs_esm_analyzer,
|
||||
self.fs().clone(),
|
||||
DenoFsNodeResolverEnv::new(self.fs().clone()),
|
||||
self.node_resolver().await?.clone(),
|
||||
self.npm_resolver().await?.clone().into_npm_resolver(),
|
||||
)))
|
||||
|
|
|
@ -23,7 +23,6 @@ use deno_core::serde::Serialize;
|
|||
use deno_core::serde_json;
|
||||
use deno_core::serde_json::json;
|
||||
use deno_core::ModuleSpecifier;
|
||||
use deno_runtime::deno_node::NpmResolver;
|
||||
use deno_runtime::deno_node::PathClean;
|
||||
use deno_semver::jsr::JsrPackageNvReference;
|
||||
use deno_semver::jsr::JsrPackageReqReference;
|
||||
|
@ -34,6 +33,7 @@ use deno_semver::package::PackageReq;
|
|||
use deno_semver::package::PackageReqReference;
|
||||
use deno_semver::Version;
|
||||
use import_map::ImportMap;
|
||||
use node_resolver::NpmResolver;
|
||||
use once_cell::sync::Lazy;
|
||||
use regex::Regex;
|
||||
use std::cmp::Ordering;
|
||||
|
|
|
@ -35,11 +35,7 @@ use deno_graph::GraphImport;
|
|||
use deno_graph::ModuleSpecifier;
|
||||
use deno_npm::NpmSystemInfo;
|
||||
use deno_runtime::deno_fs;
|
||||
use deno_runtime::deno_node::errors::ClosestPkgJsonError;
|
||||
use deno_runtime::deno_node::NodeResolution;
|
||||
use deno_runtime::deno_node::NodeResolutionMode;
|
||||
use deno_runtime::deno_node::NodeResolver;
|
||||
use deno_runtime::deno_node::NpmResolver;
|
||||
use deno_runtime::deno_node::PackageJson;
|
||||
use deno_runtime::fs_util::specifier_to_file_path;
|
||||
use deno_semver::jsr::JsrPackageReqReference;
|
||||
|
@ -47,6 +43,10 @@ use deno_semver::npm::NpmPackageReqReference;
|
|||
use deno_semver::package::PackageNv;
|
||||
use deno_semver::package::PackageReq;
|
||||
use indexmap::IndexMap;
|
||||
use node_resolver::errors::ClosestPkgJsonError;
|
||||
use node_resolver::NodeResolution;
|
||||
use node_resolver::NodeResolutionMode;
|
||||
use node_resolver::NpmResolver;
|
||||
use std::borrow::Cow;
|
||||
use std::collections::BTreeMap;
|
||||
use std::collections::BTreeSet;
|
||||
|
@ -496,7 +496,7 @@ fn create_node_resolver(
|
|||
let npm_resolver = npm_resolver?;
|
||||
let fs = Arc::new(deno_fs::RealFs);
|
||||
let node_resolver_inner = Arc::new(NodeResolver::new(
|
||||
fs.clone(),
|
||||
deno_runtime::deno_node::DenoFsNodeResolverEnv::new(fs.clone()),
|
||||
npm_resolver.clone().into_npm_resolver(),
|
||||
));
|
||||
Some(Arc::new(CliNodeResolver::new(
|
||||
|
|
|
@ -64,9 +64,9 @@ use deno_graph::Module;
|
|||
use deno_graph::ModuleGraph;
|
||||
use deno_graph::Resolution;
|
||||
use deno_runtime::code_cache;
|
||||
use deno_runtime::deno_node::NodeResolutionMode;
|
||||
use deno_runtime::deno_permissions::PermissionsContainer;
|
||||
use deno_semver::npm::NpmPackageReqReference;
|
||||
use node_resolver::NodeResolutionMode;
|
||||
|
||||
pub async fn load_top_level_deps(factory: &CliFactory) -> Result<(), AnyError> {
|
||||
let npm_resolver = factory.npm_resolver().await?;
|
||||
|
|
12
cli/node.rs
12
cli/node.rs
|
@ -6,10 +6,11 @@ use deno_ast::MediaType;
|
|||
use deno_ast::ModuleSpecifier;
|
||||
use deno_core::error::AnyError;
|
||||
use deno_runtime::deno_fs;
|
||||
use deno_runtime::deno_node::analyze::CjsAnalysis as ExtNodeCjsAnalysis;
|
||||
use deno_runtime::deno_node::analyze::CjsAnalysisExports;
|
||||
use deno_runtime::deno_node::analyze::CjsCodeAnalyzer;
|
||||
use deno_runtime::deno_node::analyze::NodeCodeTranslator;
|
||||
use deno_runtime::deno_node::DenoFsNodeResolverEnv;
|
||||
use node_resolver::analyze::CjsAnalysis as ExtNodeCjsAnalysis;
|
||||
use node_resolver::analyze::CjsAnalysisExports;
|
||||
use node_resolver::analyze::CjsCodeAnalyzer;
|
||||
use node_resolver::analyze::NodeCodeTranslator;
|
||||
use serde::Deserialize;
|
||||
use serde::Serialize;
|
||||
|
||||
|
@ -17,7 +18,8 @@ use crate::cache::CacheDBHash;
|
|||
use crate::cache::NodeAnalysisCache;
|
||||
use crate::util::fs::canonicalize_path_maybe_not_exists;
|
||||
|
||||
pub type CliNodeCodeTranslator = NodeCodeTranslator<CliCjsCodeAnalyzer>;
|
||||
pub type CliNodeCodeTranslator =
|
||||
NodeCodeTranslator<CliCjsCodeAnalyzer, DenoFsNodeResolverEnv>;
|
||||
|
||||
/// Resolves a specifier that is pointing into a node_modules folder.
|
||||
///
|
||||
|
|
|
@ -11,14 +11,18 @@ use deno_core::error::AnyError;
|
|||
use deno_core::serde_json;
|
||||
use deno_package_json::PackageJsonDepValue;
|
||||
use deno_runtime::deno_fs::FileSystem;
|
||||
use deno_runtime::deno_node::errors::PackageFolderResolveError;
|
||||
use deno_runtime::deno_node::errors::PackageFolderResolveIoError;
|
||||
use deno_runtime::deno_node::errors::PackageNotFoundError;
|
||||
use deno_runtime::deno_node::load_pkg_json;
|
||||
use deno_runtime::deno_node::DenoPkgJsonFsAdapter;
|
||||
use deno_runtime::deno_node::NodePermissions;
|
||||
use deno_runtime::deno_node::NpmResolver;
|
||||
use deno_runtime::deno_node::NodeRequireResolver;
|
||||
use deno_runtime::deno_node::NpmProcessStateProvider;
|
||||
use deno_runtime::deno_node::PackageJson;
|
||||
use deno_semver::package::PackageReq;
|
||||
use node_resolver::errors::PackageFolderResolveError;
|
||||
use node_resolver::errors::PackageFolderResolveIoError;
|
||||
use node_resolver::errors::PackageJsonLoadError;
|
||||
use node_resolver::errors::PackageNotFoundError;
|
||||
use node_resolver::load_pkg_json;
|
||||
use node_resolver::NpmResolver;
|
||||
|
||||
use crate::args::NpmProcessState;
|
||||
use crate::args::NpmProcessStateKind;
|
||||
|
@ -49,6 +53,15 @@ pub struct ByonmCliNpmResolver {
|
|||
root_node_modules_dir: Option<PathBuf>,
|
||||
}
|
||||
|
||||
impl ByonmCliNpmResolver {
|
||||
fn load_pkg_json(
|
||||
&self,
|
||||
path: &Path,
|
||||
) -> Result<Option<Arc<PackageJson>>, PackageJsonLoadError> {
|
||||
load_pkg_json(&DenoPkgJsonFsAdapter(self.fs.as_ref()), path)
|
||||
}
|
||||
}
|
||||
|
||||
impl ByonmCliNpmResolver {
|
||||
/// Finds the ancestor package.json that contains the specified dependency.
|
||||
pub fn find_ancestor_package_json_with_dep(
|
||||
|
@ -60,9 +73,7 @@ impl ByonmCliNpmResolver {
|
|||
let mut current_folder = referrer_path.parent()?;
|
||||
loop {
|
||||
let pkg_json_path = current_folder.join("package.json");
|
||||
if let Ok(Some(pkg_json)) =
|
||||
load_pkg_json(self.fs.as_ref(), &pkg_json_path)
|
||||
{
|
||||
if let Ok(Some(pkg_json)) = self.load_pkg_json(&pkg_json_path) {
|
||||
if let Some(deps) = &pkg_json.dependencies {
|
||||
if deps.contains_key(dep_name) {
|
||||
return Some(pkg_json);
|
||||
|
@ -119,9 +130,7 @@ impl ByonmCliNpmResolver {
|
|||
let mut current_path = file_path.as_path();
|
||||
while let Some(dir_path) = current_path.parent() {
|
||||
let package_json_path = dir_path.join("package.json");
|
||||
if let Some(pkg_json) =
|
||||
load_pkg_json(self.fs.as_ref(), &package_json_path)?
|
||||
{
|
||||
if let Some(pkg_json) = self.load_pkg_json(&package_json_path)? {
|
||||
if let Some(alias) =
|
||||
resolve_alias_from_pkg_json(req, pkg_json.as_ref())
|
||||
{
|
||||
|
@ -136,9 +145,7 @@ impl ByonmCliNpmResolver {
|
|||
if let Some(root_node_modules_dir) = &self.root_node_modules_dir {
|
||||
let root_pkg_json_path =
|
||||
root_node_modules_dir.parent().unwrap().join("package.json");
|
||||
if let Some(pkg_json) =
|
||||
load_pkg_json(self.fs.as_ref(), &root_pkg_json_path)?
|
||||
{
|
||||
if let Some(pkg_json) = self.load_pkg_json(&root_pkg_json_path)? {
|
||||
if let Some(alias) = resolve_alias_from_pkg_json(req, pkg_json.as_ref())
|
||||
{
|
||||
return Ok((pkg_json, alias));
|
||||
|
@ -158,17 +165,6 @@ impl ByonmCliNpmResolver {
|
|||
}
|
||||
|
||||
impl NpmResolver for ByonmCliNpmResolver {
|
||||
fn get_npm_process_state(&self) -> String {
|
||||
serde_json::to_string(&NpmProcessState {
|
||||
kind: NpmProcessStateKind::Byonm,
|
||||
local_node_modules_path: self
|
||||
.root_node_modules_dir
|
||||
.as_ref()
|
||||
.map(|p| p.to_string_lossy().to_string()),
|
||||
})
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
fn resolve_package_folder_from_package(
|
||||
&self,
|
||||
name: &str,
|
||||
|
@ -226,7 +222,9 @@ impl NpmResolver for ByonmCliNpmResolver {
|
|||
.to_ascii_lowercase()
|
||||
.contains("/node_modules/")
|
||||
}
|
||||
}
|
||||
|
||||
impl NodeRequireResolver for ByonmCliNpmResolver {
|
||||
fn ensure_read_permission(
|
||||
&self,
|
||||
permissions: &mut dyn NodePermissions,
|
||||
|
@ -242,11 +240,34 @@ impl NpmResolver for ByonmCliNpmResolver {
|
|||
}
|
||||
}
|
||||
|
||||
impl NpmProcessStateProvider for ByonmCliNpmResolver {
|
||||
fn get_npm_process_state(&self) -> String {
|
||||
serde_json::to_string(&NpmProcessState {
|
||||
kind: NpmProcessStateKind::Byonm,
|
||||
local_node_modules_path: self
|
||||
.root_node_modules_dir
|
||||
.as_ref()
|
||||
.map(|p| p.to_string_lossy().to_string()),
|
||||
})
|
||||
.unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
impl CliNpmResolver for ByonmCliNpmResolver {
|
||||
fn into_npm_resolver(self: Arc<Self>) -> Arc<dyn NpmResolver> {
|
||||
self
|
||||
}
|
||||
|
||||
fn into_require_resolver(self: Arc<Self>) -> Arc<dyn NodeRequireResolver> {
|
||||
self
|
||||
}
|
||||
|
||||
fn into_process_state_provider(
|
||||
self: Arc<Self>,
|
||||
) -> Arc<dyn NpmProcessStateProvider> {
|
||||
self
|
||||
}
|
||||
|
||||
fn clone_snapshotted(&self) -> Arc<dyn CliNpmResolver> {
|
||||
Arc::new(Self {
|
||||
fs: self.fs.clone(),
|
||||
|
|
|
@ -20,12 +20,14 @@ use deno_npm::NpmPackageId;
|
|||
use deno_npm::NpmResolutionPackage;
|
||||
use deno_npm::NpmSystemInfo;
|
||||
use deno_runtime::deno_fs::FileSystem;
|
||||
use deno_runtime::deno_node::errors::PackageFolderResolveError;
|
||||
use deno_runtime::deno_node::errors::PackageFolderResolveIoError;
|
||||
use deno_runtime::deno_node::NodePermissions;
|
||||
use deno_runtime::deno_node::NpmResolver;
|
||||
use deno_runtime::deno_node::NodeRequireResolver;
|
||||
use deno_runtime::deno_node::NpmProcessStateProvider;
|
||||
use deno_semver::package::PackageNv;
|
||||
use deno_semver::package::PackageReq;
|
||||
use node_resolver::errors::PackageFolderResolveError;
|
||||
use node_resolver::errors::PackageFolderResolveIoError;
|
||||
use node_resolver::NpmResolver;
|
||||
use resolution::AddPkgReqsResult;
|
||||
|
||||
use crate::args::CliLockfile;
|
||||
|
@ -531,14 +533,6 @@ fn npm_process_state(
|
|||
}
|
||||
|
||||
impl NpmResolver for ManagedCliNpmResolver {
|
||||
/// Gets the state of npm for the process.
|
||||
fn get_npm_process_state(&self) -> String {
|
||||
npm_process_state(
|
||||
self.resolution.serialized_valid_snapshot(),
|
||||
self.fs_resolver.node_modules_path().map(|p| p.as_path()),
|
||||
)
|
||||
}
|
||||
|
||||
fn resolve_package_folder_from_package(
|
||||
&self,
|
||||
name: &str,
|
||||
|
@ -563,7 +557,9 @@ impl NpmResolver for ManagedCliNpmResolver {
|
|||
debug_assert!(root_dir_url.as_str().ends_with('/'));
|
||||
specifier.as_ref().starts_with(root_dir_url.as_str())
|
||||
}
|
||||
}
|
||||
|
||||
impl NodeRequireResolver for ManagedCliNpmResolver {
|
||||
fn ensure_read_permission(
|
||||
&self,
|
||||
permissions: &mut dyn NodePermissions,
|
||||
|
@ -573,11 +569,30 @@ impl NpmResolver for ManagedCliNpmResolver {
|
|||
}
|
||||
}
|
||||
|
||||
impl NpmProcessStateProvider for ManagedCliNpmResolver {
|
||||
fn get_npm_process_state(&self) -> String {
|
||||
npm_process_state(
|
||||
self.resolution.serialized_valid_snapshot(),
|
||||
self.fs_resolver.node_modules_path().map(|p| p.as_path()),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl CliNpmResolver for ManagedCliNpmResolver {
|
||||
fn into_npm_resolver(self: Arc<Self>) -> Arc<dyn NpmResolver> {
|
||||
self
|
||||
}
|
||||
|
||||
fn into_require_resolver(self: Arc<Self>) -> Arc<dyn NodeRequireResolver> {
|
||||
self
|
||||
}
|
||||
|
||||
fn into_process_state_provider(
|
||||
self: Arc<Self>,
|
||||
) -> Arc<dyn NpmProcessStateProvider> {
|
||||
self
|
||||
}
|
||||
|
||||
fn clone_snapshotted(&self) -> Arc<dyn CliNpmResolver> {
|
||||
// create a new snapshotted npm resolution and resolver
|
||||
let npm_resolution = Arc::new(NpmResolution::new(
|
||||
|
|
|
@ -18,8 +18,8 @@ use deno_npm::NpmPackageCacheFolderId;
|
|||
use deno_npm::NpmPackageId;
|
||||
use deno_npm::NpmResolutionPackage;
|
||||
use deno_runtime::deno_fs::FileSystem;
|
||||
use deno_runtime::deno_node::errors::PackageFolderResolveError;
|
||||
use deno_runtime::deno_node::NodePermissions;
|
||||
use node_resolver::errors::PackageFolderResolveError;
|
||||
|
||||
use crate::npm::managed::cache::TarballCache;
|
||||
|
||||
|
|
|
@ -14,10 +14,10 @@ use deno_npm::NpmPackageCacheFolderId;
|
|||
use deno_npm::NpmPackageId;
|
||||
use deno_npm::NpmSystemInfo;
|
||||
use deno_runtime::deno_fs::FileSystem;
|
||||
use deno_runtime::deno_node::errors::PackageFolderResolveError;
|
||||
use deno_runtime::deno_node::errors::PackageNotFoundError;
|
||||
use deno_runtime::deno_node::errors::ReferrerNotFoundError;
|
||||
use deno_runtime::deno_node::NodePermissions;
|
||||
use node_resolver::errors::PackageFolderResolveError;
|
||||
use node_resolver::errors::PackageNotFoundError;
|
||||
use node_resolver::errors::ReferrerNotFoundError;
|
||||
|
||||
use super::super::cache::NpmCache;
|
||||
use super::super::cache::TarballCache;
|
||||
|
|
|
@ -32,12 +32,12 @@ use deno_npm::NpmPackageId;
|
|||
use deno_npm::NpmResolutionPackage;
|
||||
use deno_npm::NpmSystemInfo;
|
||||
use deno_runtime::deno_fs;
|
||||
use deno_runtime::deno_node::errors::PackageFolderResolveError;
|
||||
use deno_runtime::deno_node::errors::PackageFolderResolveIoError;
|
||||
use deno_runtime::deno_node::errors::PackageNotFoundError;
|
||||
use deno_runtime::deno_node::errors::ReferrerNotFoundError;
|
||||
use deno_runtime::deno_node::NodePermissions;
|
||||
use deno_semver::package::PackageNv;
|
||||
use node_resolver::errors::PackageFolderResolveError;
|
||||
use node_resolver::errors::PackageFolderResolveIoError;
|
||||
use node_resolver::errors::PackageNotFoundError;
|
||||
use node_resolver::errors::ReferrerNotFoundError;
|
||||
use serde::Deserialize;
|
||||
use serde::Serialize;
|
||||
|
||||
|
|
|
@ -13,10 +13,12 @@ use deno_ast::ModuleSpecifier;
|
|||
use deno_core::error::AnyError;
|
||||
use deno_core::serde_json;
|
||||
use deno_npm::registry::NpmPackageInfo;
|
||||
use deno_runtime::deno_node::NpmResolver;
|
||||
use deno_runtime::deno_node::NodeRequireResolver;
|
||||
use deno_runtime::deno_node::NpmProcessStateProvider;
|
||||
use deno_runtime::deno_permissions::PermissionsContainer;
|
||||
use deno_semver::package::PackageNv;
|
||||
use deno_semver::package::PackageReq;
|
||||
use node_resolver::NpmResolver;
|
||||
|
||||
use crate::args::npm_registry_url;
|
||||
use crate::file_fetcher::FileFetcher;
|
||||
|
@ -63,6 +65,10 @@ pub enum InnerCliNpmResolverRef<'a> {
|
|||
|
||||
pub trait CliNpmResolver: NpmResolver {
|
||||
fn into_npm_resolver(self: Arc<Self>) -> Arc<dyn NpmResolver>;
|
||||
fn into_require_resolver(self: Arc<Self>) -> Arc<dyn NodeRequireResolver>;
|
||||
fn into_process_state_provider(
|
||||
self: Arc<Self>,
|
||||
) -> Arc<dyn NpmProcessStateProvider>;
|
||||
|
||||
fn clone_snapshotted(&self) -> Arc<dyn CliNpmResolver>;
|
||||
|
||||
|
|
|
@ -23,23 +23,23 @@ use deno_npm::resolution::NpmResolutionError;
|
|||
use deno_package_json::PackageJsonDepValue;
|
||||
use deno_runtime::deno_fs;
|
||||
use deno_runtime::deno_fs::FileSystem;
|
||||
use deno_runtime::deno_node::errors::ClosestPkgJsonError;
|
||||
use deno_runtime::deno_node::errors::NodeResolveError;
|
||||
use deno_runtime::deno_node::errors::NodeResolveErrorKind;
|
||||
use deno_runtime::deno_node::errors::PackageFolderResolveErrorKind;
|
||||
use deno_runtime::deno_node::errors::PackageFolderResolveIoError;
|
||||
use deno_runtime::deno_node::errors::PackageNotFoundError;
|
||||
use deno_runtime::deno_node::errors::PackageResolveErrorKind;
|
||||
use deno_runtime::deno_node::errors::UrlToNodeResolutionError;
|
||||
use deno_runtime::deno_node::is_builtin_node_module;
|
||||
use deno_runtime::deno_node::NodeModuleKind;
|
||||
use deno_runtime::deno_node::NodeResolution;
|
||||
use deno_runtime::deno_node::NodeResolutionMode;
|
||||
use deno_runtime::deno_node::NodeResolver;
|
||||
use deno_runtime::deno_node::PackageJson;
|
||||
use deno_runtime::fs_util::specifier_to_file_path;
|
||||
use deno_semver::npm::NpmPackageReqReference;
|
||||
use deno_semver::package::PackageReq;
|
||||
use node_resolver::errors::ClosestPkgJsonError;
|
||||
use node_resolver::errors::NodeResolveError;
|
||||
use node_resolver::errors::NodeResolveErrorKind;
|
||||
use node_resolver::errors::PackageFolderResolveErrorKind;
|
||||
use node_resolver::errors::PackageFolderResolveIoError;
|
||||
use node_resolver::errors::PackageNotFoundError;
|
||||
use node_resolver::errors::PackageResolveErrorKind;
|
||||
use node_resolver::errors::UrlToNodeResolutionError;
|
||||
use node_resolver::NodeModuleKind;
|
||||
use node_resolver::NodeResolution;
|
||||
use node_resolver::NodeResolutionMode;
|
||||
use node_resolver::PackageJson;
|
||||
use std::borrow::Cow;
|
||||
use std::path::Path;
|
||||
use std::path::PathBuf;
|
||||
|
|
|
@ -5,6 +5,42 @@
|
|||
#![allow(dead_code)]
|
||||
#![allow(unused_imports)]
|
||||
|
||||
use deno_ast::MediaType;
|
||||
use deno_config::workspace::MappedResolution;
|
||||
use deno_config::workspace::MappedResolutionError;
|
||||
use deno_config::workspace::WorkspaceResolver;
|
||||
use deno_core::anyhow::Context;
|
||||
use deno_core::error::generic_error;
|
||||
use deno_core::error::type_error;
|
||||
use deno_core::error::AnyError;
|
||||
use deno_core::futures::FutureExt;
|
||||
use deno_core::v8_set_flags;
|
||||
use deno_core::FeatureChecker;
|
||||
use deno_core::ModuleLoader;
|
||||
use deno_core::ModuleSourceCode;
|
||||
use deno_core::ModuleSpecifier;
|
||||
use deno_core::ModuleType;
|
||||
use deno_core::RequestedModuleType;
|
||||
use deno_core::ResolutionKind;
|
||||
use deno_npm::npm_rc::ResolvedNpmRc;
|
||||
use deno_package_json::PackageJsonDepValue;
|
||||
use deno_runtime::deno_fs;
|
||||
use deno_runtime::deno_node::NodeResolver;
|
||||
use deno_runtime::deno_permissions::Permissions;
|
||||
use deno_runtime::deno_permissions::PermissionsContainer;
|
||||
use deno_runtime::deno_tls::rustls::RootCertStore;
|
||||
use deno_runtime::deno_tls::RootCertStoreProvider;
|
||||
use deno_runtime::WorkerExecutionMode;
|
||||
use deno_runtime::WorkerLogLevel;
|
||||
use deno_semver::npm::NpmPackageReqReference;
|
||||
use eszip::EszipRelativeFileBaseUrl;
|
||||
use import_map::parse_from_json;
|
||||
use node_resolver::analyze::NodeCodeTranslator;
|
||||
use node_resolver::NodeResolutionMode;
|
||||
use std::borrow::Cow;
|
||||
use std::rc::Rc;
|
||||
use std::sync::Arc;
|
||||
|
||||
use crate::args::create_default_npmrc;
|
||||
use crate::args::get_root_cert_store;
|
||||
use crate::args::npm_pkg_req_ref_to_binary_command;
|
||||
|
@ -33,41 +69,6 @@ use crate::worker::CliMainWorkerFactory;
|
|||
use crate::worker::CliMainWorkerOptions;
|
||||
use crate::worker::ModuleLoaderAndSourceMapGetter;
|
||||
use crate::worker::ModuleLoaderFactory;
|
||||
use deno_ast::MediaType;
|
||||
use deno_config::workspace::MappedResolution;
|
||||
use deno_config::workspace::MappedResolutionError;
|
||||
use deno_config::workspace::WorkspaceResolver;
|
||||
use deno_core::anyhow::Context;
|
||||
use deno_core::error::generic_error;
|
||||
use deno_core::error::type_error;
|
||||
use deno_core::error::AnyError;
|
||||
use deno_core::futures::FutureExt;
|
||||
use deno_core::v8_set_flags;
|
||||
use deno_core::FeatureChecker;
|
||||
use deno_core::ModuleLoader;
|
||||
use deno_core::ModuleSourceCode;
|
||||
use deno_core::ModuleSpecifier;
|
||||
use deno_core::ModuleType;
|
||||
use deno_core::RequestedModuleType;
|
||||
use deno_core::ResolutionKind;
|
||||
use deno_npm::npm_rc::ResolvedNpmRc;
|
||||
use deno_package_json::PackageJsonDepValue;
|
||||
use deno_runtime::deno_fs;
|
||||
use deno_runtime::deno_node::analyze::NodeCodeTranslator;
|
||||
use deno_runtime::deno_node::NodeResolutionMode;
|
||||
use deno_runtime::deno_node::NodeResolver;
|
||||
use deno_runtime::deno_permissions::Permissions;
|
||||
use deno_runtime::deno_permissions::PermissionsContainer;
|
||||
use deno_runtime::deno_tls::rustls::RootCertStore;
|
||||
use deno_runtime::deno_tls::RootCertStoreProvider;
|
||||
use deno_runtime::WorkerExecutionMode;
|
||||
use deno_runtime::WorkerLogLevel;
|
||||
use deno_semver::npm::NpmPackageReqReference;
|
||||
use eszip::EszipRelativeFileBaseUrl;
|
||||
use import_map::parse_from_json;
|
||||
use std::borrow::Cow;
|
||||
use std::rc::Rc;
|
||||
use std::sync::Arc;
|
||||
|
||||
pub mod binary;
|
||||
mod file_system;
|
||||
|
@ -549,7 +550,7 @@ pub async fn run(
|
|||
|
||||
let has_node_modules_dir = npm_resolver.root_node_modules_path().is_some();
|
||||
let node_resolver = Arc::new(NodeResolver::new(
|
||||
fs.clone(),
|
||||
deno_runtime::deno_node::DenoFsNodeResolverEnv::new(fs.clone()),
|
||||
npm_resolver.clone().into_npm_resolver(),
|
||||
));
|
||||
let cjs_resolutions = Arc::new(CjsResolutionStore::default());
|
||||
|
@ -559,7 +560,7 @@ pub async fn run(
|
|||
CliCjsCodeAnalyzer::new(node_analysis_cache, fs.clone());
|
||||
let node_code_translator = Arc::new(NodeCodeTranslator::new(
|
||||
cjs_esm_code_analyzer,
|
||||
fs.clone(),
|
||||
deno_runtime::deno_node::DenoFsNodeResolverEnv::new(fs.clone()),
|
||||
node_resolver.clone(),
|
||||
npm_resolver.clone().into_npm_resolver(),
|
||||
));
|
||||
|
|
|
@ -308,7 +308,7 @@ pub async fn add(
|
|||
.context("Failed to update configuration file")?;
|
||||
|
||||
// clear the previously cached package.json from memory before reloading it
|
||||
deno_node::PackageJsonThreadLocalCache::clear();
|
||||
node_resolver::PackageJsonThreadLocalCache::clear();
|
||||
// make a new CliFactory to pick up the updated config file
|
||||
let cli_factory = CliFactory::from_flags(flags);
|
||||
// cache deps
|
||||
|
|
|
@ -30,14 +30,14 @@ use deno_graph::GraphKind;
|
|||
use deno_graph::Module;
|
||||
use deno_graph::ModuleGraph;
|
||||
use deno_graph::ResolutionResolved;
|
||||
use deno_runtime::deno_node::errors::NodeJsErrorCode;
|
||||
use deno_runtime::deno_node::errors::NodeJsErrorCoded;
|
||||
use deno_runtime::deno_node::NodeModuleKind;
|
||||
use deno_runtime::deno_node::NodeResolution;
|
||||
use deno_runtime::deno_node::NodeResolutionMode;
|
||||
use deno_runtime::deno_node::NodeResolver;
|
||||
use deno_semver::npm::NpmPackageReqReference;
|
||||
use lsp_types::Url;
|
||||
use node_resolver::errors::NodeJsErrorCode;
|
||||
use node_resolver::errors::NodeJsErrorCoded;
|
||||
use node_resolver::NodeModuleKind;
|
||||
use node_resolver::NodeResolution;
|
||||
use node_resolver::NodeResolutionMode;
|
||||
use once_cell::sync::Lazy;
|
||||
use std::borrow::Cow;
|
||||
use std::collections::HashMap;
|
||||
|
|
|
@ -22,8 +22,7 @@ use deno_runtime::code_cache;
|
|||
use deno_runtime::deno_broadcast_channel::InMemoryBroadcastChannel;
|
||||
use deno_runtime::deno_fs;
|
||||
use deno_runtime::deno_node;
|
||||
use deno_runtime::deno_node::NodeResolution;
|
||||
use deno_runtime::deno_node::NodeResolutionMode;
|
||||
use deno_runtime::deno_node::NodeExtInitServices;
|
||||
use deno_runtime::deno_node::NodeResolver;
|
||||
use deno_runtime::deno_permissions::PermissionsContainer;
|
||||
use deno_runtime::deno_tls::RootCertStoreProvider;
|
||||
|
@ -40,6 +39,8 @@ use deno_runtime::WorkerExecutionMode;
|
|||
use deno_runtime::WorkerLogLevel;
|
||||
use deno_semver::npm::NpmPackageReqReference;
|
||||
use deno_terminal::colors;
|
||||
use node_resolver::NodeResolution;
|
||||
use node_resolver::NodeResolutionMode;
|
||||
use tokio::select;
|
||||
|
||||
use crate::args::CliLockfile;
|
||||
|
@ -144,7 +145,17 @@ struct SharedWorkerState {
|
|||
}
|
||||
|
||||
impl SharedWorkerState {
|
||||
// Currently empty
|
||||
pub fn create_node_init_services(&self) -> NodeExtInitServices {
|
||||
NodeExtInitServices {
|
||||
node_require_resolver: self.npm_resolver.clone().into_require_resolver(),
|
||||
node_resolver: self.node_resolver.clone(),
|
||||
npm_process_state_provider: self
|
||||
.npm_resolver
|
||||
.clone()
|
||||
.into_process_state_provider(),
|
||||
npm_resolver: self.npm_resolver.clone().into_npm_resolver(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct CliMainWorker {
|
||||
|
@ -599,8 +610,7 @@ impl CliMainWorkerFactory {
|
|||
strace_ops: shared.options.strace_ops.clone(),
|
||||
module_loader,
|
||||
fs: shared.fs.clone(),
|
||||
node_resolver: Some(shared.node_resolver.clone()),
|
||||
npm_resolver: Some(shared.npm_resolver.clone().into_npm_resolver()),
|
||||
node_services: Some(shared.create_node_init_services()),
|
||||
get_error_class_fn: Some(&errors::get_error_class_name),
|
||||
cache_storage_dir,
|
||||
origin_storage_dir,
|
||||
|
@ -793,8 +803,7 @@ fn create_web_worker_callback(
|
|||
format_js_error_fn: Some(Arc::new(format_js_error)),
|
||||
module_loader,
|
||||
fs: shared.fs.clone(),
|
||||
node_resolver: Some(shared.node_resolver.clone()),
|
||||
npm_resolver: Some(shared.npm_resolver.clone().into_npm_resolver()),
|
||||
node_services: Some(shared.create_node_init_services()),
|
||||
worker_type: args.worker_type,
|
||||
maybe_inspector_server,
|
||||
get_error_class_fn: Some(&errors::get_error_class_name),
|
||||
|
|
|
@ -1,24 +1,24 @@
|
|||
disallowed-methods = [
|
||||
{ path = "std::env::current_dir", reason = "File system operations should be done using FileSystem trait" },
|
||||
{ path = "std::path::Path::canonicalize", reason = "File system operations should be done using NodeFs trait" },
|
||||
{ path = "std::path::Path::is_dir", reason = "File system operations should be done using NodeFs trait" },
|
||||
{ path = "std::path::Path::is_file", reason = "File system operations should be done using NodeFs trait" },
|
||||
{ path = "std::path::Path::is_symlink", reason = "File system operations should be done using NodeFs trait" },
|
||||
{ path = "std::path::Path::metadata", reason = "File system operations should be done using NodeFs trait" },
|
||||
{ path = "std::path::Path::read_dir", reason = "File system operations should be done using NodeFs trait" },
|
||||
{ path = "std::path::Path::read_link", reason = "File system operations should be done using NodeFs trait" },
|
||||
{ path = "std::path::Path::symlink_metadata", reason = "File system operations should be done using NodeFs trait" },
|
||||
{ path = "std::path::Path::try_exists", reason = "File system operations should be done using NodeFs trait" },
|
||||
{ path = "std::path::PathBuf::exists", reason = "File system operations should be done using NodeFs trait" },
|
||||
{ path = "std::path::PathBuf::canonicalize", reason = "File system operations should be done using NodeFs trait" },
|
||||
{ path = "std::path::PathBuf::is_dir", reason = "File system operations should be done using NodeFs trait" },
|
||||
{ path = "std::path::PathBuf::is_file", reason = "File system operations should be done using NodeFs trait" },
|
||||
{ path = "std::path::PathBuf::is_symlink", reason = "File system operations should be done using NodeFs trait" },
|
||||
{ path = "std::path::PathBuf::metadata", reason = "File system operations should be done using NodeFs trait" },
|
||||
{ path = "std::path::PathBuf::read_dir", reason = "File system operations should be done using NodeFs trait" },
|
||||
{ path = "std::path::PathBuf::read_link", reason = "File system operations should be done using NodeFs trait" },
|
||||
{ path = "std::path::PathBuf::symlink_metadata", reason = "File system operations should be done using NodeFs trait" },
|
||||
{ path = "std::path::PathBuf::try_exists", reason = "File system operations should be done using NodeFs trait" },
|
||||
{ path = "std::path::Path::canonicalize", reason = "File system operations should be done using FileSystem trait" },
|
||||
{ path = "std::path::Path::is_dir", reason = "File system operations should be done using FileSystem trait" },
|
||||
{ path = "std::path::Path::is_file", reason = "File system operations should be done using FileSystem trait" },
|
||||
{ path = "std::path::Path::is_symlink", reason = "File system operations should be done using FileSystem trait" },
|
||||
{ path = "std::path::Path::metadata", reason = "File system operations should be done using FileSystem trait" },
|
||||
{ path = "std::path::Path::read_dir", reason = "File system operations should be done using FileSystem trait" },
|
||||
{ path = "std::path::Path::read_link", reason = "File system operations should be done using FileSystem trait" },
|
||||
{ path = "std::path::Path::symlink_metadata", reason = "File system operations should be done using FileSystem trait" },
|
||||
{ path = "std::path::Path::try_exists", reason = "File system operations should be done using FileSystem trait" },
|
||||
{ path = "std::path::PathBuf::exists", reason = "File system operations should be done using FileSystem trait" },
|
||||
{ path = "std::path::PathBuf::canonicalize", reason = "File system operations should be done using FileSystem trait" },
|
||||
{ path = "std::path::PathBuf::is_dir", reason = "File system operations should be done using FileSystem trait" },
|
||||
{ path = "std::path::PathBuf::is_file", reason = "File system operations should be done using FileSystem trait" },
|
||||
{ path = "std::path::PathBuf::is_symlink", reason = "File system operations should be done using FileSystem trait" },
|
||||
{ path = "std::path::PathBuf::metadata", reason = "File system operations should be done using FileSystem trait" },
|
||||
{ path = "std::path::PathBuf::read_dir", reason = "File system operations should be done using FileSystem trait" },
|
||||
{ path = "std::path::PathBuf::read_link", reason = "File system operations should be done using FileSystem trait" },
|
||||
{ path = "std::path::PathBuf::symlink_metadata", reason = "File system operations should be done using FileSystem trait" },
|
||||
{ path = "std::path::PathBuf::try_exists", reason = "File system operations should be done using FileSystem trait" },
|
||||
{ path = "std::env::set_current_dir", reason = "File system operations should be done using FileSystem trait" },
|
||||
{ path = "std::env::temp_dir", reason = "File system operations should be done using FileSystem trait" },
|
||||
{ path = "std::fs::canonicalize", reason = "File system operations should be done using FileSystem trait" },
|
||||
|
|
|
@ -6,80 +6,18 @@ pub use inner::*;
|
|||
mod inner {
|
||||
#![allow(clippy::disallowed_types)]
|
||||
|
||||
use std::ops::Deref;
|
||||
use std::ops::DerefMut;
|
||||
pub use std::sync::Arc as MaybeArc;
|
||||
|
||||
pub use core::marker::Send as MaybeSend;
|
||||
pub use core::marker::Sync as MaybeSync;
|
||||
|
||||
pub struct MaybeArcMutexGuard<'lock, T>(std::sync::MutexGuard<'lock, T>);
|
||||
|
||||
impl<'lock, T> Deref for MaybeArcMutexGuard<'lock, T> {
|
||||
type Target = std::sync::MutexGuard<'lock, T>;
|
||||
fn deref(&self) -> &std::sync::MutexGuard<'lock, T> {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl<'lock, T> DerefMut for MaybeArcMutexGuard<'lock, T> {
|
||||
fn deref_mut(&mut self) -> &mut std::sync::MutexGuard<'lock, T> {
|
||||
&mut self.0
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct MaybeArcMutex<T>(std::sync::Arc<std::sync::Mutex<T>>);
|
||||
impl<T> MaybeArcMutex<T> {
|
||||
pub fn new(val: T) -> Self {
|
||||
Self(std::sync::Arc::new(std::sync::Mutex::new(val)))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'lock, T> MaybeArcMutex<T> {
|
||||
pub fn lock(&'lock self) -> MaybeArcMutexGuard<'lock, T> {
|
||||
MaybeArcMutexGuard(self.0.lock().unwrap())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "sync_fs"))]
|
||||
mod inner {
|
||||
use std::ops::Deref;
|
||||
use std::ops::DerefMut;
|
||||
pub use std::rc::Rc as MaybeArc;
|
||||
|
||||
pub trait MaybeSync {}
|
||||
impl<T> MaybeSync for T where T: ?Sized {}
|
||||
pub trait MaybeSend {}
|
||||
impl<T> MaybeSend for T where T: ?Sized {}
|
||||
|
||||
pub struct MaybeArcMutexGuard<'lock, T>(std::cell::RefMut<'lock, T>);
|
||||
|
||||
impl<'lock, T> Deref for MaybeArcMutexGuard<'lock, T> {
|
||||
type Target = std::cell::RefMut<'lock, T>;
|
||||
fn deref(&self) -> &std::cell::RefMut<'lock, T> {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl<'lock, T> DerefMut for MaybeArcMutexGuard<'lock, T> {
|
||||
fn deref_mut(&mut self) -> &mut std::cell::RefMut<'lock, T> {
|
||||
&mut self.0
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct MaybeArcMutex<T>(std::rc::Rc<std::cell::RefCell<T>>);
|
||||
impl<T> MaybeArcMutex<T> {
|
||||
pub fn new(val: T) -> Self {
|
||||
Self(std::rc::Rc::new(std::cell::RefCell::new(val)))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'lock, T> MaybeArcMutex<T> {
|
||||
pub fn lock(&'lock self) -> MaybeArcMutexGuard<'lock, T> {
|
||||
MaybeArcMutexGuard(self.0.borrow_mut())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,7 +14,7 @@ description = "Node compatibility for Deno"
|
|||
path = "lib.rs"
|
||||
|
||||
[features]
|
||||
sync_fs = ["deno_package_json/sync"]
|
||||
sync_fs = ["deno_package_json/sync", "node_resolver/sync"]
|
||||
|
||||
[dependencies]
|
||||
aead-gcm-stream = "0.1"
|
||||
|
@ -55,6 +55,7 @@ libc.workspace = true
|
|||
libz-sys.workspace = true
|
||||
md-5 = { version = "0.10.5", features = ["oid"] }
|
||||
md4 = "0.10.2"
|
||||
node_resolver.workspace = true
|
||||
num-bigint.workspace = true
|
||||
num-bigint-dig = "0.8.2"
|
||||
num-integer = "0.1.45"
|
||||
|
|
|
@ -6,7 +6,7 @@ use deno_core::v8;
|
|||
use deno_core::v8::GetPropertyNamesArgs;
|
||||
use deno_core::v8::MapFnTo;
|
||||
|
||||
use crate::resolution::NodeResolverRc;
|
||||
use crate::NodeResolverRc;
|
||||
|
||||
// NOTE(bartlomieju): somehow calling `.map_fn_to()` multiple times on a function
|
||||
// returns two different pointers. That shouldn't be the case as `.map_fn_to()`
|
||||
|
|
159
ext/node/lib.rs
159
ext/node/lib.rs
|
@ -5,7 +5,6 @@
|
|||
|
||||
use std::collections::HashSet;
|
||||
use std::path::Path;
|
||||
use std::path::PathBuf;
|
||||
|
||||
use deno_core::error::AnyError;
|
||||
use deno_core::located_script_name;
|
||||
|
@ -15,24 +14,20 @@ use deno_core::url::Url;
|
|||
use deno_core::v8;
|
||||
use deno_core::v8::ExternalReference;
|
||||
use deno_core::JsRuntime;
|
||||
use deno_core::ModuleSpecifier;
|
||||
use deno_core::OpState;
|
||||
use deno_fs::sync::MaybeSend;
|
||||
use deno_fs::sync::MaybeSync;
|
||||
use node_resolver::NpmResolverRc;
|
||||
use once_cell::sync::Lazy;
|
||||
|
||||
extern crate libz_sys as zlib;
|
||||
|
||||
pub mod analyze;
|
||||
pub mod errors;
|
||||
mod global;
|
||||
mod ops;
|
||||
mod package_json;
|
||||
mod path;
|
||||
mod polyfill;
|
||||
mod resolution;
|
||||
|
||||
pub use deno_package_json::PackageJson;
|
||||
pub use node_resolver::PathClean;
|
||||
pub use ops::ipc::ChildPipeFd;
|
||||
pub use ops::ipc::IpcJsonStreamResource;
|
||||
use ops::vm;
|
||||
|
@ -40,17 +35,9 @@ pub use ops::vm::create_v8_context;
|
|||
pub use ops::vm::init_global_template;
|
||||
pub use ops::vm::ContextInitMode;
|
||||
pub use ops::vm::VM_CONTEXT_INDEX;
|
||||
pub use package_json::load_pkg_json;
|
||||
pub use package_json::PackageJsonThreadLocalCache;
|
||||
pub use path::PathClean;
|
||||
pub use polyfill::is_builtin_node_module;
|
||||
pub use polyfill::SUPPORTED_BUILTIN_NODE_MODULES;
|
||||
pub use polyfill::SUPPORTED_BUILTIN_NODE_MODULES_WITH_PREFIX;
|
||||
pub use resolution::NodeModuleKind;
|
||||
pub use resolution::NodeResolution;
|
||||
pub use resolution::NodeResolutionMode;
|
||||
pub use resolution::NodeResolver;
|
||||
use resolution::NodeResolverRc;
|
||||
|
||||
use crate::global::global_object_middleware;
|
||||
use crate::global::global_template_middleware;
|
||||
|
@ -149,9 +136,12 @@ impl NodePermissions for deno_permissions::PermissionsContainer {
|
|||
}
|
||||
|
||||
#[allow(clippy::disallowed_types)]
|
||||
pub type NpmResolverRc = deno_fs::sync::MaybeArc<dyn NpmResolver>;
|
||||
pub type NpmProcessStateProviderRc =
|
||||
deno_fs::sync::MaybeArc<dyn NpmProcessStateProvider>;
|
||||
|
||||
pub trait NpmResolver: std::fmt::Debug + MaybeSend + MaybeSync {
|
||||
pub trait NpmProcessStateProvider:
|
||||
std::fmt::Debug + MaybeSend + MaybeSync
|
||||
{
|
||||
/// Gets a string containing the serialized npm state of the process.
|
||||
///
|
||||
/// This will be set on the `DENO_DONT_USE_INTERNAL_NODE_COMPAT_STATE` environment
|
||||
|
@ -161,34 +151,13 @@ pub trait NpmResolver: std::fmt::Debug + MaybeSend + MaybeSync {
|
|||
// This method is only used in the CLI.
|
||||
String::new()
|
||||
}
|
||||
|
||||
/// Resolves an npm package folder path from an npm package referrer.
|
||||
fn resolve_package_folder_from_package(
|
||||
&self,
|
||||
specifier: &str,
|
||||
referrer: &ModuleSpecifier,
|
||||
) -> Result<PathBuf, errors::PackageFolderResolveError>;
|
||||
|
||||
fn in_npm_package(&self, specifier: &ModuleSpecifier) -> bool;
|
||||
|
||||
fn in_npm_package_at_dir_path(&self, path: &Path) -> bool {
|
||||
let specifier =
|
||||
match ModuleSpecifier::from_directory_path(path.to_path_buf().clean()) {
|
||||
Ok(p) => p,
|
||||
Err(_) => return false,
|
||||
};
|
||||
self.in_npm_package(&specifier)
|
||||
}
|
||||
|
||||
fn in_npm_package_at_file_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)
|
||||
}
|
||||
#[allow(clippy::disallowed_types)]
|
||||
pub type NodeRequireResolverRc =
|
||||
deno_fs::sync::MaybeArc<dyn NodeRequireResolver>;
|
||||
|
||||
pub trait NodeRequireResolver: std::fmt::Debug + MaybeSend + MaybeSync {
|
||||
fn ensure_read_permission(
|
||||
&self,
|
||||
permissions: &mut dyn NodePermissions,
|
||||
|
@ -223,10 +192,17 @@ fn op_node_is_promise_rejected(value: v8::Local<v8::Value>) -> bool {
|
|||
#[op2]
|
||||
#[string]
|
||||
fn op_npm_process_state(state: &mut OpState) -> Result<String, AnyError> {
|
||||
let npm_resolver = state.borrow_mut::<NpmResolverRc>();
|
||||
let npm_resolver = state.borrow_mut::<NpmProcessStateProviderRc>();
|
||||
Ok(npm_resolver.get_npm_process_state())
|
||||
}
|
||||
|
||||
pub struct NodeExtInitServices {
|
||||
pub node_require_resolver: NodeRequireResolverRc,
|
||||
pub node_resolver: NodeResolverRc,
|
||||
pub npm_process_state_provider: NpmProcessStateProviderRc,
|
||||
pub npm_resolver: NpmResolverRc,
|
||||
}
|
||||
|
||||
deno_core::extension!(deno_node,
|
||||
deps = [ deno_io, deno_fs ],
|
||||
parameters = [P: NodePermissions],
|
||||
|
@ -643,21 +619,17 @@ deno_core::extension!(deno_node,
|
|||
"node:zlib" = "zlib.ts",
|
||||
],
|
||||
options = {
|
||||
maybe_node_resolver: Option<NodeResolverRc>,
|
||||
maybe_npm_resolver: Option<NpmResolverRc>,
|
||||
maybe_init: Option<NodeExtInitServices>,
|
||||
fs: deno_fs::FileSystemRc,
|
||||
},
|
||||
state = |state, options| {
|
||||
// you should provide both of these or neither
|
||||
debug_assert_eq!(options.maybe_node_resolver.is_some(), options.maybe_npm_resolver.is_some());
|
||||
|
||||
state.put(options.fs.clone());
|
||||
|
||||
if let Some(node_resolver) = &options.maybe_node_resolver {
|
||||
state.put(node_resolver.clone());
|
||||
}
|
||||
if let Some(npm_resolver) = &options.maybe_npm_resolver {
|
||||
state.put(npm_resolver.clone());
|
||||
if let Some(init) = &options.maybe_init {
|
||||
state.put(init.node_require_resolver.clone());
|
||||
state.put(init.node_resolver.clone());
|
||||
state.put(init.npm_resolver.clone());
|
||||
state.put(init.npm_process_state_provider.clone());
|
||||
}
|
||||
},
|
||||
global_template_middleware = global_template_middleware,
|
||||
|
@ -783,3 +755,84 @@ pub fn load_cjs_module(
|
|||
js_runtime.execute_script(located_script_name!(), source_code)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub type NodeResolver = node_resolver::NodeResolver<DenoFsNodeResolverEnv>;
|
||||
#[allow(clippy::disallowed_types)]
|
||||
pub type NodeResolverRc =
|
||||
deno_fs::sync::MaybeArc<node_resolver::NodeResolver<DenoFsNodeResolverEnv>>;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct DenoFsNodeResolverEnv {
|
||||
fs: deno_fs::FileSystemRc,
|
||||
}
|
||||
|
||||
impl DenoFsNodeResolverEnv {
|
||||
pub fn new(fs: deno_fs::FileSystemRc) -> Self {
|
||||
Self { fs }
|
||||
}
|
||||
}
|
||||
|
||||
impl node_resolver::env::NodeResolverEnv for DenoFsNodeResolverEnv {
|
||||
fn is_builtin_node_module(&self, specifier: &str) -> bool {
|
||||
is_builtin_node_module(specifier)
|
||||
}
|
||||
|
||||
fn realpath_sync(
|
||||
&self,
|
||||
path: &std::path::Path,
|
||||
) -> std::io::Result<std::path::PathBuf> {
|
||||
self
|
||||
.fs
|
||||
.realpath_sync(path)
|
||||
.map_err(|err| err.into_io_error())
|
||||
}
|
||||
|
||||
fn stat_sync(
|
||||
&self,
|
||||
path: &std::path::Path,
|
||||
) -> std::io::Result<node_resolver::env::NodeResolverFsStat> {
|
||||
self
|
||||
.fs
|
||||
.stat_sync(path)
|
||||
.map(|stat| node_resolver::env::NodeResolverFsStat {
|
||||
is_file: stat.is_file,
|
||||
is_dir: stat.is_directory,
|
||||
is_symlink: stat.is_symlink,
|
||||
})
|
||||
.map_err(|err| err.into_io_error())
|
||||
}
|
||||
|
||||
fn exists_sync(&self, path: &std::path::Path) -> bool {
|
||||
self.fs.exists_sync(path)
|
||||
}
|
||||
|
||||
fn pkg_json_fs(&self) -> &dyn deno_package_json::fs::DenoPkgJsonFs {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl deno_package_json::fs::DenoPkgJsonFs for DenoFsNodeResolverEnv {
|
||||
fn read_to_string_lossy(
|
||||
&self,
|
||||
path: &std::path::Path,
|
||||
) -> Result<String, std::io::Error> {
|
||||
self
|
||||
.fs
|
||||
.read_text_file_lossy_sync(path, None)
|
||||
.map_err(|err| err.into_io_error())
|
||||
}
|
||||
}
|
||||
|
||||
pub struct DenoPkgJsonFsAdapter<'a>(pub &'a dyn deno_fs::FileSystem);
|
||||
|
||||
impl<'a> deno_package_json::fs::DenoPkgJsonFs for DenoPkgJsonFsAdapter<'a> {
|
||||
fn read_to_string_lossy(
|
||||
&self,
|
||||
path: &Path,
|
||||
) -> Result<String, std::io::Error> {
|
||||
self
|
||||
.0
|
||||
.read_text_file_lossy_sync(path, None)
|
||||
.map_err(|err| err.into_io_error())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,16 +10,17 @@ use deno_core::JsRuntimeInspector;
|
|||
use deno_core::ModuleSpecifier;
|
||||
use deno_core::OpState;
|
||||
use deno_fs::FileSystemRc;
|
||||
use node_resolver::NodeModuleKind;
|
||||
use node_resolver::NodeResolutionMode;
|
||||
use node_resolver::REQUIRE_CONDITIONS;
|
||||
use std::cell::RefCell;
|
||||
use std::path::Path;
|
||||
use std::path::PathBuf;
|
||||
use std::rc::Rc;
|
||||
|
||||
use crate::resolution;
|
||||
use crate::resolution::NodeResolverRc;
|
||||
use crate::NodeModuleKind;
|
||||
use crate::NodePermissions;
|
||||
use crate::NodeResolutionMode;
|
||||
use crate::NodeRequireResolverRc;
|
||||
use crate::NodeResolverRc;
|
||||
use crate::NpmResolverRc;
|
||||
use crate::PackageJson;
|
||||
|
||||
|
@ -30,7 +31,7 @@ fn ensure_read_permission<P>(
|
|||
where
|
||||
P: NodePermissions + 'static,
|
||||
{
|
||||
let resolver = state.borrow::<NpmResolverRc>().clone();
|
||||
let resolver = state.borrow::<NodeRequireResolverRc>().clone();
|
||||
let permissions = state.borrow_mut::<P>();
|
||||
resolver.ensure_read_permission(permissions, file_path)
|
||||
}
|
||||
|
@ -423,7 +424,7 @@ where
|
|||
exports,
|
||||
Some(&referrer),
|
||||
NodeModuleKind::Cjs,
|
||||
resolution::REQUIRE_CONDITIONS,
|
||||
REQUIRE_CONDITIONS,
|
||||
NodeResolutionMode::Execution,
|
||||
)?;
|
||||
Ok(Some(if r.scheme() == "file" {
|
||||
|
@ -511,7 +512,7 @@ where
|
|||
exports,
|
||||
Some(&referrer),
|
||||
NodeModuleKind::Cjs,
|
||||
resolution::REQUIRE_CONDITIONS,
|
||||
REQUIRE_CONDITIONS,
|
||||
NodeResolutionMode::Execution,
|
||||
)?;
|
||||
Ok(Some(if r.scheme() == "file" {
|
||||
|
@ -590,7 +591,7 @@ where
|
|||
Some(&referrer_url),
|
||||
NodeModuleKind::Cjs,
|
||||
Some(&pkg),
|
||||
resolution::REQUIRE_CONDITIONS,
|
||||
REQUIRE_CONDITIONS,
|
||||
NodeResolutionMode::Execution,
|
||||
)?;
|
||||
Ok(Some(url_to_file_path_string(&url)?))
|
||||
|
|
|
@ -6,13 +6,13 @@ use deno_core::op2;
|
|||
use deno_core::url::Url;
|
||||
use deno_core::OpState;
|
||||
use deno_fs::FileSystemRc;
|
||||
use node_resolver::NodeResolution;
|
||||
use std::path::Path;
|
||||
use std::path::PathBuf;
|
||||
|
||||
use crate::resolution;
|
||||
use crate::resolution::NodeResolverRc;
|
||||
use crate::NodePermissions;
|
||||
use crate::NpmResolverRc;
|
||||
use crate::NodeRequireResolverRc;
|
||||
use crate::NodeResolverRc;
|
||||
|
||||
fn ensure_read_permission<P>(
|
||||
state: &mut OpState,
|
||||
|
@ -21,7 +21,7 @@ fn ensure_read_permission<P>(
|
|||
where
|
||||
P: NodePermissions + 'static,
|
||||
{
|
||||
let resolver = state.borrow::<NpmResolverRc>().clone();
|
||||
let resolver = state.borrow::<NodeRequireResolverRc>().clone();
|
||||
let permissions = state.borrow_mut::<P>();
|
||||
resolver.ensure_read_permission(permissions, file_path)
|
||||
}
|
||||
|
@ -64,9 +64,9 @@ where
|
|||
}
|
||||
let node_resolver = state.borrow::<NodeResolverRc>();
|
||||
match node_resolver.url_to_node_resolution(url)? {
|
||||
resolution::NodeResolution::Esm(u) => Ok(u.to_string()),
|
||||
resolution::NodeResolution::CommonJs(u) => wrap_cjs(u),
|
||||
_ => Err(generic_error("Neither ESM nor CJS")),
|
||||
NodeResolution::Esm(u) => Ok(u.to_string()),
|
||||
NodeResolution::CommonJs(u) => wrap_cjs(u),
|
||||
NodeResolution::BuiltIn(_) => Err(generic_error("Neither ESM nor CJS")),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,50 +0,0 @@
|
|||
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
||||
|
||||
use std::path::Component;
|
||||
use std::path::Path;
|
||||
use std::path::PathBuf;
|
||||
|
||||
use deno_core::ModuleSpecifier;
|
||||
|
||||
/// Extension to path_clean::PathClean
|
||||
pub trait PathClean<T> {
|
||||
fn clean(&self) -> T;
|
||||
}
|
||||
|
||||
impl PathClean<PathBuf> for PathBuf {
|
||||
fn clean(&self) -> PathBuf {
|
||||
let path = path_clean::PathClean::clean(self);
|
||||
if cfg!(windows) && path.to_string_lossy().contains("..\\") {
|
||||
// temporary workaround because path_clean::PathClean::clean is
|
||||
// not good enough on windows
|
||||
let mut components = Vec::new();
|
||||
|
||||
for component in path.components() {
|
||||
match component {
|
||||
Component::CurDir => {
|
||||
// skip
|
||||
}
|
||||
Component::ParentDir => {
|
||||
let maybe_last_component = components.pop();
|
||||
if !matches!(maybe_last_component, Some(Component::Normal(_))) {
|
||||
panic!("Error normalizing: {}", path.display());
|
||||
}
|
||||
}
|
||||
Component::Normal(_) | Component::RootDir | Component::Prefix(_) => {
|
||||
components.push(component);
|
||||
}
|
||||
}
|
||||
}
|
||||
components.into_iter().collect::<PathBuf>()
|
||||
} else {
|
||||
path
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn to_file_specifier(path: &Path) -> ModuleSpecifier {
|
||||
match ModuleSpecifier::from_file_path(path) {
|
||||
Ok(url) => url,
|
||||
Err(_) => panic!("Invalid path: {}", path.display()),
|
||||
}
|
||||
}
|
|
@ -1,7 +1,5 @@
|
|||
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
||||
|
||||
use deno_core::ModuleSpecifier;
|
||||
|
||||
/// e.g. `is_builtin_node_module("assert")`
|
||||
pub fn is_builtin_node_module(module_name: &str) -> bool {
|
||||
SUPPORTED_BUILTIN_NODE_MODULES
|
||||
|
@ -9,18 +7,6 @@ pub fn is_builtin_node_module(module_name: &str) -> bool {
|
|||
.any(|m| *m == module_name)
|
||||
}
|
||||
|
||||
/// Ex. returns `fs` for `node:fs`
|
||||
pub fn get_module_name_from_builtin_node_module_specifier(
|
||||
specifier: &ModuleSpecifier,
|
||||
) -> Option<&str> {
|
||||
if specifier.scheme() != "node" {
|
||||
return None;
|
||||
}
|
||||
|
||||
let (_, specifier) = specifier.as_str().split_once(':')?;
|
||||
Some(specifier)
|
||||
}
|
||||
|
||||
macro_rules! generate_builtin_node_module_lists {
|
||||
($( $module_name:literal ,)+) => {
|
||||
pub static SUPPORTED_BUILTIN_NODE_MODULES: &[&str] = &[
|
||||
|
|
32
ext/node_resolver/Cargo.toml
Normal file
32
ext/node_resolver/Cargo.toml
Normal file
|
@ -0,0 +1,32 @@
|
|||
# Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
||||
|
||||
[package]
|
||||
name = "node_resolver"
|
||||
version = "0.1.0"
|
||||
authors.workspace = true
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
readme = "README.md"
|
||||
repository.workspace = true
|
||||
description = "Node.js module resolution algorithm used in Deno"
|
||||
|
||||
[lib]
|
||||
path = "lib.rs"
|
||||
|
||||
[features]
|
||||
sync = ["deno_package_json/sync"]
|
||||
|
||||
[dependencies]
|
||||
anyhow.workspace = true
|
||||
async-trait.workspace = true
|
||||
deno_media_type.workspace = true
|
||||
deno_package_json.workspace = true
|
||||
futures.workspace = true
|
||||
lazy-regex.workspace = true
|
||||
once_cell.workspace = true
|
||||
path-clean = "=0.1.0"
|
||||
regex.workspace = true
|
||||
serde_json.workspace = true
|
||||
thiserror.workspace = true
|
||||
tokio.workspace = true
|
||||
url.workspace = true
|
6
ext/node_resolver/README.md
Normal file
6
ext/node_resolver/README.md
Normal file
|
@ -0,0 +1,6 @@
|
|||
# Node Resolver
|
||||
|
||||
[![crates](https://img.shields.io/crates/v/node_resolver.svg)](https://crates.io/crates/node_resolver)
|
||||
[![docs](https://docs.rs/node_resolver/badge.svg)](https://docs.rs/node_resolver)
|
||||
|
||||
Provides Node.js compatible resolution for the Deno project.
|
|
@ -5,17 +5,17 @@ use std::collections::HashSet;
|
|||
use std::path::Path;
|
||||
use std::path::PathBuf;
|
||||
|
||||
use deno_core::anyhow;
|
||||
use deno_core::anyhow::Context;
|
||||
use deno_core::futures::future::LocalBoxFuture;
|
||||
use deno_core::futures::stream::FuturesUnordered;
|
||||
use deno_core::futures::FutureExt;
|
||||
use deno_core::futures::StreamExt;
|
||||
use deno_core::ModuleSpecifier;
|
||||
use futures::future::LocalBoxFuture;
|
||||
use futures::stream::FuturesUnordered;
|
||||
use futures::FutureExt;
|
||||
use futures::StreamExt;
|
||||
use once_cell::sync::Lazy;
|
||||
|
||||
use deno_core::error::AnyError;
|
||||
use anyhow::Context;
|
||||
use anyhow::Error as AnyError;
|
||||
use url::Url;
|
||||
|
||||
use crate::env::NodeResolverEnv;
|
||||
use crate::package_json::load_pkg_json;
|
||||
use crate::path::to_file_specifier;
|
||||
use crate::resolution::NodeResolverRc;
|
||||
|
@ -50,28 +50,33 @@ pub trait CjsCodeAnalyzer {
|
|||
/// necessary.
|
||||
async fn analyze_cjs(
|
||||
&self,
|
||||
specifier: &ModuleSpecifier,
|
||||
specifier: &Url,
|
||||
maybe_source: Option<String>,
|
||||
) -> Result<CjsAnalysis, AnyError>;
|
||||
}
|
||||
|
||||
pub struct NodeCodeTranslator<TCjsCodeAnalyzer: CjsCodeAnalyzer> {
|
||||
pub struct NodeCodeTranslator<
|
||||
TCjsCodeAnalyzer: CjsCodeAnalyzer,
|
||||
TNodeResolverEnv: NodeResolverEnv,
|
||||
> {
|
||||
cjs_code_analyzer: TCjsCodeAnalyzer,
|
||||
fs: deno_fs::FileSystemRc,
|
||||
node_resolver: NodeResolverRc,
|
||||
env: TNodeResolverEnv,
|
||||
node_resolver: NodeResolverRc<TNodeResolverEnv>,
|
||||
npm_resolver: NpmResolverRc,
|
||||
}
|
||||
|
||||
impl<TCjsCodeAnalyzer: CjsCodeAnalyzer> NodeCodeTranslator<TCjsCodeAnalyzer> {
|
||||
impl<TCjsCodeAnalyzer: CjsCodeAnalyzer, TNodeResolverEnv: NodeResolverEnv>
|
||||
NodeCodeTranslator<TCjsCodeAnalyzer, TNodeResolverEnv>
|
||||
{
|
||||
pub fn new(
|
||||
cjs_code_analyzer: TCjsCodeAnalyzer,
|
||||
fs: deno_fs::FileSystemRc,
|
||||
node_resolver: NodeResolverRc,
|
||||
env: TNodeResolverEnv,
|
||||
node_resolver: NodeResolverRc<TNodeResolverEnv>,
|
||||
npm_resolver: NpmResolverRc,
|
||||
) -> Self {
|
||||
Self {
|
||||
cjs_code_analyzer,
|
||||
fs,
|
||||
env,
|
||||
node_resolver,
|
||||
npm_resolver,
|
||||
}
|
||||
|
@ -85,7 +90,7 @@ impl<TCjsCodeAnalyzer: CjsCodeAnalyzer> NodeCodeTranslator<TCjsCodeAnalyzer> {
|
|||
/// If successful a source code for equivalent ES module is returned.
|
||||
pub async fn translate_cjs_to_esm(
|
||||
&self,
|
||||
entry_specifier: &ModuleSpecifier,
|
||||
entry_specifier: &Url,
|
||||
source: Option<String>,
|
||||
) -> Result<String, AnyError> {
|
||||
let mut temp_var_count = 0;
|
||||
|
@ -173,7 +178,7 @@ impl<TCjsCodeAnalyzer: CjsCodeAnalyzer> NodeCodeTranslator<TCjsCodeAnalyzer> {
|
|||
|
||||
type AnalysisFuture<'a> = LocalBoxFuture<'a, Result<Analysis, AnyError>>;
|
||||
|
||||
let mut handled_reexports: HashSet<ModuleSpecifier> = HashSet::default();
|
||||
let mut handled_reexports: HashSet<Url> = HashSet::default();
|
||||
handled_reexports.insert(entry_specifier.clone());
|
||||
let mut analyze_futures: FuturesUnordered<AnalysisFuture<'a>> =
|
||||
FuturesUnordered::new();
|
||||
|
@ -282,10 +287,10 @@ impl<TCjsCodeAnalyzer: CjsCodeAnalyzer> NodeCodeTranslator<TCjsCodeAnalyzer> {
|
|||
fn resolve(
|
||||
&self,
|
||||
specifier: &str,
|
||||
referrer: &ModuleSpecifier,
|
||||
referrer: &Url,
|
||||
conditions: &[&str],
|
||||
mode: NodeResolutionMode,
|
||||
) -> Result<ModuleSpecifier, AnyError> {
|
||||
) -> Result<Url, AnyError> {
|
||||
if specifier.starts_with('/') {
|
||||
todo!();
|
||||
}
|
||||
|
@ -305,14 +310,14 @@ impl<TCjsCodeAnalyzer: CjsCodeAnalyzer> NodeCodeTranslator<TCjsCodeAnalyzer> {
|
|||
let (package_specifier, package_subpath) =
|
||||
parse_specifier(specifier).unwrap();
|
||||
|
||||
// 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,
|
||||
)?;
|
||||
|
||||
let package_json_path = module_dir.join("package.json");
|
||||
let maybe_package_json = load_pkg_json(&*self.fs, &package_json_path)?;
|
||||
let maybe_package_json =
|
||||
load_pkg_json(self.env.pkg_json_fs(), &package_json_path)?;
|
||||
if let Some(package_json) = maybe_package_json {
|
||||
if let Some(exports) = &package_json.exports {
|
||||
return self
|
||||
|
@ -332,11 +337,11 @@ impl<TCjsCodeAnalyzer: CjsCodeAnalyzer> NodeCodeTranslator<TCjsCodeAnalyzer> {
|
|||
// old school
|
||||
if package_subpath != "." {
|
||||
let d = module_dir.join(package_subpath);
|
||||
if self.fs.is_dir_sync(&d) {
|
||||
if self.env.is_dir_sync(&d) {
|
||||
// subdir might have a package.json that specifies the entrypoint
|
||||
let package_json_path = d.join("package.json");
|
||||
let maybe_package_json =
|
||||
load_pkg_json(&*self.fs, &package_json_path)?;
|
||||
load_pkg_json(self.env.pkg_json_fs(), &package_json_path)?;
|
||||
if let Some(package_json) = maybe_package_json {
|
||||
if let Some(main) = package_json.main(NodeModuleKind::Cjs) {
|
||||
return Ok(to_file_specifier(&d.join(main).clean()));
|
||||
|
@ -381,13 +386,13 @@ impl<TCjsCodeAnalyzer: CjsCodeAnalyzer> NodeCodeTranslator<TCjsCodeAnalyzer> {
|
|||
referrer: &Path,
|
||||
) -> Result<PathBuf, AnyError> {
|
||||
let p = p.clean();
|
||||
if self.fs.exists_sync(&p) {
|
||||
if self.env.exists_sync(&p) {
|
||||
let file_name = p.file_name().unwrap();
|
||||
let p_js =
|
||||
p.with_file_name(format!("{}.js", file_name.to_str().unwrap()));
|
||||
if self.fs.is_file_sync(&p_js) {
|
||||
if self.env.is_file_sync(&p_js) {
|
||||
return Ok(p_js);
|
||||
} else if self.fs.is_dir_sync(&p) {
|
||||
} else if self.env.is_dir_sync(&p) {
|
||||
return Ok(p.join("index.js"));
|
||||
} else {
|
||||
return Ok(p);
|
||||
|
@ -396,14 +401,14 @@ impl<TCjsCodeAnalyzer: CjsCodeAnalyzer> NodeCodeTranslator<TCjsCodeAnalyzer> {
|
|||
{
|
||||
let p_js =
|
||||
p.with_file_name(format!("{}.js", file_name.to_str().unwrap()));
|
||||
if self.fs.is_file_sync(&p_js) {
|
||||
if self.env.is_file_sync(&p_js) {
|
||||
return Ok(p_js);
|
||||
}
|
||||
}
|
||||
{
|
||||
let p_json =
|
||||
p.with_file_name(format!("{}.json", file_name.to_str().unwrap()));
|
||||
if self.fs.is_file_sync(&p_json) {
|
||||
if self.env.is_file_sync(&p_json) {
|
||||
return Ok(p_json);
|
||||
}
|
||||
}
|
48
ext/node_resolver/clippy.toml
Normal file
48
ext/node_resolver/clippy.toml
Normal file
|
@ -0,0 +1,48 @@
|
|||
disallowed-methods = [
|
||||
{ path = "std::env::current_dir", reason = "File system operations should be done using NodeResolverFs trait" },
|
||||
{ path = "std::path::Path::canonicalize", reason = "File system operations should be done using NodeResolverFs trait" },
|
||||
{ path = "std::path::Path::is_dir", reason = "File system operations should be done using NodeResolverFs trait" },
|
||||
{ path = "std::path::Path::is_file", reason = "File system operations should be done using NodeResolverFs trait" },
|
||||
{ path = "std::path::Path::is_symlink", reason = "File system operations should be done using NodeResolverFs trait" },
|
||||
{ path = "std::path::Path::metadata", reason = "File system operations should be done using NodeResolverFs trait" },
|
||||
{ path = "std::path::Path::read_dir", reason = "File system operations should be done using NodeResolverFs trait" },
|
||||
{ path = "std::path::Path::read_link", reason = "File system operations should be done using NodeResolverFs trait" },
|
||||
{ path = "std::path::Path::symlink_metadata", reason = "File system operations should be done using NodeResolverFs trait" },
|
||||
{ path = "std::path::Path::try_exists", reason = "File system operations should be done using NodeResolverFs trait" },
|
||||
{ path = "std::path::PathBuf::exists", reason = "File system operations should be done using NodeResolverFs trait" },
|
||||
{ path = "std::path::PathBuf::canonicalize", reason = "File system operations should be done using NodeResolverFs trait" },
|
||||
{ path = "std::path::PathBuf::is_dir", reason = "File system operations should be done using NodeResolverFs trait" },
|
||||
{ path = "std::path::PathBuf::is_file", reason = "File system operations should be done using NodeResolverFs trait" },
|
||||
{ path = "std::path::PathBuf::is_symlink", reason = "File system operations should be done using NodeResolverFs trait" },
|
||||
{ path = "std::path::PathBuf::metadata", reason = "File system operations should be done using NodeResolverFs trait" },
|
||||
{ path = "std::path::PathBuf::read_dir", reason = "File system operations should be done using NodeResolverFs trait" },
|
||||
{ path = "std::path::PathBuf::read_link", reason = "File system operations should be done using NodeResolverFs trait" },
|
||||
{ path = "std::path::PathBuf::symlink_metadata", reason = "File system operations should be done using NodeResolverFs trait" },
|
||||
{ path = "std::path::PathBuf::try_exists", reason = "File system operations should be done using NodeResolverFs trait" },
|
||||
{ path = "std::env::set_current_dir", reason = "File system operations should be done using NodeResolverFs trait" },
|
||||
{ path = "std::env::temp_dir", reason = "File system operations should be done using NodeResolverFs trait" },
|
||||
{ path = "std::fs::canonicalize", reason = "File system operations should be done using NodeResolverFs trait" },
|
||||
{ path = "std::fs::copy", reason = "File system operations should be done using NodeResolverFs trait" },
|
||||
{ path = "std::fs::create_dir_all", reason = "File system operations should be done using NodeResolverFs trait" },
|
||||
{ path = "std::fs::create_dir", reason = "File system operations should be done using NodeResolverFs trait" },
|
||||
{ path = "std::fs::DirBuilder::new", reason = "File system operations should be done using NodeResolverFs trait" },
|
||||
{ path = "std::fs::hard_link", reason = "File system operations should be done using NodeResolverFs trait" },
|
||||
{ path = "std::fs::metadata", reason = "File system operations should be done using NodeResolverFs trait" },
|
||||
{ path = "std::fs::OpenOptions::new", reason = "File system operations should be done using NodeResolverFs trait" },
|
||||
{ path = "std::fs::read_dir", reason = "File system operations should be done using NodeResolverFs trait" },
|
||||
{ path = "std::fs::read_link", reason = "File system operations should be done using NodeResolverFs trait" },
|
||||
{ path = "std::fs::read_to_string", reason = "File system operations should be done using NodeResolverFs trait" },
|
||||
{ path = "std::fs::read", reason = "File system operations should be done using NodeResolverFs trait" },
|
||||
{ path = "std::fs::remove_dir_all", reason = "File system operations should be done using NodeResolverFs trait" },
|
||||
{ path = "std::fs::remove_dir", reason = "File system operations should be done using NodeResolverFs trait" },
|
||||
{ path = "std::fs::remove_file", reason = "File system operations should be done using NodeResolverFs trait" },
|
||||
{ path = "std::fs::rename", reason = "File system operations should be done using NodeResolverFs trait" },
|
||||
{ path = "std::fs::set_permissions", reason = "File system operations should be done using NodeResolverFs trait" },
|
||||
{ path = "std::fs::symlink_metadata", reason = "File system operations should be done using NodeResolverFs trait" },
|
||||
{ path = "std::fs::write", reason = "File system operations should be done using NodeResolverFs trait" },
|
||||
{ path = "std::path::Path::canonicalize", reason = "File system operations should be done using NodeResolverFs trait" },
|
||||
{ path = "std::path::Path::exists", reason = "File system operations should be done using NodeResolverFs trait" },
|
||||
]
|
||||
disallowed-types = [
|
||||
{ path = "std::sync::Arc", reason = "use crate::sync::MaybeArc instead" },
|
||||
]
|
39
ext/node_resolver/env.rs
Normal file
39
ext/node_resolver/env.rs
Normal file
|
@ -0,0 +1,39 @@
|
|||
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
||||
|
||||
use std::path::Path;
|
||||
use std::path::PathBuf;
|
||||
|
||||
use crate::sync::MaybeSend;
|
||||
use crate::sync::MaybeSync;
|
||||
|
||||
pub struct NodeResolverFsStat {
|
||||
pub is_file: bool,
|
||||
pub is_dir: bool,
|
||||
pub is_symlink: bool,
|
||||
}
|
||||
|
||||
pub trait NodeResolverEnv: std::fmt::Debug + MaybeSend + MaybeSync {
|
||||
fn is_builtin_node_module(&self, specifier: &str) -> bool;
|
||||
|
||||
fn realpath_sync(&self, path: &Path) -> std::io::Result<PathBuf>;
|
||||
|
||||
fn stat_sync(&self, path: &Path) -> std::io::Result<NodeResolverFsStat>;
|
||||
|
||||
fn exists_sync(&self, path: &Path) -> bool;
|
||||
|
||||
fn is_file_sync(&self, path: &Path) -> bool {
|
||||
self
|
||||
.stat_sync(path)
|
||||
.map(|stat| stat.is_file)
|
||||
.unwrap_or(false)
|
||||
}
|
||||
|
||||
fn is_dir_sync(&self, path: &Path) -> bool {
|
||||
self
|
||||
.stat_sync(path)
|
||||
.map(|stat| stat.is_dir)
|
||||
.unwrap_or(false)
|
||||
}
|
||||
|
||||
fn pkg_json_fs(&self) -> &dyn deno_package_json::fs::DenoPkgJsonFs;
|
||||
}
|
|
@ -4,8 +4,8 @@ use std::borrow::Cow;
|
|||
use std::fmt::Write;
|
||||
use std::path::PathBuf;
|
||||
|
||||
use deno_core::ModuleSpecifier;
|
||||
use thiserror::Error;
|
||||
use url::Url;
|
||||
|
||||
use crate::NodeModuleKind;
|
||||
use crate::NodeResolutionMode;
|
||||
|
@ -155,7 +155,7 @@ kinded_err!(PackageFolderResolveError, PackageFolderResolveErrorKind);
|
|||
)]
|
||||
pub struct PackageNotFoundError {
|
||||
pub package_name: String,
|
||||
pub referrer: ModuleSpecifier,
|
||||
pub referrer: Url,
|
||||
/// Extra information about the referrer.
|
||||
pub referrer_extra: Option<String>,
|
||||
}
|
||||
|
@ -173,7 +173,7 @@ impl NodeJsErrorCoded for PackageNotFoundError {
|
|||
referrer_extra.as_ref().map(|r| format!(" ({})", r)).unwrap_or_default()
|
||||
)]
|
||||
pub struct ReferrerNotFoundError {
|
||||
pub referrer: ModuleSpecifier,
|
||||
pub referrer: Url,
|
||||
/// Extra information about the referrer.
|
||||
pub referrer_extra: Option<String>,
|
||||
}
|
||||
|
@ -188,7 +188,7 @@ impl NodeJsErrorCoded for ReferrerNotFoundError {
|
|||
#[error("Failed resolving '{package_name}' from referrer '{referrer}'.")]
|
||||
pub struct PackageFolderResolveIoError {
|
||||
pub package_name: String,
|
||||
pub referrer: ModuleSpecifier,
|
||||
pub referrer: Url,
|
||||
#[source]
|
||||
pub source: std::io::Error,
|
||||
}
|
||||
|
@ -264,7 +264,7 @@ pub enum PackageSubpathResolveErrorKind {
|
|||
pub struct PackageTargetNotFoundError {
|
||||
pub pkg_json_path: PathBuf,
|
||||
pub target: String,
|
||||
pub maybe_referrer: Option<ModuleSpecifier>,
|
||||
pub maybe_referrer: Option<Url>,
|
||||
pub referrer_kind: NodeModuleKind,
|
||||
pub mode: NodeResolutionMode,
|
||||
}
|
||||
|
@ -333,8 +333,8 @@ pub struct TypesNotFoundError(pub Box<TypesNotFoundErrorData>);
|
|||
|
||||
#[derive(Debug)]
|
||||
pub struct TypesNotFoundErrorData {
|
||||
pub code_specifier: ModuleSpecifier,
|
||||
pub maybe_referrer: Option<ModuleSpecifier>,
|
||||
pub code_specifier: Url,
|
||||
pub maybe_referrer: Option<Url>,
|
||||
}
|
||||
|
||||
impl NodeJsErrorCoded for TypesNotFoundError {
|
||||
|
@ -397,7 +397,7 @@ impl NodeJsErrorCoded for CanonicalizingPkgJsonDirError {
|
|||
#[derive(Debug, Error)]
|
||||
#[error("TypeScript files are not supported in npm packages: {specifier}")]
|
||||
pub struct TypeScriptNotSupportedInNpmError {
|
||||
pub specifier: ModuleSpecifier,
|
||||
pub specifier: Url,
|
||||
}
|
||||
|
||||
impl NodeJsErrorCoded for TypeScriptNotSupportedInNpmError {
|
||||
|
@ -437,7 +437,7 @@ pub enum UrlToNodeResolutionErrorKind {
|
|||
pub struct PackageImportNotDefinedError {
|
||||
pub name: String,
|
||||
pub package_json_path: Option<PathBuf>,
|
||||
pub maybe_referrer: Option<ModuleSpecifier>,
|
||||
pub maybe_referrer: Option<Url>,
|
||||
}
|
||||
|
||||
impl NodeJsErrorCoded for PackageImportNotDefinedError {
|
||||
|
@ -503,7 +503,7 @@ pub enum PackageResolveErrorKind {
|
|||
#[error("Failed joining '{path}' from '{base}'.")]
|
||||
pub struct NodeResolveRelativeJoinError {
|
||||
pub path: String,
|
||||
pub base: ModuleSpecifier,
|
||||
pub base: Url,
|
||||
#[source]
|
||||
pub source: url::ParseError,
|
||||
}
|
||||
|
@ -568,8 +568,8 @@ impl NodeJsErrorCoded for FinalizeResolutionError {
|
|||
maybe_referrer.as_ref().map(|referrer| format!(" imported from '{}'", referrer)).unwrap_or_default()
|
||||
)]
|
||||
pub struct ModuleNotFoundError {
|
||||
pub specifier: ModuleSpecifier,
|
||||
pub maybe_referrer: Option<ModuleSpecifier>,
|
||||
pub specifier: Url,
|
||||
pub maybe_referrer: Option<Url>,
|
||||
pub typ: &'static str,
|
||||
}
|
||||
|
||||
|
@ -587,8 +587,8 @@ impl NodeJsErrorCoded for ModuleNotFoundError {
|
|||
maybe_referrer.as_ref().map(|referrer| format!(" imported from '{}'", referrer)).unwrap_or_default(),
|
||||
)]
|
||||
pub struct UnsupportedDirImportError {
|
||||
pub dir_url: ModuleSpecifier,
|
||||
pub maybe_referrer: Option<ModuleSpecifier>,
|
||||
pub dir_url: Url,
|
||||
pub maybe_referrer: Option<Url>,
|
||||
}
|
||||
|
||||
impl NodeJsErrorCoded for UnsupportedDirImportError {
|
||||
|
@ -603,7 +603,7 @@ pub struct InvalidPackageTargetError {
|
|||
pub sub_path: String,
|
||||
pub target: String,
|
||||
pub is_import: bool,
|
||||
pub maybe_referrer: Option<ModuleSpecifier>,
|
||||
pub maybe_referrer: Option<Url>,
|
||||
}
|
||||
|
||||
impl std::error::Error for InvalidPackageTargetError {}
|
||||
|
@ -657,7 +657,7 @@ impl NodeJsErrorCoded for InvalidPackageTargetError {
|
|||
pub struct PackagePathNotExportedError {
|
||||
pub pkg_json_path: PathBuf,
|
||||
pub subpath: String,
|
||||
pub maybe_referrer: Option<ModuleSpecifier>,
|
||||
pub maybe_referrer: Option<Url>,
|
||||
pub mode: NodeResolutionMode,
|
||||
}
|
||||
|
26
ext/node_resolver/lib.rs
Normal file
26
ext/node_resolver/lib.rs
Normal file
|
@ -0,0 +1,26 @@
|
|||
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
||||
|
||||
#![deny(clippy::print_stderr)]
|
||||
#![deny(clippy::print_stdout)]
|
||||
|
||||
pub mod analyze;
|
||||
pub mod env;
|
||||
pub mod errors;
|
||||
mod npm;
|
||||
mod package_json;
|
||||
mod path;
|
||||
mod resolution;
|
||||
mod sync;
|
||||
|
||||
pub use deno_package_json::PackageJson;
|
||||
pub use npm::NpmResolver;
|
||||
pub use npm::NpmResolverRc;
|
||||
pub use package_json::load_pkg_json;
|
||||
pub use package_json::PackageJsonThreadLocalCache;
|
||||
pub use path::PathClean;
|
||||
pub use resolution::NodeModuleKind;
|
||||
pub use resolution::NodeResolution;
|
||||
pub use resolution::NodeResolutionMode;
|
||||
pub use resolution::NodeResolver;
|
||||
pub use resolution::DEFAULT_CONDITIONS;
|
||||
pub use resolution::REQUIRE_CONDITIONS;
|
41
ext/node_resolver/npm.rs
Normal file
41
ext/node_resolver/npm.rs
Normal file
|
@ -0,0 +1,41 @@
|
|||
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
||||
|
||||
use std::path::Path;
|
||||
use std::path::PathBuf;
|
||||
|
||||
use url::Url;
|
||||
|
||||
use crate::errors;
|
||||
use crate::path::PathClean;
|
||||
use crate::sync::MaybeSend;
|
||||
use crate::sync::MaybeSync;
|
||||
|
||||
#[allow(clippy::disallowed_types)]
|
||||
pub type NpmResolverRc = crate::sync::MaybeArc<dyn NpmResolver>;
|
||||
|
||||
pub trait NpmResolver: std::fmt::Debug + MaybeSend + MaybeSync {
|
||||
/// Resolves an npm package folder path from an npm package referrer.
|
||||
fn resolve_package_folder_from_package(
|
||||
&self,
|
||||
specifier: &str,
|
||||
referrer: &Url,
|
||||
) -> Result<PathBuf, errors::PackageFolderResolveError>;
|
||||
|
||||
fn in_npm_package(&self, specifier: &Url) -> bool;
|
||||
|
||||
fn in_npm_package_at_dir_path(&self, path: &Path) -> bool {
|
||||
let specifier = match Url::from_directory_path(path.to_path_buf().clean()) {
|
||||
Ok(p) => p,
|
||||
Err(_) => return false,
|
||||
};
|
||||
self.in_npm_package(&specifier)
|
||||
}
|
||||
|
||||
fn in_npm_package_at_file_path(&self, path: &Path) -> bool {
|
||||
let specifier = match Url::from_file_path(path.to_path_buf().clean()) {
|
||||
Ok(p) => p,
|
||||
Err(_) => return false,
|
||||
};
|
||||
self.in_npm_package(&specifier)
|
||||
}
|
||||
}
|
|
@ -33,31 +33,14 @@ impl deno_package_json::PackageJsonCache for PackageJsonThreadLocalCache {
|
|||
}
|
||||
}
|
||||
|
||||
pub struct DenoPkgJsonFsAdapter<'a>(pub &'a dyn deno_fs::FileSystem);
|
||||
|
||||
impl<'a> deno_package_json::fs::DenoPkgJsonFs for DenoPkgJsonFsAdapter<'a> {
|
||||
fn read_to_string_lossy(
|
||||
&self,
|
||||
path: &Path,
|
||||
) -> Result<String, std::io::Error> {
|
||||
self
|
||||
.0
|
||||
.read_text_file_lossy_sync(path, None)
|
||||
.map_err(|err| err.into_io_error())
|
||||
}
|
||||
}
|
||||
|
||||
/// Helper to load a package.json file using the thread local cache
|
||||
/// in deno_node.
|
||||
/// in node_resolver.
|
||||
pub fn load_pkg_json(
|
||||
fs: &dyn deno_fs::FileSystem,
|
||||
fs: &dyn deno_package_json::fs::DenoPkgJsonFs,
|
||||
path: &Path,
|
||||
) -> Result<Option<PackageJsonRc>, PackageJsonLoadError> {
|
||||
let result = PackageJson::load_from_path(
|
||||
path,
|
||||
&DenoPkgJsonFsAdapter(fs),
|
||||
Some(&PackageJsonThreadLocalCache),
|
||||
);
|
||||
let result =
|
||||
PackageJson::load_from_path(path, fs, Some(&PackageJsonThreadLocalCache));
|
||||
match result {
|
||||
Ok(pkg_json) => Ok(Some(pkg_json)),
|
||||
Err(deno_package_json::PackageJsonLoadError::Io { source, .. })
|
142
ext/node_resolver/path.rs
Normal file
142
ext/node_resolver/path.rs
Normal file
|
@ -0,0 +1,142 @@
|
|||
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
||||
|
||||
use std::path::Component;
|
||||
use std::path::Path;
|
||||
use std::path::PathBuf;
|
||||
|
||||
use url::Url;
|
||||
|
||||
/// Extension to path_clean::PathClean
|
||||
pub trait PathClean<T> {
|
||||
fn clean(&self) -> T;
|
||||
}
|
||||
|
||||
impl PathClean<PathBuf> for PathBuf {
|
||||
fn clean(&self) -> PathBuf {
|
||||
let path = path_clean::PathClean::clean(self);
|
||||
if cfg!(windows) && path.to_string_lossy().contains("..\\") {
|
||||
// temporary workaround because path_clean::PathClean::clean is
|
||||
// not good enough on windows
|
||||
let mut components = Vec::new();
|
||||
|
||||
for component in path.components() {
|
||||
match component {
|
||||
Component::CurDir => {
|
||||
// skip
|
||||
}
|
||||
Component::ParentDir => {
|
||||
let maybe_last_component = components.pop();
|
||||
if !matches!(maybe_last_component, Some(Component::Normal(_))) {
|
||||
panic!("Error normalizing: {}", path.display());
|
||||
}
|
||||
}
|
||||
Component::Normal(_) | Component::RootDir | Component::Prefix(_) => {
|
||||
components.push(component);
|
||||
}
|
||||
}
|
||||
}
|
||||
components.into_iter().collect::<PathBuf>()
|
||||
} else {
|
||||
path
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn to_file_specifier(path: &Path) -> Url {
|
||||
match Url::from_file_path(path) {
|
||||
Ok(url) => url,
|
||||
Err(_) => panic!("Invalid path: {}", path.display()),
|
||||
}
|
||||
}
|
||||
|
||||
// todo(dsherret): we have the below code also in deno_core and it
|
||||
// would be good to somehow re-use it in both places (we don't want
|
||||
// to create a dependency on deno_core here)
|
||||
|
||||
#[cfg(not(windows))]
|
||||
#[inline]
|
||||
pub fn strip_unc_prefix(path: PathBuf) -> PathBuf {
|
||||
path
|
||||
}
|
||||
|
||||
/// Strips the unc prefix (ex. \\?\) from Windows paths.
|
||||
#[cfg(windows)]
|
||||
pub fn strip_unc_prefix(path: PathBuf) -> PathBuf {
|
||||
use std::path::Component;
|
||||
use std::path::Prefix;
|
||||
|
||||
let mut components = path.components();
|
||||
match components.next() {
|
||||
Some(Component::Prefix(prefix)) => {
|
||||
match prefix.kind() {
|
||||
// \\?\device
|
||||
Prefix::Verbatim(device) => {
|
||||
let mut path = PathBuf::new();
|
||||
path.push(format!(r"\\{}\", device.to_string_lossy()));
|
||||
path.extend(components.filter(|c| !matches!(c, Component::RootDir)));
|
||||
path
|
||||
}
|
||||
// \\?\c:\path
|
||||
Prefix::VerbatimDisk(_) => {
|
||||
let mut path = PathBuf::new();
|
||||
path.push(prefix.as_os_str().to_string_lossy().replace(r"\\?\", ""));
|
||||
path.extend(components);
|
||||
path
|
||||
}
|
||||
// \\?\UNC\hostname\share_name\path
|
||||
Prefix::VerbatimUNC(hostname, share_name) => {
|
||||
let mut path = PathBuf::new();
|
||||
path.push(format!(
|
||||
r"\\{}\{}\",
|
||||
hostname.to_string_lossy(),
|
||||
share_name.to_string_lossy()
|
||||
));
|
||||
path.extend(components.filter(|c| !matches!(c, Component::RootDir)));
|
||||
path
|
||||
}
|
||||
_ => path,
|
||||
}
|
||||
}
|
||||
_ => path,
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
#[cfg(windows)]
|
||||
#[test]
|
||||
fn test_strip_unc_prefix() {
|
||||
use std::path::PathBuf;
|
||||
|
||||
run_test(r"C:\", r"C:\");
|
||||
run_test(r"C:\test\file.txt", r"C:\test\file.txt");
|
||||
|
||||
run_test(r"\\?\C:\", r"C:\");
|
||||
run_test(r"\\?\C:\test\file.txt", r"C:\test\file.txt");
|
||||
|
||||
run_test(r"\\.\C:\", r"\\.\C:\");
|
||||
run_test(r"\\.\C:\Test\file.txt", r"\\.\C:\Test\file.txt");
|
||||
|
||||
run_test(r"\\?\UNC\localhost\", r"\\localhost");
|
||||
run_test(r"\\?\UNC\localhost\c$\", r"\\localhost\c$");
|
||||
run_test(
|
||||
r"\\?\UNC\localhost\c$\Windows\file.txt",
|
||||
r"\\localhost\c$\Windows\file.txt",
|
||||
);
|
||||
run_test(r"\\?\UNC\wsl$\deno.json", r"\\wsl$\deno.json");
|
||||
|
||||
run_test(r"\\?\server1", r"\\server1");
|
||||
run_test(r"\\?\server1\e$\", r"\\server1\e$\");
|
||||
run_test(
|
||||
r"\\?\server1\e$\test\file.txt",
|
||||
r"\\server1\e$\test\file.txt",
|
||||
);
|
||||
|
||||
fn run_test(input: &str, expected: &str) {
|
||||
assert_eq!(
|
||||
super::strip_unc_prefix(PathBuf::from(input)),
|
||||
PathBuf::from(expected)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -5,16 +5,15 @@ use std::collections::HashMap;
|
|||
use std::path::Path;
|
||||
use std::path::PathBuf;
|
||||
|
||||
use deno_core::anyhow::bail;
|
||||
use deno_core::error::AnyError;
|
||||
use deno_core::serde_json::Map;
|
||||
use deno_core::serde_json::Value;
|
||||
use deno_core::url::Url;
|
||||
use deno_core::ModuleSpecifier;
|
||||
use deno_fs::FileSystemRc;
|
||||
use anyhow::bail;
|
||||
use anyhow::Error as AnyError;
|
||||
use deno_media_type::MediaType;
|
||||
use deno_package_json::PackageJsonRc;
|
||||
use serde_json::Map;
|
||||
use serde_json::Value;
|
||||
use url::Url;
|
||||
|
||||
use crate::env::NodeResolverEnv;
|
||||
use crate::errors;
|
||||
use crate::errors::CanonicalizingPkgJsonDirError;
|
||||
use crate::errors::ClosestPkgJsonError;
|
||||
|
@ -49,12 +48,11 @@ use crate::errors::TypesNotFoundErrorData;
|
|||
use crate::errors::UnsupportedDirImportError;
|
||||
use crate::errors::UnsupportedEsmUrlSchemeError;
|
||||
use crate::errors::UrlToNodeResolutionError;
|
||||
use crate::is_builtin_node_module;
|
||||
use crate::path::strip_unc_prefix;
|
||||
use crate::path::to_file_specifier;
|
||||
use crate::polyfill::get_module_name_from_builtin_node_module_specifier;
|
||||
use crate::NpmResolverRc;
|
||||
use crate::PackageJson;
|
||||
use crate::PathClean;
|
||||
use deno_package_json::PackageJson;
|
||||
|
||||
pub static DEFAULT_CONDITIONS: &[&str] = &["deno", "node", "import"];
|
||||
pub static REQUIRE_CONDITIONS: &[&str] = &["require", "node"];
|
||||
|
@ -76,21 +74,21 @@ impl NodeResolutionMode {
|
|||
|
||||
#[derive(Debug)]
|
||||
pub enum NodeResolution {
|
||||
Esm(ModuleSpecifier),
|
||||
CommonJs(ModuleSpecifier),
|
||||
Esm(Url),
|
||||
CommonJs(Url),
|
||||
BuiltIn(String),
|
||||
}
|
||||
|
||||
impl NodeResolution {
|
||||
pub fn into_url(self) -> ModuleSpecifier {
|
||||
pub fn into_url(self) -> Url {
|
||||
match self {
|
||||
Self::Esm(u) => u,
|
||||
Self::CommonJs(u) => u,
|
||||
Self::BuiltIn(specifier) => {
|
||||
if specifier.starts_with("node:") {
|
||||
ModuleSpecifier::parse(&specifier).unwrap()
|
||||
Url::parse(&specifier).unwrap()
|
||||
} else {
|
||||
ModuleSpecifier::parse(&format!("node:{specifier}")).unwrap()
|
||||
Url::parse(&format!("node:{specifier}")).unwrap()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -98,7 +96,7 @@ impl NodeResolution {
|
|||
|
||||
pub fn into_specifier_and_media_type(
|
||||
resolution: Option<Self>,
|
||||
) -> (ModuleSpecifier, MediaType) {
|
||||
) -> (Url, MediaType) {
|
||||
match resolution {
|
||||
Some(NodeResolution::CommonJs(specifier)) => {
|
||||
let media_type = MediaType::from_specifier(&specifier);
|
||||
|
@ -126,7 +124,7 @@ impl NodeResolution {
|
|||
}
|
||||
Some(resolution) => (resolution.into_url(), MediaType::Dts),
|
||||
None => (
|
||||
ModuleSpecifier::parse("internal:///missing_dependency.d.ts").unwrap(),
|
||||
Url::parse("internal:///missing_dependency.d.ts").unwrap(),
|
||||
MediaType::Dts,
|
||||
),
|
||||
}
|
||||
|
@ -134,25 +132,25 @@ impl NodeResolution {
|
|||
}
|
||||
|
||||
#[allow(clippy::disallowed_types)]
|
||||
pub type NodeResolverRc = deno_fs::sync::MaybeArc<NodeResolver>;
|
||||
pub type NodeResolverRc<TEnv> = crate::sync::MaybeArc<NodeResolver<TEnv>>;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct NodeResolver {
|
||||
fs: FileSystemRc,
|
||||
pub struct NodeResolver<TEnv: NodeResolverEnv> {
|
||||
env: TEnv,
|
||||
npm_resolver: NpmResolverRc,
|
||||
in_npm_package_cache: deno_fs::sync::MaybeArcMutex<HashMap<String, bool>>,
|
||||
in_npm_package_cache: crate::sync::MaybeArcMutex<HashMap<String, bool>>,
|
||||
}
|
||||
|
||||
impl NodeResolver {
|
||||
pub fn new(fs: FileSystemRc, npm_resolver: NpmResolverRc) -> Self {
|
||||
impl<TEnv: NodeResolverEnv> NodeResolver<TEnv> {
|
||||
pub fn new(env: TEnv, npm_resolver: NpmResolverRc) -> Self {
|
||||
Self {
|
||||
fs,
|
||||
env,
|
||||
npm_resolver,
|
||||
in_npm_package_cache: deno_fs::sync::MaybeArcMutex::new(HashMap::new()),
|
||||
in_npm_package_cache: crate::sync::MaybeArcMutex::new(HashMap::new()),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn in_npm_package(&self, specifier: &ModuleSpecifier) -> bool {
|
||||
pub fn in_npm_package(&self, specifier: &Url) -> bool {
|
||||
self.npm_resolver.in_npm_package(specifier)
|
||||
}
|
||||
|
||||
|
@ -163,8 +161,7 @@ impl NodeResolver {
|
|||
return *result;
|
||||
}
|
||||
|
||||
let result =
|
||||
if let Ok(specifier) = deno_core::ModuleSpecifier::parse(&specifier) {
|
||||
let result = if let Ok(specifier) = Url::parse(&specifier) {
|
||||
self.npm_resolver.in_npm_package(&specifier)
|
||||
} else {
|
||||
false
|
||||
|
@ -178,14 +175,14 @@ impl NodeResolver {
|
|||
pub fn resolve(
|
||||
&self,
|
||||
specifier: &str,
|
||||
referrer: &ModuleSpecifier,
|
||||
referrer: &Url,
|
||||
referrer_kind: NodeModuleKind,
|
||||
mode: NodeResolutionMode,
|
||||
) -> Result<NodeResolution, NodeResolveError> {
|
||||
// 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 crate::is_builtin_node_module(specifier) {
|
||||
if self.env.is_builtin_node_module(specifier) {
|
||||
return Ok(NodeResolution::BuiltIn(specifier.to_string()));
|
||||
}
|
||||
|
||||
|
@ -248,11 +245,11 @@ impl NodeResolver {
|
|||
fn module_resolve(
|
||||
&self,
|
||||
specifier: &str,
|
||||
referrer: &ModuleSpecifier,
|
||||
referrer: &Url,
|
||||
referrer_kind: NodeModuleKind,
|
||||
conditions: &[&str],
|
||||
mode: NodeResolutionMode,
|
||||
) -> Result<ModuleSpecifier, NodeResolveError> {
|
||||
) -> Result<Url, NodeResolveError> {
|
||||
if should_be_treated_as_relative_or_absolute_path(specifier) {
|
||||
Ok(referrer.join(specifier).map_err(|err| {
|
||||
NodeResolveRelativeJoinError {
|
||||
|
@ -289,9 +286,9 @@ impl NodeResolver {
|
|||
|
||||
fn finalize_resolution(
|
||||
&self,
|
||||
resolved: ModuleSpecifier,
|
||||
maybe_referrer: Option<&ModuleSpecifier>,
|
||||
) -> Result<ModuleSpecifier, FinalizeResolutionError> {
|
||||
resolved: Url,
|
||||
maybe_referrer: Option<&Url>,
|
||||
) -> Result<Url, FinalizeResolutionError> {
|
||||
let encoded_sep_re = lazy_regex::regex!(r"%2F|%2C");
|
||||
|
||||
if encoded_sep_re.is_match(resolved.path()) {
|
||||
|
@ -325,9 +322,9 @@ impl NodeResolver {
|
|||
p_str.to_string()
|
||||
};
|
||||
|
||||
let (is_dir, is_file) = if let Ok(stats) = self.fs.stat_sync(Path::new(&p))
|
||||
let (is_dir, is_file) = if let Ok(stats) = self.env.stat_sync(Path::new(&p))
|
||||
{
|
||||
(stats.is_directory, stats.is_file)
|
||||
(stats.is_dir, stats.is_file)
|
||||
} else {
|
||||
(false, false)
|
||||
};
|
||||
|
@ -357,7 +354,7 @@ impl NodeResolver {
|
|||
&self,
|
||||
package_dir: &Path,
|
||||
package_subpath: Option<&str>,
|
||||
maybe_referrer: Option<&ModuleSpecifier>,
|
||||
maybe_referrer: Option<&Url>,
|
||||
mode: NodeResolutionMode,
|
||||
) -> Result<NodeResolution, ResolvePkgSubpathFromDenoModuleError> {
|
||||
let node_module_kind = NodeModuleKind::Esm;
|
||||
|
@ -430,7 +427,7 @@ impl NodeResolver {
|
|||
|
||||
pub fn url_to_node_resolution(
|
||||
&self,
|
||||
url: ModuleSpecifier,
|
||||
url: Url,
|
||||
) -> Result<NodeResolution, UrlToNodeResolutionError> {
|
||||
let url_str = url.as_str().to_lowercase();
|
||||
if url_str.starts_with("http") || url_str.ends_with(".json") {
|
||||
|
@ -459,11 +456,11 @@ impl NodeResolver {
|
|||
fn path_to_declaration_url(
|
||||
&self,
|
||||
path: &Path,
|
||||
maybe_referrer: Option<&ModuleSpecifier>,
|
||||
maybe_referrer: Option<&Url>,
|
||||
referrer_kind: NodeModuleKind,
|
||||
) -> Result<ModuleSpecifier, TypesNotFoundError> {
|
||||
fn probe_extensions(
|
||||
fs: &dyn deno_fs::FileSystem,
|
||||
) -> Result<Url, TypesNotFoundError> {
|
||||
fn probe_extensions<TEnv: NodeResolverEnv>(
|
||||
fs: &TEnv,
|
||||
path: &Path,
|
||||
lowercase_path: &str,
|
||||
referrer_kind: NodeModuleKind,
|
||||
|
@ -514,11 +511,11 @@ impl NodeResolver {
|
|||
return Ok(to_file_specifier(path));
|
||||
}
|
||||
if let Some(path) =
|
||||
probe_extensions(&*self.fs, path, &lowercase_path, referrer_kind)
|
||||
probe_extensions(&self.env, path, &lowercase_path, referrer_kind)
|
||||
{
|
||||
return Ok(to_file_specifier(&path));
|
||||
}
|
||||
if self.fs.is_dir_sync(path) {
|
||||
if self.env.is_dir_sync(path) {
|
||||
let resolution_result = self.resolve_package_dir_subpath(
|
||||
path,
|
||||
/* sub path */ ".",
|
||||
|
@ -535,7 +532,7 @@ impl NodeResolver {
|
|||
}
|
||||
let index_path = path.join("index.js");
|
||||
if let Some(path) = probe_extensions(
|
||||
&*self.fs,
|
||||
&self.env,
|
||||
&index_path,
|
||||
&index_path.to_string_lossy().to_lowercase(),
|
||||
referrer_kind,
|
||||
|
@ -554,15 +551,15 @@ impl NodeResolver {
|
|||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub(super) fn package_imports_resolve(
|
||||
pub fn package_imports_resolve(
|
||||
&self,
|
||||
name: &str,
|
||||
maybe_referrer: Option<&ModuleSpecifier>,
|
||||
maybe_referrer: Option<&Url>,
|
||||
referrer_kind: NodeModuleKind,
|
||||
referrer_pkg_json: Option<&PackageJson>,
|
||||
conditions: &[&str],
|
||||
mode: NodeResolutionMode,
|
||||
) -> Result<ModuleSpecifier, PackageImportsResolveError> {
|
||||
) -> Result<Url, PackageImportsResolveError> {
|
||||
if name == "#" || name.starts_with("#/") || name.ends_with('/') {
|
||||
let reason = "is not a valid internal imports specifier name";
|
||||
return Err(
|
||||
|
@ -659,13 +656,13 @@ impl NodeResolver {
|
|||
subpath: &str,
|
||||
match_: &str,
|
||||
package_json_path: &Path,
|
||||
maybe_referrer: Option<&ModuleSpecifier>,
|
||||
maybe_referrer: Option<&Url>,
|
||||
referrer_kind: NodeModuleKind,
|
||||
pattern: bool,
|
||||
internal: bool,
|
||||
conditions: &[&str],
|
||||
mode: NodeResolutionMode,
|
||||
) -> Result<ModuleSpecifier, PackageTargetResolveError> {
|
||||
) -> Result<Url, PackageTargetResolveError> {
|
||||
if !subpath.is_empty() && !pattern && !target.ends_with('/') {
|
||||
return Err(
|
||||
InvalidPackageTargetError {
|
||||
|
@ -739,11 +736,8 @@ impl NodeResolver {
|
|||
return match result {
|
||||
Ok(url) => Ok(url),
|
||||
Err(err) => {
|
||||
if is_builtin_node_module(target) {
|
||||
Ok(
|
||||
ModuleSpecifier::parse(&format!("node:{}", target))
|
||||
.unwrap(),
|
||||
)
|
||||
if self.env.is_builtin_node_module(target) {
|
||||
Ok(Url::parse(&format!("node:{}", target)).unwrap())
|
||||
} else {
|
||||
Err(err)
|
||||
}
|
||||
|
@ -824,13 +818,13 @@ impl NodeResolver {
|
|||
target: &Value,
|
||||
subpath: &str,
|
||||
package_subpath: &str,
|
||||
maybe_referrer: Option<&ModuleSpecifier>,
|
||||
maybe_referrer: Option<&Url>,
|
||||
referrer_kind: NodeModuleKind,
|
||||
pattern: bool,
|
||||
internal: bool,
|
||||
conditions: &[&str],
|
||||
mode: NodeResolutionMode,
|
||||
) -> Result<Option<ModuleSpecifier>, PackageTargetResolveError> {
|
||||
) -> Result<Option<Url>, PackageTargetResolveError> {
|
||||
let result = self.resolve_package_target_inner(
|
||||
package_json_path,
|
||||
target,
|
||||
|
@ -880,13 +874,13 @@ impl NodeResolver {
|
|||
target: &Value,
|
||||
subpath: &str,
|
||||
package_subpath: &str,
|
||||
maybe_referrer: Option<&ModuleSpecifier>,
|
||||
maybe_referrer: Option<&Url>,
|
||||
referrer_kind: NodeModuleKind,
|
||||
pattern: bool,
|
||||
internal: bool,
|
||||
conditions: &[&str],
|
||||
mode: NodeResolutionMode,
|
||||
) -> Result<Option<ModuleSpecifier>, PackageTargetResolveError> {
|
||||
) -> Result<Option<Url>, PackageTargetResolveError> {
|
||||
if let Some(target) = target.as_str() {
|
||||
let url = self.resolve_package_target_string(
|
||||
target,
|
||||
|
@ -1007,11 +1001,11 @@ impl NodeResolver {
|
|||
package_json_path: &Path,
|
||||
package_subpath: &str,
|
||||
package_exports: &Map<String, Value>,
|
||||
maybe_referrer: Option<&ModuleSpecifier>,
|
||||
maybe_referrer: Option<&Url>,
|
||||
referrer_kind: NodeModuleKind,
|
||||
conditions: &[&str],
|
||||
mode: NodeResolutionMode,
|
||||
) -> Result<ModuleSpecifier, PackageExportsResolveError> {
|
||||
) -> Result<Url, PackageExportsResolveError> {
|
||||
if package_exports.contains_key(package_subpath)
|
||||
&& package_subpath.find('*').is_none()
|
||||
&& !package_subpath.ends_with('/')
|
||||
|
@ -1120,11 +1114,11 @@ impl NodeResolver {
|
|||
pub(super) fn package_resolve(
|
||||
&self,
|
||||
specifier: &str,
|
||||
referrer: &ModuleSpecifier,
|
||||
referrer: &Url,
|
||||
referrer_kind: NodeModuleKind,
|
||||
conditions: &[&str],
|
||||
mode: NodeResolutionMode,
|
||||
) -> Result<ModuleSpecifier, PackageResolveError> {
|
||||
) -> Result<Url, PackageResolveError> {
|
||||
let (package_name, package_subpath, _is_scoped) =
|
||||
parse_npm_pkg_name(specifier, referrer)?;
|
||||
|
||||
|
@ -1162,11 +1156,11 @@ impl NodeResolver {
|
|||
&self,
|
||||
package_name: &str,
|
||||
package_subpath: &str,
|
||||
referrer: &ModuleSpecifier,
|
||||
referrer: &Url,
|
||||
referrer_kind: NodeModuleKind,
|
||||
conditions: &[&str],
|
||||
mode: NodeResolutionMode,
|
||||
) -> Result<ModuleSpecifier, PackageResolveError> {
|
||||
) -> Result<Url, PackageResolveError> {
|
||||
let result = self.resolve_package_subpath_for_package_inner(
|
||||
package_name,
|
||||
package_subpath,
|
||||
|
@ -1175,7 +1169,7 @@ impl NodeResolver {
|
|||
conditions,
|
||||
mode,
|
||||
);
|
||||
if mode.is_types() && !matches!(result, Ok(ModuleSpecifier { .. })) {
|
||||
if mode.is_types() && !matches!(result, Ok(Url { .. })) {
|
||||
// try to resolve with the @types package
|
||||
let package_name = types_package_name(package_name);
|
||||
if let Ok(result) = self.resolve_package_subpath_for_package_inner(
|
||||
|
@ -1197,11 +1191,11 @@ impl NodeResolver {
|
|||
&self,
|
||||
package_name: &str,
|
||||
package_subpath: &str,
|
||||
referrer: &ModuleSpecifier,
|
||||
referrer: &Url,
|
||||
referrer_kind: NodeModuleKind,
|
||||
conditions: &[&str],
|
||||
mode: NodeResolutionMode,
|
||||
) -> Result<ModuleSpecifier, PackageResolveError> {
|
||||
) -> Result<Url, PackageResolveError> {
|
||||
let package_dir_path = self
|
||||
.npm_resolver
|
||||
.resolve_package_folder_from_package(package_name, referrer)?;
|
||||
|
@ -1237,11 +1231,11 @@ impl NodeResolver {
|
|||
&self,
|
||||
package_dir_path: &Path,
|
||||
package_subpath: &str,
|
||||
maybe_referrer: Option<&ModuleSpecifier>,
|
||||
maybe_referrer: Option<&Url>,
|
||||
referrer_kind: NodeModuleKind,
|
||||
conditions: &[&str],
|
||||
mode: NodeResolutionMode,
|
||||
) -> Result<ModuleSpecifier, PackageSubpathResolveError> {
|
||||
) -> Result<Url, PackageSubpathResolveError> {
|
||||
let package_json_path = package_dir_path.join("package.json");
|
||||
match self.load_package_json(&package_json_path)? {
|
||||
Some(pkg_json) => self.resolve_package_subpath(
|
||||
|
@ -1271,11 +1265,11 @@ impl NodeResolver {
|
|||
&self,
|
||||
package_json: &PackageJson,
|
||||
package_subpath: &str,
|
||||
referrer: Option<&ModuleSpecifier>,
|
||||
referrer: Option<&Url>,
|
||||
referrer_kind: NodeModuleKind,
|
||||
conditions: &[&str],
|
||||
mode: NodeResolutionMode,
|
||||
) -> Result<ModuleSpecifier, PackageSubpathResolveError> {
|
||||
) -> Result<Url, PackageSubpathResolveError> {
|
||||
if let Some(exports) = &package_json.exports {
|
||||
let result = self.package_exports_resolve(
|
||||
&package_json.path,
|
||||
|
@ -1328,10 +1322,10 @@ impl NodeResolver {
|
|||
&self,
|
||||
directory: &Path,
|
||||
package_subpath: &str,
|
||||
referrer: Option<&ModuleSpecifier>,
|
||||
referrer: Option<&Url>,
|
||||
referrer_kind: NodeModuleKind,
|
||||
mode: NodeResolutionMode,
|
||||
) -> Result<ModuleSpecifier, TypesNotFoundError> {
|
||||
) -> Result<Url, TypesNotFoundError> {
|
||||
assert_ne!(package_subpath, ".");
|
||||
let file_path = directory.join(package_subpath);
|
||||
if mode.is_types() {
|
||||
|
@ -1345,10 +1339,10 @@ impl NodeResolver {
|
|||
&self,
|
||||
directory: &Path,
|
||||
package_subpath: &str,
|
||||
maybe_referrer: Option<&ModuleSpecifier>,
|
||||
maybe_referrer: Option<&Url>,
|
||||
referrer_kind: NodeModuleKind,
|
||||
mode: NodeResolutionMode,
|
||||
) -> Result<ModuleSpecifier, LegacyResolveError> {
|
||||
) -> Result<Url, LegacyResolveError> {
|
||||
if package_subpath == "." {
|
||||
self.legacy_index_resolve(directory, maybe_referrer, referrer_kind, mode)
|
||||
} else {
|
||||
|
@ -1366,7 +1360,7 @@ impl NodeResolver {
|
|||
|
||||
pub fn get_closest_package_json(
|
||||
&self,
|
||||
url: &ModuleSpecifier,
|
||||
url: &Url,
|
||||
) -> Result<Option<PackageJsonRc>, ClosestPkgJsonError> {
|
||||
let Ok(file_path) = url.to_file_path() else {
|
||||
return Ok(None);
|
||||
|
@ -1380,10 +1374,10 @@ impl NodeResolver {
|
|||
) -> Result<Option<PackageJsonRc>, ClosestPkgJsonError> {
|
||||
let parent_dir = file_path.parent().unwrap();
|
||||
let current_dir =
|
||||
deno_core::strip_unc_prefix(self.fs.realpath_sync(parent_dir).map_err(
|
||||
strip_unc_prefix(self.env.realpath_sync(parent_dir).map_err(
|
||||
|source| CanonicalizingPkgJsonDirError {
|
||||
dir_path: parent_dir.to_path_buf(),
|
||||
source: source.into_io_error(),
|
||||
source,
|
||||
},
|
||||
)?);
|
||||
for current_dir in current_dir.ancestors() {
|
||||
|
@ -1396,20 +1390,23 @@ impl NodeResolver {
|
|||
Ok(None)
|
||||
}
|
||||
|
||||
pub(super) fn load_package_json(
|
||||
pub fn load_package_json(
|
||||
&self,
|
||||
package_json_path: &Path,
|
||||
) -> Result<Option<PackageJsonRc>, PackageJsonLoadError> {
|
||||
crate::package_json::load_pkg_json(&*self.fs, package_json_path)
|
||||
crate::package_json::load_pkg_json(
|
||||
self.env.pkg_json_fs(),
|
||||
package_json_path,
|
||||
)
|
||||
}
|
||||
|
||||
pub(super) fn legacy_main_resolve(
|
||||
&self,
|
||||
package_json: &PackageJson,
|
||||
maybe_referrer: Option<&ModuleSpecifier>,
|
||||
maybe_referrer: Option<&Url>,
|
||||
referrer_kind: NodeModuleKind,
|
||||
mode: NodeResolutionMode,
|
||||
) -> Result<ModuleSpecifier, LegacyResolveError> {
|
||||
) -> Result<Url, LegacyResolveError> {
|
||||
let maybe_main = if mode.is_types() {
|
||||
match package_json.types.as_ref() {
|
||||
Some(types) => Some(types.as_str()),
|
||||
|
@ -1437,7 +1434,7 @@ impl NodeResolver {
|
|||
|
||||
if let Some(main) = maybe_main {
|
||||
let guess = package_json.path.parent().unwrap().join(main).clean();
|
||||
if self.fs.is_file_sync(&guess) {
|
||||
if self.env.is_file_sync(&guess) {
|
||||
return Ok(to_file_specifier(&guess));
|
||||
}
|
||||
|
||||
|
@ -1466,7 +1463,7 @@ impl NodeResolver {
|
|||
.unwrap()
|
||||
.join(format!("{main}{ending}"))
|
||||
.clean();
|
||||
if self.fs.is_file_sync(&guess) {
|
||||
if self.env.is_file_sync(&guess) {
|
||||
// TODO(bartlomieju): emitLegacyIndexDeprecation()
|
||||
return Ok(to_file_specifier(&guess));
|
||||
}
|
||||
|
@ -1484,10 +1481,10 @@ impl NodeResolver {
|
|||
fn legacy_index_resolve(
|
||||
&self,
|
||||
directory: &Path,
|
||||
maybe_referrer: Option<&ModuleSpecifier>,
|
||||
maybe_referrer: Option<&Url>,
|
||||
referrer_kind: NodeModuleKind,
|
||||
mode: NodeResolutionMode,
|
||||
) -> Result<ModuleSpecifier, LegacyResolveError> {
|
||||
) -> Result<Url, LegacyResolveError> {
|
||||
let index_file_names = if mode.is_types() {
|
||||
// todo(dsherret): investigate exactly how typescript does this
|
||||
match referrer_kind {
|
||||
|
@ -1499,7 +1496,7 @@ impl NodeResolver {
|
|||
};
|
||||
for index_file_name in index_file_names {
|
||||
let guess = directory.join(index_file_name).clean();
|
||||
if self.fs.is_file_sync(&guess) {
|
||||
if self.env.is_file_sync(&guess) {
|
||||
// TODO(bartlomieju): emitLegacyIndexDeprecation()
|
||||
return Ok(to_file_specifier(&guess));
|
||||
}
|
||||
|
@ -1615,13 +1612,13 @@ fn resolve_bin_entry_value<'a>(
|
|||
}
|
||||
}
|
||||
|
||||
fn to_file_path(url: &ModuleSpecifier) -> PathBuf {
|
||||
fn to_file_path(url: &Url) -> PathBuf {
|
||||
url
|
||||
.to_file_path()
|
||||
.unwrap_or_else(|_| panic!("Provided URL was not file:// URL: {url}"))
|
||||
}
|
||||
|
||||
fn to_file_path_string(url: &ModuleSpecifier) -> String {
|
||||
fn to_file_path_string(url: &Url) -> String {
|
||||
to_file_path(url).display().to_string()
|
||||
}
|
||||
|
||||
|
@ -1696,7 +1693,7 @@ fn with_known_extension(path: &Path, ext: &str) -> PathBuf {
|
|||
path.with_file_name(format!("{file_name}.{ext}"))
|
||||
}
|
||||
|
||||
fn to_specifier_display_string(url: &ModuleSpecifier) -> String {
|
||||
fn to_specifier_display_string(url: &Url) -> String {
|
||||
if let Ok(path) = url.to_file_path() {
|
||||
path.display().to_string()
|
||||
} else {
|
||||
|
@ -1708,7 +1705,7 @@ fn throw_invalid_subpath(
|
|||
subpath: String,
|
||||
package_json_path: &Path,
|
||||
internal: bool,
|
||||
maybe_referrer: Option<&ModuleSpecifier>,
|
||||
maybe_referrer: Option<&Url>,
|
||||
) -> InvalidModuleSpecifierError {
|
||||
let ie = if internal { "imports" } else { "exports" };
|
||||
let reason = format!(
|
||||
|
@ -1725,7 +1722,7 @@ fn throw_invalid_subpath(
|
|||
|
||||
pub fn parse_npm_pkg_name(
|
||||
specifier: &str,
|
||||
referrer: &ModuleSpecifier,
|
||||
referrer: &Url,
|
||||
) -> Result<(String, String, bool), InvalidModuleSpecifierError> {
|
||||
let mut separator_index = specifier.find('/');
|
||||
let mut valid_package_name = true;
|
||||
|
@ -1824,9 +1821,21 @@ fn types_package_name(package_name: &str) -> String {
|
|||
format!("@types/{}", package_name.replace('/', "__"))
|
||||
}
|
||||
|
||||
/// Ex. returns `fs` for `node:fs`
|
||||
fn get_module_name_from_builtin_node_module_specifier(
|
||||
specifier: &Url,
|
||||
) -> Option<&str> {
|
||||
if specifier.scheme() != "node" {
|
||||
return None;
|
||||
}
|
||||
|
||||
let (_, specifier) = specifier.as_str().split_once(':')?;
|
||||
Some(specifier)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use deno_core::serde_json::json;
|
||||
use serde_json::json;
|
||||
|
||||
use super::*;
|
||||
|
86
ext/node_resolver/sync.rs
Normal file
86
ext/node_resolver/sync.rs
Normal file
|
@ -0,0 +1,86 @@
|
|||
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
||||
|
||||
pub use inner::*;
|
||||
|
||||
#[cfg(feature = "sync")]
|
||||
mod inner {
|
||||
#![allow(clippy::disallowed_types)]
|
||||
|
||||
use std::ops::Deref;
|
||||
use std::ops::DerefMut;
|
||||
pub use std::sync::Arc as MaybeArc;
|
||||
|
||||
pub struct MaybeArcMutexGuard<'lock, T>(std::sync::MutexGuard<'lock, T>);
|
||||
|
||||
impl<'lock, T> Deref for MaybeArcMutexGuard<'lock, T> {
|
||||
type Target = std::sync::MutexGuard<'lock, T>;
|
||||
fn deref(&self) -> &std::sync::MutexGuard<'lock, T> {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl<'lock, T> DerefMut for MaybeArcMutexGuard<'lock, T> {
|
||||
fn deref_mut(&mut self) -> &mut std::sync::MutexGuard<'lock, T> {
|
||||
&mut self.0
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct MaybeArcMutex<T>(std::sync::Arc<std::sync::Mutex<T>>);
|
||||
impl<T> MaybeArcMutex<T> {
|
||||
pub fn new(val: T) -> Self {
|
||||
Self(std::sync::Arc::new(std::sync::Mutex::new(val)))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'lock, T> MaybeArcMutex<T> {
|
||||
pub fn lock(&'lock self) -> MaybeArcMutexGuard<'lock, T> {
|
||||
MaybeArcMutexGuard(self.0.lock().unwrap())
|
||||
}
|
||||
}
|
||||
|
||||
pub use core::marker::Send as MaybeSend;
|
||||
pub use core::marker::Sync as MaybeSync;
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "sync"))]
|
||||
mod inner {
|
||||
use std::ops::Deref;
|
||||
use std::ops::DerefMut;
|
||||
|
||||
pub use std::rc::Rc as MaybeArc;
|
||||
|
||||
pub struct MaybeArcMutexGuard<'lock, T>(std::cell::RefMut<'lock, T>);
|
||||
|
||||
impl<'lock, T> Deref for MaybeArcMutexGuard<'lock, T> {
|
||||
type Target = std::cell::RefMut<'lock, T>;
|
||||
fn deref(&self) -> &std::cell::RefMut<'lock, T> {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl<'lock, T> DerefMut for MaybeArcMutexGuard<'lock, T> {
|
||||
fn deref_mut(&mut self) -> &mut std::cell::RefMut<'lock, T> {
|
||||
&mut self.0
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct MaybeArcMutex<T>(std::rc::Rc<std::cell::RefCell<T>>);
|
||||
impl<T> MaybeArcMutex<T> {
|
||||
pub fn new(val: T) -> Self {
|
||||
Self(std::rc::Rc::new(std::cell::RefCell::new(val)))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'lock, T> MaybeArcMutex<T> {
|
||||
pub fn lock(&'lock self) -> MaybeArcMutexGuard<'lock, T> {
|
||||
MaybeArcMutexGuard(self.0.borrow_mut())
|
||||
}
|
||||
}
|
||||
|
||||
pub trait MaybeSync {}
|
||||
impl<T> MaybeSync for T where T: ?Sized {}
|
||||
pub trait MaybeSend {}
|
||||
impl<T> MaybeSend for T where T: ?Sized {}
|
||||
}
|
|
@ -94,6 +94,7 @@ deno_webgpu.workspace = true
|
|||
deno_webidl.workspace = true
|
||||
deno_websocket.workspace = true
|
||||
deno_webstorage.workspace = true
|
||||
node_resolver = { workspace = true, features = ["sync"] }
|
||||
|
||||
dlopen2.workspace = true
|
||||
encoding_rs.workspace = true
|
||||
|
|
|
@ -254,7 +254,7 @@ pub fn create_runtime_snapshot(
|
|||
deno_http::deno_http::init_ops_and_esm::<DefaultHttpPropertyExtractor>(),
|
||||
deno_io::deno_io::init_ops_and_esm(Default::default()),
|
||||
deno_fs::deno_fs::init_ops_and_esm::<Permissions>(fs.clone()),
|
||||
deno_node::deno_node::init_ops_and_esm::<Permissions>(None, None, fs),
|
||||
deno_node::deno_node::init_ops_and_esm::<Permissions>(None, fs),
|
||||
runtime::init_ops_and_esm(),
|
||||
ops::runtime::deno_runtime::init_ops("deno:runtime".parse().unwrap()),
|
||||
ops::worker_host::deno_worker_host::init_ops(
|
||||
|
|
|
@ -43,7 +43,7 @@ use deno_fs::FileSystem;
|
|||
use deno_http::DefaultHttpPropertyExtractor;
|
||||
use deno_io::Stdio;
|
||||
use deno_kv::dynamic::MultiBackendDbHandler;
|
||||
use deno_node::NodeResolver;
|
||||
use deno_node::NodeExtInitServices;
|
||||
use deno_permissions::PermissionsContainer;
|
||||
use deno_terminal::colors;
|
||||
use deno_tls::RootCertStoreProvider;
|
||||
|
@ -364,8 +364,7 @@ pub struct WebWorkerOptions {
|
|||
pub seed: Option<u64>,
|
||||
pub fs: Arc<dyn FileSystem>,
|
||||
pub module_loader: Rc<dyn ModuleLoader>,
|
||||
pub node_resolver: Option<Arc<NodeResolver>>,
|
||||
pub npm_resolver: Option<Arc<dyn deno_node::NpmResolver>>,
|
||||
pub node_services: Option<NodeExtInitServices>,
|
||||
pub create_web_worker_cb: Arc<ops::worker_host::CreateWebWorkerCb>,
|
||||
pub format_js_error_fn: Option<Arc<FormatJsErrorFn>>,
|
||||
pub worker_type: WebWorkerType,
|
||||
|
@ -490,8 +489,7 @@ impl WebWorker {
|
|||
options.fs.clone(),
|
||||
),
|
||||
deno_node::deno_node::init_ops_and_esm::<PermissionsContainer>(
|
||||
options.node_resolver,
|
||||
options.npm_resolver,
|
||||
options.node_services,
|
||||
options.fs,
|
||||
),
|
||||
// Runtime ops that are always initialized for WebWorkers
|
||||
|
|
|
@ -38,6 +38,7 @@ use deno_fs::FileSystem;
|
|||
use deno_http::DefaultHttpPropertyExtractor;
|
||||
use deno_io::Stdio;
|
||||
use deno_kv::dynamic::MultiBackendDbHandler;
|
||||
use deno_node::NodeExtInitServices;
|
||||
use deno_permissions::PermissionsContainer;
|
||||
use deno_tls::RootCertStoreProvider;
|
||||
use deno_tls::TlsKeys;
|
||||
|
@ -155,8 +156,7 @@ pub struct WorkerOptions {
|
|||
/// If not provided runtime will error if code being
|
||||
/// executed tries to load modules.
|
||||
pub module_loader: Rc<dyn ModuleLoader>,
|
||||
pub node_resolver: Option<Arc<deno_node::NodeResolver>>,
|
||||
pub npm_resolver: Option<Arc<dyn deno_node::NpmResolver>>,
|
||||
pub node_services: Option<NodeExtInitServices>,
|
||||
// Callbacks invoked when creating new instance of WebWorker
|
||||
pub create_web_worker_cb: Arc<ops::worker_host::CreateWebWorkerCb>,
|
||||
pub format_js_error_fn: Option<Arc<FormatJsErrorFn>>,
|
||||
|
@ -224,8 +224,7 @@ impl Default for WorkerOptions {
|
|||
cache_storage_dir: Default::default(),
|
||||
broadcast_channel: Default::default(),
|
||||
root_cert_store_provider: Default::default(),
|
||||
node_resolver: Default::default(),
|
||||
npm_resolver: Default::default(),
|
||||
node_services: Default::default(),
|
||||
blob_store: Default::default(),
|
||||
extensions: Default::default(),
|
||||
startup_snapshot: Default::default(),
|
||||
|
@ -414,8 +413,7 @@ impl MainWorker {
|
|||
options.fs.clone(),
|
||||
),
|
||||
deno_node::deno_node::init_ops_and_esm::<PermissionsContainer>(
|
||||
options.node_resolver,
|
||||
options.npm_resolver,
|
||||
options.node_services,
|
||||
options.fs,
|
||||
),
|
||||
// Ops from this crate
|
||||
|
|
Loading…
Reference in a new issue