From 826e42a5b5880c974ae019a7a21aade6a718062c Mon Sep 17 00:00:00 2001 From: David Sherret Date: Fri, 1 Nov 2024 12:27:00 -0400 Subject: fix: improved support for cjs and cts modules (#26558) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * cts support * better cjs/cts type checking * deno compile cjs/cts support * More efficient detect cjs (going towards stabilization) * Determination of whether .js, .ts, .jsx, or .tsx is cjs or esm is only done after loading * Support `import x = require(...);` Co-authored-by: Bartek IwaƄczuk --- resolvers/deno/npm/mod.rs | 1 + 1 file changed, 1 insertion(+) (limited to 'resolvers/deno/npm/mod.rs') diff --git a/resolvers/deno/npm/mod.rs b/resolvers/deno/npm/mod.rs index 9d885cad3..45e2341c7 100644 --- a/resolvers/deno/npm/mod.rs +++ b/resolvers/deno/npm/mod.rs @@ -3,6 +3,7 @@ mod byonm; mod local; +pub use byonm::ByonmInNpmPackageChecker; pub use byonm::ByonmNpmResolver; pub use byonm::ByonmNpmResolverCreateOptions; pub use byonm::ByonmResolvePkgFolderFromDenoReqError; -- cgit v1.2.3 From 617350e79c58b6e01984e3d7c7436d243d0e5cff Mon Sep 17 00:00:00 2001 From: David Sherret Date: Thu, 14 Nov 2024 15:24:25 -0500 Subject: refactor(resolver): move more resolution code into deno_resolver (#26873) Follow-up to cjs refactor. This moves most of the resolution code into the deno_resolver crate. Still pending is the npm resolution code. --- resolvers/deno/npm/mod.rs | 250 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 248 insertions(+), 2 deletions(-) (limited to 'resolvers/deno/npm/mod.rs') diff --git a/resolvers/deno/npm/mod.rs b/resolvers/deno/npm/mod.rs index 45e2341c7..b0aec71b0 100644 --- a/resolvers/deno/npm/mod.rs +++ b/resolvers/deno/npm/mod.rs @@ -1,10 +1,256 @@ // Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. -mod byonm; -mod local; +use std::fmt::Debug; +use std::path::PathBuf; +use std::sync::Arc; + +use deno_semver::npm::NpmPackageReqReference; +use deno_semver::package::PackageReq; +use node_resolver::env::NodeResolverEnv; +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::PackageSubpathResolveError; +use node_resolver::InNpmPackageChecker; +use node_resolver::NodeModuleKind; +use node_resolver::NodeResolution; +use node_resolver::NodeResolutionMode; +use node_resolver::NodeResolver; +use thiserror::Error; +use url::Url; + +use crate::fs::DenoResolverFs; pub use byonm::ByonmInNpmPackageChecker; pub use byonm::ByonmNpmResolver; pub use byonm::ByonmNpmResolverCreateOptions; pub use byonm::ByonmResolvePkgFolderFromDenoReqError; pub use local::normalize_pkg_name_for_node_modules_deno_folder; + +mod byonm; +mod local; + +#[derive(Debug, Error)] +#[error("Could not resolve \"{}\", but found it in a package.json. Deno expects the node_modules/ directory to be up to date. Did you forget to run `deno install`?", specifier)] +pub struct NodeModulesOutOfDateError { + pub specifier: String, +} + +#[derive(Debug, Error)] +#[error("Could not find '{}'. Deno expects the node_modules/ directory to be up to date. Did you forget to run `deno install`?", package_json_path.display())] +pub struct MissingPackageNodeModulesFolderError { + pub package_json_path: PathBuf, +} + +#[derive(Debug, Error)] +pub enum ResolveIfForNpmPackageError { + #[error(transparent)] + NodeResolve(#[from] NodeResolveError), + #[error(transparent)] + NodeModulesOutOfDate(#[from] NodeModulesOutOfDateError), +} + +#[derive(Debug, Error)] +pub enum ResolveReqWithSubPathError { + #[error(transparent)] + MissingPackageNodeModulesFolder(#[from] MissingPackageNodeModulesFolderError), + #[error(transparent)] + ResolvePkgFolderFromDenoReq(#[from] ResolvePkgFolderFromDenoReqError), + #[error(transparent)] + PackageSubpathResolve(#[from] PackageSubpathResolveError), +} + +#[derive(Debug, Error)] +pub enum ResolvePkgFolderFromDenoReqError { + // todo(dsherret): don't use anyhow here + #[error(transparent)] + Managed(anyhow::Error), + #[error(transparent)] + Byonm(#[from] ByonmResolvePkgFolderFromDenoReqError), +} + +// todo(dsherret): a temporary trait until we extract +// out the CLI npm resolver into here +pub trait CliNpmReqResolver: Debug + Send + Sync { + fn resolve_pkg_folder_from_deno_module_req( + &self, + req: &PackageReq, + referrer: &Url, + ) -> Result; +} + +pub struct NpmReqResolverOptions< + Fs: DenoResolverFs, + TNodeResolverEnv: NodeResolverEnv, +> { + /// The resolver when "bring your own node_modules" is enabled where Deno + /// does not setup the node_modules directories automatically, but instead + /// uses what already exists on the file system. + pub byonm_resolver: Option>>, + pub fs: Fs, + pub in_npm_pkg_checker: Arc, + pub node_resolver: Arc>, + pub npm_req_resolver: Arc, +} + +#[derive(Debug)] +pub struct NpmReqResolver +{ + byonm_resolver: Option>>, + fs: Fs, + in_npm_pkg_checker: Arc, + node_resolver: Arc>, + npm_resolver: Arc, +} + +impl + NpmReqResolver +{ + pub fn new(options: NpmReqResolverOptions) -> Self { + Self { + byonm_resolver: options.byonm_resolver, + fs: options.fs, + in_npm_pkg_checker: options.in_npm_pkg_checker, + node_resolver: options.node_resolver, + npm_resolver: options.npm_req_resolver, + } + } + + pub fn resolve_req_reference( + &self, + req_ref: &NpmPackageReqReference, + referrer: &Url, + referrer_kind: NodeModuleKind, + mode: NodeResolutionMode, + ) -> Result { + self.resolve_req_with_sub_path( + req_ref.req(), + req_ref.sub_path(), + referrer, + referrer_kind, + mode, + ) + } + + pub fn resolve_req_with_sub_path( + &self, + req: &PackageReq, + sub_path: Option<&str>, + referrer: &Url, + referrer_kind: NodeModuleKind, + mode: NodeResolutionMode, + ) -> Result { + let package_folder = self + .npm_resolver + .resolve_pkg_folder_from_deno_module_req(req, referrer)?; + let resolution_result = + self.node_resolver.resolve_package_subpath_from_deno_module( + &package_folder, + sub_path, + Some(referrer), + referrer_kind, + mode, + ); + match resolution_result { + Ok(url) => Ok(url), + Err(err) => { + if self.byonm_resolver.is_some() { + let package_json_path = package_folder.join("package.json"); + if !self.fs.exists_sync(&package_json_path) { + return Err( + MissingPackageNodeModulesFolderError { package_json_path }.into(), + ); + } + } + Err(err.into()) + } + } + } + + pub fn resolve_if_for_npm_pkg( + &self, + specifier: &str, + referrer: &Url, + referrer_kind: NodeModuleKind, + mode: NodeResolutionMode, + ) -> Result, ResolveIfForNpmPackageError> { + let resolution_result = + self + .node_resolver + .resolve(specifier, referrer, referrer_kind, mode); + match resolution_result { + Ok(res) => Ok(Some(res)), + Err(err) => { + let err = err.into_kind(); + match err { + NodeResolveErrorKind::RelativeJoin(_) + | NodeResolveErrorKind::PackageImportsResolve(_) + | NodeResolveErrorKind::UnsupportedEsmUrlScheme(_) + | NodeResolveErrorKind::DataUrlReferrer(_) + | NodeResolveErrorKind::TypesNotFound(_) + | NodeResolveErrorKind::FinalizeResolution(_) => { + Err(ResolveIfForNpmPackageError::NodeResolve(err.into())) + } + NodeResolveErrorKind::PackageResolve(err) => { + let err = err.into_kind(); + match err { + PackageResolveErrorKind::ClosestPkgJson(_) + | PackageResolveErrorKind::InvalidModuleSpecifier(_) + | PackageResolveErrorKind::ExportsResolve(_) + | PackageResolveErrorKind::SubpathResolve(_) => { + Err(ResolveIfForNpmPackageError::NodeResolve( + NodeResolveErrorKind::PackageResolve(err.into()).into(), + )) + } + PackageResolveErrorKind::PackageFolderResolve(err) => { + match err.as_kind() { + PackageFolderResolveErrorKind::Io( + PackageFolderResolveIoError { package_name, .. }, + ) + | PackageFolderResolveErrorKind::PackageNotFound( + PackageNotFoundError { package_name, .. }, + ) => { + if self.in_npm_pkg_checker.in_npm_package(referrer) { + return Err(ResolveIfForNpmPackageError::NodeResolve( + NodeResolveErrorKind::PackageResolve(err.into()).into(), + )); + } + if let Some(byonm_npm_resolver) = &self.byonm_resolver { + if byonm_npm_resolver + .find_ancestor_package_json_with_dep( + package_name, + referrer, + ) + .is_some() + { + return Err( + ResolveIfForNpmPackageError::NodeModulesOutOfDate( + NodeModulesOutOfDateError { + specifier: specifier.to_string(), + }, + ), + ); + } + } + Ok(None) + } + PackageFolderResolveErrorKind::ReferrerNotFound(_) => { + if self.in_npm_pkg_checker.in_npm_package(referrer) { + return Err(ResolveIfForNpmPackageError::NodeResolve( + NodeResolveErrorKind::PackageResolve(err.into()).into(), + )); + } + Ok(None) + } + } + } + } + } + } + } + } + } +} -- cgit v1.2.3 From 48b94c099526eb262287e101a75cb4571b8972b0 Mon Sep 17 00:00:00 2001 From: David Sherret Date: Fri, 15 Nov 2024 23:22:50 -0500 Subject: refactor: use boxed_error in some places (#26887) --- resolvers/deno/npm/mod.rs | 52 +++++++++++++++++++++++++++++++---------------- 1 file changed, 35 insertions(+), 17 deletions(-) (limited to 'resolvers/deno/npm/mod.rs') diff --git a/resolvers/deno/npm/mod.rs b/resolvers/deno/npm/mod.rs index b0aec71b0..09e35b15c 100644 --- a/resolvers/deno/npm/mod.rs +++ b/resolvers/deno/npm/mod.rs @@ -4,6 +4,7 @@ use std::fmt::Debug; use std::path::PathBuf; use std::sync::Arc; +use boxed_error::Boxed; use deno_semver::npm::NpmPackageReqReference; use deno_semver::package::PackageReq; use node_resolver::env::NodeResolverEnv; @@ -45,16 +46,24 @@ pub struct MissingPackageNodeModulesFolderError { pub package_json_path: PathBuf, } +#[derive(Debug, Boxed)] +pub struct ResolveIfForNpmPackageError( + pub Box, +); + #[derive(Debug, Error)] -pub enum ResolveIfForNpmPackageError { +pub enum ResolveIfForNpmPackageErrorKind { #[error(transparent)] NodeResolve(#[from] NodeResolveError), #[error(transparent)] NodeModulesOutOfDate(#[from] NodeModulesOutOfDateError), } +#[derive(Debug, Boxed)] +pub struct ResolveReqWithSubPathError(pub Box); + #[derive(Debug, Error)] -pub enum ResolveReqWithSubPathError { +pub enum ResolveReqWithSubPathErrorKind { #[error(transparent)] MissingPackageNodeModulesFolder(#[from] MissingPackageNodeModulesFolderError), #[error(transparent)] @@ -191,20 +200,21 @@ impl | NodeResolveErrorKind::UnsupportedEsmUrlScheme(_) | NodeResolveErrorKind::DataUrlReferrer(_) | NodeResolveErrorKind::TypesNotFound(_) - | NodeResolveErrorKind::FinalizeResolution(_) => { - Err(ResolveIfForNpmPackageError::NodeResolve(err.into())) - } + | NodeResolveErrorKind::FinalizeResolution(_) => Err( + ResolveIfForNpmPackageErrorKind::NodeResolve(err.into()).into_box(), + ), NodeResolveErrorKind::PackageResolve(err) => { let err = err.into_kind(); match err { PackageResolveErrorKind::ClosestPkgJson(_) | PackageResolveErrorKind::InvalidModuleSpecifier(_) | PackageResolveErrorKind::ExportsResolve(_) - | PackageResolveErrorKind::SubpathResolve(_) => { - Err(ResolveIfForNpmPackageError::NodeResolve( + | PackageResolveErrorKind::SubpathResolve(_) => Err( + ResolveIfForNpmPackageErrorKind::NodeResolve( NodeResolveErrorKind::PackageResolve(err.into()).into(), - )) - } + ) + .into_box(), + ), PackageResolveErrorKind::PackageFolderResolve(err) => { match err.as_kind() { PackageFolderResolveErrorKind::Io( @@ -214,9 +224,13 @@ impl PackageNotFoundError { package_name, .. }, ) => { if self.in_npm_pkg_checker.in_npm_package(referrer) { - return Err(ResolveIfForNpmPackageError::NodeResolve( - NodeResolveErrorKind::PackageResolve(err.into()).into(), - )); + return Err( + ResolveIfForNpmPackageErrorKind::NodeResolve( + NodeResolveErrorKind::PackageResolve(err.into()) + .into(), + ) + .into_box(), + ); } if let Some(byonm_npm_resolver) = &self.byonm_resolver { if byonm_npm_resolver @@ -227,11 +241,11 @@ impl .is_some() { return Err( - ResolveIfForNpmPackageError::NodeModulesOutOfDate( + ResolveIfForNpmPackageErrorKind::NodeModulesOutOfDate( NodeModulesOutOfDateError { specifier: specifier.to_string(), }, - ), + ).into_box(), ); } } @@ -239,9 +253,13 @@ impl } PackageFolderResolveErrorKind::ReferrerNotFound(_) => { if self.in_npm_pkg_checker.in_npm_package(referrer) { - return Err(ResolveIfForNpmPackageError::NodeResolve( - NodeResolveErrorKind::PackageResolve(err.into()).into(), - )); + return Err( + ResolveIfForNpmPackageErrorKind::NodeResolve( + NodeResolveErrorKind::PackageResolve(err.into()) + .into(), + ) + .into_box(), + ); } Ok(None) } -- cgit v1.2.3