mirror of
https://github.com/denoland/deno.git
synced 2025-01-19 04:16:00 -05:00
refactor(npm): extract out some npm fs resolution code from the cli (#27607)
Moves the npm fs resolvers into the deno_resolution crate. This does not entirely move things out, but is a step in that direction.
This commit is contained in:
parent
ce0968ef3a
commit
093f3ba565
24 changed files with 312 additions and 213 deletions
6
Cargo.lock
generated
6
Cargo.lock
generated
|
@ -2096,12 +2096,10 @@ dependencies = [
|
||||||
name = "deno_npm_cache"
|
name = "deno_npm_cache"
|
||||||
version = "0.3.0"
|
version = "0.3.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
|
||||||
"async-trait",
|
"async-trait",
|
||||||
"base64 0.21.7",
|
"base64 0.21.7",
|
||||||
"boxed_error",
|
"boxed_error",
|
||||||
"deno_cache_dir",
|
"deno_cache_dir",
|
||||||
"deno_core",
|
|
||||||
"deno_error",
|
"deno_error",
|
||||||
"deno_npm",
|
"deno_npm",
|
||||||
"deno_path_util",
|
"deno_path_util",
|
||||||
|
@ -2197,16 +2195,20 @@ name = "deno_resolver"
|
||||||
version = "0.15.0"
|
version = "0.15.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
|
"async-trait",
|
||||||
"base32",
|
"base32",
|
||||||
"boxed_error",
|
"boxed_error",
|
||||||
"dashmap",
|
"dashmap",
|
||||||
|
"deno_cache_dir",
|
||||||
"deno_config",
|
"deno_config",
|
||||||
"deno_error",
|
"deno_error",
|
||||||
"deno_media_type",
|
"deno_media_type",
|
||||||
|
"deno_npm",
|
||||||
"deno_package_json",
|
"deno_package_json",
|
||||||
"deno_path_util",
|
"deno_path_util",
|
||||||
"deno_semver",
|
"deno_semver",
|
||||||
"node_resolver",
|
"node_resolver",
|
||||||
|
"parking_lot",
|
||||||
"sys_traits",
|
"sys_traits",
|
||||||
"test_server",
|
"test_server",
|
||||||
"thiserror 2.0.3",
|
"thiserror 2.0.3",
|
||||||
|
|
|
@ -70,7 +70,7 @@ impl HttpClientProvider {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_or_create(&self) -> Result<HttpClient, AnyError> {
|
pub fn get_or_create(&self) -> Result<HttpClient, JsErrorBox> {
|
||||||
use std::collections::hash_map::Entry;
|
use std::collections::hash_map::Entry;
|
||||||
let thread_id = std::thread::current().id();
|
let thread_id = std::thread::current().id();
|
||||||
let mut clients = self.clients_by_thread_id.lock();
|
let mut clients = self.clients_by_thread_id.lock();
|
||||||
|
@ -87,7 +87,8 @@ impl HttpClientProvider {
|
||||||
},
|
},
|
||||||
..self.options.clone()
|
..self.options.clone()
|
||||||
},
|
},
|
||||||
)?;
|
)
|
||||||
|
.map_err(JsErrorBox::from_err)?;
|
||||||
entry.insert(client.clone());
|
entry.insert(client.clone());
|
||||||
Ok(HttpClient::new(client))
|
Ok(HttpClient::new(client))
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,13 +13,13 @@ use deno_npm::resolution::AddPkgReqsOptions;
|
||||||
use deno_npm::resolution::NpmResolutionError;
|
use deno_npm::resolution::NpmResolutionError;
|
||||||
use deno_npm::resolution::NpmResolutionSnapshot;
|
use deno_npm::resolution::NpmResolutionSnapshot;
|
||||||
use deno_npm::NpmResolutionPackage;
|
use deno_npm::NpmResolutionPackage;
|
||||||
|
use deno_resolver::npm::managed::NpmResolution;
|
||||||
use deno_semver::jsr::JsrDepPackageReq;
|
use deno_semver::jsr::JsrDepPackageReq;
|
||||||
use deno_semver::package::PackageNv;
|
use deno_semver::package::PackageNv;
|
||||||
use deno_semver::package::PackageReq;
|
use deno_semver::package::PackageReq;
|
||||||
use deno_semver::SmallStackString;
|
use deno_semver::SmallStackString;
|
||||||
use deno_semver::VersionReq;
|
use deno_semver::VersionReq;
|
||||||
|
|
||||||
use super::resolution::NpmResolution;
|
|
||||||
use crate::args::CliLockfile;
|
use crate::args::CliLockfile;
|
||||||
use crate::npm::CliNpmRegistryInfoProvider;
|
use crate::npm::CliNpmRegistryInfoProvider;
|
||||||
use crate::util::sync::TaskQueue;
|
use crate::util::sync::TaskQueue;
|
||||||
|
|
|
@ -11,8 +11,8 @@ use deno_core::futures::StreamExt;
|
||||||
use deno_error::JsErrorBox;
|
use deno_error::JsErrorBox;
|
||||||
use deno_npm::NpmResolutionPackage;
|
use deno_npm::NpmResolutionPackage;
|
||||||
use deno_npm::NpmSystemInfo;
|
use deno_npm::NpmSystemInfo;
|
||||||
|
use deno_resolver::npm::managed::NpmResolution;
|
||||||
|
|
||||||
use super::super::resolution::NpmResolution;
|
|
||||||
use super::common::lifecycle_scripts::LifecycleScriptsStrategy;
|
use super::common::lifecycle_scripts::LifecycleScriptsStrategy;
|
||||||
use super::common::NpmPackageFsInstaller;
|
use super::common::NpmPackageFsInstaller;
|
||||||
use crate::args::LifecycleScriptsConfig;
|
use crate::args::LifecycleScriptsConfig;
|
||||||
|
|
|
@ -24,19 +24,19 @@ use deno_npm::resolution::NpmResolutionSnapshot;
|
||||||
use deno_npm::NpmResolutionPackage;
|
use deno_npm::NpmResolutionPackage;
|
||||||
use deno_npm::NpmSystemInfo;
|
use deno_npm::NpmSystemInfo;
|
||||||
use deno_path_util::fs::atomic_write_file_with_retries;
|
use deno_path_util::fs::atomic_write_file_with_retries;
|
||||||
|
use deno_resolver::npm::get_package_folder_id_folder_name;
|
||||||
|
use deno_resolver::npm::managed::NpmResolution;
|
||||||
use deno_semver::package::PackageNv;
|
use deno_semver::package::PackageNv;
|
||||||
use deno_semver::StackString;
|
use deno_semver::StackString;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
|
||||||
use super::super::resolution::NpmResolution;
|
|
||||||
use super::common::bin_entries;
|
use super::common::bin_entries;
|
||||||
use super::common::NpmPackageFsInstaller;
|
use super::common::NpmPackageFsInstaller;
|
||||||
use crate::args::LifecycleScriptsConfig;
|
use crate::args::LifecycleScriptsConfig;
|
||||||
use crate::args::NpmInstallDepsProvider;
|
use crate::args::NpmInstallDepsProvider;
|
||||||
use crate::cache::CACHE_PERM;
|
use crate::cache::CACHE_PERM;
|
||||||
use crate::colors;
|
use crate::colors;
|
||||||
use crate::npm::managed::resolvers::get_package_folder_id_folder_name;
|
|
||||||
use crate::npm::managed::PackageCaching;
|
use crate::npm::managed::PackageCaching;
|
||||||
use crate::npm::CliNpmCache;
|
use crate::npm::CliNpmCache;
|
||||||
use crate::npm::CliNpmTarballCache;
|
use crate::npm::CliNpmTarballCache;
|
||||||
|
|
|
@ -4,11 +4,11 @@ use std::path::PathBuf;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use deno_npm::NpmSystemInfo;
|
use deno_npm::NpmSystemInfo;
|
||||||
|
use deno_resolver::npm::managed::NpmResolution;
|
||||||
|
|
||||||
pub use self::common::NpmPackageFsInstaller;
|
pub use self::common::NpmPackageFsInstaller;
|
||||||
use self::global::GlobalNpmPackageInstaller;
|
use self::global::GlobalNpmPackageInstaller;
|
||||||
use self::local::LocalNpmPackageInstaller;
|
use self::local::LocalNpmPackageInstaller;
|
||||||
use super::resolution::NpmResolution;
|
|
||||||
use crate::args::LifecycleScriptsConfig;
|
use crate::args::LifecycleScriptsConfig;
|
||||||
use crate::args::NpmInstallDepsProvider;
|
use crate::args::NpmInstallDepsProvider;
|
||||||
use crate::npm::CliNpmCache;
|
use crate::npm::CliNpmCache;
|
||||||
|
|
|
@ -23,6 +23,10 @@ use deno_npm::NpmResolutionPackage;
|
||||||
use deno_npm::NpmSystemInfo;
|
use deno_npm::NpmSystemInfo;
|
||||||
use deno_npm_cache::NpmCacheSetting;
|
use deno_npm_cache::NpmCacheSetting;
|
||||||
use deno_path_util::fs::canonicalize_path_maybe_not_exists;
|
use deno_path_util::fs::canonicalize_path_maybe_not_exists;
|
||||||
|
use deno_resolver::npm::managed::create_npm_fs_resolver;
|
||||||
|
use deno_resolver::npm::managed::NpmPackageFsResolver;
|
||||||
|
use deno_resolver::npm::managed::NpmPackageFsResolverPackageFolderError;
|
||||||
|
use deno_resolver::npm::managed::NpmResolution;
|
||||||
use deno_resolver::npm::CliNpmReqResolver;
|
use deno_resolver::npm::CliNpmReqResolver;
|
||||||
use deno_runtime::colors;
|
use deno_runtime::colors;
|
||||||
use deno_runtime::ops::process::NpmProcessStateProvider;
|
use deno_runtime::ops::process::NpmProcessStateProvider;
|
||||||
|
@ -37,9 +41,6 @@ use node_resolver::errors::PackageFolderResolveIoError;
|
||||||
use node_resolver::InNpmPackageChecker;
|
use node_resolver::InNpmPackageChecker;
|
||||||
use node_resolver::NpmPackageFolderResolver;
|
use node_resolver::NpmPackageFolderResolver;
|
||||||
|
|
||||||
use self::resolution::NpmResolution;
|
|
||||||
use self::resolvers::create_npm_fs_resolver;
|
|
||||||
use self::resolvers::NpmPackageFsResolver;
|
|
||||||
use super::CliNpmCache;
|
use super::CliNpmCache;
|
||||||
use super::CliNpmCacheHttpClient;
|
use super::CliNpmCacheHttpClient;
|
||||||
use super::CliNpmRegistryInfoProvider;
|
use super::CliNpmRegistryInfoProvider;
|
||||||
|
@ -60,8 +61,6 @@ use crate::util::sync::AtomicFlag;
|
||||||
|
|
||||||
mod installer;
|
mod installer;
|
||||||
mod installers;
|
mod installers;
|
||||||
mod resolution;
|
|
||||||
mod resolvers;
|
|
||||||
|
|
||||||
pub enum CliNpmResolverManagedSnapshotOption {
|
pub enum CliNpmResolverManagedSnapshotOption {
|
||||||
ResolveFromLockfile(Arc<CliLockfile>),
|
ResolveFromLockfile(Arc<CliLockfile>),
|
||||||
|
@ -104,6 +103,7 @@ pub async fn create_managed_npm_resolver_for_lsp(
|
||||||
create_inner(
|
create_inner(
|
||||||
http_client,
|
http_client,
|
||||||
npm_cache,
|
npm_cache,
|
||||||
|
options.npm_cache_dir,
|
||||||
options.npm_install_deps_provider,
|
options.npm_install_deps_provider,
|
||||||
npm_api,
|
npm_api,
|
||||||
options.sys,
|
options.sys,
|
||||||
|
@ -133,6 +133,7 @@ pub async fn create_managed_npm_resolver(
|
||||||
Ok(create_inner(
|
Ok(create_inner(
|
||||||
http_client,
|
http_client,
|
||||||
npm_cache,
|
npm_cache,
|
||||||
|
options.npm_cache_dir,
|
||||||
options.npm_install_deps_provider,
|
options.npm_install_deps_provider,
|
||||||
api,
|
api,
|
||||||
options.sys,
|
options.sys,
|
||||||
|
@ -150,6 +151,7 @@ pub async fn create_managed_npm_resolver(
|
||||||
fn create_inner(
|
fn create_inner(
|
||||||
http_client: Arc<CliNpmCacheHttpClient>,
|
http_client: Arc<CliNpmCacheHttpClient>,
|
||||||
npm_cache: Arc<CliNpmCache>,
|
npm_cache: Arc<CliNpmCache>,
|
||||||
|
npm_cache_dir: Arc<NpmCacheDir>,
|
||||||
npm_install_deps_provider: Arc<NpmInstallDepsProvider>,
|
npm_install_deps_provider: Arc<NpmInstallDepsProvider>,
|
||||||
registry_info_provider: Arc<CliNpmRegistryInfoProvider>,
|
registry_info_provider: Arc<CliNpmRegistryInfoProvider>,
|
||||||
sys: CliSys,
|
sys: CliSys,
|
||||||
|
@ -181,7 +183,8 @@ fn create_inner(
|
||||||
lifecycle_scripts.clone(),
|
lifecycle_scripts.clone(),
|
||||||
);
|
);
|
||||||
let fs_resolver = create_npm_fs_resolver(
|
let fs_resolver = create_npm_fs_resolver(
|
||||||
npm_cache.clone(),
|
&npm_cache_dir,
|
||||||
|
&npm_rc,
|
||||||
resolution.clone(),
|
resolution.clone(),
|
||||||
sys.clone(),
|
sys.clone(),
|
||||||
node_modules_dir_path,
|
node_modules_dir_path,
|
||||||
|
@ -192,7 +195,9 @@ fn create_inner(
|
||||||
maybe_lockfile,
|
maybe_lockfile,
|
||||||
registry_info_provider,
|
registry_info_provider,
|
||||||
npm_cache,
|
npm_cache,
|
||||||
|
npm_cache_dir,
|
||||||
npm_install_deps_provider,
|
npm_install_deps_provider,
|
||||||
|
npm_rc,
|
||||||
resolution,
|
resolution,
|
||||||
sys,
|
sys,
|
||||||
tarball_cache,
|
tarball_cache,
|
||||||
|
@ -314,7 +319,9 @@ pub struct ManagedCliNpmResolver {
|
||||||
maybe_lockfile: Option<Arc<CliLockfile>>,
|
maybe_lockfile: Option<Arc<CliLockfile>>,
|
||||||
registry_info_provider: Arc<CliNpmRegistryInfoProvider>,
|
registry_info_provider: Arc<CliNpmRegistryInfoProvider>,
|
||||||
npm_cache: Arc<CliNpmCache>,
|
npm_cache: Arc<CliNpmCache>,
|
||||||
|
npm_cache_dir: Arc<NpmCacheDir>,
|
||||||
npm_install_deps_provider: Arc<NpmInstallDepsProvider>,
|
npm_install_deps_provider: Arc<NpmInstallDepsProvider>,
|
||||||
|
npm_rc: Arc<ResolvedNpmRc>,
|
||||||
sys: CliSys,
|
sys: CliSys,
|
||||||
resolution: Arc<NpmResolution>,
|
resolution: Arc<NpmResolution>,
|
||||||
resolution_installer: NpmResolutionInstaller,
|
resolution_installer: NpmResolutionInstaller,
|
||||||
|
@ -338,7 +345,7 @@ pub enum ResolvePkgFolderFromPkgIdError {
|
||||||
#[class(inherit)]
|
#[class(inherit)]
|
||||||
#[error("{0}")]
|
#[error("{0}")]
|
||||||
NpmPackageFsResolverPackageFolder(
|
NpmPackageFsResolverPackageFolder(
|
||||||
#[from] resolvers::NpmPackageFsResolverPackageFolderError,
|
#[from] NpmPackageFsResolverPackageFolderError,
|
||||||
),
|
),
|
||||||
#[class(inherit)]
|
#[class(inherit)]
|
||||||
#[error("{0}")]
|
#[error("{0}")]
|
||||||
|
@ -363,7 +370,9 @@ impl ManagedCliNpmResolver {
|
||||||
maybe_lockfile: Option<Arc<CliLockfile>>,
|
maybe_lockfile: Option<Arc<CliLockfile>>,
|
||||||
registry_info_provider: Arc<CliNpmRegistryInfoProvider>,
|
registry_info_provider: Arc<CliNpmRegistryInfoProvider>,
|
||||||
npm_cache: Arc<CliNpmCache>,
|
npm_cache: Arc<CliNpmCache>,
|
||||||
|
npm_cache_dir: Arc<NpmCacheDir>,
|
||||||
npm_install_deps_provider: Arc<NpmInstallDepsProvider>,
|
npm_install_deps_provider: Arc<NpmInstallDepsProvider>,
|
||||||
|
npm_rc: Arc<ResolvedNpmRc>,
|
||||||
resolution: Arc<NpmResolution>,
|
resolution: Arc<NpmResolution>,
|
||||||
sys: CliSys,
|
sys: CliSys,
|
||||||
tarball_cache: Arc<CliNpmTarballCache>,
|
tarball_cache: Arc<CliNpmTarballCache>,
|
||||||
|
@ -382,7 +391,9 @@ impl ManagedCliNpmResolver {
|
||||||
maybe_lockfile,
|
maybe_lockfile,
|
||||||
registry_info_provider,
|
registry_info_provider,
|
||||||
npm_cache,
|
npm_cache,
|
||||||
|
npm_cache_dir,
|
||||||
npm_install_deps_provider,
|
npm_install_deps_provider,
|
||||||
|
npm_rc,
|
||||||
text_only_progress_bar,
|
text_only_progress_bar,
|
||||||
resolution,
|
resolution,
|
||||||
resolution_installer,
|
resolution_installer,
|
||||||
|
@ -671,11 +682,11 @@ impl ManagedCliNpmResolver {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn global_cache_root_path(&self) -> &Path {
|
pub fn global_cache_root_path(&self) -> &Path {
|
||||||
self.npm_cache.root_dir_path()
|
self.npm_cache_dir.root_dir()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn global_cache_root_url(&self) -> &Url {
|
pub fn global_cache_root_url(&self) -> &Url {
|
||||||
self.npm_cache.root_dir_url()
|
self.npm_cache_dir.root_dir_url()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -772,7 +783,8 @@ impl CliNpmResolver for ManagedCliNpmResolver {
|
||||||
self.lifecycle_scripts.clone(),
|
self.lifecycle_scripts.clone(),
|
||||||
),
|
),
|
||||||
create_npm_fs_resolver(
|
create_npm_fs_resolver(
|
||||||
self.npm_cache.clone(),
|
&self.npm_cache_dir,
|
||||||
|
&self.npm_rc,
|
||||||
npm_resolution.clone(),
|
npm_resolution.clone(),
|
||||||
self.sys.clone(),
|
self.sys.clone(),
|
||||||
self.root_node_modules_path().map(ToOwned::to_owned),
|
self.root_node_modules_path().map(ToOwned::to_owned),
|
||||||
|
@ -780,7 +792,9 @@ impl CliNpmResolver for ManagedCliNpmResolver {
|
||||||
self.maybe_lockfile.clone(),
|
self.maybe_lockfile.clone(),
|
||||||
self.registry_info_provider.clone(),
|
self.registry_info_provider.clone(),
|
||||||
self.npm_cache.clone(),
|
self.npm_cache.clone(),
|
||||||
|
self.npm_cache_dir.clone(),
|
||||||
self.npm_install_deps_provider.clone(),
|
self.npm_install_deps_provider.clone(),
|
||||||
|
self.npm_rc.clone(),
|
||||||
npm_resolution,
|
npm_resolution,
|
||||||
self.sys.clone(),
|
self.sys.clone(),
|
||||||
self.tarball_cache.clone(),
|
self.tarball_cache.clone(),
|
||||||
|
|
|
@ -1,33 +0,0 @@
|
||||||
// Copyright 2018-2025 the Deno authors. MIT license.
|
|
||||||
|
|
||||||
mod common;
|
|
||||||
mod global;
|
|
||||||
mod local;
|
|
||||||
|
|
||||||
use std::path::PathBuf;
|
|
||||||
use std::sync::Arc;
|
|
||||||
|
|
||||||
pub use self::common::NpmPackageFsResolver;
|
|
||||||
pub use self::common::NpmPackageFsResolverPackageFolderError;
|
|
||||||
use self::global::GlobalNpmPackageResolver;
|
|
||||||
pub use self::local::get_package_folder_id_folder_name;
|
|
||||||
use self::local::LocalNpmPackageResolver;
|
|
||||||
use super::resolution::NpmResolution;
|
|
||||||
use crate::npm::CliNpmCache;
|
|
||||||
use crate::sys::CliSys;
|
|
||||||
|
|
||||||
pub fn create_npm_fs_resolver(
|
|
||||||
npm_cache: Arc<CliNpmCache>,
|
|
||||||
resolution: Arc<NpmResolution>,
|
|
||||||
sys: CliSys,
|
|
||||||
maybe_node_modules_path: Option<PathBuf>,
|
|
||||||
) -> Arc<dyn NpmPackageFsResolver> {
|
|
||||||
match maybe_node_modules_path {
|
|
||||||
Some(node_modules_folder) => Arc::new(LocalNpmPackageResolver::new(
|
|
||||||
resolution,
|
|
||||||
sys,
|
|
||||||
node_modules_folder,
|
|
||||||
)),
|
|
||||||
None => Arc::new(GlobalNpmPackageResolver::new(npm_cache, resolution)),
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -11,6 +11,7 @@ use dashmap::DashMap;
|
||||||
use deno_core::error::AnyError;
|
use deno_core::error::AnyError;
|
||||||
use deno_core::serde_json;
|
use deno_core::serde_json;
|
||||||
use deno_core::url::Url;
|
use deno_core::url::Url;
|
||||||
|
use deno_error::JsErrorBox;
|
||||||
use deno_npm::npm_rc::ResolvedNpmRc;
|
use deno_npm::npm_rc::ResolvedNpmRc;
|
||||||
use deno_npm::registry::NpmPackageInfo;
|
use deno_npm::registry::NpmPackageInfo;
|
||||||
use deno_resolver::npm::ByonmInNpmPackageChecker;
|
use deno_resolver::npm::ByonmInNpmPackageChecker;
|
||||||
|
@ -100,7 +101,7 @@ impl deno_npm_cache::NpmCacheHttpClient for CliNpmCacheHttpClient {
|
||||||
};
|
};
|
||||||
deno_npm_cache::DownloadError {
|
deno_npm_cache::DownloadError {
|
||||||
status_code,
|
status_code,
|
||||||
error: err.into(),
|
error: JsErrorBox::from_err(err),
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,18 +18,20 @@ sync = ["dashmap"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
anyhow.workspace = true
|
anyhow.workspace = true
|
||||||
|
async-trait.workspace = true
|
||||||
base32.workspace = true
|
base32.workspace = true
|
||||||
boxed_error.workspace = true
|
boxed_error.workspace = true
|
||||||
dashmap = { workspace = true, optional = true }
|
dashmap = { workspace = true, optional = true }
|
||||||
|
deno_cache_dir.workspace = true
|
||||||
deno_config.workspace = true
|
deno_config.workspace = true
|
||||||
deno_error.workspace = true
|
deno_error.workspace = true
|
||||||
deno_media_type.workspace = true
|
deno_media_type.workspace = true
|
||||||
deno_package_json.workspace = true
|
deno_npm.workspace = true
|
||||||
deno_package_json.features = ["sync"]
|
deno_package_json = { workspace = true, features = ["sync"] }
|
||||||
deno_path_util.workspace = true
|
deno_path_util.workspace = true
|
||||||
deno_semver.workspace = true
|
deno_semver.workspace = true
|
||||||
node_resolver.workspace = true
|
node_resolver = { workspace = true, features = ["sync"] }
|
||||||
node_resolver.features = ["sync"]
|
parking_lot.workspace = true
|
||||||
sys_traits.workspace = true
|
sys_traits.workspace = true
|
||||||
thiserror.workspace = true
|
thiserror.workspace = true
|
||||||
url.workspace = true
|
url.workspace = true
|
||||||
|
|
|
@ -6,12 +6,14 @@
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
use boxed_error::Boxed;
|
use boxed_error::Boxed;
|
||||||
|
use deno_cache_dir::npm::NpmCacheDir;
|
||||||
use deno_config::workspace::MappedResolution;
|
use deno_config::workspace::MappedResolution;
|
||||||
use deno_config::workspace::MappedResolutionDiagnostic;
|
use deno_config::workspace::MappedResolutionDiagnostic;
|
||||||
use deno_config::workspace::MappedResolutionError;
|
use deno_config::workspace::MappedResolutionError;
|
||||||
use deno_config::workspace::WorkspaceResolvePkgJsonFolderError;
|
use deno_config::workspace::WorkspaceResolvePkgJsonFolderError;
|
||||||
use deno_config::workspace::WorkspaceResolver;
|
use deno_config::workspace::WorkspaceResolver;
|
||||||
use deno_error::JsError;
|
use deno_error::JsError;
|
||||||
|
use deno_npm::npm_rc::ResolvedNpmRc;
|
||||||
use deno_package_json::PackageJsonDepValue;
|
use deno_package_json::PackageJsonDepValue;
|
||||||
use deno_package_json::PackageJsonDepValueParseError;
|
use deno_package_json::PackageJsonDepValueParseError;
|
||||||
use deno_semver::npm::NpmPackageReqReference;
|
use deno_semver::npm::NpmPackageReqReference;
|
||||||
|
@ -47,6 +49,12 @@ mod sync;
|
||||||
#[allow(clippy::disallowed_types)]
|
#[allow(clippy::disallowed_types)]
|
||||||
pub type WorkspaceResolverRc = crate::sync::MaybeArc<WorkspaceResolver>;
|
pub type WorkspaceResolverRc = crate::sync::MaybeArc<WorkspaceResolver>;
|
||||||
|
|
||||||
|
#[allow(clippy::disallowed_types)]
|
||||||
|
pub(crate) type ResolvedNpmRcRc = crate::sync::MaybeArc<ResolvedNpmRc>;
|
||||||
|
|
||||||
|
#[allow(clippy::disallowed_types)]
|
||||||
|
pub(crate) type NpmCacheDirRc = crate::sync::MaybeArc<NpmCacheDir>;
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct DenoResolution {
|
pub struct DenoResolution {
|
||||||
pub url: Url,
|
pub url: Url,
|
||||||
|
|
|
@ -2,6 +2,58 @@
|
||||||
|
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
|
|
||||||
|
use deno_cache_dir::npm::mixed_case_package_name_decode;
|
||||||
|
use deno_npm::NpmPackageCacheFolderId;
|
||||||
|
use deno_semver::package::PackageNv;
|
||||||
|
use deno_semver::StackString;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn get_package_folder_id_folder_name(
|
||||||
|
folder_id: &NpmPackageCacheFolderId,
|
||||||
|
) -> String {
|
||||||
|
get_package_folder_id_folder_name_from_parts(
|
||||||
|
&folder_id.nv,
|
||||||
|
folder_id.copy_index,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_package_folder_id_folder_name_from_parts(
|
||||||
|
nv: &PackageNv,
|
||||||
|
copy_index: u8,
|
||||||
|
) -> String {
|
||||||
|
let copy_str = if copy_index == 0 {
|
||||||
|
Cow::Borrowed("")
|
||||||
|
} else {
|
||||||
|
Cow::Owned(format!("_{}", copy_index))
|
||||||
|
};
|
||||||
|
let name = normalize_pkg_name_for_node_modules_deno_folder(&nv.name);
|
||||||
|
format!("{}@{}{}", name, nv.version, copy_str)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_package_folder_id_from_folder_name(
|
||||||
|
folder_name: &str,
|
||||||
|
) -> Option<NpmPackageCacheFolderId> {
|
||||||
|
let folder_name = folder_name.replace('+', "/");
|
||||||
|
let (name, ending) = folder_name.rsplit_once('@')?;
|
||||||
|
let name: StackString = if let Some(encoded_name) = name.strip_prefix('_') {
|
||||||
|
StackString::from_string(mixed_case_package_name_decode(encoded_name)?)
|
||||||
|
} else {
|
||||||
|
name.into()
|
||||||
|
};
|
||||||
|
let (raw_version, copy_index) = match ending.split_once('_') {
|
||||||
|
Some((raw_version, copy_index)) => {
|
||||||
|
let copy_index = copy_index.parse::<u8>().ok()?;
|
||||||
|
(raw_version, copy_index)
|
||||||
|
}
|
||||||
|
None => (ending, 0),
|
||||||
|
};
|
||||||
|
let version = deno_semver::Version::parse_from_npm(raw_version).ok()?;
|
||||||
|
Some(NpmPackageCacheFolderId {
|
||||||
|
nv: PackageNv { name, version },
|
||||||
|
copy_index,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
/// Normalizes a package name for use at `node_modules/.deno/<pkg-name>@<version>[_<copy_index>]`
|
/// Normalizes a package name for use at `node_modules/.deno/<pkg-name>@<version>[_<copy_index>]`
|
||||||
pub fn normalize_pkg_name_for_node_modules_deno_folder(name: &str) -> Cow<str> {
|
pub fn normalize_pkg_name_for_node_modules_deno_folder(name: &str) -> Cow<str> {
|
||||||
let name = if name.to_lowercase() == name {
|
let name = if name.to_lowercase() == name {
|
||||||
|
@ -25,3 +77,36 @@ fn mixed_case_package_name_encode(name: &str) -> String {
|
||||||
)
|
)
|
||||||
.to_lowercase()
|
.to_lowercase()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use deno_npm::NpmPackageCacheFolderId;
|
||||||
|
use deno_semver::package::PackageNv;
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_get_package_folder_id_folder_name() {
|
||||||
|
let cases = vec![
|
||||||
|
(
|
||||||
|
NpmPackageCacheFolderId {
|
||||||
|
nv: PackageNv::from_str("@types/foo@1.2.3").unwrap(),
|
||||||
|
copy_index: 1,
|
||||||
|
},
|
||||||
|
"@types+foo@1.2.3_1".to_string(),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
NpmPackageCacheFolderId {
|
||||||
|
nv: PackageNv::from_str("JSON@3.2.1").unwrap(),
|
||||||
|
copy_index: 0,
|
||||||
|
},
|
||||||
|
"_jjju6tq@3.2.1".to_string(),
|
||||||
|
),
|
||||||
|
];
|
||||||
|
for (input, output) in cases {
|
||||||
|
assert_eq!(get_package_folder_id_folder_name(&input), output);
|
||||||
|
let folder_id = get_package_folder_id_from_folder_name(&output).unwrap();
|
||||||
|
assert_eq!(folder_id, input);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -4,10 +4,14 @@ use std::path::Path;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use deno_ast::ModuleSpecifier;
|
|
||||||
use deno_npm::NpmPackageCacheFolderId;
|
use deno_npm::NpmPackageCacheFolderId;
|
||||||
use deno_npm::NpmPackageId;
|
use deno_npm::NpmPackageId;
|
||||||
use node_resolver::errors::PackageFolderResolveError;
|
use node_resolver::errors::PackageFolderResolveError;
|
||||||
|
use url::Url;
|
||||||
|
|
||||||
|
#[allow(clippy::disallowed_types)]
|
||||||
|
pub(super) type NpmPackageFsResolverRc =
|
||||||
|
crate::sync::MaybeArc<dyn NpmPackageFsResolver>;
|
||||||
|
|
||||||
#[derive(Debug, thiserror::Error, deno_error::JsError)]
|
#[derive(Debug, thiserror::Error, deno_error::JsError)]
|
||||||
#[class(generic)]
|
#[class(generic)]
|
||||||
|
@ -34,11 +38,11 @@ pub trait NpmPackageFsResolver: Send + Sync {
|
||||||
fn resolve_package_folder_from_package(
|
fn resolve_package_folder_from_package(
|
||||||
&self,
|
&self,
|
||||||
name: &str,
|
name: &str,
|
||||||
referrer: &ModuleSpecifier,
|
referrer: &Url,
|
||||||
) -> Result<PathBuf, PackageFolderResolveError>;
|
) -> Result<PathBuf, PackageFolderResolveError>;
|
||||||
|
|
||||||
fn resolve_package_cache_folder_id_from_specifier(
|
fn resolve_package_cache_folder_id_from_specifier(
|
||||||
&self,
|
&self,
|
||||||
specifier: &ModuleSpecifier,
|
specifier: &Url,
|
||||||
) -> Result<Option<NpmPackageCacheFolderId>, std::io::Error>;
|
) -> Result<Option<NpmPackageCacheFolderId>, std::io::Error>;
|
||||||
}
|
}
|
|
@ -4,30 +4,60 @@
|
||||||
|
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::sync::Arc;
|
|
||||||
|
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use deno_ast::ModuleSpecifier;
|
|
||||||
use deno_npm::NpmPackageCacheFolderId;
|
use deno_npm::NpmPackageCacheFolderId;
|
||||||
use deno_npm::NpmPackageId;
|
use deno_npm::NpmPackageId;
|
||||||
|
use deno_semver::package::PackageNv;
|
||||||
|
use deno_semver::StackString;
|
||||||
|
use deno_semver::Version;
|
||||||
use node_resolver::errors::PackageFolderResolveError;
|
use node_resolver::errors::PackageFolderResolveError;
|
||||||
use node_resolver::errors::PackageNotFoundError;
|
use node_resolver::errors::PackageNotFoundError;
|
||||||
use node_resolver::errors::ReferrerNotFoundError;
|
use node_resolver::errors::ReferrerNotFoundError;
|
||||||
|
use url::Url;
|
||||||
|
|
||||||
use super::super::resolution::NpmResolution;
|
use super::resolution::NpmResolutionRc;
|
||||||
use super::common::NpmPackageFsResolver;
|
use super::NpmCacheDirRc;
|
||||||
use crate::npm::CliNpmCache;
|
use super::NpmPackageFsResolver;
|
||||||
|
use crate::ResolvedNpmRcRc;
|
||||||
|
|
||||||
/// Resolves packages from the global npm cache.
|
/// Resolves packages from the global npm cache.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct GlobalNpmPackageResolver {
|
pub struct GlobalNpmPackageResolver {
|
||||||
cache: Arc<CliNpmCache>,
|
cache: NpmCacheDirRc,
|
||||||
resolution: Arc<NpmResolution>,
|
npm_rc: ResolvedNpmRcRc,
|
||||||
|
resolution: NpmResolutionRc,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl GlobalNpmPackageResolver {
|
impl GlobalNpmPackageResolver {
|
||||||
pub fn new(cache: Arc<CliNpmCache>, resolution: Arc<NpmResolution>) -> Self {
|
pub fn new(
|
||||||
Self { cache, resolution }
|
cache: NpmCacheDirRc,
|
||||||
|
npm_rc: ResolvedNpmRcRc,
|
||||||
|
resolution: NpmResolutionRc,
|
||||||
|
) -> Self {
|
||||||
|
Self {
|
||||||
|
cache,
|
||||||
|
npm_rc,
|
||||||
|
resolution,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn resolve_package_cache_folder_id_from_specifier_inner(
|
||||||
|
&self,
|
||||||
|
specifier: &Url,
|
||||||
|
) -> Option<NpmPackageCacheFolderId> {
|
||||||
|
self
|
||||||
|
.cache
|
||||||
|
.resolve_package_folder_id_from_specifier(specifier)
|
||||||
|
.and_then(|cache_id| {
|
||||||
|
Some(NpmPackageCacheFolderId {
|
||||||
|
nv: PackageNv {
|
||||||
|
name: StackString::from_string(cache_id.name),
|
||||||
|
version: Version::parse_from_npm(&cache_id.version).ok()?,
|
||||||
|
},
|
||||||
|
copy_index: cache_id.copy_index,
|
||||||
|
})
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -38,21 +68,26 @@ impl NpmPackageFsResolver for GlobalNpmPackageResolver {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn maybe_package_folder(&self, id: &NpmPackageId) -> Option<PathBuf> {
|
fn maybe_package_folder(&self, id: &NpmPackageId) -> Option<PathBuf> {
|
||||||
let folder_id = self
|
let folder_copy_index = self
|
||||||
.resolution
|
.resolution
|
||||||
.resolve_pkg_cache_folder_id_from_pkg_id(id)?;
|
.resolve_pkg_cache_folder_copy_index_from_pkg_id(id)?;
|
||||||
Some(self.cache.package_folder_for_id(&folder_id))
|
let registry_url = self.npm_rc.get_registry_url(&id.nv.name);
|
||||||
|
Some(self.cache.package_folder_for_id(
|
||||||
|
&id.nv.name,
|
||||||
|
&id.nv.version.to_string(),
|
||||||
|
folder_copy_index,
|
||||||
|
registry_url,
|
||||||
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn resolve_package_folder_from_package(
|
fn resolve_package_folder_from_package(
|
||||||
&self,
|
&self,
|
||||||
name: &str,
|
name: &str,
|
||||||
referrer: &ModuleSpecifier,
|
referrer: &Url,
|
||||||
) -> Result<PathBuf, PackageFolderResolveError> {
|
) -> Result<PathBuf, PackageFolderResolveError> {
|
||||||
use deno_npm::resolution::PackageNotFoundFromReferrerError;
|
use deno_npm::resolution::PackageNotFoundFromReferrerError;
|
||||||
let Some(referrer_cache_folder_id) = self
|
let Some(referrer_cache_folder_id) =
|
||||||
.cache
|
self.resolve_package_cache_folder_id_from_specifier_inner(referrer)
|
||||||
.resolve_package_folder_id_from_specifier(referrer)
|
|
||||||
else {
|
else {
|
||||||
return Err(
|
return Err(
|
||||||
ReferrerNotFoundError {
|
ReferrerNotFoundError {
|
||||||
|
@ -106,12 +141,8 @@ impl NpmPackageFsResolver for GlobalNpmPackageResolver {
|
||||||
|
|
||||||
fn resolve_package_cache_folder_id_from_specifier(
|
fn resolve_package_cache_folder_id_from_specifier(
|
||||||
&self,
|
&self,
|
||||||
specifier: &ModuleSpecifier,
|
specifier: &Url,
|
||||||
) -> Result<Option<NpmPackageCacheFolderId>, std::io::Error> {
|
) -> Result<Option<NpmPackageCacheFolderId>, std::io::Error> {
|
||||||
Ok(
|
Ok(self.resolve_package_cache_folder_id_from_specifier_inner(specifier))
|
||||||
self
|
|
||||||
.cache
|
|
||||||
.resolve_package_folder_id_from_specifier(specifier),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -5,49 +5,50 @@
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::sync::Arc;
|
|
||||||
|
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use deno_ast::ModuleSpecifier;
|
|
||||||
use deno_cache_dir::npm::mixed_case_package_name_decode;
|
|
||||||
use deno_core::url::Url;
|
|
||||||
use deno_npm::NpmPackageCacheFolderId;
|
use deno_npm::NpmPackageCacheFolderId;
|
||||||
use deno_npm::NpmPackageId;
|
use deno_npm::NpmPackageId;
|
||||||
use deno_path_util::fs::canonicalize_path_maybe_not_exists;
|
use deno_path_util::fs::canonicalize_path_maybe_not_exists;
|
||||||
use deno_resolver::npm::normalize_pkg_name_for_node_modules_deno_folder;
|
use deno_path_util::url_from_directory_path;
|
||||||
use deno_semver::package::PackageNv;
|
|
||||||
use deno_semver::StackString;
|
|
||||||
use node_resolver::errors::PackageFolderResolveError;
|
use node_resolver::errors::PackageFolderResolveError;
|
||||||
use node_resolver::errors::PackageFolderResolveIoError;
|
use node_resolver::errors::PackageFolderResolveIoError;
|
||||||
use node_resolver::errors::PackageNotFoundError;
|
use node_resolver::errors::PackageNotFoundError;
|
||||||
use node_resolver::errors::ReferrerNotFoundError;
|
use node_resolver::errors::ReferrerNotFoundError;
|
||||||
|
use sys_traits::FsCanonicalize;
|
||||||
use sys_traits::FsMetadata;
|
use sys_traits::FsMetadata;
|
||||||
|
use url::Url;
|
||||||
|
|
||||||
use super::super::resolution::NpmResolution;
|
use super::resolution::NpmResolutionRc;
|
||||||
use super::common::NpmPackageFsResolver;
|
use super::NpmPackageFsResolver;
|
||||||
use crate::sys::CliSys;
|
use crate::npm::local::get_package_folder_id_folder_name_from_parts;
|
||||||
|
use crate::npm::local::get_package_folder_id_from_folder_name;
|
||||||
|
|
||||||
/// Resolver that creates a local node_modules directory
|
/// Resolver that creates a local node_modules directory
|
||||||
/// and resolves packages from it.
|
/// and resolves packages from it.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct LocalNpmPackageResolver {
|
pub struct LocalNpmPackageResolver<
|
||||||
resolution: Arc<NpmResolution>,
|
TSys: FsCanonicalize + FsMetadata + Send + Sync,
|
||||||
sys: CliSys,
|
> {
|
||||||
|
resolution: NpmResolutionRc,
|
||||||
|
sys: TSys,
|
||||||
root_node_modules_path: PathBuf,
|
root_node_modules_path: PathBuf,
|
||||||
root_node_modules_url: Url,
|
root_node_modules_url: Url,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LocalNpmPackageResolver {
|
impl<TSys: FsCanonicalize + FsMetadata + Send + Sync>
|
||||||
|
LocalNpmPackageResolver<TSys>
|
||||||
|
{
|
||||||
#[allow(clippy::too_many_arguments)]
|
#[allow(clippy::too_many_arguments)]
|
||||||
pub fn new(
|
pub fn new(
|
||||||
resolution: Arc<NpmResolution>,
|
resolution: NpmResolutionRc,
|
||||||
sys: CliSys,
|
sys: TSys,
|
||||||
node_modules_folder: PathBuf,
|
node_modules_folder: PathBuf,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
resolution,
|
resolution,
|
||||||
sys,
|
sys,
|
||||||
root_node_modules_url: Url::from_directory_path(&node_modules_folder)
|
root_node_modules_url: url_from_directory_path(&node_modules_folder)
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
root_node_modules_path: node_modules_folder,
|
root_node_modules_path: node_modules_folder,
|
||||||
}
|
}
|
||||||
|
@ -67,7 +68,7 @@ impl LocalNpmPackageResolver {
|
||||||
|
|
||||||
fn resolve_folder_for_specifier(
|
fn resolve_folder_for_specifier(
|
||||||
&self,
|
&self,
|
||||||
specifier: &ModuleSpecifier,
|
specifier: &Url,
|
||||||
) -> Result<Option<PathBuf>, std::io::Error> {
|
) -> Result<Option<PathBuf>, std::io::Error> {
|
||||||
let Some(relative_url) =
|
let Some(relative_url) =
|
||||||
self.root_node_modules_url.make_relative(specifier)
|
self.root_node_modules_url.make_relative(specifier)
|
||||||
|
@ -78,7 +79,7 @@ impl LocalNpmPackageResolver {
|
||||||
return Ok(None);
|
return Ok(None);
|
||||||
}
|
}
|
||||||
// it's within the directory, so use it
|
// it's within the directory, so use it
|
||||||
let Some(path) = specifier.to_file_path().ok() else {
|
let Some(path) = deno_path_util::url_to_file_path(specifier).ok() else {
|
||||||
return Ok(None);
|
return Ok(None);
|
||||||
};
|
};
|
||||||
// Canonicalize the path so it's not pointing to the symlinked directory
|
// Canonicalize the path so it's not pointing to the symlinked directory
|
||||||
|
@ -88,7 +89,7 @@ impl LocalNpmPackageResolver {
|
||||||
|
|
||||||
fn resolve_package_folder_from_specifier(
|
fn resolve_package_folder_from_specifier(
|
||||||
&self,
|
&self,
|
||||||
specifier: &ModuleSpecifier,
|
specifier: &Url,
|
||||||
) -> Result<Option<PathBuf>, std::io::Error> {
|
) -> Result<Option<PathBuf>, std::io::Error> {
|
||||||
let Some(local_path) = self.resolve_folder_for_specifier(specifier)? else {
|
let Some(local_path) = self.resolve_folder_for_specifier(specifier)? else {
|
||||||
return Ok(None);
|
return Ok(None);
|
||||||
|
@ -99,31 +100,36 @@ impl LocalNpmPackageResolver {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait(?Send)]
|
#[async_trait(?Send)]
|
||||||
impl NpmPackageFsResolver for LocalNpmPackageResolver {
|
impl<TSys: FsCanonicalize + FsMetadata + Send + Sync> NpmPackageFsResolver
|
||||||
|
for LocalNpmPackageResolver<TSys>
|
||||||
|
{
|
||||||
fn node_modules_path(&self) -> Option<&Path> {
|
fn node_modules_path(&self) -> Option<&Path> {
|
||||||
Some(self.root_node_modules_path.as_ref())
|
Some(self.root_node_modules_path.as_ref())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn maybe_package_folder(&self, id: &NpmPackageId) -> Option<PathBuf> {
|
fn maybe_package_folder(&self, id: &NpmPackageId) -> Option<PathBuf> {
|
||||||
let cache_folder_id = self
|
let folder_copy_index = self
|
||||||
.resolution
|
.resolution
|
||||||
.resolve_pkg_cache_folder_id_from_pkg_id(id)?;
|
.resolve_pkg_cache_folder_copy_index_from_pkg_id(id)?;
|
||||||
// package is stored at:
|
// package is stored at:
|
||||||
// node_modules/.deno/<package_cache_folder_id_folder_name>/node_modules/<package_name>
|
// node_modules/.deno/<package_cache_folder_id_folder_name>/node_modules/<package_name>
|
||||||
Some(
|
Some(
|
||||||
self
|
self
|
||||||
.root_node_modules_path
|
.root_node_modules_path
|
||||||
.join(".deno")
|
.join(".deno")
|
||||||
.join(get_package_folder_id_folder_name(&cache_folder_id))
|
.join(get_package_folder_id_folder_name_from_parts(
|
||||||
|
&id.nv,
|
||||||
|
folder_copy_index,
|
||||||
|
))
|
||||||
.join("node_modules")
|
.join("node_modules")
|
||||||
.join(&cache_folder_id.nv.name),
|
.join(&id.nv.name),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn resolve_package_folder_from_package(
|
fn resolve_package_folder_from_package(
|
||||||
&self,
|
&self,
|
||||||
name: &str,
|
name: &str,
|
||||||
referrer: &ModuleSpecifier,
|
referrer: &Url,
|
||||||
) -> Result<PathBuf, PackageFolderResolveError> {
|
) -> Result<PathBuf, PackageFolderResolveError> {
|
||||||
let maybe_local_path = self
|
let maybe_local_path = self
|
||||||
.resolve_folder_for_specifier(referrer)
|
.resolve_folder_for_specifier(referrer)
|
||||||
|
@ -173,7 +179,7 @@ impl NpmPackageFsResolver for LocalNpmPackageResolver {
|
||||||
|
|
||||||
fn resolve_package_cache_folder_id_from_specifier(
|
fn resolve_package_cache_folder_id_from_specifier(
|
||||||
&self,
|
&self,
|
||||||
specifier: &ModuleSpecifier,
|
specifier: &Url,
|
||||||
) -> Result<Option<NpmPackageCacheFolderId>, std::io::Error> {
|
) -> Result<Option<NpmPackageCacheFolderId>, std::io::Error> {
|
||||||
let Some(folder_path) =
|
let Some(folder_path) =
|
||||||
self.resolve_package_folder_from_specifier(specifier)?
|
self.resolve_package_folder_from_specifier(specifier)?
|
||||||
|
@ -198,43 +204,6 @@ impl NpmPackageFsResolver for LocalNpmPackageResolver {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_package_folder_id_folder_name(
|
|
||||||
folder_id: &NpmPackageCacheFolderId,
|
|
||||||
) -> String {
|
|
||||||
let copy_str = if folder_id.copy_index == 0 {
|
|
||||||
Cow::Borrowed("")
|
|
||||||
} else {
|
|
||||||
Cow::Owned(format!("_{}", folder_id.copy_index))
|
|
||||||
};
|
|
||||||
let nv = &folder_id.nv;
|
|
||||||
let name = normalize_pkg_name_for_node_modules_deno_folder(&nv.name);
|
|
||||||
format!("{}@{}{}", name, nv.version, copy_str)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_package_folder_id_from_folder_name(
|
|
||||||
folder_name: &str,
|
|
||||||
) -> Option<NpmPackageCacheFolderId> {
|
|
||||||
let folder_name = folder_name.replace('+', "/");
|
|
||||||
let (name, ending) = folder_name.rsplit_once('@')?;
|
|
||||||
let name: StackString = if let Some(encoded_name) = name.strip_prefix('_') {
|
|
||||||
StackString::from_string(mixed_case_package_name_decode(encoded_name)?)
|
|
||||||
} else {
|
|
||||||
name.into()
|
|
||||||
};
|
|
||||||
let (raw_version, copy_index) = match ending.split_once('_') {
|
|
||||||
Some((raw_version, copy_index)) => {
|
|
||||||
let copy_index = copy_index.parse::<u8>().ok()?;
|
|
||||||
(raw_version, copy_index)
|
|
||||||
}
|
|
||||||
None => (ending, 0),
|
|
||||||
};
|
|
||||||
let version = deno_semver::Version::parse_from_npm(raw_version).ok()?;
|
|
||||||
Some(NpmPackageCacheFolderId {
|
|
||||||
nv: PackageNv { name, version },
|
|
||||||
copy_index,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn join_package_name(path: &Path, package_name: &str) -> PathBuf {
|
fn join_package_name(path: &Path, package_name: &str) -> PathBuf {
|
||||||
let mut path = path.to_path_buf();
|
let mut path = path.to_path_buf();
|
||||||
// ensure backslashes are used on windows
|
// ensure backslashes are used on windows
|
||||||
|
@ -243,36 +212,3 @@ fn join_package_name(path: &Path, package_name: &str) -> PathBuf {
|
||||||
}
|
}
|
||||||
path
|
path
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod test {
|
|
||||||
use deno_npm::NpmPackageCacheFolderId;
|
|
||||||
use deno_semver::package::PackageNv;
|
|
||||||
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_get_package_folder_id_folder_name() {
|
|
||||||
let cases = vec![
|
|
||||||
(
|
|
||||||
NpmPackageCacheFolderId {
|
|
||||||
nv: PackageNv::from_str("@types/foo@1.2.3").unwrap(),
|
|
||||||
copy_index: 1,
|
|
||||||
},
|
|
||||||
"@types+foo@1.2.3_1".to_string(),
|
|
||||||
),
|
|
||||||
(
|
|
||||||
NpmPackageCacheFolderId {
|
|
||||||
nv: PackageNv::from_str("JSON@3.2.1").unwrap(),
|
|
||||||
copy_index: 0,
|
|
||||||
},
|
|
||||||
"_jjju6tq@3.2.1".to_string(),
|
|
||||||
),
|
|
||||||
];
|
|
||||||
for (input, output) in cases {
|
|
||||||
assert_eq!(get_package_folder_id_folder_name(&input), output);
|
|
||||||
let folder_id = get_package_folder_id_from_folder_name(&output).unwrap();
|
|
||||||
assert_eq!(folder_id, input);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
45
resolvers/deno/npm/managed/mod.rs
Normal file
45
resolvers/deno/npm/managed/mod.rs
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
// Copyright 2018-2025 the Deno authors. MIT license.
|
||||||
|
|
||||||
|
mod common;
|
||||||
|
mod global;
|
||||||
|
mod local;
|
||||||
|
mod resolution;
|
||||||
|
|
||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
use sys_traits::FsCanonicalize;
|
||||||
|
use sys_traits::FsMetadata;
|
||||||
|
|
||||||
|
pub use self::common::NpmPackageFsResolver;
|
||||||
|
pub use self::common::NpmPackageFsResolverPackageFolderError;
|
||||||
|
use self::common::NpmPackageFsResolverRc;
|
||||||
|
use self::global::GlobalNpmPackageResolver;
|
||||||
|
use self::local::LocalNpmPackageResolver;
|
||||||
|
pub use self::resolution::NpmResolution;
|
||||||
|
use self::resolution::NpmResolutionRc;
|
||||||
|
use crate::sync::new_rc;
|
||||||
|
use crate::NpmCacheDirRc;
|
||||||
|
use crate::ResolvedNpmRcRc;
|
||||||
|
|
||||||
|
pub fn create_npm_fs_resolver<
|
||||||
|
TSys: FsCanonicalize + FsMetadata + Send + Sync + 'static,
|
||||||
|
>(
|
||||||
|
npm_cache_dir: &NpmCacheDirRc,
|
||||||
|
npm_rc: &ResolvedNpmRcRc,
|
||||||
|
resolution: NpmResolutionRc,
|
||||||
|
sys: TSys,
|
||||||
|
maybe_node_modules_path: Option<PathBuf>,
|
||||||
|
) -> NpmPackageFsResolverRc {
|
||||||
|
match maybe_node_modules_path {
|
||||||
|
Some(node_modules_folder) => new_rc(LocalNpmPackageResolver::new(
|
||||||
|
resolution,
|
||||||
|
sys,
|
||||||
|
node_modules_folder,
|
||||||
|
)),
|
||||||
|
None => new_rc(GlobalNpmPackageResolver::new(
|
||||||
|
npm_cache_dir.clone(),
|
||||||
|
npm_rc.clone(),
|
||||||
|
resolution,
|
||||||
|
)),
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,7 +2,6 @@
|
||||||
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use deno_core::parking_lot::RwLock;
|
|
||||||
use deno_npm::resolution::NpmPackagesPartitioned;
|
use deno_npm::resolution::NpmPackagesPartitioned;
|
||||||
use deno_npm::resolution::NpmResolutionSnapshot;
|
use deno_npm::resolution::NpmResolutionSnapshot;
|
||||||
use deno_npm::resolution::PackageCacheFolderIdNotFoundError;
|
use deno_npm::resolution::PackageCacheFolderIdNotFoundError;
|
||||||
|
@ -16,10 +15,12 @@ use deno_npm::NpmResolutionPackage;
|
||||||
use deno_npm::NpmSystemInfo;
|
use deno_npm::NpmSystemInfo;
|
||||||
use deno_semver::package::PackageNv;
|
use deno_semver::package::PackageNv;
|
||||||
use deno_semver::package::PackageReq;
|
use deno_semver::package::PackageReq;
|
||||||
|
use parking_lot::RwLock;
|
||||||
|
|
||||||
/// Handles updating and storing npm resolution in memory where the underlying
|
#[allow(clippy::disallowed_types)]
|
||||||
/// snapshot can be updated concurrently. Additionally handles updating the lockfile
|
pub(super) type NpmResolutionRc = crate::sync::MaybeArc<NpmResolution>;
|
||||||
/// based on changes to the resolution.
|
|
||||||
|
/// Handles updating and storing npm resolution in memory.
|
||||||
///
|
///
|
||||||
/// This does not interact with the file system.
|
/// This does not interact with the file system.
|
||||||
pub struct NpmResolution {
|
pub struct NpmResolution {
|
||||||
|
@ -50,15 +51,15 @@ impl NpmResolution {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn resolve_pkg_cache_folder_id_from_pkg_id(
|
pub fn resolve_pkg_cache_folder_copy_index_from_pkg_id(
|
||||||
&self,
|
&self,
|
||||||
id: &NpmPackageId,
|
id: &NpmPackageId,
|
||||||
) -> Option<NpmPackageCacheFolderId> {
|
) -> Option<u8> {
|
||||||
self
|
self
|
||||||
.snapshot
|
.snapshot
|
||||||
.read()
|
.read()
|
||||||
.package_from_id(id)
|
.package_from_id(id)
|
||||||
.map(|p| p.get_package_cache_folder_id())
|
.map(|p| p.copy_index)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn resolve_pkg_id_from_pkg_cache_folder_id(
|
pub fn resolve_pkg_id_from_pkg_cache_folder_id(
|
|
@ -4,15 +4,9 @@ use std::fmt::Debug;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
use boxed_error::Boxed;
|
use boxed_error::Boxed;
|
||||||
pub use byonm::ByonmInNpmPackageChecker;
|
|
||||||
pub use byonm::ByonmNpmResolver;
|
|
||||||
pub use byonm::ByonmNpmResolverCreateOptions;
|
|
||||||
pub use byonm::ByonmNpmResolverRc;
|
|
||||||
pub use byonm::ByonmResolvePkgFolderFromDenoReqError;
|
|
||||||
use deno_error::JsError;
|
use deno_error::JsError;
|
||||||
use deno_semver::npm::NpmPackageReqReference;
|
use deno_semver::npm::NpmPackageReqReference;
|
||||||
use deno_semver::package::PackageReq;
|
use deno_semver::package::PackageReq;
|
||||||
pub use local::normalize_pkg_name_for_node_modules_deno_folder;
|
|
||||||
use node_resolver::errors::NodeResolveError;
|
use node_resolver::errors::NodeResolveError;
|
||||||
use node_resolver::errors::NodeResolveErrorKind;
|
use node_resolver::errors::NodeResolveErrorKind;
|
||||||
use node_resolver::errors::PackageFolderResolveErrorKind;
|
use node_resolver::errors::PackageFolderResolveErrorKind;
|
||||||
|
@ -33,8 +27,17 @@ use sys_traits::FsReadDir;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
|
pub use self::byonm::ByonmInNpmPackageChecker;
|
||||||
|
pub use self::byonm::ByonmNpmResolver;
|
||||||
|
pub use self::byonm::ByonmNpmResolverCreateOptions;
|
||||||
|
pub use self::byonm::ByonmNpmResolverRc;
|
||||||
|
pub use self::byonm::ByonmResolvePkgFolderFromDenoReqError;
|
||||||
|
pub use self::local::get_package_folder_id_folder_name;
|
||||||
|
pub use self::local::normalize_pkg_name_for_node_modules_deno_folder;
|
||||||
|
|
||||||
mod byonm;
|
mod byonm;
|
||||||
mod local;
|
mod local;
|
||||||
|
pub mod managed;
|
||||||
|
|
||||||
#[derive(Debug, Error, JsError)]
|
#[derive(Debug, Error, JsError)]
|
||||||
#[class(generic)]
|
#[class(generic)]
|
||||||
|
|
|
@ -46,3 +46,9 @@ mod inner {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::disallowed_types)]
|
||||||
|
#[inline]
|
||||||
|
pub fn new_rc<T>(value: T) -> MaybeArc<T> {
|
||||||
|
MaybeArc::new(value)
|
||||||
|
}
|
||||||
|
|
|
@ -14,11 +14,6 @@ description = "Helpers for downloading and caching npm dependencies for Deno"
|
||||||
path = "lib.rs"
|
path = "lib.rs"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
# todo(dsherret): remove this dependency
|
|
||||||
anyhow.workspace = true
|
|
||||||
# todo(dsherret): remove this dependency
|
|
||||||
deno_core.workspace = true
|
|
||||||
|
|
||||||
async-trait.workspace = true
|
async-trait.workspace = true
|
||||||
base64.workspace = true
|
base64.workspace = true
|
||||||
boxed_error.workspace = true
|
boxed_error.workspace = true
|
||||||
|
|
|
@ -6,7 +6,6 @@ use std::path::Path;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use anyhow::Error as AnyError;
|
|
||||||
use deno_cache_dir::file_fetcher::CacheSetting;
|
use deno_cache_dir::file_fetcher::CacheSetting;
|
||||||
use deno_cache_dir::npm::NpmCacheDir;
|
use deno_cache_dir::npm::NpmCacheDir;
|
||||||
use deno_error::JsErrorBox;
|
use deno_error::JsErrorBox;
|
||||||
|
@ -51,7 +50,7 @@ pub use tarball::TarballCache;
|
||||||
#[class(generic)]
|
#[class(generic)]
|
||||||
pub struct DownloadError {
|
pub struct DownloadError {
|
||||||
pub status_code: Option<StatusCode>,
|
pub status_code: Option<StatusCode>,
|
||||||
pub error: AnyError,
|
pub error: JsErrorBox,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::error::Error for DownloadError {
|
impl std::error::Error for DownloadError {
|
||||||
|
@ -312,15 +311,17 @@ impl<
|
||||||
&self,
|
&self,
|
||||||
name: &str,
|
name: &str,
|
||||||
package_info: &NpmPackageInfo,
|
package_info: &NpmPackageInfo,
|
||||||
) -> Result<(), AnyError> {
|
) -> Result<(), JsErrorBox> {
|
||||||
let file_cache_path = self.get_registry_package_info_file_cache_path(name);
|
let file_cache_path = self.get_registry_package_info_file_cache_path(name);
|
||||||
let file_text = serde_json::to_string(&package_info)?;
|
let file_text =
|
||||||
|
serde_json::to_string(&package_info).map_err(JsErrorBox::from_err)?;
|
||||||
atomic_write_file_with_retries(
|
atomic_write_file_with_retries(
|
||||||
&self.sys,
|
&self.sys,
|
||||||
&file_cache_path,
|
&file_cache_path,
|
||||||
file_text.as_bytes(),
|
file_text.as_bytes(),
|
||||||
0o644,
|
0o644,
|
||||||
)?;
|
)
|
||||||
|
.map_err(JsErrorBox::from_err)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,11 +5,6 @@ use std::collections::HashSet;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use deno_core::futures::future::LocalBoxFuture;
|
|
||||||
use deno_core::futures::FutureExt;
|
|
||||||
use deno_core::parking_lot::Mutex;
|
|
||||||
use deno_core::serde_json;
|
|
||||||
use deno_core::url::Url;
|
|
||||||
use deno_error::JsErrorBox;
|
use deno_error::JsErrorBox;
|
||||||
use deno_npm::npm_rc::ResolvedNpmRc;
|
use deno_npm::npm_rc::ResolvedNpmRc;
|
||||||
use deno_npm::registry::NpmPackageInfo;
|
use deno_npm::registry::NpmPackageInfo;
|
||||||
|
@ -17,6 +12,9 @@ use deno_npm::registry::NpmRegistryApi;
|
||||||
use deno_npm::registry::NpmRegistryPackageInfoLoadError;
|
use deno_npm::registry::NpmRegistryPackageInfoLoadError;
|
||||||
use deno_unsync::sync::AtomicFlag;
|
use deno_unsync::sync::AtomicFlag;
|
||||||
use deno_unsync::sync::MultiRuntimeAsyncValueCreator;
|
use deno_unsync::sync::MultiRuntimeAsyncValueCreator;
|
||||||
|
use futures::future::LocalBoxFuture;
|
||||||
|
use futures::FutureExt;
|
||||||
|
use parking_lot::Mutex;
|
||||||
use sys_traits::FsCreateDirAll;
|
use sys_traits::FsCreateDirAll;
|
||||||
use sys_traits::FsHardLink;
|
use sys_traits::FsHardLink;
|
||||||
use sys_traits::FsMetadata;
|
use sys_traits::FsMetadata;
|
||||||
|
@ -26,6 +24,7 @@ use sys_traits::FsRemoveFile;
|
||||||
use sys_traits::FsRename;
|
use sys_traits::FsRename;
|
||||||
use sys_traits::SystemRandom;
|
use sys_traits::SystemRandom;
|
||||||
use sys_traits::ThreadSleep;
|
use sys_traits::ThreadSleep;
|
||||||
|
use url::Url;
|
||||||
|
|
||||||
use crate::remote::maybe_auth_header_for_npm_registry;
|
use crate::remote::maybe_auth_header_for_npm_registry;
|
||||||
use crate::NpmCache;
|
use crate::NpmCache;
|
||||||
|
|
|
@ -3,16 +3,15 @@
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use deno_core::futures::future::LocalBoxFuture;
|
|
||||||
use deno_core::futures::FutureExt;
|
|
||||||
use deno_core::parking_lot::Mutex;
|
|
||||||
use deno_core::url::Url;
|
|
||||||
use deno_error::JsErrorBox;
|
use deno_error::JsErrorBox;
|
||||||
use deno_npm::npm_rc::ResolvedNpmRc;
|
use deno_npm::npm_rc::ResolvedNpmRc;
|
||||||
use deno_npm::registry::NpmPackageVersionDistInfo;
|
use deno_npm::registry::NpmPackageVersionDistInfo;
|
||||||
use deno_semver::package::PackageNv;
|
use deno_semver::package::PackageNv;
|
||||||
use deno_unsync::sync::MultiRuntimeAsyncValueCreator;
|
use deno_unsync::sync::MultiRuntimeAsyncValueCreator;
|
||||||
|
use futures::future::LocalBoxFuture;
|
||||||
|
use futures::FutureExt;
|
||||||
use http::StatusCode;
|
use http::StatusCode;
|
||||||
|
use parking_lot::Mutex;
|
||||||
use sys_traits::FsCreateDirAll;
|
use sys_traits::FsCreateDirAll;
|
||||||
use sys_traits::FsHardLink;
|
use sys_traits::FsHardLink;
|
||||||
use sys_traits::FsMetadata;
|
use sys_traits::FsMetadata;
|
||||||
|
@ -22,6 +21,7 @@ use sys_traits::FsRemoveFile;
|
||||||
use sys_traits::FsRename;
|
use sys_traits::FsRename;
|
||||||
use sys_traits::SystemRandom;
|
use sys_traits::SystemRandom;
|
||||||
use sys_traits::ThreadSleep;
|
use sys_traits::ThreadSleep;
|
||||||
|
use url::Url;
|
||||||
|
|
||||||
use crate::remote::maybe_auth_header_for_npm_registry;
|
use crate::remote::maybe_auth_header_for_npm_registry;
|
||||||
use crate::tarball_extract::verify_and_extract_tarball;
|
use crate::tarball_extract::verify_and_extract_tarball;
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
This crate is a work in progress:
|
This crate is a work in progress:
|
||||||
|
|
||||||
1. Remove `deno_core` dependency.
|
|
||||||
1. Remove `anyhow` dependency.
|
|
||||||
1. Add a clippy.toml file that bans accessing the file system directory and
|
1. Add a clippy.toml file that bans accessing the file system directory and
|
||||||
instead does it through a trait.
|
instead does it through a trait.
|
||||||
1. Make this crate work in Wasm.
|
1. Make this crate work in Wasm.
|
||||||
|
|
Loading…
Add table
Reference in a new issue