2025-01-01 04:12:39 +09:00
// Copyright 2018-2025 the Deno authors. MIT license.
2024-09-30 09:33:32 -04:00
2024-11-14 15:24:25 -05:00
use std ::fmt ::Debug ;
2025-01-14 10:01:05 -05:00
use std ::path ::Path ;
2024-11-14 15:24:25 -05:00
use std ::path ::PathBuf ;
2024-11-15 23:22:50 -05:00
use boxed_error ::Boxed ;
2025-01-08 14:52:32 -08:00
use deno_error ::JsError ;
2024-11-14 15:24:25 -05:00
use deno_semver ::npm ::NpmPackageReqReference ;
use deno_semver ::package ::PackageReq ;
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 ;
2025-01-14 10:01:05 -05:00
use node_resolver ::InNpmPackageChecker ;
2024-12-30 12:38:20 -05:00
use node_resolver ::IsBuiltInNodeModuleChecker ;
2024-11-14 15:24:25 -05:00
use node_resolver ::NodeResolution ;
2024-11-26 14:38:24 -05:00
use node_resolver ::NodeResolutionKind ;
2024-12-15 08:18:04 +00:00
use node_resolver ::NodeResolverRc ;
2025-01-14 10:01:05 -05:00
use node_resolver ::NpmPackageFolderResolver ;
2024-11-26 14:38:24 -05:00
use node_resolver ::ResolutionMode ;
2024-12-30 12:38:20 -05:00
use sys_traits ::FsCanonicalize ;
use sys_traits ::FsMetadata ;
use sys_traits ::FsRead ;
use sys_traits ::FsReadDir ;
2024-11-14 15:24:25 -05:00
use thiserror ::Error ;
use url ::Url ;
2025-01-09 12:10:07 -05:00
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 ;
2025-01-09 14:04:52 -05:00
use self ::managed ::create_managed_in_npm_pkg_checker ;
2025-01-14 10:01:05 -05:00
use self ::managed ::ManagedInNpmPackageChecker ;
2025-01-09 14:04:52 -05:00
use self ::managed ::ManagedInNpmPkgCheckerCreateOptions ;
2025-01-10 14:48:43 -05:00
pub use self ::managed ::ManagedNpmResolver ;
2025-01-14 10:01:05 -05:00
use self ::managed ::ManagedNpmResolverCreateOptions ;
2025-01-10 14:48:43 -05:00
pub use self ::managed ::ManagedNpmResolverRc ;
2025-01-09 14:04:52 -05:00
use crate ::sync ::new_rc ;
2025-01-14 10:01:05 -05:00
use crate ::sync ::MaybeSend ;
use crate ::sync ::MaybeSync ;
2025-01-09 12:10:07 -05:00
2024-11-14 15:24:25 -05:00
mod byonm ;
mod local ;
2025-01-09 12:10:07 -05:00
pub mod managed ;
2024-11-14 15:24:25 -05:00
2025-01-09 14:04:52 -05:00
pub enum CreateInNpmPkgCheckerOptions < ' a > {
Managed ( ManagedInNpmPkgCheckerCreateOptions < ' a > ) ,
Byonm ,
}
2025-01-14 10:01:05 -05:00
#[ derive(Debug, Clone) ]
pub enum DenoInNpmPackageChecker {
Managed ( ManagedInNpmPackageChecker ) ,
Byonm ( ByonmInNpmPackageChecker ) ,
}
impl DenoInNpmPackageChecker {
pub fn new ( options : CreateInNpmPkgCheckerOptions ) -> Self {
match options {
CreateInNpmPkgCheckerOptions ::Managed ( options ) = > {
DenoInNpmPackageChecker ::Managed ( create_managed_in_npm_pkg_checker (
options ,
) )
}
CreateInNpmPkgCheckerOptions ::Byonm = > {
DenoInNpmPackageChecker ::Byonm ( ByonmInNpmPackageChecker )
}
}
}
}
impl InNpmPackageChecker for DenoInNpmPackageChecker {
fn in_npm_package ( & self , specifier : & Url ) -> bool {
match self {
DenoInNpmPackageChecker ::Managed ( c ) = > c . in_npm_package ( specifier ) ,
DenoInNpmPackageChecker ::Byonm ( c ) = > c . in_npm_package ( specifier ) ,
2025-01-09 14:04:52 -05:00
}
}
}
2025-01-08 14:52:32 -08:00
#[ derive(Debug, Error, JsError) ]
#[ class(generic) ]
2024-11-14 15:24:25 -05:00
#[ 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 ,
}
2025-01-08 14:52:32 -08:00
#[ derive(Debug, Error, JsError) ]
#[ class(generic) ]
2024-11-14 15:24:25 -05:00
#[ 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 ,
}
2025-01-08 14:52:32 -08:00
#[ derive(Debug, Boxed, JsError) ]
2024-11-15 23:22:50 -05:00
pub struct ResolveIfForNpmPackageError (
pub Box < ResolveIfForNpmPackageErrorKind > ,
) ;
2025-01-08 14:52:32 -08:00
#[ derive(Debug, Error, JsError) ]
2024-11-15 23:22:50 -05:00
pub enum ResolveIfForNpmPackageErrorKind {
2025-01-08 14:52:32 -08:00
#[ class(inherit) ]
2024-11-14 15:24:25 -05:00
#[ error(transparent) ]
NodeResolve ( #[ from ] NodeResolveError ) ,
2025-01-08 14:52:32 -08:00
#[ class(inherit) ]
2024-11-14 15:24:25 -05:00
#[ error(transparent) ]
NodeModulesOutOfDate ( #[ from ] NodeModulesOutOfDateError ) ,
}
2025-01-08 14:52:32 -08:00
#[ derive(Debug, Boxed, JsError) ]
2024-11-15 23:22:50 -05:00
pub struct ResolveReqWithSubPathError ( pub Box < ResolveReqWithSubPathErrorKind > ) ;
2025-01-08 14:52:32 -08:00
#[ derive(Debug, Error, JsError) ]
2024-11-15 23:22:50 -05:00
pub enum ResolveReqWithSubPathErrorKind {
2025-01-08 14:52:32 -08:00
#[ class(inherit) ]
2024-11-14 15:24:25 -05:00
#[ error(transparent) ]
MissingPackageNodeModulesFolder ( #[ from ] MissingPackageNodeModulesFolderError ) ,
2025-01-08 14:52:32 -08:00
#[ class(inherit) ]
2024-11-14 15:24:25 -05:00
#[ error(transparent) ]
ResolvePkgFolderFromDenoReq ( #[ from ] ResolvePkgFolderFromDenoReqError ) ,
2025-01-08 14:52:32 -08:00
#[ class(inherit) ]
2024-11-14 15:24:25 -05:00
#[ error(transparent) ]
PackageSubpathResolve ( #[ from ] PackageSubpathResolveError ) ,
}
2025-01-08 14:52:32 -08:00
#[ derive(Debug, Error, JsError) ]
2024-11-14 15:24:25 -05:00
pub enum ResolvePkgFolderFromDenoReqError {
2025-01-08 14:52:32 -08:00
#[ class(inherit) ]
2025-01-10 14:48:43 -05:00
#[ error(transparent) ]
Managed ( managed ::ManagedResolvePkgFolderFromDenoReqError ) ,
2025-01-08 14:52:32 -08:00
#[ class(inherit) ]
2024-11-14 15:24:25 -05:00
#[ error(transparent) ]
2025-01-10 14:48:43 -05:00
Byonm ( byonm ::ByonmResolvePkgFolderFromDenoReqError ) ,
2024-11-14 15:24:25 -05:00
}
2025-01-14 10:01:05 -05:00
pub enum NpmResolverCreateOptions <
TSys : FsRead
+ FsCanonicalize
+ FsMetadata
+ std ::fmt ::Debug
+ MaybeSend
+ MaybeSync
+ Clone
+ 'static ,
2025-01-10 14:48:43 -05:00
> {
2025-01-14 10:01:05 -05:00
Managed ( ManagedNpmResolverCreateOptions < TSys > ) ,
Byonm ( ByonmNpmResolverCreateOptions < TSys > ) ,
}
#[ derive(Debug, Clone) ]
pub enum NpmResolver < TSys : FsCanonicalize + FsMetadata + FsRead + FsReadDir > {
2025-01-10 14:48:43 -05:00
/// 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.
Byonm ( ByonmNpmResolverRc < TSys > ) ,
Managed ( ManagedNpmResolverRc < TSys > ) ,
}
2024-12-15 08:18:04 +00:00
2025-01-14 10:01:05 -05:00
impl < TSys : FsCanonicalize + FsMetadata + FsRead + FsReadDir > NpmResolver < TSys > {
pub fn new <
TCreateSys : FsCanonicalize
+ FsMetadata
+ FsRead
+ FsReadDir
+ std ::fmt ::Debug
+ MaybeSend
+ MaybeSync
+ Clone
+ 'static ,
> (
options : NpmResolverCreateOptions < TCreateSys > ,
) -> NpmResolver < TCreateSys > {
match options {
NpmResolverCreateOptions ::Managed ( options ) = > {
NpmResolver ::Managed ( new_rc ( ManagedNpmResolver ::< TCreateSys > ::new ::<
TCreateSys ,
> ( options ) ) )
}
NpmResolverCreateOptions ::Byonm ( options ) = > {
NpmResolver ::Byonm ( new_rc ( ByonmNpmResolver ::new ( options ) ) )
}
}
}
pub fn is_byonm ( & self ) -> bool {
matches! ( self , NpmResolver ::Byonm ( _ ) )
}
pub fn is_managed ( & self ) -> bool {
matches! ( self , NpmResolver ::Managed ( _ ) )
}
pub fn as_managed ( & self ) -> Option < & ManagedNpmResolver < TSys > > {
match self {
NpmResolver ::Managed ( resolver ) = > Some ( resolver ) ,
NpmResolver ::Byonm ( _ ) = > None ,
}
}
pub fn root_node_modules_path ( & self ) -> Option < & Path > {
match self {
NpmResolver ::Byonm ( resolver ) = > resolver . root_node_modules_path ( ) ,
NpmResolver ::Managed ( resolver ) = > resolver . root_node_modules_path ( ) ,
}
}
2025-01-10 14:48:43 -05:00
pub fn resolve_pkg_folder_from_deno_module_req (
2024-11-14 15:24:25 -05:00
& self ,
req : & PackageReq ,
referrer : & Url ,
2025-01-10 14:48:43 -05:00
) -> Result < PathBuf , ResolvePkgFolderFromDenoReqError > {
match self {
2025-01-14 10:01:05 -05:00
NpmResolver ::Byonm ( byonm_resolver ) = > byonm_resolver
2025-01-10 14:48:43 -05:00
. resolve_pkg_folder_from_deno_module_req ( req , referrer )
. map_err ( ResolvePkgFolderFromDenoReqError ::Byonm ) ,
2025-01-14 10:01:05 -05:00
NpmResolver ::Managed ( managed_resolver ) = > managed_resolver
2025-01-10 14:48:43 -05:00
. resolve_pkg_folder_from_deno_module_req ( req , referrer )
. map_err ( ResolvePkgFolderFromDenoReqError ::Managed ) ,
}
}
2024-11-14 15:24:25 -05:00
}
2025-01-14 10:01:05 -05:00
impl < TSys : FsCanonicalize + FsMetadata + FsRead + FsReadDir >
NpmPackageFolderResolver for NpmResolver < TSys >
{
fn resolve_package_folder_from_package (
& self ,
specifier : & str ,
referrer : & Url ,
) -> Result < PathBuf , node_resolver ::errors ::PackageFolderResolveError > {
match self {
NpmResolver ::Byonm ( byonm_resolver ) = > {
byonm_resolver . resolve_package_folder_from_package ( specifier , referrer )
}
NpmResolver ::Managed ( managed_resolver ) = > managed_resolver
. resolve_package_folder_from_package ( specifier , referrer ) ,
}
}
}
2024-11-14 15:24:25 -05:00
pub struct NpmReqResolverOptions <
2025-01-14 10:01:05 -05:00
TInNpmPackageChecker : InNpmPackageChecker ,
2024-12-30 12:38:20 -05:00
TIsBuiltInNodeModuleChecker : IsBuiltInNodeModuleChecker ,
2025-01-14 10:01:05 -05:00
TNpmPackageFolderResolver : NpmPackageFolderResolver ,
2024-12-30 12:38:20 -05:00
TSys : FsCanonicalize + FsMetadata + FsRead + FsReadDir ,
2024-11-14 15:24:25 -05:00
> {
2025-01-14 10:01:05 -05:00
pub in_npm_pkg_checker : TInNpmPackageChecker ,
pub node_resolver : NodeResolverRc <
TInNpmPackageChecker ,
TIsBuiltInNodeModuleChecker ,
TNpmPackageFolderResolver ,
TSys ,
> ,
pub npm_resolver : NpmResolver < TSys > ,
2024-12-30 12:38:20 -05:00
pub sys : TSys ,
2024-11-14 15:24:25 -05:00
}
2024-12-15 08:18:04 +00:00
#[ allow(clippy::disallowed_types) ]
2025-01-14 10:01:05 -05:00
pub type NpmReqResolverRc <
TInNpmPackageChecker ,
TIsBuiltInNodeModuleChecker ,
TNpmPackageFolderResolver ,
TSys ,
> = crate ::sync ::MaybeArc <
NpmReqResolver <
TInNpmPackageChecker ,
TIsBuiltInNodeModuleChecker ,
TNpmPackageFolderResolver ,
TSys ,
> ,
> ;
2024-12-15 08:18:04 +00:00
2024-11-14 15:24:25 -05:00
#[ derive(Debug) ]
2024-12-30 12:38:20 -05:00
pub struct NpmReqResolver <
2025-01-14 10:01:05 -05:00
TInNpmPackageChecker : InNpmPackageChecker ,
2024-12-30 12:38:20 -05:00
TIsBuiltInNodeModuleChecker : IsBuiltInNodeModuleChecker ,
2025-01-14 10:01:05 -05:00
TNpmPackageFolderResolver : NpmPackageFolderResolver ,
2024-12-30 12:38:20 -05:00
TSys : FsCanonicalize + FsMetadata + FsRead + FsReadDir ,
> {
sys : TSys ,
2025-01-14 10:01:05 -05:00
in_npm_pkg_checker : TInNpmPackageChecker ,
node_resolver : NodeResolverRc <
TInNpmPackageChecker ,
TIsBuiltInNodeModuleChecker ,
TNpmPackageFolderResolver ,
TSys ,
> ,
npm_resolver : NpmResolver < TSys > ,
2024-11-14 15:24:25 -05:00
}
2024-12-30 12:38:20 -05:00
impl <
2025-01-14 10:01:05 -05:00
TInNpmPackageChecker : InNpmPackageChecker ,
2024-12-30 12:38:20 -05:00
TIsBuiltInNodeModuleChecker : IsBuiltInNodeModuleChecker ,
2025-01-14 10:01:05 -05:00
TNpmPackageFolderResolver : NpmPackageFolderResolver ,
2024-12-30 12:38:20 -05:00
TSys : FsCanonicalize + FsMetadata + FsRead + FsReadDir ,
2025-01-14 10:01:05 -05:00
>
NpmReqResolver <
TInNpmPackageChecker ,
TIsBuiltInNodeModuleChecker ,
TNpmPackageFolderResolver ,
TSys ,
>
2024-11-14 15:24:25 -05:00
{
2024-12-30 12:38:20 -05:00
pub fn new (
2025-01-14 10:01:05 -05:00
options : NpmReqResolverOptions <
TInNpmPackageChecker ,
TIsBuiltInNodeModuleChecker ,
TNpmPackageFolderResolver ,
TSys ,
> ,
2024-12-30 12:38:20 -05:00
) -> Self {
2024-11-14 15:24:25 -05:00
Self {
2024-12-30 12:38:20 -05:00
sys : options . sys ,
2024-11-14 15:24:25 -05:00
in_npm_pkg_checker : options . in_npm_pkg_checker ,
node_resolver : options . node_resolver ,
2025-01-10 14:48:43 -05:00
npm_resolver : options . npm_resolver ,
2024-11-14 15:24:25 -05:00
}
}
pub fn resolve_req_reference (
& self ,
req_ref : & NpmPackageReqReference ,
referrer : & Url ,
2024-11-26 14:38:24 -05:00
resolution_mode : ResolutionMode ,
resolution_kind : NodeResolutionKind ,
2024-11-14 15:24:25 -05:00
) -> Result < Url , ResolveReqWithSubPathError > {
self . resolve_req_with_sub_path (
req_ref . req ( ) ,
req_ref . sub_path ( ) ,
referrer ,
2024-11-26 14:38:24 -05:00
resolution_mode ,
resolution_kind ,
2024-11-14 15:24:25 -05:00
)
}
pub fn resolve_req_with_sub_path (
& self ,
req : & PackageReq ,
sub_path : Option < & str > ,
referrer : & Url ,
2024-11-26 14:38:24 -05:00
resolution_mode : ResolutionMode ,
resolution_kind : NodeResolutionKind ,
2024-11-14 15:24:25 -05:00
) -> 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 ) ,
2024-11-26 14:38:24 -05:00
resolution_mode ,
resolution_kind ,
2024-11-14 15:24:25 -05:00
) ;
match resolution_result {
Ok ( url ) = > Ok ( url ) ,
Err ( err ) = > {
2025-01-14 10:01:05 -05:00
if matches! ( self . npm_resolver , NpmResolver ::Byonm ( _ ) ) {
2024-11-14 15:24:25 -05:00
let package_json_path = package_folder . join ( " package.json " ) ;
2024-12-30 12:38:20 -05:00
if ! self . sys . fs_exists_no_err ( & package_json_path ) {
2024-11-14 15:24:25 -05:00
return Err (
MissingPackageNodeModulesFolderError { package_json_path } . into ( ) ,
) ;
}
}
Err ( err . into ( ) )
}
}
}
pub fn resolve_if_for_npm_pkg (
& self ,
specifier : & str ,
referrer : & Url ,
2024-11-26 14:38:24 -05:00
resolution_mode : ResolutionMode ,
resolution_kind : NodeResolutionKind ,
2024-11-14 15:24:25 -05:00
) -> Result < Option < NodeResolution > , ResolveIfForNpmPackageError > {
2024-11-26 14:38:24 -05:00
let resolution_result = self . node_resolver . resolve (
specifier ,
referrer ,
resolution_mode ,
resolution_kind ,
) ;
2024-11-14 15:24:25 -05:00
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
}
2025-01-14 10:01:05 -05:00
if let NpmResolver ::Byonm ( byonm_npm_resolver ) =
& self . npm_resolver
2025-01-10 14:48:43 -05:00
{
2024-11-14 15:24:25 -05:00
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 )
}
}
}
}
}
}
}
}
}
}