2024-01-01 14:58:21 -05:00
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
2021-12-16 05:45:41 -05:00
2024-07-03 20:54:33 -04:00
use crate ::args ::config_to_deno_graph_workspace_member ;
2024-02-15 14:49:35 -05:00
use crate ::args ::jsr_url ;
2024-06-28 20:18:21 -04:00
use crate ::args ::CliLockfile ;
2023-02-09 22:00:23 -05:00
use crate ::args ::CliOptions ;
2024-03-07 08:59:57 -05:00
use crate ::args ::DENO_DISABLE_PEDANTIC_NODE_WARNINGS ;
2022-12-09 09:40:48 -05:00
use crate ::cache ;
2024-11-28 08:51:24 -05:00
use crate ::cache ::FetchCacher ;
2023-08-01 20:49:09 -04:00
use crate ::cache ::GlobalHttpCache ;
2023-10-25 18:13:22 -04:00
use crate ::cache ::ModuleInfoCache ;
2023-04-14 16:22:33 -04:00
use crate ::cache ::ParsedSourceCache ;
2021-12-16 05:45:41 -05:00
use crate ::colors ;
use crate ::errors ::get_error_class_name ;
2023-04-14 16:22:33 -04:00
use crate ::file_fetcher ::FileFetcher ;
2023-04-21 21:02:46 -04:00
use crate ::npm ::CliNpmResolver ;
2024-11-13 10:10:09 -05:00
use crate ::resolver ::CjsTracker ;
use crate ::resolver ::CliResolver ;
2024-09-28 19:17:48 -04:00
use crate ::resolver ::CliSloppyImportsResolver ;
use crate ::resolver ::SloppyImportsCachedFs ;
2022-12-09 09:40:48 -05:00
use crate ::tools ::check ;
2023-04-14 18:05:46 -04:00
use crate ::tools ::check ::TypeChecker ;
2023-10-19 01:05:00 -04:00
use crate ::util ::file_watcher ::WatcherCommunicator ;
2024-01-08 12:18:42 -05:00
use crate ::util ::fs ::canonicalize_path ;
2024-11-13 10:10:09 -05:00
use deno_config ::deno_json ::JsxImportSourceConfig ;
2024-07-03 20:54:33 -04:00
use deno_config ::workspace ::JsrPackageConfig ;
2024-09-30 15:46:43 -04:00
use deno_core ::anyhow ::bail ;
2024-09-04 09:43:32 -04:00
use deno_graph ::source ::LoaderChecksum ;
2024-11-26 14:38:24 -05:00
use deno_graph ::source ::ResolutionKind ;
2024-09-26 10:24:49 -04:00
use deno_graph ::FillFromLockfileOptions ;
2024-05-28 14:58:43 -04:00
use deno_graph ::JsrLoadError ;
use deno_graph ::ModuleLoadError ;
2024-07-03 20:54:33 -04:00
use deno_graph ::WorkspaceFastCheckOption ;
2022-06-28 16:45:55 -04:00
2021-12-16 05:45:41 -05:00
use deno_core ::error ::custom_error ;
use deno_core ::error ::AnyError ;
2023-04-14 16:22:33 -04:00
use deno_core ::parking_lot ::Mutex ;
2021-12-16 05:45:41 -05:00
use deno_core ::ModuleSpecifier ;
2023-04-14 16:22:33 -04:00
use deno_graph ::source ::Loader ;
2023-10-20 00:02:08 -04:00
use deno_graph ::source ::ResolveError ;
2023-06-06 17:07:46 -04:00
use deno_graph ::GraphKind ;
2023-03-21 11:46:40 -04:00
use deno_graph ::ModuleError ;
2021-12-16 05:45:41 -05:00
use deno_graph ::ModuleGraph ;
use deno_graph ::ModuleGraphError ;
2023-01-24 15:14:49 -05:00
use deno_graph ::ResolutionError ;
use deno_graph ::SpecifierError ;
2024-09-28 07:55:01 -04:00
use deno_path_util ::url_to_file_path ;
2024-11-26 14:38:24 -05:00
use deno_resolver ::sloppy_imports ::SloppyImportsResolutionKind ;
2023-12-01 15:12:10 -05:00
use deno_runtime ::deno_fs ::FileSystem ;
2023-04-21 21:02:46 -04:00
use deno_runtime ::deno_node ;
2024-09-25 21:50:54 -04:00
use deno_runtime ::deno_permissions ::PermissionsContainer ;
2024-08-28 14:17:47 -04:00
use deno_semver ::jsr ::JsrDepPackageReq ;
2023-09-18 10:46:44 -04:00
use deno_semver ::package ::PackageNv ;
2023-01-27 17:36:23 -05:00
use import_map ::ImportMapError ;
2024-11-01 12:27:00 -04:00
use node_resolver ::InNpmPackageChecker ;
2023-02-24 14:42:45 -05:00
use std ::collections ::HashSet ;
2024-08-28 14:17:47 -04:00
use std ::error ::Error ;
use std ::ops ::Deref ;
2023-06-14 18:29:19 -04:00
use std ::path ::PathBuf ;
2021-12-16 05:45:41 -05:00
use std ::sync ::Arc ;
2024-09-26 12:31:03 -04:00
#[ derive(Clone) ]
2023-02-15 11:30:54 -05:00
pub struct GraphValidOptions {
pub check_js : bool ,
2024-09-25 09:04:57 -04:00
pub kind : GraphKind ,
2024-09-26 12:31:03 -04:00
/// Whether to exit the process for integrity check errors such as
/// lockfile checksum mismatches and JSR integrity failures.
/// Otherwise, surfaces integrity errors as errors.
pub exit_integrity_errors : bool ,
2023-02-15 11:30:54 -05:00
}
2023-02-09 22:00:23 -05:00
/// Check if `roots` and their deps are available. Returns `Ok(())` if
/// so. Returns `Err(_)` if there is a known module graph or resolution
/// error statically reachable from `roots`.
///
/// It is preferable to use this over using deno_graph's API directly
/// because it will have enhanced error message information specifically
/// for the CLI.
pub fn graph_valid (
graph : & ModuleGraph ,
2024-05-28 14:58:43 -04:00
fs : & Arc < dyn FileSystem > ,
2023-02-09 22:00:23 -05:00
roots : & [ ModuleSpecifier ] ,
2023-02-15 11:30:54 -05:00
options : GraphValidOptions ,
2023-02-09 22:00:23 -05:00
) -> Result < ( ) , AnyError > {
2024-09-26 12:31:03 -04:00
if options . exit_integrity_errors {
graph_exit_integrity_errors ( graph ) ;
2024-05-28 14:58:43 -04:00
}
2024-09-26 12:31:03 -04:00
let mut errors = graph_walk_errors (
graph ,
fs ,
roots ,
GraphWalkErrorsOptions {
check_js : options . check_js ,
kind : options . kind ,
} ,
) ;
if let Some ( error ) = errors . next ( ) {
Err ( error )
} else {
// finally surface the npm resolution result
if let Err ( err ) = & graph . npm_dep_graph_result {
return Err ( custom_error (
get_error_class_name ( err ) ,
format_deno_graph_error ( err . as_ref ( ) . deref ( ) ) ,
) ) ;
}
Ok ( ( ) )
}
}
#[ derive(Clone) ]
pub struct GraphWalkErrorsOptions {
pub check_js : bool ,
pub kind : GraphKind ,
}
/// Walks the errors found in the module graph that should be surfaced to users
/// and enhances them with CLI information.
pub fn graph_walk_errors < ' a > (
graph : & ' a ModuleGraph ,
fs : & ' a Arc < dyn FileSystem > ,
roots : & ' a [ ModuleSpecifier ] ,
options : GraphWalkErrorsOptions ,
) -> impl Iterator < Item = AnyError > + ' a {
graph
2023-02-15 11:30:54 -05:00
. walk (
2024-06-05 11:04:16 -04:00
roots . iter ( ) ,
2023-02-15 11:30:54 -05:00
deno_graph ::WalkOptions {
check_js : options . check_js ,
2024-09-25 09:04:57 -04:00
kind : options . kind ,
2024-09-26 12:31:03 -04:00
follow_dynamic : false ,
2024-04-11 19:00:17 -04:00
prefer_fast_check_graph : false ,
2023-02-15 11:30:54 -05:00
} ,
)
. errors ( )
. flat_map ( | error | {
let is_root = match & error {
2023-10-24 17:43:19 -04:00
ModuleGraphError ::ResolutionError ( _ )
| ModuleGraphError ::TypesResolutionError ( _ ) = > false ,
2023-03-21 11:46:40 -04:00
ModuleGraphError ::ModuleError ( error ) = > {
roots . contains ( error . specifier ( ) )
}
2023-02-15 11:30:54 -05:00
} ;
2023-10-24 17:43:19 -04:00
let mut message = match & error {
ModuleGraphError ::ResolutionError ( resolution_error ) = > {
enhanced_resolution_error_message ( resolution_error )
}
ModuleGraphError ::TypesResolutionError ( resolution_error ) = > {
format! (
" Failed resolving types. {} " ,
2023-12-07 15:59:13 -05:00
enhanced_resolution_error_message ( resolution_error )
2023-10-24 17:43:19 -04:00
)
}
2024-05-28 14:58:43 -04:00
ModuleGraphError ::ModuleError ( error ) = > {
2024-09-26 12:31:03 -04:00
enhanced_integrity_error_message ( error )
2024-05-28 14:58:43 -04:00
. or_else ( | | enhanced_sloppy_imports_error_message ( fs , error ) )
2024-08-28 14:17:47 -04:00
. unwrap_or_else ( | | format_deno_graph_error ( error ) )
2023-12-07 15:59:13 -05:00
}
2023-02-15 11:30:54 -05:00
} ;
2021-12-16 05:45:41 -05:00
2023-02-15 11:30:54 -05:00
if let Some ( range ) = error . maybe_range ( ) {
if ! is_root & & ! range . specifier . as_str ( ) . contains ( " /$deno$eval " ) {
2023-12-01 15:12:10 -05:00
message . push_str ( " \n at " ) ;
message . push_str ( & format_range_with_colors ( range ) ) ;
2023-02-15 11:30:54 -05:00
}
2021-12-16 05:45:41 -05:00
}
2024-04-16 16:46:31 -04:00
if graph . graph_kind ( ) = = GraphKind ::TypesOnly
& & matches! (
error ,
ModuleGraphError ::ModuleError ( ModuleError ::UnsupportedMediaType ( .. ) )
)
{
log ::debug! ( " Ignoring: {} " , message ) ;
return None ;
}
2023-02-15 11:30:54 -05:00
Some ( custom_error ( get_error_class_name ( & error . into ( ) ) , message ) )
2024-09-26 12:31:03 -04:00
} )
2021-12-16 05:45:41 -05:00
}
2024-09-26 12:31:03 -04:00
pub fn graph_exit_integrity_errors ( graph : & ModuleGraph ) {
2024-05-28 14:58:43 -04:00
for error in graph . module_errors ( ) {
2024-09-26 12:31:03 -04:00
exit_for_integrity_error ( error ) ;
2024-05-28 14:58:43 -04:00
}
}
2024-02-15 14:49:35 -05:00
2024-09-26 12:31:03 -04:00
fn exit_for_integrity_error ( err : & ModuleError ) {
if let Some ( err_message ) = enhanced_integrity_error_message ( err ) {
2024-05-28 14:58:43 -04:00
log ::error! ( " {} {} " , colors ::red ( " error: " ) , err_message ) ;
2024-11-14 07:16:28 -05:00
deno_runtime ::exit ( 10 ) ;
2021-12-16 05:45:41 -05:00
}
}
2022-12-09 09:40:48 -05:00
2023-10-25 18:13:22 -04:00
pub struct CreateGraphOptions < ' a > {
pub graph_kind : GraphKind ,
pub roots : Vec < ModuleSpecifier > ,
2024-02-16 17:10:06 -05:00
pub is_dynamic : bool ,
2024-01-09 18:20:52 -05:00
/// Specify `None` to use the default CLI loader.
pub loader : Option < & ' a mut dyn Loader > ,
2023-10-25 18:13:22 -04:00
}
2024-02-20 16:29:57 -05:00
pub struct ModuleGraphCreator {
2023-04-14 16:22:33 -04:00
options : Arc < CliOptions > ,
2023-09-29 09:26:25 -04:00
npm_resolver : Arc < dyn CliNpmResolver > ,
2024-02-20 16:29:57 -05:00
module_graph_builder : Arc < ModuleGraphBuilder > ,
2023-04-14 18:05:46 -04:00
type_checker : Arc < TypeChecker > ,
2023-04-14 16:22:33 -04:00
}
2023-02-22 14:15:25 -05:00
2024-02-20 16:29:57 -05:00
impl ModuleGraphCreator {
2023-04-14 16:22:33 -04:00
pub fn new (
options : Arc < CliOptions > ,
2023-09-29 09:26:25 -04:00
npm_resolver : Arc < dyn CliNpmResolver > ,
2024-02-20 16:29:57 -05:00
module_graph_builder : Arc < ModuleGraphBuilder > ,
2023-04-14 18:05:46 -04:00
type_checker : Arc < TypeChecker > ,
2023-04-14 16:22:33 -04:00
) -> Self {
Self {
options ,
npm_resolver ,
2024-02-20 16:29:57 -05:00
module_graph_builder ,
2023-04-14 18:05:46 -04:00
type_checker ,
2023-04-14 16:22:33 -04:00
}
2022-12-09 09:40:48 -05:00
}
2023-10-25 18:13:22 -04:00
pub async fn create_graph (
& self ,
graph_kind : GraphKind ,
roots : Vec < ModuleSpecifier > ,
) -> Result < deno_graph ::ModuleGraph , AnyError > {
2024-02-20 16:29:57 -05:00
let mut cache = self . module_graph_builder . create_graph_loader ( ) ;
2023-10-25 18:13:22 -04:00
self
. create_graph_with_loader ( graph_kind , roots , & mut cache )
. await
}
2023-04-14 16:22:33 -04:00
pub async fn create_graph_with_loader (
& self ,
2023-06-06 17:07:46 -04:00
graph_kind : GraphKind ,
2023-04-14 16:22:33 -04:00
roots : Vec < ModuleSpecifier > ,
loader : & mut dyn Loader ,
2024-02-19 10:28:41 -05:00
) -> Result < ModuleGraph , AnyError > {
2023-10-25 18:13:22 -04:00
self
. create_graph_with_options ( CreateGraphOptions {
2024-02-16 17:10:06 -05:00
is_dynamic : false ,
2023-10-25 18:13:22 -04:00
graph_kind ,
roots ,
2024-01-09 18:20:52 -05:00
loader : Some ( loader ) ,
2023-10-25 18:13:22 -04:00
} )
. await
}
2024-03-07 11:30:30 -05:00
pub async fn create_and_validate_publish_graph (
2024-02-19 10:28:41 -05:00
& self ,
2024-07-03 20:54:33 -04:00
package_configs : & [ JsrPackageConfig ] ,
2024-03-07 11:30:30 -05:00
build_fast_check_graph : bool ,
2024-02-19 10:28:41 -05:00
) -> Result < ModuleGraph , AnyError > {
2024-11-28 08:51:24 -05:00
struct PublishLoader ( FetchCacher ) ;
impl Loader for PublishLoader {
fn load (
& self ,
specifier : & deno_ast ::ModuleSpecifier ,
options : deno_graph ::source ::LoadOptions ,
) -> deno_graph ::source ::LoadFuture {
if specifier . scheme ( ) = = " bun " {
return Box ::pin ( std ::future ::ready ( Ok ( Some (
deno_graph ::source ::LoadResponse ::External {
specifier : specifier . clone ( ) ,
} ,
) ) ) ) ;
}
self . 0. load ( specifier , options )
}
}
2024-09-25 21:50:54 -04:00
fn graph_has_external_remote ( graph : & ModuleGraph ) -> bool {
// Earlier on, we marked external non-JSR modules as external.
// If the graph contains any of those, it would cause type checking
// to crash, so since publishing is going to fail anyway, skip type
// checking.
graph . modules ( ) . any ( | module | match module {
deno_graph ::Module ::External ( external_module ) = > {
matches! ( external_module . specifier . scheme ( ) , " http " | " https " )
}
_ = > false ,
} )
}
2024-02-19 10:28:41 -05:00
let mut roots = Vec ::new ( ) ;
2024-07-03 20:54:33 -04:00
for package_config in package_configs {
roots . extend ( package_config . config_file . resolve_export_value_urls ( ) ? ) ;
2024-02-19 10:28:41 -05:00
}
2024-11-28 08:51:24 -05:00
let loader = self . module_graph_builder . create_graph_loader ( ) ;
let mut publish_loader = PublishLoader ( loader ) ;
2024-02-20 16:29:57 -05:00
let mut graph = self
2024-02-19 10:28:41 -05:00
. create_graph_with_options ( CreateGraphOptions {
is_dynamic : false ,
graph_kind : deno_graph ::GraphKind ::All ,
roots ,
2024-11-28 08:51:24 -05:00
loader : Some ( & mut publish_loader ) ,
2024-02-19 10:28:41 -05:00
} )
2024-02-20 16:29:57 -05:00
. await ? ;
2024-03-07 11:30:30 -05:00
self . graph_valid ( & graph ) ? ;
2024-09-25 21:50:54 -04:00
if self . options . type_check_mode ( ) . is_true ( )
& & ! graph_has_external_remote ( & graph )
{
2024-02-21 08:35:25 -05:00
self . type_check_graph ( graph . clone ( ) ) . await ? ;
}
2024-09-25 21:50:54 -04:00
2024-03-07 11:30:30 -05:00
if build_fast_check_graph {
2024-07-03 20:54:33 -04:00
let fast_check_workspace_members = package_configs
. iter ( )
. map ( | p | config_to_deno_graph_workspace_member ( & p . config_file ) )
. collect ::< Result < Vec < _ > , _ > > ( ) ? ;
2024-03-07 11:30:30 -05:00
self . module_graph_builder . build_fast_check_graph (
& mut graph ,
BuildFastCheckGraphOptions {
2024-07-03 20:54:33 -04:00
workspace_fast_check : WorkspaceFastCheckOption ::Enabled (
& fast_check_workspace_members ,
) ,
2024-03-07 11:30:30 -05:00
} ,
) ? ;
}
2024-09-25 21:50:54 -04:00
2024-02-20 16:29:57 -05:00
Ok ( graph )
2024-02-19 10:28:41 -05:00
}
2023-10-25 18:13:22 -04:00
pub async fn create_graph_with_options (
& self ,
options : CreateGraphOptions < '_ > ,
2024-02-19 10:28:41 -05:00
) -> Result < ModuleGraph , AnyError > {
2023-10-25 18:13:22 -04:00
let mut graph = ModuleGraph ::new ( options . graph_kind ) ;
2024-02-16 17:10:06 -05:00
2023-04-14 16:22:33 -04:00
self
2024-02-20 16:29:57 -05:00
. module_graph_builder
2024-02-16 17:10:06 -05:00
. build_graph_with_npm_resolution ( & mut graph , options )
2023-04-14 16:22:33 -04:00
. await ? ;
2023-09-29 09:26:25 -04:00
if let Some ( npm_resolver ) = self . npm_resolver . as_managed ( ) {
if graph . has_node_specifier & & self . options . type_check_mode ( ) . is_true ( ) {
npm_resolver . inject_synthetic_types_node_package ( ) . await ? ;
}
2023-01-24 09:05:54 -05:00
}
2023-04-14 16:22:33 -04:00
Ok ( graph )
}
pub async fn create_graph_and_maybe_check (
& self ,
roots : Vec < ModuleSpecifier > ,
) -> Result < Arc < deno_graph ::ModuleGraph > , AnyError > {
2023-06-07 10:09:10 -04:00
let graph_kind = self . options . type_check_mode ( ) . as_graph_kind ( ) ;
2023-06-14 18:29:19 -04:00
2024-02-16 17:10:06 -05:00
let graph = self
. create_graph_with_options ( CreateGraphOptions {
is_dynamic : false ,
graph_kind ,
2023-04-14 16:22:33 -04:00
roots ,
2024-02-16 17:10:06 -05:00
loader : None ,
} )
2023-04-14 16:22:33 -04:00
. await ? ;
2024-03-07 11:30:30 -05:00
self . graph_valid ( & graph ) ? ;
2023-04-14 16:22:33 -04:00
2023-06-07 10:09:10 -04:00
if self . options . type_check_mode ( ) . is_true ( ) {
2024-02-20 16:29:57 -05:00
// provide the graph to the type checker, then get it back after it's done
2024-02-21 08:35:25 -05:00
let graph = self . type_check_graph ( graph ) . await ? ;
2024-02-20 16:29:57 -05:00
Ok ( graph )
} else {
Ok ( Arc ::new ( graph ) )
2022-12-09 09:40:48 -05:00
}
}
2024-02-21 08:35:25 -05:00
2024-03-07 11:30:30 -05:00
pub fn graph_valid ( & self , graph : & ModuleGraph ) -> Result < ( ) , AnyError > {
self . module_graph_builder . graph_valid ( graph )
}
2024-02-21 08:35:25 -05:00
async fn type_check_graph (
& self ,
graph : ModuleGraph ,
) -> Result < Arc < ModuleGraph > , AnyError > {
self
. type_checker
. check (
graph ,
check ::CheckOptions {
build_fast_check_graph : true ,
lib : self . options . ts_type_lib_window ( ) ,
log_ignored_options : true ,
reload : self . options . reload_flag ( ) ,
type_check_mode : self . options . type_check_mode ( ) ,
} ,
)
. await
}
2024-02-20 16:29:57 -05:00
}
2022-12-09 09:40:48 -05:00
2024-07-03 20:54:33 -04:00
pub struct BuildFastCheckGraphOptions < ' a > {
2024-02-20 16:29:57 -05:00
/// Whether to do fast check on workspace members. This
/// is mostly only useful when publishing.
2024-07-03 20:54:33 -04:00
pub workspace_fast_check : deno_graph ::WorkspaceFastCheckOption < ' a > ,
2024-02-20 16:29:57 -05:00
}
pub struct ModuleGraphBuilder {
caches : Arc < cache ::Caches > ,
2024-11-13 10:10:09 -05:00
cjs_tracker : Arc < CjsTracker > ,
2024-11-01 12:27:00 -04:00
cli_options : Arc < CliOptions > ,
file_fetcher : Arc < FileFetcher > ,
2024-02-20 16:29:57 -05:00
fs : Arc < dyn FileSystem > ,
2024-11-01 12:27:00 -04:00
global_http_cache : Arc < GlobalHttpCache > ,
in_npm_pkg_checker : Arc < dyn InNpmPackageChecker > ,
2024-06-28 20:18:21 -04:00
lockfile : Option < Arc < CliLockfile > > ,
2024-02-20 16:29:57 -05:00
maybe_file_watcher_reporter : Option < FileWatcherReporter > ,
2024-11-01 12:27:00 -04:00
module_info_cache : Arc < ModuleInfoCache > ,
npm_resolver : Arc < dyn CliNpmResolver > ,
parsed_source_cache : Arc < ParsedSourceCache > ,
2024-11-13 10:10:09 -05:00
resolver : Arc < CliResolver > ,
2024-09-25 21:50:54 -04:00
root_permissions_container : PermissionsContainer ,
2024-02-20 16:29:57 -05:00
}
impl ModuleGraphBuilder {
#[ allow(clippy::too_many_arguments) ]
pub fn new (
caches : Arc < cache ::Caches > ,
2024-11-13 10:10:09 -05:00
cjs_tracker : Arc < CjsTracker > ,
2024-11-01 12:27:00 -04:00
cli_options : Arc < CliOptions > ,
file_fetcher : Arc < FileFetcher > ,
2024-02-20 16:29:57 -05:00
fs : Arc < dyn FileSystem > ,
2024-11-01 12:27:00 -04:00
global_http_cache : Arc < GlobalHttpCache > ,
in_npm_pkg_checker : Arc < dyn InNpmPackageChecker > ,
2024-06-28 20:18:21 -04:00
lockfile : Option < Arc < CliLockfile > > ,
2024-02-20 16:29:57 -05:00
maybe_file_watcher_reporter : Option < FileWatcherReporter > ,
2024-11-01 12:27:00 -04:00
module_info_cache : Arc < ModuleInfoCache > ,
npm_resolver : Arc < dyn CliNpmResolver > ,
parsed_source_cache : Arc < ParsedSourceCache > ,
2024-11-13 10:10:09 -05:00
resolver : Arc < CliResolver > ,
2024-09-25 21:50:54 -04:00
root_permissions_container : PermissionsContainer ,
2024-02-20 16:29:57 -05:00
) -> Self {
Self {
caches ,
2024-11-13 10:10:09 -05:00
cjs_tracker ,
2024-11-01 12:27:00 -04:00
cli_options ,
file_fetcher ,
2024-02-20 16:29:57 -05:00
fs ,
2024-11-01 12:27:00 -04:00
global_http_cache ,
in_npm_pkg_checker ,
2024-02-20 16:29:57 -05:00
lockfile ,
maybe_file_watcher_reporter ,
2024-11-01 12:27:00 -04:00
module_info_cache ,
npm_resolver ,
parsed_source_cache ,
resolver ,
2024-09-25 21:50:54 -04:00
root_permissions_container ,
2024-01-09 18:20:52 -05:00
}
}
2023-04-14 16:22:33 -04:00
pub async fn build_graph_with_npm_resolution < ' a > (
2024-02-16 17:10:06 -05:00
& self ,
graph : & mut ModuleGraph ,
options : CreateGraphOptions < ' a > ,
) -> Result < ( ) , AnyError > {
enum MutLoaderRef < ' a > {
Borrowed ( & ' a mut dyn Loader ) ,
Owned ( cache ::FetchCacher ) ,
}
impl < ' a > MutLoaderRef < ' a > {
pub fn as_mut_loader ( & mut self ) -> & mut dyn Loader {
match self {
Self ::Borrowed ( loader ) = > * loader ,
Self ::Owned ( loader ) = > loader ,
}
}
}
2024-06-28 20:18:21 -04:00
struct LockfileLocker < ' a > ( & ' a CliLockfile ) ;
2024-05-28 14:58:43 -04:00
impl < ' a > deno_graph ::source ::Locker for LockfileLocker < ' a > {
fn get_remote_checksum (
& self ,
specifier : & deno_ast ::ModuleSpecifier ,
) -> Option < LoaderChecksum > {
self
. 0
. lock ( )
. remote ( )
. get ( specifier . as_str ( ) )
. map ( | s | LoaderChecksum ::new ( s . clone ( ) ) )
}
fn has_remote_checksum (
& self ,
specifier : & deno_ast ::ModuleSpecifier ,
) -> bool {
self . 0. lock ( ) . remote ( ) . contains_key ( specifier . as_str ( ) )
}
fn set_remote_checksum (
& mut self ,
specifier : & deno_ast ::ModuleSpecifier ,
checksum : LoaderChecksum ,
) {
self
. 0
. lock ( )
. insert_remote ( specifier . to_string ( ) , checksum . into_string ( ) )
}
fn get_pkg_manifest_checksum (
& self ,
package_nv : & PackageNv ,
) -> Option < LoaderChecksum > {
self
. 0
. lock ( )
. content
. packages
. jsr
2024-08-28 14:17:47 -04:00
. get ( package_nv )
2024-05-28 14:58:43 -04:00
. map ( | s | LoaderChecksum ::new ( s . integrity . clone ( ) ) )
}
fn set_pkg_manifest_checksum (
& mut self ,
package_nv : & PackageNv ,
checksum : LoaderChecksum ,
) {
// a value would only exist in here if two workers raced
// to insert the same package manifest checksum
self
. 0
. lock ( )
2024-08-28 14:17:47 -04:00
. insert_package ( package_nv . clone ( ) , checksum . into_string ( ) ) ;
2024-05-28 14:58:43 -04:00
}
}
2024-07-09 17:07:16 -04:00
let maybe_imports = if options . graph_kind . include_types ( ) {
2024-11-01 12:27:00 -04:00
self . cli_options . to_compiler_option_types ( ) ?
2024-07-09 17:07:16 -04:00
} else {
Vec ::new ( )
} ;
2024-11-01 12:27:00 -04:00
let analyzer = self . module_info_cache . as_module_analyzer ( ) ;
2024-02-16 17:10:06 -05:00
let mut loader = match options . loader {
Some ( loader ) = > MutLoaderRef ::Borrowed ( loader ) ,
None = > MutLoaderRef ::Owned ( self . create_graph_loader ( ) ) ,
} ;
2024-02-20 16:29:57 -05:00
let cli_resolver = & self . resolver ;
2024-11-13 10:10:09 -05:00
let graph_resolver = self . create_graph_resolver ( ) ? ;
2024-06-05 11:04:16 -04:00
let graph_npm_resolver = cli_resolver . create_graph_npm_resolver ( ) ;
2024-02-16 17:10:06 -05:00
let maybe_file_watcher_reporter = self
. maybe_file_watcher_reporter
. as_ref ( )
. map ( | r | r . as_reporter ( ) ) ;
2024-05-28 14:58:43 -04:00
let mut locker = self
. lockfile
. as_ref ( )
. map ( | lockfile | LockfileLocker ( lockfile ) ) ;
2024-02-16 17:10:06 -05:00
self
. build_graph_with_npm_resolution_and_build_options (
graph ,
options . roots ,
loader . as_mut_loader ( ) ,
deno_graph ::BuildOptions {
2024-04-18 21:43:28 -04:00
imports : maybe_imports ,
2024-02-16 17:10:06 -05:00
is_dynamic : options . is_dynamic ,
2024-04-18 20:51:16 -04:00
passthrough_jsr_specifiers : false ,
2024-02-21 16:58:37 -05:00
executor : Default ::default ( ) ,
2024-04-11 19:00:17 -04:00
file_system : & DenoGraphFsAdapter ( self . fs . as_ref ( ) ) ,
2024-04-18 21:43:28 -04:00
jsr_url_provider : & CliJsrUrlProvider ,
2024-06-05 11:04:16 -04:00
npm_resolver : Some ( & graph_npm_resolver ) ,
2024-04-11 19:00:17 -04:00
module_analyzer : & analyzer ,
2024-02-16 17:10:06 -05:00
reporter : maybe_file_watcher_reporter ,
2024-11-13 10:10:09 -05:00
resolver : Some ( & graph_resolver ) ,
2024-05-28 14:58:43 -04:00
locker : locker . as_mut ( ) . map ( | l | l as _ ) ,
2024-02-16 17:10:06 -05:00
} ,
)
. await
}
async fn build_graph_with_npm_resolution_and_build_options < ' a > (
2023-04-14 16:22:33 -04:00
& self ,
graph : & mut ModuleGraph ,
roots : Vec < ModuleSpecifier > ,
2024-05-28 14:58:43 -04:00
loader : & ' a mut dyn deno_graph ::source ::Loader ,
2023-04-14 16:22:33 -04:00
options : deno_graph ::BuildOptions < ' a > ,
) -> Result < ( ) , AnyError > {
2023-05-23 18:51:48 -04:00
// ensure an "npm install" is done if the user has explicitly
// opted into using a node_modules directory
2024-08-29 18:57:43 -04:00
if self
2024-11-01 12:27:00 -04:00
. cli_options
2024-08-30 17:58:24 -04:00
. node_modules_dir ( ) ?
2024-08-29 18:57:43 -04:00
. map ( | m | m . uses_node_modules_dir ( ) )
. unwrap_or ( false )
{
2023-09-30 12:06:38 -04:00
if let Some ( npm_resolver ) = self . npm_resolver . as_managed ( ) {
npm_resolver . ensure_top_level_package_json_install ( ) . await ? ;
}
2023-05-23 18:51:48 -04:00
}
2024-05-28 14:58:43 -04:00
// fill the graph with the information from the lockfile
let is_first_execution = graph . roots . is_empty ( ) ;
if is_first_execution {
// populate the information from the lockfile
2023-08-29 13:03:02 -04:00
if let Some ( lockfile ) = & self . lockfile {
let lockfile = lockfile . lock ( ) ;
2024-09-26 10:24:49 -04:00
graph . fill_from_lockfile ( FillFromLockfileOptions {
redirects : lockfile
. content
. redirects
. iter ( )
. map ( | ( from , to ) | ( from . as_str ( ) , to . as_str ( ) ) ) ,
package_specifiers : lockfile
. content
. packages
. specifiers
. iter ( )
. map ( | ( dep , id ) | ( dep , id . as_str ( ) ) ) ,
} ) ;
2023-09-18 10:46:44 -04:00
}
}
2023-09-07 09:09:16 -04:00
2024-05-28 14:58:43 -04:00
let initial_redirects_len = graph . redirects . len ( ) ;
let initial_package_deps_len = graph . packages . package_deps_sum ( ) ;
let initial_package_mappings_len = graph . packages . mappings ( ) . len ( ) ;
2022-12-09 09:40:48 -05:00
2024-09-30 15:46:43 -04:00
if roots . iter ( ) . any ( | r | r . scheme ( ) = = " npm " )
& & self . npm_resolver . as_byonm ( ) . is_some ( )
{
bail! ( " Resolving npm specifier entrypoints this way is currently not supported with \" nodeModules \" : \" manual \" . In the meantime, try with --node-modules-dir=auto instead " ) ;
}
2024-05-28 14:58:43 -04:00
graph . build ( roots , loader , options ) . await ;
2023-09-07 09:09:16 -04:00
2024-05-28 14:58:43 -04:00
let has_redirects_changed = graph . redirects . len ( ) ! = initial_redirects_len ;
let has_jsr_package_deps_changed =
graph . packages . package_deps_sum ( ) ! = initial_package_deps_len ;
let has_jsr_package_mappings_changed =
graph . packages . mappings ( ) . len ( ) ! = initial_package_mappings_len ;
if has_redirects_changed
| | has_jsr_package_deps_changed
| | has_jsr_package_mappings_changed
{
if let Some ( lockfile ) = & self . lockfile {
let mut lockfile = lockfile . lock ( ) ;
// https redirects
if has_redirects_changed {
let graph_redirects = graph . redirects . iter ( ) . filter ( | ( from , _ ) | {
! matches! ( from . scheme ( ) , " npm " | " file " | " deno " )
} ) ;
for ( from , to ) in graph_redirects {
lockfile . insert_redirect ( from . to_string ( ) , to . to_string ( ) ) ;
}
}
// jsr package mappings
if has_jsr_package_mappings_changed {
for ( from , to ) in graph . packages . mappings ( ) {
lockfile . insert_package_specifier (
2024-08-28 14:17:47 -04:00
JsrDepPackageReq ::jsr ( from . clone ( ) ) ,
to . version . to_string ( ) ,
2024-05-28 14:58:43 -04:00
) ;
}
}
// jsr packages
if has_jsr_package_deps_changed {
2024-08-28 14:17:47 -04:00
for ( nv , deps ) in graph . packages . packages_with_deps ( ) {
lockfile . add_package_deps ( nv , deps . cloned ( ) ) ;
2024-05-28 14:58:43 -04:00
}
}
}
}
2023-04-14 16:22:33 -04:00
Ok ( ( ) )
}
2023-02-22 14:15:25 -05:00
2024-02-20 16:29:57 -05:00
pub fn build_fast_check_graph (
& self ,
graph : & mut ModuleGraph ,
options : BuildFastCheckGraphOptions ,
) -> Result < ( ) , AnyError > {
if ! graph . graph_kind ( ) . include_types ( ) {
return Ok ( ( ) ) ;
}
log ::debug! ( " Building fast check graph " ) ;
2024-07-03 20:54:33 -04:00
let fast_check_cache = if matches! (
options . workspace_fast_check ,
deno_graph ::WorkspaceFastCheckOption ::Disabled
) {
2024-02-20 16:29:57 -05:00
Some ( cache ::FastCheckCache ::new ( self . caches . fast_check_db ( ) ) )
} else {
None
} ;
let parser = self . parsed_source_cache . as_capturing_parser ( ) ;
let cli_resolver = & self . resolver ;
2024-11-13 10:10:09 -05:00
let graph_resolver = self . create_graph_resolver ( ) ? ;
2024-06-05 11:04:16 -04:00
let graph_npm_resolver = cli_resolver . create_graph_npm_resolver ( ) ;
2024-02-20 16:29:57 -05:00
graph . build_fast_check_type_graph (
deno_graph ::BuildFastCheckTypeGraphOptions {
2024-11-01 12:27:00 -04:00
es_parser : Some ( & parser ) ,
2024-02-20 16:29:57 -05:00
fast_check_cache : fast_check_cache . as_ref ( ) . map ( | c | c as _ ) ,
fast_check_dts : false ,
2024-11-01 12:27:00 -04:00
jsr_url_provider : & CliJsrUrlProvider ,
2024-11-13 10:10:09 -05:00
resolver : Some ( & graph_resolver ) ,
2024-06-05 11:04:16 -04:00
npm_resolver : Some ( & graph_npm_resolver ) ,
2024-07-03 20:54:33 -04:00
workspace_fast_check : options . workspace_fast_check ,
2024-02-20 16:29:57 -05:00
} ,
) ;
Ok ( ( ) )
}
2023-04-14 16:22:33 -04:00
/// Creates the default loader used for creating a graph.
pub fn create_graph_loader ( & self ) -> cache ::FetchCacher {
2024-09-25 21:50:54 -04:00
self . create_fetch_cacher ( self . root_permissions_container . clone ( ) )
2023-04-14 16:22:33 -04:00
}
pub fn create_fetch_cacher (
& self ,
2024-09-25 21:50:54 -04:00
permissions : PermissionsContainer ,
2023-04-14 16:22:33 -04:00
) -> cache ::FetchCacher {
cache ::FetchCacher ::new (
self . file_fetcher . clone ( ) ,
2024-11-01 12:27:00 -04:00
self . fs . clone ( ) ,
2023-08-01 20:49:09 -04:00
self . global_http_cache . clone ( ) ,
2024-11-01 12:27:00 -04:00
self . in_npm_pkg_checker . clone ( ) ,
2023-10-25 18:13:22 -04:00
self . module_info_cache . clone ( ) ,
2024-09-25 21:50:54 -04:00
cache ::FetchCacherOptions {
2024-11-01 12:27:00 -04:00
file_header_overrides : self . cli_options . resolve_file_header_overrides ( ) ,
2024-09-25 21:50:54 -04:00
permissions ,
is_deno_publish : matches ! (
2024-11-01 12:27:00 -04:00
self . cli_options . sub_command ( ) ,
2024-09-25 21:50:54 -04:00
crate ::args ::DenoSubcommand ::Publish { .. }
) ,
} ,
2023-04-14 16:22:33 -04:00
)
}
2024-03-07 11:30:30 -05:00
/// Check if `roots` and their deps are available. Returns `Ok(())` if
/// so. Returns `Err(_)` if there is a known module graph or resolution
/// error statically reachable from `roots` and not a dynamic import.
pub fn graph_valid ( & self , graph : & ModuleGraph ) -> Result < ( ) , AnyError > {
2024-06-05 11:04:16 -04:00
self . graph_roots_valid (
graph ,
& graph . roots . iter ( ) . cloned ( ) . collect ::< Vec < _ > > ( ) ,
)
2024-03-07 11:30:30 -05:00
}
pub fn graph_roots_valid (
& self ,
graph : & ModuleGraph ,
roots : & [ ModuleSpecifier ] ,
) -> Result < ( ) , AnyError > {
graph_valid (
graph ,
2024-05-28 14:58:43 -04:00
& self . fs ,
2024-03-07 11:30:30 -05:00
roots ,
GraphValidOptions {
2024-11-01 12:27:00 -04:00
kind : if self . cli_options . type_check_mode ( ) . is_true ( ) {
2024-09-25 09:04:57 -04:00
GraphKind ::All
} else {
GraphKind ::CodeOnly
} ,
2024-11-01 12:27:00 -04:00
check_js : self . cli_options . check_js ( ) ,
2024-09-26 12:31:03 -04:00
exit_integrity_errors : true ,
2024-03-07 11:30:30 -05:00
} ,
)
}
2024-11-13 10:10:09 -05:00
fn create_graph_resolver ( & self ) -> Result < CliGraphResolver , AnyError > {
let jsx_import_source_config = self
. cli_options
. workspace ( )
. to_maybe_jsx_import_source_config ( ) ? ;
Ok ( CliGraphResolver {
cjs_tracker : & self . cjs_tracker ,
resolver : & self . resolver ,
jsx_import_source_config ,
} )
}
2023-02-22 14:15:25 -05:00
}
2023-01-24 15:14:49 -05:00
/// Adds more explanatory information to a resolution error.
pub fn enhanced_resolution_error_message ( error : & ResolutionError ) -> String {
2024-08-28 14:17:47 -04:00
let mut message = format_deno_graph_error ( error ) ;
2023-01-24 15:14:49 -05:00
2024-09-05 02:25:56 -04:00
let maybe_hint = if let Some ( specifier ) =
get_resolution_error_bare_node_specifier ( error )
{
2024-03-07 08:59:57 -05:00
if ! * DENO_DISABLE_PEDANTIC_NODE_WARNINGS {
2024-09-05 02:25:56 -04:00
Some ( format! ( " If you want to use a built-in Node module, add a \" node: \" prefix (ex. \" node: {specifier} \" ). " ) )
} else {
None
2024-03-07 08:59:57 -05:00
}
2024-09-05 02:25:56 -04:00
} else {
get_import_prefix_missing_error ( error ) . map ( | specifier | {
format! (
2024-09-05 05:08:22 -04:00
" If you want to use a JSR or npm package, try running `deno add jsr:{}` or `deno add npm:{}` " ,
specifier , specifier
2024-09-05 02:25:56 -04:00
)
} )
} ;
if let Some ( hint ) = maybe_hint {
message . push_str ( & format! ( " \n {} {} " , colors ::cyan ( " hint: " ) , hint ) ) ;
2023-01-27 17:36:23 -05:00
}
message
}
2024-05-28 14:58:43 -04:00
fn enhanced_sloppy_imports_error_message (
fs : & Arc < dyn FileSystem > ,
2023-12-07 15:59:13 -05:00
error : & ModuleError ,
2024-05-28 14:58:43 -04:00
) -> Option < String > {
match error {
ModuleError ::LoadingErr ( specifier , _ , ModuleLoadError ::Loader ( _ ) ) // ex. "Is a directory" error
2024-03-07 11:30:30 -05:00
| ModuleError ::Missing ( specifier , _ ) = > {
2024-09-28 19:17:48 -04:00
let additional_message = CliSloppyImportsResolver ::new ( SloppyImportsCachedFs ::new ( fs . clone ( ) ) )
2024-11-26 14:38:24 -05:00
. resolve ( specifier , SloppyImportsResolutionKind ::Execution ) ?
2024-07-25 09:07:59 -04:00
. as_suggestion_message ( ) ;
2024-05-28 14:58:43 -04:00
Some ( format! (
" {} {} or run with --unstable-sloppy-imports " ,
error ,
additional_message ,
) )
}
_ = > None ,
}
}
2024-09-26 12:31:03 -04:00
fn enhanced_integrity_error_message ( err : & ModuleError ) -> Option < String > {
2024-05-28 14:58:43 -04:00
match err {
ModuleError ::LoadingErr (
specifier ,
_ ,
ModuleLoadError ::Jsr ( JsrLoadError ::ContentChecksumIntegrity (
checksum_err ,
) ) ,
) = > {
Some ( format! (
concat! (
" Integrity check failed in package. The package may have been tampered with. \n \n " ,
" Specifier: {} \n " ,
" Actual: {} \n " ,
" Expected: {} \n \n " ,
" If you modified your global cache, run again with the --reload flag to restore " ,
" its state. If you want to modify dependencies locally run again with the " ,
" --vendor flag or specify ` \" vendor \" : true` in a deno.json then modify the contents " ,
" of the vendor/ folder. "
) ,
2024-02-27 13:30:21 -05:00
specifier ,
2024-05-28 14:58:43 -04:00
checksum_err . actual ,
checksum_err . expected ,
) )
}
ModuleError ::LoadingErr (
_specifier ,
_ ,
ModuleLoadError ::Jsr (
JsrLoadError ::PackageVersionManifestChecksumIntegrity (
package_nv ,
checksum_err ,
) ,
) ,
) = > {
Some ( format! (
concat! (
" Integrity check failed for package. The source code is invalid, as it does not match the expected hash in the lock file. \n \n " ,
" Package: {} \n " ,
" Actual: {} \n " ,
" Expected: {} \n \n " ,
" This could be caused by: \n " ,
" * the lock file may be corrupt \n " ,
" * the source itself may be corrupt \n \n " ,
2024-08-20 14:13:17 -04:00
" Investigate the lockfile; delete it to regenerate the lockfile or --reload to reload the source code from the server. "
2024-05-28 14:58:43 -04:00
) ,
package_nv ,
checksum_err . actual ,
checksum_err . expected ,
) )
}
ModuleError ::LoadingErr (
specifier ,
_ ,
ModuleLoadError ::HttpsChecksumIntegrity ( checksum_err ) ,
) = > {
Some ( format! (
concat! (
" Integrity check failed for remote specifier. The source code is invalid, as it does not match the expected hash in the lock file. \n \n " ,
" Specifier: {} \n " ,
" Actual: {} \n " ,
" Expected: {} \n \n " ,
" This could be caused by: \n " ,
" * the lock file may be corrupt \n " ,
" * the source itself may be corrupt \n \n " ,
2024-08-20 14:13:17 -04:00
" Investigate the lockfile; delete it to regenerate the lockfile or --reload to reload the source code from the server. "
2024-05-28 14:58:43 -04:00
) ,
specifier ,
checksum_err . actual ,
checksum_err . expected ,
) )
2023-12-07 15:59:13 -05:00
}
_ = > None ,
}
}
2023-01-27 17:36:23 -05:00
pub fn get_resolution_error_bare_node_specifier (
error : & ResolutionError ,
) -> Option < & str > {
2023-05-28 14:44:41 -04:00
get_resolution_error_bare_specifier ( error )
. filter ( | specifier | deno_node ::is_builtin_node_module ( specifier ) )
2023-01-27 17:36:23 -05:00
}
fn get_resolution_error_bare_specifier (
error : & ResolutionError ,
) -> Option < & str > {
2023-01-24 15:14:49 -05:00
if let ResolutionError ::InvalidSpecifier {
2024-06-25 21:42:18 -04:00
error : SpecifierError ::ImportPrefixMissing { specifier , .. } ,
2023-01-24 15:14:49 -05:00
..
} = error
{
2023-01-27 17:36:23 -05:00
Some ( specifier . as_str ( ) )
} else if let ResolutionError ::ResolverError { error , .. } = error {
2023-10-20 00:02:08 -04:00
if let ResolveError ::Other ( error ) = ( * error ) . as_ref ( ) {
if let Some ( ImportMapError ::UnmappedBareSpecifier ( specifier , _ ) ) =
error . downcast_ref ::< ImportMapError > ( )
{
Some ( specifier . as_str ( ) )
} else {
None
}
2023-01-27 17:36:23 -05:00
} else {
None
2023-01-24 15:14:49 -05:00
}
2023-01-27 17:36:23 -05:00
} else {
None
2023-01-24 15:14:49 -05:00
}
2023-01-27 17:36:23 -05:00
}
2023-01-24 15:14:49 -05:00
2024-09-05 02:25:56 -04:00
fn get_import_prefix_missing_error ( error : & ResolutionError ) -> Option < & str > {
let mut maybe_specifier = None ;
if let ResolutionError ::InvalidSpecifier {
error : SpecifierError ::ImportPrefixMissing { specifier , .. } ,
2024-09-05 05:08:22 -04:00
range ,
2024-09-05 02:25:56 -04:00
} = error
{
2024-09-05 05:08:22 -04:00
if range . specifier . scheme ( ) = = " file " {
maybe_specifier = Some ( specifier ) ;
}
} else if let ResolutionError ::ResolverError { error , range , .. } = error {
if range . specifier . scheme ( ) = = " file " {
match error . as_ref ( ) {
ResolveError ::Specifier ( specifier_error ) = > {
if let SpecifierError ::ImportPrefixMissing { specifier , .. } =
specifier_error
{
maybe_specifier = Some ( specifier ) ;
}
2024-09-05 02:25:56 -04:00
}
2024-09-05 05:08:22 -04:00
ResolveError ::Other ( other_error ) = > {
if let Some ( SpecifierError ::ImportPrefixMissing {
specifier , ..
} ) = other_error . downcast_ref ::< SpecifierError > ( )
{
maybe_specifier = Some ( specifier ) ;
}
2024-09-05 02:25:56 -04:00
}
}
}
}
// NOTE(bartlomieju): For now, return None if a specifier contains a dot or a space. This is because
// suggesting to `deno add bad-module.ts` makes no sense and is worse than not providing
// a suggestion at all. This should be improved further in the future
if let Some ( specifier ) = maybe_specifier {
if specifier . contains ( '.' ) | | specifier . contains ( ' ' ) {
return None ;
}
}
maybe_specifier . map ( | s | s . as_str ( ) )
}
2023-06-14 18:29:19 -04:00
/// Gets if any of the specified root's "file:" dependents are in the
/// provided changed set.
pub fn has_graph_root_local_dependent_changed (
graph : & ModuleGraph ,
root : & ModuleSpecifier ,
2024-01-08 12:18:42 -05:00
canonicalized_changed_paths : & HashSet < PathBuf > ,
2023-06-14 18:29:19 -04:00
) -> bool {
let mut dependent_specifiers = graph . walk (
2024-06-05 11:04:16 -04:00
std ::iter ::once ( root ) ,
2023-06-14 18:29:19 -04:00
deno_graph ::WalkOptions {
follow_dynamic : true ,
2024-09-25 09:04:57 -04:00
kind : GraphKind ::All ,
2024-04-11 19:00:17 -04:00
prefer_fast_check_graph : true ,
2023-06-14 18:29:19 -04:00
check_js : true ,
} ,
) ;
while let Some ( ( s , _ ) ) = dependent_specifiers . next ( ) {
2024-09-28 07:55:01 -04:00
if let Ok ( path ) = url_to_file_path ( s ) {
2024-01-08 12:18:42 -05:00
if let Ok ( path ) = canonicalize_path ( & path ) {
if canonicalized_changed_paths . contains ( & path ) {
return true ;
}
}
} else {
2023-06-14 18:29:19 -04:00
// skip walking this remote module's dependencies
dependent_specifiers . skip_previous_dependencies ( ) ;
}
}
false
}
#[ derive(Clone, Debug) ]
pub struct FileWatcherReporter {
2023-10-30 20:25:58 -04:00
watcher_communicator : Arc < WatcherCommunicator > ,
2023-06-14 18:29:19 -04:00
file_paths : Arc < Mutex < Vec < PathBuf > > > ,
}
impl FileWatcherReporter {
2023-10-30 20:25:58 -04:00
pub fn new ( watcher_communicator : Arc < WatcherCommunicator > ) -> Self {
2023-06-14 18:29:19 -04:00
Self {
2023-10-19 01:05:00 -04:00
watcher_communicator ,
2023-06-14 18:29:19 -04:00
file_paths : Default ::default ( ) ,
}
}
pub fn as_reporter ( & self ) -> & dyn deno_graph ::source ::Reporter {
self
}
}
impl deno_graph ::source ::Reporter for FileWatcherReporter {
fn on_load (
& self ,
specifier : & ModuleSpecifier ,
modules_done : usize ,
modules_total : usize ,
) {
let mut file_paths = self . file_paths . lock ( ) ;
if specifier . scheme ( ) = = " file " {
2024-10-26 23:00:19 -04:00
// Don't trust that the path is a valid path at this point:
// https://github.com/denoland/deno/issues/26209.
if let Ok ( file_path ) = specifier . to_file_path ( ) {
file_paths . push ( file_path ) ;
}
2023-06-14 18:29:19 -04:00
}
if modules_done = = modules_total {
2023-10-19 01:05:00 -04:00
self
. watcher_communicator
. watch_paths ( file_paths . drain ( .. ) . collect ( ) )
. unwrap ( ) ;
2023-06-14 18:29:19 -04:00
}
}
}
2023-12-01 15:12:10 -05:00
pub struct DenoGraphFsAdapter < ' a > (
pub & ' a dyn deno_runtime ::deno_fs ::FileSystem ,
) ;
impl < ' a > deno_graph ::source ::FileSystem for DenoGraphFsAdapter < ' a > {
fn read_dir (
& self ,
dir_url : & deno_graph ::ModuleSpecifier ,
) -> Vec < deno_graph ::source ::DirEntry > {
use deno_core ::anyhow ;
use deno_graph ::source ::DirEntry ;
use deno_graph ::source ::DirEntryKind ;
let dir_path = match dir_url . to_file_path ( ) {
Ok ( path ) = > path ,
// ignore, treat as non-analyzable
Err ( ( ) ) = > return vec! [ ] ,
} ;
let entries = match self . 0. read_dir_sync ( & dir_path ) {
Ok ( dir ) = > dir ,
Err ( err )
if matches! (
err . kind ( ) ,
std ::io ::ErrorKind ::PermissionDenied | std ::io ::ErrorKind ::NotFound
) = >
{
return vec! [ ] ;
}
Err ( err ) = > {
return vec! [ DirEntry {
kind : DirEntryKind ::Error (
anyhow ::Error ::from ( err )
. context ( " Failed to read directory. " . to_string ( ) ) ,
) ,
url : dir_url . clone ( ) ,
} ] ;
}
} ;
let mut dir_entries = Vec ::with_capacity ( entries . len ( ) ) ;
for entry in entries {
let entry_path = dir_path . join ( & entry . name ) ;
dir_entries . push ( if entry . is_directory {
DirEntry {
kind : DirEntryKind ::Dir ,
url : ModuleSpecifier ::from_directory_path ( & entry_path ) . unwrap ( ) ,
}
} else if entry . is_file {
DirEntry {
kind : DirEntryKind ::File ,
url : ModuleSpecifier ::from_file_path ( & entry_path ) . unwrap ( ) ,
}
} else if entry . is_symlink {
DirEntry {
kind : DirEntryKind ::Symlink ,
url : ModuleSpecifier ::from_file_path ( & entry_path ) . unwrap ( ) ,
}
} else {
continue ;
} ) ;
}
dir_entries
}
}
2024-11-26 14:38:24 -05:00
pub fn format_range_with_colors ( referrer : & deno_graph ::Range ) -> String {
2023-12-01 15:12:10 -05:00
format! (
" {}:{}:{} " ,
2024-11-26 14:38:24 -05:00
colors ::cyan ( referrer . specifier . as_str ( ) ) ,
colors ::yellow ( & ( referrer . range . start . line + 1 ) . to_string ( ) ) ,
colors ::yellow ( & ( referrer . range . start . character + 1 ) . to_string ( ) )
2023-12-01 15:12:10 -05:00
)
}
2024-02-20 16:29:57 -05:00
#[ derive(Debug, Default, Clone, Copy) ]
2024-04-24 17:43:34 -04:00
pub struct CliJsrUrlProvider ;
2024-02-20 16:29:57 -05:00
impl deno_graph ::source ::JsrUrlProvider for CliJsrUrlProvider {
fn url ( & self ) -> & 'static ModuleSpecifier {
jsr_url ( )
}
}
2024-08-28 14:17:47 -04:00
// todo(dsherret): We should change ModuleError to use thiserror so that
// we don't need to do this.
fn format_deno_graph_error ( err : & dyn Error ) -> String {
use std ::fmt ::Write ;
let mut message = format! ( " {} " , err ) ;
let mut maybe_source = err . source ( ) ;
if maybe_source . is_some ( ) {
let mut past_message = message . clone ( ) ;
let mut count = 0 ;
let mut display_count = 0 ;
while let Some ( source ) = maybe_source {
let current_message = format! ( " {} " , source ) ;
maybe_source = source . source ( ) ;
// sometimes an error might be repeated due to
// being boxed multiple times in another AnyError
if current_message ! = past_message {
write! ( message , " \n {}: " , display_count , ) . unwrap ( ) ;
for ( i , line ) in current_message . lines ( ) . enumerate ( ) {
if i > 0 {
write! ( message , " \n {} " , line ) . unwrap ( ) ;
} else {
write! ( message , " {} " , line ) . unwrap ( ) ;
}
}
display_count + = 1 ;
}
if count > 8 {
write! ( message , " \n {}: ... " , count ) . unwrap ( ) ;
break ;
}
past_message = current_message ;
count + = 1 ;
}
}
message
}
2024-11-13 10:10:09 -05:00
#[ derive(Debug) ]
struct CliGraphResolver < ' a > {
cjs_tracker : & ' a CjsTracker ,
resolver : & ' a CliResolver ,
jsx_import_source_config : Option < JsxImportSourceConfig > ,
}
impl < ' a > deno_graph ::source ::Resolver for CliGraphResolver < ' a > {
fn default_jsx_import_source ( & self ) -> Option < String > {
self
. jsx_import_source_config
. as_ref ( )
. and_then ( | c | c . default_specifier . clone ( ) )
}
fn default_jsx_import_source_types ( & self ) -> Option < String > {
self
. jsx_import_source_config
. as_ref ( )
. and_then ( | c | c . default_types_specifier . clone ( ) )
}
fn jsx_import_source_module ( & self ) -> & str {
self
. jsx_import_source_config
. as_ref ( )
. map ( | c | c . module . as_str ( ) )
. unwrap_or ( deno_graph ::source ::DEFAULT_JSX_IMPORT_SOURCE_MODULE )
}
fn resolve (
& self ,
raw_specifier : & str ,
referrer_range : & deno_graph ::Range ,
2024-11-26 14:38:24 -05:00
resolution_kind : ResolutionKind ,
2024-11-13 10:10:09 -05:00
) -> Result < ModuleSpecifier , ResolveError > {
self . resolver . resolve (
raw_specifier ,
2024-11-26 14:38:24 -05:00
& referrer_range . specifier ,
referrer_range . range . start ,
referrer_range
. resolution_mode
. map ( to_node_resolution_mode )
. unwrap_or_else ( | | {
self
. cjs_tracker
. get_referrer_kind ( & referrer_range . specifier )
} ) ,
to_node_resolution_kind ( resolution_kind ) ,
2024-11-13 10:10:09 -05:00
)
}
}
2024-11-26 14:38:24 -05:00
pub fn to_node_resolution_kind (
kind : ResolutionKind ,
) -> node_resolver ::NodeResolutionKind {
match kind {
ResolutionKind ::Execution = > node_resolver ::NodeResolutionKind ::Execution ,
ResolutionKind ::Types = > node_resolver ::NodeResolutionKind ::Types ,
}
}
pub fn to_node_resolution_mode (
mode : deno_graph ::source ::ResolutionMode ,
) -> node_resolver ::ResolutionMode {
match mode {
deno_graph ::source ::ResolutionMode ::Import = > {
node_resolver ::ResolutionMode ::Import
}
deno_graph ::source ::ResolutionMode ::Require = > {
node_resolver ::ResolutionMode ::Require
}
}
}
2023-01-27 17:36:23 -05:00
#[ cfg(test) ]
mod test {
use std ::sync ::Arc ;
use deno_ast ::ModuleSpecifier ;
2023-10-20 00:02:08 -04:00
use deno_graph ::source ::ResolveError ;
2024-11-26 14:38:24 -05:00
use deno_graph ::PositionRange ;
2023-01-27 17:36:23 -05:00
use deno_graph ::Range ;
use deno_graph ::ResolutionError ;
use deno_graph ::SpecifierError ;
2023-12-06 19:03:18 -05:00
use super ::* ;
2023-01-27 17:36:23 -05:00
#[ test ]
fn import_map_node_resolution_error ( ) {
let cases = vec! [ ( " fs " , Some ( " fs " ) ) , ( " other " , None ) ] ;
for ( input , output ) in cases {
let import_map = import_map ::ImportMap ::new (
ModuleSpecifier ::parse ( " file:///deno.json " ) . unwrap ( ) ,
) ;
let specifier = ModuleSpecifier ::parse ( " file:///file.ts " ) . unwrap ( ) ;
let err = import_map . resolve ( input , & specifier ) . err ( ) . unwrap ( ) ;
let err = ResolutionError ::ResolverError {
2023-10-20 00:02:08 -04:00
error : Arc ::new ( ResolveError ::Other ( err . into ( ) ) ) ,
2023-01-27 17:36:23 -05:00
specifier : input . to_string ( ) ,
range : Range {
specifier ,
2024-11-26 14:38:24 -05:00
resolution_mode : None ,
range : PositionRange ::zeroed ( ) ,
2023-01-27 17:36:23 -05:00
} ,
} ;
assert_eq! ( get_resolution_error_bare_node_specifier ( & err ) , output ) ;
}
}
#[ test ]
fn bare_specifier_node_resolution_error ( ) {
let cases = vec! [ ( " process " , Some ( " process " ) ) , ( " other " , None ) ] ;
for ( input , output ) in cases {
let specifier = ModuleSpecifier ::parse ( " file:///file.ts " ) . unwrap ( ) ;
let err = ResolutionError ::InvalidSpecifier {
range : Range {
specifier ,
2024-11-26 14:38:24 -05:00
resolution_mode : None ,
range : PositionRange ::zeroed ( ) ,
2023-01-27 17:36:23 -05:00
} ,
2024-06-25 21:42:18 -04:00
error : SpecifierError ::ImportPrefixMissing {
specifier : input . to_string ( ) ,
referrer : None ,
} ,
2023-01-27 17:36:23 -05:00
} ;
assert_eq! ( get_resolution_error_bare_node_specifier ( & err ) , output , ) ;
}
}
2023-01-24 15:14:49 -05:00
}