diff options
Diffstat (limited to 'cli/npm/resolvers/mod.rs')
-rw-r--r-- | cli/npm/resolvers/mod.rs | 270 |
1 files changed, 170 insertions, 100 deletions
diff --git a/cli/npm/resolvers/mod.rs b/cli/npm/resolvers/mod.rs index efaad93ee..07a122a3e 100644 --- a/cli/npm/resolvers/mod.rs +++ b/cli/npm/resolvers/mod.rs @@ -49,17 +49,77 @@ pub struct NpmProcessState { pub local_node_modules_path: Option<String>, } -/// Brings together the npm resolution with the file system. -pub struct CliNpmResolver { +pub enum InnerCliNpmResolverRef<'a> { + Managed(&'a ManagedCliNpmResolver), + #[allow(dead_code)] + Byonm(&'a ByonmCliNpmResolver), +} + +pub trait CliNpmResolver: NpmResolver { + fn into_npm_resolver(self: Arc<Self>) -> Arc<dyn NpmResolver>; + + fn root_dir_url(&self) -> &Url; + + fn as_inner(&self) -> InnerCliNpmResolverRef; + + fn as_managed(&self) -> Option<&ManagedCliNpmResolver> { + match self.as_inner() { + InnerCliNpmResolverRef::Managed(inner) => Some(inner), + InnerCliNpmResolverRef::Byonm(_) => None, + } + } + + fn node_modules_path(&self) -> Option<PathBuf>; + + /// Checks if the provided package req's folder is cached. + fn is_pkg_req_folder_cached(&self, req: &PackageReq) -> bool; + + fn resolve_pkg_nv_ref_from_pkg_req_ref( + &self, + req_ref: &NpmPackageReqReference, + ) -> Result<NpmPackageNvReference, PackageReqNotFoundError>; + + /// Resolve the root folder of the package the provided specifier is in. + /// + /// This will error when the provided specifier is not in an npm package. + fn resolve_pkg_folder_from_specifier( + &self, + specifier: &ModuleSpecifier, + ) -> Result<Option<PathBuf>, AnyError>; + + fn resolve_pkg_folder_from_deno_module_req( + &self, + req: &PackageReq, + ) -> Result<PathBuf, AnyError>; + + fn resolve_pkg_folder_from_deno_module( + &self, + nv: &PackageNv, + ) -> Result<PathBuf, AnyError>; + + /// Gets the state of npm for the process. + fn get_npm_process_state(&self) -> String; + + // todo(#18967): should instead return a hash state of the resolver + // or perhaps this could be non-BYONM only and byonm always runs deno check + fn package_reqs(&self) -> HashMap<PackageReq, PackageNv>; +} + +// todo(dsherret): implement this +pub struct ByonmCliNpmResolver; + +/// An npm resolver where the resolution is managed by Deno rather than +/// the user bringing their own node_modules (BYONM) on the file system. +pub struct ManagedCliNpmResolver { fs: Arc<dyn FileSystem>, fs_resolver: Arc<dyn NpmPackageFsResolver>, resolution: Arc<NpmResolution>, maybe_lockfile: Option<Arc<Mutex<Lockfile>>>, } -impl std::fmt::Debug for CliNpmResolver { +impl std::fmt::Debug for ManagedCliNpmResolver { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.debug_struct("NpmPackageResolver") + f.debug_struct("ManagedNpmResolver") .field("fs", &"<omitted>") .field("fs_resolver", &"<omitted>") .field("resolution", &"<omitted>") @@ -68,7 +128,7 @@ impl std::fmt::Debug for CliNpmResolver { } } -impl CliNpmResolver { +impl ManagedCliNpmResolver { pub fn new( fs: Arc<dyn FileSystem>, resolution: Arc<NpmResolution>, @@ -83,44 +143,6 @@ impl CliNpmResolver { } } - pub fn root_dir_url(&self) -> &Url { - self.fs_resolver.root_dir_url() - } - - pub fn node_modules_path(&self) -> Option<PathBuf> { - self.fs_resolver.node_modules_path() - } - - /// Checks if the provided package req's folder is cached. - pub fn is_pkg_req_folder_cached(&self, req: &PackageReq) -> bool { - self - .resolve_pkg_id_from_pkg_req(req) - .ok() - .and_then(|id| self.fs_resolver.package_folder(&id).ok()) - .map(|folder| folder.exists()) - .unwrap_or(false) - } - - pub fn resolve_pkg_nv_ref_from_pkg_req_ref( - &self, - req_ref: &NpmPackageReqReference, - ) -> Result<NpmPackageNvReference, PackageReqNotFoundError> { - let pkg_nv = self - .resolve_pkg_id_from_pkg_req(req_ref.req()) - .map(|id| id.nv)?; - Ok(NpmPackageNvReference::new(PackageNvReference { - nv: pkg_nv, - sub_path: req_ref.sub_path().map(|s| s.to_string()), - })) - } - - pub fn resolve_pkg_id_from_pkg_req( - &self, - req: &PackageReq, - ) -> Result<NpmPackageId, PackageReqNotFoundError> { - self.resolution.resolve_pkg_id_from_pkg_req(req) - } - pub fn resolve_pkg_folder_from_pkg_id( &self, pkg_id: &NpmPackageId, @@ -140,43 +162,6 @@ impl CliNpmResolver { Ok(path) } - /// Resolve the root folder of the package the provided specifier is in. - /// - /// This will error when the provided specifier is not in an npm package. - pub fn resolve_pkg_folder_from_specifier( - &self, - specifier: &ModuleSpecifier, - ) -> Result<Option<PathBuf>, AnyError> { - let Some(path) = self - .fs_resolver - .resolve_package_folder_from_specifier(specifier)? - else { - return Ok(None); - }; - log::debug!( - "Resolved package folder of {} to {}", - specifier, - path.display() - ); - Ok(Some(path)) - } - - pub fn resolve_pkg_folder_from_deno_module_req( - &self, - req: &PackageReq, - ) -> Result<PathBuf, AnyError> { - let pkg_id = self.resolve_pkg_id_from_pkg_req(req)?; - self.resolve_pkg_folder_from_pkg_id(&pkg_id) - } - - pub fn resolve_pkg_folder_from_deno_module( - &self, - nv: &PackageNv, - ) -> Result<PathBuf, AnyError> { - let pkg_id = self.resolution.resolve_pkg_id_from_deno_module(nv)?; - self.resolve_pkg_folder_from_pkg_id(&pkg_id) - } - /// Resolves the package nv from the provided specifier. pub fn resolve_pkg_id_from_specifier( &self, @@ -235,25 +220,6 @@ impl CliNpmResolver { self.resolution.set_package_reqs(packages).await } - /// Gets the state of npm for the process. - pub fn get_npm_process_state(&self) -> String { - serde_json::to_string(&NpmProcessState { - snapshot: self - .resolution - .serialized_valid_snapshot() - .into_serialized(), - local_node_modules_path: self - .fs_resolver - .node_modules_path() - .map(|p| p.to_string_lossy().to_string()), - }) - .unwrap() - } - - pub fn package_reqs(&self) -> HashMap<PackageReq, PackageNv> { - self.resolution.package_reqs() - } - pub fn snapshot(&self) -> NpmResolutionSnapshot { self.resolution.snapshot() } @@ -278,9 +244,16 @@ impl CliNpmResolver { self.fs_resolver.cache_packages().await?; Ok(()) } + + fn resolve_pkg_id_from_pkg_req( + &self, + req: &PackageReq, + ) -> Result<NpmPackageId, PackageReqNotFoundError> { + self.resolution.resolve_pkg_id_from_pkg_req(req) + } } -impl NpmResolver for CliNpmResolver { +impl NpmResolver for ManagedCliNpmResolver { fn resolve_package_folder_from_package( &self, name: &str, @@ -316,6 +289,103 @@ impl NpmResolver for CliNpmResolver { } } +impl CliNpmResolver for ManagedCliNpmResolver { + fn into_npm_resolver(self: Arc<Self>) -> Arc<dyn NpmResolver> { + self + } + + fn root_dir_url(&self) -> &Url { + self.fs_resolver.root_dir_url() + } + + fn as_inner(&self) -> InnerCliNpmResolverRef { + InnerCliNpmResolverRef::Managed(self) + } + + fn node_modules_path(&self) -> Option<PathBuf> { + self.fs_resolver.node_modules_path() + } + + /// Checks if the provided package req's folder is cached. + fn is_pkg_req_folder_cached(&self, req: &PackageReq) -> bool { + self + .resolve_pkg_id_from_pkg_req(req) + .ok() + .and_then(|id| self.fs_resolver.package_folder(&id).ok()) + .map(|folder| folder.exists()) + .unwrap_or(false) + } + + fn resolve_pkg_nv_ref_from_pkg_req_ref( + &self, + req_ref: &NpmPackageReqReference, + ) -> Result<NpmPackageNvReference, PackageReqNotFoundError> { + let pkg_nv = self + .resolve_pkg_id_from_pkg_req(req_ref.req()) + .map(|id| id.nv)?; + Ok(NpmPackageNvReference::new(PackageNvReference { + nv: pkg_nv, + sub_path: req_ref.sub_path().map(|s| s.to_string()), + })) + } + + /// Resolve the root folder of the package the provided specifier is in. + /// + /// This will error when the provided specifier is not in an npm package. + fn resolve_pkg_folder_from_specifier( + &self, + specifier: &ModuleSpecifier, + ) -> Result<Option<PathBuf>, AnyError> { + let Some(path) = self + .fs_resolver + .resolve_package_folder_from_specifier(specifier)? + else { + return Ok(None); + }; + log::debug!( + "Resolved package folder of {} to {}", + specifier, + path.display() + ); + Ok(Some(path)) + } + + fn resolve_pkg_folder_from_deno_module_req( + &self, + req: &PackageReq, + ) -> Result<PathBuf, AnyError> { + let pkg_id = self.resolve_pkg_id_from_pkg_req(req)?; + self.resolve_pkg_folder_from_pkg_id(&pkg_id) + } + + fn resolve_pkg_folder_from_deno_module( + &self, + nv: &PackageNv, + ) -> Result<PathBuf, AnyError> { + let pkg_id = self.resolution.resolve_pkg_id_from_deno_module(nv)?; + self.resolve_pkg_folder_from_pkg_id(&pkg_id) + } + + /// Gets the state of npm for the process. + fn get_npm_process_state(&self) -> String { + serde_json::to_string(&NpmProcessState { + snapshot: self + .resolution + .serialized_valid_snapshot() + .into_serialized(), + local_node_modules_path: self + .fs_resolver + .node_modules_path() + .map(|p| p.to_string_lossy().to_string()), + }) + .unwrap() + } + + fn package_reqs(&self) -> HashMap<PackageReq, PackageNv> { + self.resolution.package_reqs() + } +} + pub fn create_npm_fs_resolver( fs: Arc<dyn FileSystem>, cache: Arc<NpmCache>, |