2024-09-30 09:33:32 -04:00
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
2024-11-14 15:24:25 -05:00
use std ::fmt ::Debug ;
use std ::path ::PathBuf ;
use std ::sync ::Arc ;
2024-11-15 23:22:50 -05:00
use boxed_error ::Boxed ;
2024-11-14 15:24:25 -05:00
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 ;
2024-09-30 09:33:32 -04:00
2024-11-01 12:27:00 -04:00
pub use byonm ::ByonmInNpmPackageChecker ;
2024-09-30 09:33:32 -04:00
pub use byonm ::ByonmNpmResolver ;
pub use byonm ::ByonmNpmResolverCreateOptions ;
2024-10-02 16:17:39 -04:00
pub use byonm ::ByonmResolvePkgFolderFromDenoReqError ;
2024-09-30 09:33:32 -04:00
pub use local ::normalize_pkg_name_for_node_modules_deno_folder ;
2024-11-14 15:24:25 -05:00
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 ,
}
2024-11-15 23:22:50 -05:00
#[ derive(Debug, Boxed) ]
pub struct ResolveIfForNpmPackageError (
pub Box < ResolveIfForNpmPackageErrorKind > ,
) ;
2024-11-14 15:24:25 -05:00
#[ derive(Debug, Error) ]
2024-11-15 23:22:50 -05:00
pub enum ResolveIfForNpmPackageErrorKind {
2024-11-14 15:24:25 -05:00
#[ error(transparent) ]
NodeResolve ( #[ from ] NodeResolveError ) ,
#[ error(transparent) ]
NodeModulesOutOfDate ( #[ from ] NodeModulesOutOfDateError ) ,
}
2024-11-15 23:22:50 -05:00
#[ derive(Debug, Boxed) ]
pub struct ResolveReqWithSubPathError ( pub Box < ResolveReqWithSubPathErrorKind > ) ;
2024-11-14 15:24:25 -05:00
#[ derive(Debug, Error) ]
2024-11-15 23:22:50 -05:00
pub enum ResolveReqWithSubPathErrorKind {
2024-11-14 15:24:25 -05:00
#[ 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 < PathBuf , ResolvePkgFolderFromDenoReqError > ;
}
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 < Arc < ByonmNpmResolver < Fs , TNodeResolverEnv > > > ,
pub fs : Fs ,
pub in_npm_pkg_checker : Arc < dyn InNpmPackageChecker > ,
pub node_resolver : Arc < NodeResolver < TNodeResolverEnv > > ,
pub npm_req_resolver : Arc < dyn CliNpmReqResolver > ,
}
#[ derive(Debug) ]
pub struct NpmReqResolver < Fs : DenoResolverFs , TNodeResolverEnv : NodeResolverEnv >
{
byonm_resolver : Option < Arc < ByonmNpmResolver < Fs , TNodeResolverEnv > > > ,
fs : Fs ,
in_npm_pkg_checker : Arc < dyn InNpmPackageChecker > ,
node_resolver : Arc < NodeResolver < TNodeResolverEnv > > ,
npm_resolver : Arc < dyn CliNpmReqResolver > ,
}
impl < Fs : DenoResolverFs , TNodeResolverEnv : NodeResolverEnv >
NpmReqResolver < Fs , TNodeResolverEnv >
{
pub fn new ( options : NpmReqResolverOptions < Fs , TNodeResolverEnv > ) -> 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 < Url , ResolveReqWithSubPathError > {
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 < Url , ResolveReqWithSubPathError > {
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 < Option < NodeResolution > , 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 ( _ )
2024-11-15 23:22:50 -05:00
| NodeResolveErrorKind ::FinalizeResolution ( _ ) = > Err (
ResolveIfForNpmPackageErrorKind ::NodeResolve ( err . into ( ) ) . into_box ( ) ,
) ,
2024-11-14 15:24:25 -05:00
NodeResolveErrorKind ::PackageResolve ( err ) = > {
let err = err . into_kind ( ) ;
match err {
PackageResolveErrorKind ::ClosestPkgJson ( _ )
| PackageResolveErrorKind ::InvalidModuleSpecifier ( _ )
| PackageResolveErrorKind ::ExportsResolve ( _ )
2024-11-15 23:22:50 -05:00
| PackageResolveErrorKind ::SubpathResolve ( _ ) = > Err (
ResolveIfForNpmPackageErrorKind ::NodeResolve (
2024-11-14 15:24:25 -05:00
NodeResolveErrorKind ::PackageResolve ( err . into ( ) ) . into ( ) ,
2024-11-15 23:22:50 -05:00
)
. into_box ( ) ,
) ,
2024-11-14 15:24:25 -05:00
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 ) {
2024-11-15 23:22:50 -05:00
return Err (
ResolveIfForNpmPackageErrorKind ::NodeResolve (
NodeResolveErrorKind ::PackageResolve ( err . into ( ) )
. into ( ) ,
)
. into_box ( ) ,
) ;
2024-11-14 15:24:25 -05:00
}
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 (
2024-11-15 23:22:50 -05:00
ResolveIfForNpmPackageErrorKind ::NodeModulesOutOfDate (
2024-11-14 15:24:25 -05:00
NodeModulesOutOfDateError {
specifier : specifier . to_string ( ) ,
} ,
2024-11-15 23:22:50 -05:00
) . into_box ( ) ,
2024-11-14 15:24:25 -05:00
) ;
}
}
Ok ( None )
}
PackageFolderResolveErrorKind ::ReferrerNotFound ( _ ) = > {
if self . in_npm_pkg_checker . in_npm_package ( referrer ) {
2024-11-15 23:22:50 -05:00
return Err (
ResolveIfForNpmPackageErrorKind ::NodeResolve (
NodeResolveErrorKind ::PackageResolve ( err . into ( ) )
. into ( ) ,
)
. into_box ( ) ,
) ;
2024-11-14 15:24:25 -05:00
}
Ok ( None )
}
}
}
}
}
}
}
}
}
}