2023-01-02 16:00:42 -05:00
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
2022-06-27 16:54:09 -04:00
2022-11-25 17:00:28 -05:00
mod config_file ;
mod flags ;
2022-06-27 16:54:09 -04:00
mod flags_allow_net ;
2023-01-25 15:13:40 -05:00
mod import_map ;
mod lockfile ;
2023-02-20 13:14:06 -05:00
pub mod package_json ;
2022-06-27 16:54:09 -04:00
2023-01-25 16:51:04 -05:00
pub use self ::import_map ::resolve_import_map_from_specifier ;
2023-05-22 21:28:36 -04:00
pub use self ::lockfile ::snapshot_from_lockfile ;
2023-03-03 17:27:05 -05:00
use self ::package_json ::PackageJsonDeps ;
2023-01-25 15:13:40 -05:00
use ::import_map ::ImportMap ;
2023-03-22 10:15:53 -04:00
use deno_core ::resolve_url_or_path ;
2023-04-13 10:47:45 -04:00
use deno_npm ::resolution ::ValidSerializedNpmResolutionSnapshot ;
2023-05-17 17:38:50 -04:00
use deno_npm ::NpmSystemInfo ;
2023-05-01 16:42:05 -04:00
use deno_runtime ::deno_tls ::RootCertStoreProvider ;
2023-04-06 18:46:44 -04:00
use deno_semver ::npm ::NpmPackageReqReference ;
2023-02-22 22:45:35 -05:00
use indexmap ::IndexMap ;
2023-02-20 13:14:06 -05:00
2022-12-09 20:30:47 -05:00
pub use config_file ::BenchConfig ;
2022-06-28 16:45:55 -04:00
pub use config_file ::CompilerOptions ;
pub use config_file ::ConfigFile ;
pub use config_file ::EmitConfigOptions ;
2023-01-07 15:22:09 -05:00
pub use config_file ::FilesConfig ;
2022-06-28 16:45:55 -04:00
pub use config_file ::FmtOptionsConfig ;
2022-11-25 17:00:28 -05:00
pub use config_file ::JsxImportSourceConfig ;
2022-06-28 16:45:55 -04:00
pub use config_file ::LintRulesConfig ;
pub use config_file ::ProseWrap ;
pub use config_file ::TsConfig ;
2022-11-25 18:29:48 -05:00
pub use config_file ::TsConfigForEmit ;
pub use config_file ::TsConfigType ;
pub use config_file ::TsTypeLib ;
2022-06-27 16:54:09 -04:00
pub use flags ::* ;
2022-11-25 17:00:28 -05:00
pub use lockfile ::Lockfile ;
pub use lockfile ::LockfileError ;
2023-05-10 20:06:59 -04:00
pub use package_json ::PackageJsonDepsProvider ;
2022-06-28 16:45:55 -04:00
use deno_ast ::ModuleSpecifier ;
use deno_core ::anyhow ::anyhow ;
use deno_core ::anyhow ::bail ;
use deno_core ::anyhow ::Context ;
use deno_core ::error ::AnyError ;
use deno_core ::normalize_path ;
2022-11-02 11:32:30 -04:00
use deno_core ::parking_lot ::Mutex ;
2023-02-20 13:14:06 -05:00
use deno_core ::serde_json ;
2022-06-28 16:45:55 -04:00
use deno_core ::url ::Url ;
use deno_runtime ::colors ;
2023-02-20 13:14:06 -05:00
use deno_runtime ::deno_node ::PackageJson ;
2023-01-07 15:22:09 -05:00
use deno_runtime ::deno_tls ::rustls ;
2022-06-28 16:45:55 -04:00
use deno_runtime ::deno_tls ::rustls ::RootCertStore ;
2023-01-07 15:22:09 -05:00
use deno_runtime ::deno_tls ::rustls_native_certs ::load_native_certs ;
use deno_runtime ::deno_tls ::rustls_pemfile ;
use deno_runtime ::deno_tls ::webpki_roots ;
2022-06-28 16:45:55 -04:00
use deno_runtime ::inspector_server ::InspectorServer ;
use deno_runtime ::permissions ::PermissionsOptions ;
2023-02-20 13:14:06 -05:00
use once_cell ::sync ::Lazy ;
2023-05-01 16:42:05 -04:00
use once_cell ::sync ::OnceCell ;
2023-03-22 10:15:53 -04:00
use std ::collections ::HashMap ;
2022-06-28 16:45:55 -04:00
use std ::env ;
2022-11-28 17:28:54 -05:00
use std ::io ::BufReader ;
2023-01-17 19:18:24 -05:00
use std ::io ::Cursor ;
2022-06-28 16:45:55 -04:00
use std ::net ::SocketAddr ;
2023-01-07 15:22:09 -05:00
use std ::num ::NonZeroUsize ;
2023-02-20 13:14:06 -05:00
use std ::path ::Path ;
2022-06-28 16:45:55 -04:00
use std ::path ::PathBuf ;
2022-11-02 11:32:30 -04:00
use std ::sync ::Arc ;
2023-05-01 16:42:05 -04:00
use thiserror ::Error ;
2022-06-28 16:45:55 -04:00
2023-01-25 15:13:40 -05:00
use crate ::file_fetcher ::FileFetcher ;
2023-04-12 08:36:11 -04:00
use crate ::npm ::CliNpmRegistryApi ;
2023-02-20 13:14:06 -05:00
use crate ::npm ::NpmProcessState ;
2022-11-28 17:28:54 -05:00
use crate ::util ::fs ::canonicalize_path_maybe_not_exists ;
2022-06-28 16:45:55 -04:00
use crate ::version ;
2023-01-07 15:22:09 -05:00
use self ::config_file ::FmtConfig ;
use self ::config_file ::LintConfig ;
use self ::config_file ::MaybeImportsResult ;
use self ::config_file ::TestConfig ;
2022-11-28 17:28:54 -05:00
/// Indicates how cached source files should be handled.
#[ derive(Debug, Clone, Eq, PartialEq) ]
pub enum CacheSetting {
/// Only the cached files should be used. Any files not in the cache will
/// error. This is the equivalent of `--cached-only` in the CLI.
Only ,
/// No cached source files should be used, and all files should be reloaded.
/// This is the equivalent of `--reload` in the CLI.
ReloadAll ,
/// Only some cached resources should be used. This is the equivalent of
/// `--reload=https://deno.land/std` or
/// `--reload=https://deno.land/std,https://deno.land/x/example`.
ReloadSome ( Vec < String > ) ,
/// The usability of a cached value is determined by analyzing the cached
/// headers and other metadata associated with a cached response, reloading
/// any cached "non-fresh" cached responses.
RespectHeaders ,
/// The cached source files should be used for local modules. This is the
/// default behavior of the CLI.
Use ,
}
impl CacheSetting {
pub fn should_use_for_npm_package ( & self , package_name : & str ) -> bool {
match self {
CacheSetting ::ReloadAll = > false ,
CacheSetting ::ReloadSome ( list ) = > {
if list . iter ( ) . any ( | i | i = = " npm: " ) {
return false ;
}
2023-01-27 10:43:16 -05:00
let specifier = format! ( " npm: {package_name} " ) ;
2022-11-28 17:28:54 -05:00
if list . contains ( & specifier ) {
return false ;
}
true
}
_ = > true ,
}
}
}
2023-01-07 15:22:09 -05:00
#[ derive(Clone, Debug, Eq, PartialEq) ]
pub struct BenchOptions {
pub files : FilesConfig ,
pub filter : Option < String > ,
2023-02-12 12:40:45 -05:00
pub json : bool ,
2023-03-26 10:55:58 -04:00
pub no_run : bool ,
2023-01-07 15:22:09 -05:00
}
impl BenchOptions {
pub fn resolve (
maybe_bench_config : Option < BenchConfig > ,
maybe_bench_flags : Option < BenchFlags > ,
) -> Result < Self , AnyError > {
let bench_flags = maybe_bench_flags . unwrap_or_default ( ) ;
Ok ( Self {
files : resolve_files (
maybe_bench_config . map ( | c | c . files ) ,
Some ( bench_flags . files ) ,
2023-05-22 21:39:59 -04:00
) ? ,
2023-01-07 15:22:09 -05:00
filter : bench_flags . filter ,
2023-02-12 12:40:45 -05:00
json : bench_flags . json ,
2023-03-26 10:55:58 -04:00
no_run : bench_flags . no_run ,
2023-01-07 15:22:09 -05:00
} )
}
}
#[ derive(Clone, Debug, Default) ]
pub struct FmtOptions {
pub is_stdin : bool ,
pub check : bool ,
pub options : FmtOptionsConfig ,
pub files : FilesConfig ,
}
impl FmtOptions {
pub fn resolve (
maybe_fmt_config : Option < FmtConfig > ,
mut maybe_fmt_flags : Option < FmtFlags > ,
) -> Result < Self , AnyError > {
let is_stdin = if let Some ( fmt_flags ) = maybe_fmt_flags . as_mut ( ) {
let args = & mut fmt_flags . files . include ;
if args . len ( ) = = 1 & & args [ 0 ] . to_string_lossy ( ) = = " - " {
args . pop ( ) ; // remove the "-" arg
true
} else {
false
}
} else {
false
} ;
let ( maybe_config_options , maybe_config_files ) =
maybe_fmt_config . map ( | c | ( c . options , c . files ) ) . unzip ( ) ;
Ok ( Self {
is_stdin ,
check : maybe_fmt_flags . as_ref ( ) . map ( | f | f . check ) . unwrap_or ( false ) ,
options : resolve_fmt_options (
maybe_fmt_flags . as_ref ( ) ,
maybe_config_options ,
) ,
files : resolve_files (
maybe_config_files ,
maybe_fmt_flags . map ( | f | f . files ) ,
2023-05-22 21:39:59 -04:00
) ? ,
2023-01-07 15:22:09 -05:00
} )
}
}
fn resolve_fmt_options (
fmt_flags : Option < & FmtFlags > ,
options : Option < FmtOptionsConfig > ,
) -> FmtOptionsConfig {
let mut options = options . unwrap_or_default ( ) ;
if let Some ( fmt_flags ) = fmt_flags {
if let Some ( use_tabs ) = fmt_flags . use_tabs {
options . use_tabs = Some ( use_tabs ) ;
}
if let Some ( line_width ) = fmt_flags . line_width {
options . line_width = Some ( line_width . get ( ) ) ;
}
if let Some ( indent_width ) = fmt_flags . indent_width {
options . indent_width = Some ( indent_width . get ( ) ) ;
}
if let Some ( single_quote ) = fmt_flags . single_quote {
options . single_quote = Some ( single_quote ) ;
}
if let Some ( prose_wrap ) = & fmt_flags . prose_wrap {
options . prose_wrap = Some ( match prose_wrap . as_str ( ) {
" always " = > ProseWrap ::Always ,
" never " = > ProseWrap ::Never ,
" preserve " = > ProseWrap ::Preserve ,
// validators in `flags.rs` makes other values unreachable
_ = > unreachable! ( ) ,
} ) ;
}
2023-01-24 15:07:00 -05:00
2023-01-25 15:06:00 -05:00
if let Some ( no_semis ) = & fmt_flags . no_semicolons {
options . semi_colons = Some ( ! no_semis ) ;
2023-01-24 15:07:00 -05:00
}
2023-01-07 15:22:09 -05:00
}
options
}
#[ derive(Clone) ]
pub struct TestOptions {
pub files : FilesConfig ,
pub doc : bool ,
pub no_run : bool ,
pub fail_fast : Option < NonZeroUsize > ,
pub allow_none : bool ,
pub filter : Option < String > ,
pub shuffle : Option < u64 > ,
pub concurrent_jobs : NonZeroUsize ,
pub trace_ops : bool ,
}
impl TestOptions {
pub fn resolve (
maybe_test_config : Option < TestConfig > ,
maybe_test_flags : Option < TestFlags > ,
) -> Result < Self , AnyError > {
let test_flags = maybe_test_flags . unwrap_or_default ( ) ;
Ok ( Self {
files : resolve_files (
maybe_test_config . map ( | c | c . files ) ,
Some ( test_flags . files ) ,
2023-05-22 21:39:59 -04:00
) ? ,
2023-01-07 15:22:09 -05:00
allow_none : test_flags . allow_none ,
concurrent_jobs : test_flags
. concurrent_jobs
. unwrap_or_else ( | | NonZeroUsize ::new ( 1 ) . unwrap ( ) ) ,
doc : test_flags . doc ,
fail_fast : test_flags . fail_fast ,
filter : test_flags . filter ,
no_run : test_flags . no_run ,
shuffle : test_flags . shuffle ,
trace_ops : test_flags . trace_ops ,
} )
}
}
2023-03-09 14:18:00 -05:00
#[ derive(Clone, Default, Debug) ]
2023-01-07 15:22:09 -05:00
pub enum LintReporterKind {
2023-03-09 14:18:00 -05:00
#[ default ]
2023-01-07 15:22:09 -05:00
Pretty ,
Json ,
Compact ,
}
#[ derive(Clone, Debug, Default) ]
pub struct LintOptions {
pub rules : LintRulesConfig ,
pub files : FilesConfig ,
pub is_stdin : bool ,
pub reporter_kind : LintReporterKind ,
}
impl LintOptions {
pub fn resolve (
maybe_lint_config : Option < LintConfig > ,
mut maybe_lint_flags : Option < LintFlags > ,
) -> Result < Self , AnyError > {
let is_stdin = if let Some ( lint_flags ) = maybe_lint_flags . as_mut ( ) {
let args = & mut lint_flags . files . include ;
if args . len ( ) = = 1 & & args [ 0 ] . to_string_lossy ( ) = = " - " {
args . pop ( ) ; // remove the "-" arg
true
} else {
false
}
} else {
false
} ;
let mut maybe_reporter_kind =
maybe_lint_flags . as_ref ( ) . and_then ( | lint_flags | {
if lint_flags . json {
Some ( LintReporterKind ::Json )
} else if lint_flags . compact {
Some ( LintReporterKind ::Compact )
} else {
None
}
} ) ;
if maybe_reporter_kind . is_none ( ) {
// Flag not set, so try to get lint reporter from the config file.
if let Some ( lint_config ) = & maybe_lint_config {
maybe_reporter_kind = match lint_config . report . as_deref ( ) {
Some ( " json " ) = > Some ( LintReporterKind ::Json ) ,
Some ( " compact " ) = > Some ( LintReporterKind ::Compact ) ,
Some ( " pretty " ) = > Some ( LintReporterKind ::Pretty ) ,
Some ( _ ) = > {
bail! ( " Invalid lint report type in config file " )
}
None = > None ,
}
}
}
let (
maybe_file_flags ,
maybe_rules_tags ,
maybe_rules_include ,
maybe_rules_exclude ,
) = maybe_lint_flags
. map ( | f | {
(
f . files ,
f . maybe_rules_tags ,
f . maybe_rules_include ,
f . maybe_rules_exclude ,
)
} )
. unwrap_or_default ( ) ;
let ( maybe_config_files , maybe_config_rules ) =
maybe_lint_config . map ( | c | ( c . files , c . rules ) ) . unzip ( ) ;
Ok ( Self {
reporter_kind : maybe_reporter_kind . unwrap_or_default ( ) ,
is_stdin ,
2023-05-22 21:39:59 -04:00
files : resolve_files ( maybe_config_files , Some ( maybe_file_flags ) ) ? ,
2023-01-07 15:22:09 -05:00
rules : resolve_lint_rules_options (
maybe_config_rules ,
maybe_rules_tags ,
maybe_rules_include ,
maybe_rules_exclude ,
) ,
} )
}
}
fn resolve_lint_rules_options (
maybe_lint_rules_config : Option < LintRulesConfig > ,
mut maybe_rules_tags : Option < Vec < String > > ,
mut maybe_rules_include : Option < Vec < String > > ,
mut maybe_rules_exclude : Option < Vec < String > > ,
) -> LintRulesConfig {
if let Some ( config_rules ) = maybe_lint_rules_config {
// Try to get configured rules. CLI flags take precedence
// over config file, i.e. if there's `rules.include` in config file
// and `--rules-include` CLI flag, only the flag value is taken into account.
if maybe_rules_include . is_none ( ) {
maybe_rules_include = config_rules . include ;
}
if maybe_rules_exclude . is_none ( ) {
maybe_rules_exclude = config_rules . exclude ;
}
if maybe_rules_tags . is_none ( ) {
maybe_rules_tags = config_rules . tags ;
}
}
LintRulesConfig {
exclude : maybe_rules_exclude ,
include : maybe_rules_include ,
tags : maybe_rules_tags ,
}
}
2023-02-20 13:14:06 -05:00
/// Discover `package.json` file. If `maybe_stop_at` is provided, we will stop
/// crawling up the directory tree at that path.
fn discover_package_json (
flags : & Flags ,
maybe_stop_at : Option < PathBuf > ,
2023-03-13 21:12:09 -04:00
current_dir : & Path ,
2023-02-20 13:14:06 -05:00
) -> Result < Option < PackageJson > , AnyError > {
// TODO(bartlomieju): discover for all subcommands, but print warnings that
// `package.json` is ignored in bundle/compile/etc.
2023-03-13 21:12:09 -04:00
if let Some ( package_json_dir ) = flags . package_json_search_dir ( current_dir ) {
2023-02-22 22:45:35 -05:00
let package_json_dir =
canonicalize_path_maybe_not_exists ( & package_json_dir ) ? ;
2023-02-23 10:58:10 -05:00
return package_json ::discover_from ( & package_json_dir , maybe_stop_at ) ;
2023-02-20 13:14:06 -05:00
}
log ::debug! ( " No package.json file found " ) ;
Ok ( None )
}
2023-05-01 16:42:05 -04:00
struct CliRootCertStoreProvider {
cell : OnceCell < RootCertStore > ,
maybe_root_path : Option < PathBuf > ,
maybe_ca_stores : Option < Vec < String > > ,
maybe_ca_data : Option < CaData > ,
}
impl CliRootCertStoreProvider {
pub fn new (
maybe_root_path : Option < PathBuf > ,
maybe_ca_stores : Option < Vec < String > > ,
maybe_ca_data : Option < CaData > ,
) -> Self {
Self {
cell : Default ::default ( ) ,
maybe_root_path ,
maybe_ca_stores ,
maybe_ca_data ,
}
}
}
impl RootCertStoreProvider for CliRootCertStoreProvider {
fn get_or_try_init ( & self ) -> Result < & RootCertStore , AnyError > {
self
. cell
. get_or_try_init ( | | {
get_root_cert_store (
self . maybe_root_path . clone ( ) ,
self . maybe_ca_stores . clone ( ) ,
self . maybe_ca_data . clone ( ) ,
)
} )
. map_err ( | e | e . into ( ) )
}
}
#[ derive(Error, Debug, Clone) ]
pub enum RootCertStoreLoadError {
#[ error(
" Unknown certificate store \" {0} \" specified (allowed: \" system,mozilla \" ) "
) ]
UnknownStore ( String ) ,
#[ error( " Unable to add pem file to certificate store: {0} " ) ]
FailedAddPemFile ( String ) ,
#[ error( " Failed opening CA file: {0} " ) ]
CaFileOpenError ( String ) ,
}
2022-11-28 17:28:54 -05:00
/// Create and populate a root cert store based on the passed options and
/// environment.
pub fn get_root_cert_store (
maybe_root_path : Option < PathBuf > ,
maybe_ca_stores : Option < Vec < String > > ,
2023-01-17 19:18:24 -05:00
maybe_ca_data : Option < CaData > ,
2023-05-01 16:42:05 -04:00
) -> Result < RootCertStore , RootCertStoreLoadError > {
2022-11-28 17:28:54 -05:00
let mut root_cert_store = RootCertStore ::empty ( ) ;
let ca_stores : Vec < String > = maybe_ca_stores
. or_else ( | | {
let env_ca_store = env ::var ( " DENO_TLS_CA_STORE " ) . ok ( ) ? ;
Some (
env_ca_store
. split ( ',' )
. map ( | s | s . trim ( ) . to_string ( ) )
. filter ( | s | ! s . is_empty ( ) )
. collect ( ) ,
)
} )
. unwrap_or_else ( | | vec! [ " mozilla " . to_string ( ) ] ) ;
for store in ca_stores . iter ( ) {
match store . as_str ( ) {
" mozilla " = > {
root_cert_store . add_server_trust_anchors (
webpki_roots ::TLS_SERVER_ROOTS . 0. iter ( ) . map ( | ta | {
rustls ::OwnedTrustAnchor ::from_subject_spki_name_constraints (
ta . subject ,
ta . spki ,
ta . name_constraints ,
)
} ) ,
) ;
}
" system " = > {
let roots = load_native_certs ( ) . expect ( " could not load platform certs " ) ;
for root in roots {
root_cert_store
. add ( & rustls ::Certificate ( root . 0 ) )
. expect ( " Failed to add platform cert to root cert store " ) ;
}
}
_ = > {
2023-05-01 16:42:05 -04:00
return Err ( RootCertStoreLoadError ::UnknownStore ( store . clone ( ) ) ) ;
2022-11-28 17:28:54 -05:00
}
}
}
2023-01-17 19:18:24 -05:00
let ca_data =
maybe_ca_data . or_else ( | | env ::var ( " DENO_CERT " ) . ok ( ) . map ( CaData ::File ) ) ;
if let Some ( ca_data ) = ca_data {
let result = match ca_data {
CaData ::File ( ca_file ) = > {
let ca_file = if let Some ( root ) = & maybe_root_path {
root . join ( & ca_file )
} else {
PathBuf ::from ( ca_file )
} ;
2023-05-01 16:42:05 -04:00
let certfile = std ::fs ::File ::open ( ca_file ) . map_err ( | err | {
RootCertStoreLoadError ::CaFileOpenError ( err . to_string ( ) )
} ) ? ;
2023-01-17 19:18:24 -05:00
let mut reader = BufReader ::new ( certfile ) ;
rustls_pemfile ::certs ( & mut reader )
}
CaData ::Bytes ( data ) = > {
let mut reader = BufReader ::new ( Cursor ::new ( data ) ) ;
rustls_pemfile ::certs ( & mut reader )
}
2022-11-28 17:28:54 -05:00
} ;
2023-01-17 19:18:24 -05:00
match result {
2022-11-28 17:28:54 -05:00
Ok ( certs ) = > {
root_cert_store . add_parsable_certificates ( & certs ) ;
}
Err ( e ) = > {
2023-05-01 16:42:05 -04:00
return Err ( RootCertStoreLoadError ::FailedAddPemFile ( e . to_string ( ) ) ) ;
2022-11-28 17:28:54 -05:00
}
}
}
Ok ( root_cert_store )
}
2023-02-20 13:14:06 -05:00
const RESOLUTION_STATE_ENV_VAR_NAME : & str =
" DENO_DONT_USE_INTERNAL_NODE_COMPAT_STATE " ;
static NPM_PROCESS_STATE : Lazy < Option < NpmProcessState > > = Lazy ::new ( | | {
let state = std ::env ::var ( RESOLUTION_STATE_ENV_VAR_NAME ) . ok ( ) ? ;
let state : NpmProcessState = serde_json ::from_str ( & state ) . ok ( ) ? ;
// remove the environment variable so that sub processes
// that are spawned do not also use this.
std ::env ::remove_var ( RESOLUTION_STATE_ENV_VAR_NAME ) ;
Some ( state )
} ) ;
2022-06-29 20:41:48 -04:00
/// Overrides for the options below that when set will
/// use these values over the values derived from the
/// CLI flags or config file.
#[ derive(Default) ]
struct CliOptionOverrides {
import_map_specifier : Option < Option < ModuleSpecifier > > ,
}
2023-05-10 20:06:59 -04:00
/// Holds the resolved options of many sources used by subcommands
2022-06-28 16:45:55 -04:00
/// and provides some helper function for creating common objects.
2022-06-29 11:51:11 -04:00
pub struct CliOptions {
// the source of the options is a detail the rest of the
2022-06-28 16:45:55 -04:00
// application need not concern itself with, so keep these private
flags : Flags ,
2023-03-13 21:12:09 -04:00
initial_cwd : PathBuf ,
2023-02-22 20:16:16 -05:00
maybe_node_modules_folder : Option < PathBuf > ,
2022-06-28 16:45:55 -04:00
maybe_config_file : Option < ConfigFile > ,
2023-02-20 13:14:06 -05:00
maybe_package_json : Option < PackageJson > ,
2022-11-02 11:32:30 -04:00
maybe_lockfile : Option < Arc < Mutex < Lockfile > > > ,
2022-06-29 20:41:48 -04:00
overrides : CliOptionOverrides ,
2022-06-28 16:45:55 -04:00
}
2022-06-29 11:51:11 -04:00
impl CliOptions {
2022-11-02 11:32:30 -04:00
pub fn new (
flags : Flags ,
2023-02-22 20:16:16 -05:00
initial_cwd : PathBuf ,
2022-11-02 11:32:30 -04:00
maybe_config_file : Option < ConfigFile > ,
2023-05-22 21:28:36 -04:00
maybe_lockfile : Option < Arc < Mutex < Lockfile > > > ,
2023-02-20 13:14:06 -05:00
maybe_package_json : Option < PackageJson > ,
2023-02-22 20:16:16 -05:00
) -> Result < Self , AnyError > {
2022-06-28 16:45:55 -04:00
if let Some ( insecure_allowlist ) =
flags . unsafely_ignore_certificate_errors . as_ref ( )
{
let domains = if insecure_allowlist . is_empty ( ) {
" for all hostnames " . to_string ( )
} else {
format! ( " for: {} " , insecure_allowlist . join ( " , " ) )
} ;
let msg =
2023-01-27 10:43:16 -05:00
format! ( " DANGER: TLS certificate validation is disabled {domains} " ) ;
2022-07-01 11:50:16 -04:00
// use eprintln instead of log::warn so this always gets shown
2022-06-28 16:45:55 -04:00
eprintln! ( " {} " , colors ::yellow ( msg ) ) ;
}
2023-02-22 20:16:16 -05:00
let maybe_node_modules_folder = resolve_local_node_modules_folder (
& initial_cwd ,
& flags ,
maybe_config_file . as_ref ( ) ,
maybe_package_json . as_ref ( ) ,
)
. with_context ( | | " Resolving node_modules folder. " ) ? ;
2022-11-02 11:32:30 -04:00
2023-02-22 20:16:16 -05:00
Ok ( Self {
flags ,
2023-03-13 21:12:09 -04:00
initial_cwd ,
2022-06-28 16:45:55 -04:00
maybe_config_file ,
2022-11-02 11:32:30 -04:00
maybe_lockfile ,
2023-02-20 13:14:06 -05:00
maybe_package_json ,
2023-02-22 20:16:16 -05:00
maybe_node_modules_folder ,
2022-06-29 20:41:48 -04:00
overrides : Default ::default ( ) ,
2023-02-22 20:16:16 -05:00
} )
2022-07-01 11:50:16 -04:00
}
pub fn from_flags ( flags : Flags ) -> Result < Self , AnyError > {
2023-02-22 20:16:16 -05:00
let initial_cwd =
std ::env ::current_dir ( ) . with_context ( | | " Failed getting cwd. " ) ? ;
let maybe_config_file = ConfigFile ::discover ( & flags , & initial_cwd ) ? ;
2023-02-20 13:14:06 -05:00
let mut maybe_package_json = None ;
2023-02-24 14:23:07 -05:00
if flags . config_flag = = ConfigFlag ::Disabled
| | flags . no_npm
| | has_flag_env_var ( " DENO_NO_PACKAGE_JSON " )
{
2023-02-24 13:51:21 -05:00
log ::debug! ( " package.json auto-discovery is disabled " )
} else if let Some ( config_file ) = & maybe_config_file {
2023-02-20 13:14:06 -05:00
let specifier = config_file . specifier . clone ( ) ;
if specifier . scheme ( ) = = " file " {
let maybe_stop_at = specifier
. to_file_path ( )
. unwrap ( )
. parent ( )
. map ( | p | p . to_path_buf ( ) ) ;
2023-03-13 21:12:09 -04:00
maybe_package_json =
discover_package_json ( & flags , maybe_stop_at , & initial_cwd ) ? ;
2023-02-20 13:14:06 -05:00
}
} else {
2023-03-13 21:12:09 -04:00
maybe_package_json = discover_package_json ( & flags , None , & initial_cwd ) ? ;
2023-02-20 13:14:06 -05:00
}
2023-02-24 13:51:21 -05:00
2022-11-02 11:32:30 -04:00
let maybe_lock_file =
2023-01-23 17:41:02 -05:00
lockfile ::discover ( & flags , maybe_config_file . as_ref ( ) ) ? ;
2023-02-22 20:16:16 -05:00
Self ::new (
2023-02-20 13:14:06 -05:00
flags ,
2023-02-22 20:16:16 -05:00
initial_cwd ,
2023-02-20 13:14:06 -05:00
maybe_config_file ,
2023-05-22 21:28:36 -04:00
maybe_lock_file . map ( | l | Arc ::new ( Mutex ::new ( l ) ) ) ,
2023-02-20 13:14:06 -05:00
maybe_package_json ,
2023-02-22 20:16:16 -05:00
)
2022-06-28 16:45:55 -04:00
}
2023-03-13 21:12:09 -04:00
#[ inline(always) ]
pub fn initial_cwd ( & self ) -> & Path {
& self . initial_cwd
}
2022-06-28 16:45:55 -04:00
pub fn maybe_config_file_specifier ( & self ) -> Option < ModuleSpecifier > {
self . maybe_config_file . as_ref ( ) . map ( | f | f . specifier . clone ( ) )
}
pub fn ts_type_lib_window ( & self ) -> TsTypeLib {
if self . flags . unstable {
TsTypeLib ::UnstableDenoWindow
} else {
TsTypeLib ::DenoWindow
}
}
pub fn ts_type_lib_worker ( & self ) -> TsTypeLib {
if self . flags . unstable {
TsTypeLib ::UnstableDenoWorker
} else {
TsTypeLib ::DenoWorker
}
}
pub fn cache_setting ( & self ) -> CacheSetting {
if self . flags . cached_only {
CacheSetting ::Only
} else if ! self . flags . cache_blocklist . is_empty ( ) {
CacheSetting ::ReloadSome ( self . flags . cache_blocklist . clone ( ) )
} else if self . flags . reload {
CacheSetting ::ReloadAll
} else {
CacheSetting ::Use
}
}
2023-05-17 17:38:50 -04:00
pub fn npm_system_info ( & self ) -> NpmSystemInfo {
match self . sub_command ( ) {
DenoSubcommand ::Compile ( CompileFlags {
target : Some ( target ) ,
..
} ) = > {
// the values of NpmSystemInfo align with the possible values for the
// `arch` and `platform` fields of Node.js' `process` global:
// https://nodejs.org/api/process.html
match target . as_str ( ) {
" aarch64-apple-darwin " = > NpmSystemInfo {
os : " darwin " . to_string ( ) ,
cpu : " arm64 " . to_string ( ) ,
} ,
" x86_64-apple-darwin " = > NpmSystemInfo {
os : " darwin " . to_string ( ) ,
cpu : " x64 " . to_string ( ) ,
} ,
" x86_64-unknown-linux-gnu " = > NpmSystemInfo {
os : " linux " . to_string ( ) ,
cpu : " x64 " . to_string ( ) ,
} ,
" x86_64-pc-windows-msvc " = > NpmSystemInfo {
os : " win32 " . to_string ( ) ,
cpu : " x64 " . to_string ( ) ,
} ,
value = > {
log ::warn! ( " Not implemented NPM system info for target '{value}'. Using current system default. This may impact NPM " ) ;
NpmSystemInfo ::default ( )
}
}
}
_ = > NpmSystemInfo ::default ( ) ,
}
}
2022-06-28 16:45:55 -04:00
/// Based on an optional command line import map path and an optional
2023-01-25 15:13:40 -05:00
/// configuration file, return a resolved module specifier to an import map
/// and a boolean indicating if unknown keys should not result in diagnostics.
2022-06-29 20:41:48 -04:00
pub fn resolve_import_map_specifier (
2022-06-28 16:45:55 -04:00
& self ,
) -> Result < Option < ModuleSpecifier > , AnyError > {
2022-06-29 20:41:48 -04:00
match self . overrides . import_map_specifier . clone ( ) {
2023-01-25 15:13:40 -05:00
Some ( maybe_path ) = > Ok ( maybe_path ) ,
2022-06-29 20:41:48 -04:00
None = > resolve_import_map_specifier (
self . flags . import_map_path . as_deref ( ) ,
self . maybe_config_file . as_ref ( ) ,
2023-03-13 21:12:09 -04:00
& self . initial_cwd ,
2022-06-29 20:41:48 -04:00
) ,
}
}
2023-01-25 15:13:40 -05:00
pub async fn resolve_import_map (
& self ,
file_fetcher : & FileFetcher ,
) -> Result < Option < ImportMap > , AnyError > {
let import_map_specifier = match self . resolve_import_map_specifier ( ) ? {
Some ( specifier ) = > specifier ,
None = > return Ok ( None ) ,
} ;
2023-01-25 16:51:04 -05:00
resolve_import_map_from_specifier (
& import_map_specifier ,
2023-02-20 13:14:06 -05:00
self . maybe_config_file ( ) . as_ref ( ) ,
2023-01-25 16:51:04 -05:00
file_fetcher ,
)
. await
2023-03-21 14:13:32 -04:00
. with_context ( | | {
format! ( " Unable to load ' {import_map_specifier} ' import map " )
} )
2023-01-25 16:51:04 -05:00
. map ( Some )
2023-01-25 15:13:40 -05:00
}
2023-03-22 10:15:53 -04:00
pub fn resolve_main_module ( & self ) -> Result < ModuleSpecifier , AnyError > {
match & self . flags . subcommand {
DenoSubcommand ::Bundle ( bundle_flags ) = > {
resolve_url_or_path ( & bundle_flags . source_file , self . initial_cwd ( ) )
. map_err ( AnyError ::from )
}
DenoSubcommand ::Compile ( compile_flags ) = > {
resolve_url_or_path ( & compile_flags . source_file , self . initial_cwd ( ) )
. map_err ( AnyError ::from )
}
DenoSubcommand ::Eval ( _ ) = > {
resolve_url_or_path ( " ./$deno$eval " , self . initial_cwd ( ) )
. map_err ( AnyError ::from )
}
DenoSubcommand ::Repl ( _ ) = > {
resolve_url_or_path ( " ./$deno$repl.ts " , self . initial_cwd ( ) )
. map_err ( AnyError ::from )
}
DenoSubcommand ::Run ( run_flags ) = > {
if run_flags . is_stdin ( ) {
std ::env ::current_dir ( )
. context ( " Unable to get CWD " )
. and_then ( | cwd | {
2023-03-23 12:45:43 -04:00
resolve_url_or_path ( " ./$deno$stdin.ts " , & cwd )
. map_err ( AnyError ::from )
2023-03-22 10:15:53 -04:00
} )
} else if self . flags . watch . is_some ( ) {
resolve_url_or_path ( & run_flags . script , self . initial_cwd ( ) )
. map_err ( AnyError ::from )
} else if NpmPackageReqReference ::from_str ( & run_flags . script ) . is_ok ( ) {
ModuleSpecifier ::parse ( & run_flags . script ) . map_err ( AnyError ::from )
} else {
resolve_url_or_path ( & run_flags . script , self . initial_cwd ( ) )
. map_err ( AnyError ::from )
}
}
_ = > {
bail! ( " No main module. " )
}
}
}
pub fn resolve_file_header_overrides (
& self ,
) -> HashMap < ModuleSpecifier , HashMap < String , String > > {
let maybe_main_specifier = self . resolve_main_module ( ) . ok ( ) ;
// TODO(Cre3per): This mapping moved to deno_ast with https://github.com/denoland/deno_ast/issues/133 and should be available in deno_ast >= 0.25.0 via `MediaType::from_path(...).as_media_type()`
let maybe_content_type =
self . flags . ext . as_ref ( ) . and_then ( | el | match el . as_str ( ) {
" ts " = > Some ( " text/typescript " ) ,
" tsx " = > Some ( " text/tsx " ) ,
" js " = > Some ( " text/javascript " ) ,
" jsx " = > Some ( " text/jsx " ) ,
_ = > None ,
} ) ;
if let ( Some ( main_specifier ) , Some ( content_type ) ) =
( maybe_main_specifier , maybe_content_type )
{
HashMap ::from ( [ (
main_specifier ,
HashMap ::from ( [ ( " content-type " . to_string ( ) , content_type . to_string ( ) ) ] ) ,
) ] )
} else {
HashMap ::default ( )
}
}
2023-03-12 23:32:59 -04:00
pub async fn resolve_npm_resolution_snapshot (
& self ,
2023-04-12 08:36:11 -04:00
api : & CliNpmRegistryApi ,
2023-04-13 10:47:45 -04:00
) -> Result < Option < ValidSerializedNpmResolutionSnapshot > , AnyError > {
2023-02-22 20:16:16 -05:00
if let Some ( state ) = & * NPM_PROCESS_STATE {
2023-02-20 13:14:06 -05:00
// TODO(bartlomieju): remove this clone
2023-04-13 10:47:45 -04:00
return Ok ( Some ( state . snapshot . clone ( ) . into_valid ( ) ? ) ) ;
2023-03-12 23:32:59 -04:00
}
2023-05-01 14:35:23 -04:00
if let Some ( lockfile ) = self . maybe_lockfile ( ) {
2023-03-12 23:32:59 -04:00
if ! lockfile . lock ( ) . overwrite {
return Ok ( Some (
2023-04-06 18:46:44 -04:00
snapshot_from_lockfile ( lockfile . clone ( ) , api )
2023-03-12 23:32:59 -04:00
. await
. with_context ( | | {
format! (
" failed reading lockfile '{}' " ,
lockfile . lock ( ) . filename . display ( )
)
} ) ? ,
) ) ;
}
2023-02-20 13:14:06 -05:00
}
2023-03-12 23:32:59 -04:00
Ok ( None )
2023-02-20 13:14:06 -05:00
}
// If the main module should be treated as being in an npm package.
// This is triggered via a secret environment variable which is used
// for functionality like child_process.fork. Users should NOT depend
// on this functionality.
pub fn is_npm_main ( & self ) -> bool {
2023-02-22 20:16:16 -05:00
NPM_PROCESS_STATE . is_some ( )
2023-02-20 13:14:06 -05:00
}
2022-06-29 20:41:48 -04:00
/// Overrides the import map specifier to use.
pub fn set_import_map_specifier ( & mut self , path : Option < ModuleSpecifier > ) {
self . overrides . import_map_specifier = Some ( path ) ;
2022-06-28 16:45:55 -04:00
}
2023-02-22 20:16:16 -05:00
pub fn has_node_modules_dir ( & self ) -> bool {
self . maybe_node_modules_folder . is_some ( )
}
2023-02-20 13:14:06 -05:00
2023-02-22 20:16:16 -05:00
pub fn node_modules_dir_path ( & self ) -> Option < PathBuf > {
self . maybe_node_modules_folder . clone ( )
2022-12-16 17:41:51 -05:00
}
2023-05-19 18:39:27 -04:00
pub fn node_modules_dir_enablement ( & self ) -> Option < bool > {
self . flags . node_modules_dir . or_else ( | | {
self
. maybe_config_file
. as_ref ( )
. and_then ( | c | c . node_modules_dir ( ) )
} )
}
2023-02-22 20:16:16 -05:00
pub fn node_modules_dir_specifier ( & self ) -> Option < ModuleSpecifier > {
self
. maybe_node_modules_folder
2022-09-22 11:17:02 -04:00
. as_ref ( )
2023-02-22 20:16:16 -05:00
. map ( | path | ModuleSpecifier ::from_directory_path ( path ) . unwrap ( ) )
2022-09-22 11:17:02 -04:00
}
2023-05-01 16:42:05 -04:00
pub fn resolve_root_cert_store_provider (
& self ,
) -> Arc < dyn RootCertStoreProvider > {
Arc ::new ( CliRootCertStoreProvider ::new (
2022-06-28 16:45:55 -04:00
None ,
self . flags . ca_stores . clone ( ) ,
2023-01-17 19:18:24 -05:00
self . flags . ca_data . clone ( ) ,
2023-05-01 16:42:05 -04:00
) )
2022-06-28 16:45:55 -04:00
}
pub fn resolve_ts_config_for_emit (
& self ,
config_type : TsConfigType ,
2022-11-25 18:29:48 -05:00
) -> Result < TsConfigForEmit , AnyError > {
config_file ::get_ts_config_for_emit (
config_type ,
self . maybe_config_file . as_ref ( ) ,
)
2022-06-28 16:45:55 -04:00
}
pub fn resolve_inspector_server ( & self ) -> Option < InspectorServer > {
2022-12-12 09:33:30 -05:00
let maybe_inspect_host = self
. flags
. inspect
. or ( self . flags . inspect_brk )
. or ( self . flags . inspect_wait ) ;
2022-06-28 16:45:55 -04:00
maybe_inspect_host
. map ( | host | InspectorServer ::new ( host , version ::get_user_agent ( ) ) )
}
2023-05-01 14:35:23 -04:00
pub fn maybe_lockfile ( & self ) -> Option < Arc < Mutex < Lockfile > > > {
2022-11-02 11:32:30 -04:00
self . maybe_lockfile . clone ( )
2022-06-28 16:45:55 -04:00
}
pub fn resolve_tasks_config (
& self ,
2023-02-22 22:45:35 -05:00
) -> Result < IndexMap < String , String > , AnyError > {
2022-06-28 16:45:55 -04:00
if let Some ( config_file ) = & self . maybe_config_file {
config_file . resolve_tasks_config ( )
2023-02-22 22:45:35 -05:00
} else if self . maybe_package_json . is_some ( ) {
Ok ( Default ::default ( ) )
2022-06-28 16:45:55 -04:00
} else {
bail! ( " No config file found " )
}
}
2022-08-24 13:36:05 -04:00
/// Return the JSX import source configuration.
pub fn to_maybe_jsx_import_source_config (
& self ,
) -> Option < JsxImportSourceConfig > {
2022-06-28 16:45:55 -04:00
self
. maybe_config_file
. as_ref ( )
2022-08-24 13:36:05 -04:00
. and_then ( | c | c . to_maybe_jsx_import_source_config ( ) )
2022-06-28 16:45:55 -04:00
}
/// Return any imports that should be brought into the scope of the module
/// graph.
pub fn to_maybe_imports ( & self ) -> MaybeImportsResult {
if let Some ( config_file ) = & self . maybe_config_file {
2023-02-09 22:00:23 -05:00
config_file . to_maybe_imports ( )
2022-06-28 16:45:55 -04:00
} else {
2023-02-09 22:00:23 -05:00
Ok ( Vec ::new ( ) )
2022-06-28 16:45:55 -04:00
}
}
2023-02-20 13:14:06 -05:00
pub fn maybe_config_file ( & self ) -> & Option < ConfigFile > {
2023-01-07 15:22:09 -05:00
& self . maybe_config_file
}
2023-02-20 13:14:06 -05:00
pub fn maybe_package_json ( & self ) -> & Option < PackageJson > {
& self . maybe_package_json
}
2023-03-03 17:27:05 -05:00
pub fn maybe_package_json_deps ( & self ) -> Option < PackageJsonDeps > {
2023-02-22 22:45:35 -05:00
if matches! (
self . flags . subcommand ,
DenoSubcommand ::Task ( TaskFlags { task : None , .. } )
) {
// don't have any package json dependencies for deno task with no args
2023-03-03 17:27:05 -05:00
None
2023-02-20 13:14:06 -05:00
} else {
2023-03-03 17:27:05 -05:00
self
. maybe_package_json ( )
. as_ref ( )
. map ( package_json ::get_local_package_json_version_reqs )
2023-02-20 13:14:06 -05:00
}
}
2023-01-07 15:22:09 -05:00
pub fn resolve_fmt_options (
& self ,
fmt_flags : FmtFlags ,
) -> Result < FmtOptions , AnyError > {
let maybe_fmt_config = if let Some ( config_file ) = & self . maybe_config_file {
config_file . to_fmt_config ( ) ?
2022-06-28 16:45:55 -04:00
} else {
2023-01-07 15:22:09 -05:00
None
} ;
FmtOptions ::resolve ( maybe_fmt_config , Some ( fmt_flags ) )
2022-06-28 16:45:55 -04:00
}
2023-01-07 15:22:09 -05:00
pub fn resolve_lint_options (
& self ,
lint_flags : LintFlags ,
) -> Result < LintOptions , AnyError > {
let maybe_lint_config = if let Some ( config_file ) = & self . maybe_config_file {
config_file . to_lint_config ( ) ?
2022-07-18 15:12:19 -04:00
} else {
2023-01-07 15:22:09 -05:00
None
} ;
LintOptions ::resolve ( maybe_lint_config , Some ( lint_flags ) )
2022-07-18 15:12:19 -04:00
}
2023-01-07 15:22:09 -05:00
pub fn resolve_test_options (
& self ,
test_flags : TestFlags ,
) -> Result < TestOptions , AnyError > {
let maybe_test_config = if let Some ( config_file ) = & self . maybe_config_file {
config_file . to_test_config ( ) ?
2022-12-09 20:30:47 -05:00
} else {
2023-01-07 15:22:09 -05:00
None
} ;
TestOptions ::resolve ( maybe_test_config , Some ( test_flags ) )
2022-12-09 20:30:47 -05:00
}
2023-01-07 15:22:09 -05:00
pub fn resolve_bench_options (
& self ,
bench_flags : BenchFlags ,
) -> Result < BenchOptions , AnyError > {
let maybe_bench_config = if let Some ( config_file ) = & self . maybe_config_file
{
config_file . to_bench_config ( ) ?
2022-06-28 16:45:55 -04:00
} else {
2023-01-07 15:22:09 -05:00
None
} ;
BenchOptions ::resolve ( maybe_bench_config , Some ( bench_flags ) )
2022-06-28 16:45:55 -04:00
}
/// Vector of user script CLI arguments.
pub fn argv ( & self ) -> & Vec < String > {
& self . flags . argv
}
2023-01-17 19:18:24 -05:00
pub fn ca_data ( & self ) -> & Option < CaData > {
& self . flags . ca_data
2022-12-08 11:50:09 -05:00
}
pub fn ca_stores ( & self ) -> & Option < Vec < String > > {
& self . flags . ca_stores
}
2022-06-28 16:45:55 -04:00
pub fn check_js ( & self ) -> bool {
self
. maybe_config_file
. as_ref ( )
. map ( | cf | cf . get_check_js ( ) )
. unwrap_or ( false )
}
2022-08-12 15:21:17 -04:00
pub fn coverage_dir ( & self ) -> Option < String > {
fn allow_coverage ( sub_command : & DenoSubcommand ) -> bool {
match sub_command {
DenoSubcommand ::Test ( _ ) = > true ,
DenoSubcommand ::Run ( flags ) = > ! flags . is_stdin ( ) ,
_ = > false ,
}
}
if allow_coverage ( self . sub_command ( ) ) {
self
. flags
. coverage_dir
. as_ref ( )
. map ( ToOwned ::to_owned )
. or_else ( | | env ::var ( " DENO_UNSTABLE_COVERAGE_DIR " ) . ok ( ) )
} else {
None
}
2022-06-28 16:45:55 -04:00
}
pub fn enable_testing_features ( & self ) -> bool {
self . flags . enable_testing_features
}
2023-03-22 10:15:53 -04:00
pub fn ext_flag ( & self ) -> & Option < String > {
& self . flags . ext
}
2022-07-19 11:58:18 -04:00
/// If the --inspect or --inspect-brk flags are used.
pub fn is_inspecting ( & self ) -> bool {
2022-12-12 09:33:30 -05:00
self . flags . inspect . is_some ( )
| | self . flags . inspect_brk . is_some ( )
| | self . flags . inspect_wait . is_some ( )
2022-07-19 11:58:18 -04:00
}
2022-06-28 16:45:55 -04:00
pub fn inspect_brk ( & self ) -> Option < SocketAddr > {
self . flags . inspect_brk
}
2022-12-12 09:33:30 -05:00
pub fn inspect_wait ( & self ) -> Option < SocketAddr > {
self . flags . inspect_wait
}
2022-06-28 16:45:55 -04:00
pub fn log_level ( & self ) -> Option < log ::Level > {
self . flags . log_level
}
2022-11-30 17:25:20 -05:00
pub fn is_quiet ( & self ) -> bool {
self
. log_level ( )
. map ( | l | l = = log ::Level ::Error )
. unwrap_or ( false )
}
2022-12-08 11:50:09 -05:00
pub fn location_flag ( & self ) -> & Option < Url > {
& self . flags . location
2022-06-28 16:45:55 -04:00
}
2023-05-25 14:27:45 -04:00
pub fn maybe_custom_root ( & self ) -> & Option < PathBuf > {
& self . flags . cache_path
2022-06-28 16:45:55 -04:00
}
pub fn no_clear_screen ( & self ) -> bool {
self . flags . no_clear_screen
}
2022-12-08 11:50:09 -05:00
pub fn no_prompt ( & self ) -> bool {
resolve_no_prompt ( & self . flags )
}
2022-06-28 16:45:55 -04:00
pub fn no_remote ( & self ) -> bool {
self . flags . no_remote
}
2022-09-07 09:33:51 -04:00
pub fn no_npm ( & self ) -> bool {
self . flags . no_npm
}
2022-06-28 16:45:55 -04:00
pub fn permissions_options ( & self ) -> PermissionsOptions {
2022-12-08 11:50:09 -05:00
PermissionsOptions {
allow_env : self . flags . allow_env . clone ( ) ,
allow_hrtime : self . flags . allow_hrtime ,
allow_net : self . flags . allow_net . clone ( ) ,
allow_ffi : self . flags . allow_ffi . clone ( ) ,
allow_read : self . flags . allow_read . clone ( ) ,
allow_run : self . flags . allow_run . clone ( ) ,
allow_sys : self . flags . allow_sys . clone ( ) ,
allow_write : self . flags . allow_write . clone ( ) ,
prompt : ! self . no_prompt ( ) ,
}
2022-06-28 16:45:55 -04:00
}
pub fn reload_flag ( & self ) -> bool {
self . flags . reload
}
pub fn seed ( & self ) -> Option < u64 > {
self . flags . seed
}
pub fn sub_command ( & self ) -> & DenoSubcommand {
& self . flags . subcommand
}
pub fn type_check_mode ( & self ) -> TypeCheckMode {
self . flags . type_check_mode
}
2022-12-08 11:50:09 -05:00
pub fn unsafely_ignore_certificate_errors ( & self ) -> & Option < Vec < String > > {
& self . flags . unsafely_ignore_certificate_errors
2022-06-28 16:45:55 -04:00
}
pub fn unstable ( & self ) -> bool {
self . flags . unstable
}
2022-12-08 11:50:09 -05:00
pub fn v8_flags ( & self ) -> & Vec < String > {
& self . flags . v8_flags
}
pub fn watch_paths ( & self ) -> & Option < Vec < PathBuf > > {
& self . flags . watch
2022-06-28 16:45:55 -04:00
}
}
2023-02-22 20:16:16 -05:00
/// Resolves the path to use for a local node_modules folder.
fn resolve_local_node_modules_folder (
cwd : & Path ,
flags : & Flags ,
maybe_config_file : Option < & ConfigFile > ,
maybe_package_json : Option < & PackageJson > ,
) -> Result < Option < PathBuf > , AnyError > {
2023-05-18 18:10:44 -04:00
let use_node_modules_dir = flags
. node_modules_dir
. or_else ( | | maybe_config_file . and_then ( | c | c . node_modules_dir ( ) ) ) ;
let path = if use_node_modules_dir = = Some ( false ) {
2023-02-22 20:16:16 -05:00
return Ok ( None ) ;
} else if let Some ( state ) = & * NPM_PROCESS_STATE {
return Ok ( state . local_node_modules_path . as_ref ( ) . map ( PathBuf ::from ) ) ;
} else if let Some ( package_json_path ) = maybe_package_json . map ( | c | & c . path ) {
// always auto-discover the local_node_modules_folder when a package.json exists
package_json_path . parent ( ) . unwrap ( ) . join ( " node_modules " )
2023-05-18 18:10:44 -04:00
} else if use_node_modules_dir . is_none ( ) {
2023-02-22 20:16:16 -05:00
return Ok ( None ) ;
} else if let Some ( config_path ) = maybe_config_file
. as_ref ( )
. and_then ( | c | c . specifier . to_file_path ( ) . ok ( ) )
{
config_path . parent ( ) . unwrap ( ) . join ( " node_modules " )
} else {
cwd . join ( " node_modules " )
} ;
Ok ( Some ( canonicalize_path_maybe_not_exists ( & path ) ? ) )
}
2022-06-28 16:45:55 -04:00
fn resolve_import_map_specifier (
maybe_import_map_path : Option < & str > ,
maybe_config_file : Option < & ConfigFile > ,
2023-03-13 21:12:09 -04:00
current_dir : & Path ,
2022-06-28 16:45:55 -04:00
) -> Result < Option < ModuleSpecifier > , AnyError > {
if let Some ( import_map_path ) = maybe_import_map_path {
if let Some ( config_file ) = & maybe_config_file {
if config_file . to_import_map_path ( ) . is_some ( ) {
2022-07-01 11:50:16 -04:00
log ::warn! ( " {} the configuration file \" {} \" contains an entry for \" importMap \" that is being ignored. " , colors ::yellow ( " Warning " ) , config_file . specifier ) ;
2022-06-28 16:45:55 -04:00
}
}
2023-03-13 21:12:09 -04:00
let specifier =
deno_core ::resolve_url_or_path ( import_map_path , current_dir )
2023-03-21 14:13:32 -04:00
. with_context ( | | {
format! ( " Bad URL ( \" {import_map_path} \" ) for import map. " )
} ) ? ;
2022-06-28 16:45:55 -04:00
return Ok ( Some ( specifier ) ) ;
} else if let Some ( config_file ) = & maybe_config_file {
2023-01-25 15:13:40 -05:00
// if the config file is an import map we prefer to use it, over `importMap`
// field
if config_file . is_an_import_map ( ) {
if let Some ( _import_map_path ) = config_file . to_import_map_path ( ) {
log ::warn! ( " {} \" importMap \" setting is ignored when \" imports \" or \" scopes \" are specified in the config file. " , colors ::yellow ( " Warning " ) ) ;
}
return Ok ( Some ( config_file . specifier . clone ( ) ) ) ;
}
2022-06-28 16:45:55 -04:00
// when the import map is specifier in a config file, it needs to be
// resolved relative to the config file, versus the CWD like with the flag
// and with config files, we support both local and remote config files,
// so we have treat them differently.
if let Some ( import_map_path ) = config_file . to_import_map_path ( ) {
2022-10-13 05:01:11 -04:00
// if the import map is an absolute URL, use it as is
if let Ok ( specifier ) = deno_core ::resolve_url ( & import_map_path ) {
return Ok ( Some ( specifier ) ) ;
}
2022-06-28 16:45:55 -04:00
let specifier =
// with local config files, it might be common to specify an import
// map like `"importMap": "import-map.json"`, which is resolvable if
// the file is resolved like a file path, so we will coerce the config
// file into a file path if possible and join the import map path to
// the file path.
if let Ok ( config_file_path ) = config_file . specifier . to_file_path ( ) {
let import_map_file_path = normalize_path ( config_file_path
. parent ( )
. ok_or_else ( | | {
anyhow! ( " Bad config file specifier: {} " , config_file . specifier )
} ) ?
. join ( & import_map_path ) ) ;
ModuleSpecifier ::from_file_path ( import_map_file_path ) . unwrap ( )
// otherwise if the config file is remote, we have no choice but to
// use "import resolution" with the config file as the base.
} else {
deno_core ::resolve_import ( & import_map_path , config_file . specifier . as_str ( ) )
2023-03-21 14:13:32 -04:00
. with_context ( | | format! (
2023-01-27 10:43:16 -05:00
" Bad URL ( \" {import_map_path} \" ) for import map. "
2022-06-28 16:45:55 -04:00
) ) ?
} ;
return Ok ( Some ( specifier ) ) ;
}
}
Ok ( None )
}
2023-04-27 10:05:20 -04:00
pub struct StorageKeyResolver ( Option < Option < String > > ) ;
impl StorageKeyResolver {
pub fn from_options ( options : & CliOptions ) -> Self {
Self ( if let Some ( location ) = & options . flags . location {
// if a location is set, then the ascii serialization of the location is
// used, unless the origin is opaque, and then no storage origin is set, as
// we can't expect the origin to be reproducible
let storage_origin = location . origin ( ) ;
if storage_origin . is_tuple ( ) {
Some ( Some ( storage_origin . ascii_serialization ( ) ) )
} else {
Some ( None )
}
} else {
// otherwise we will use the path to the config file or None to
// fall back to using the main module's path
options
. maybe_config_file
. as_ref ( )
. map ( | config_file | Some ( config_file . specifier . to_string ( ) ) )
} )
}
2023-05-01 08:59:38 -04:00
/// Creates a storage key resolver that will always resolve to being empty.
pub fn empty ( ) -> Self {
Self ( Some ( None ) )
}
2023-04-27 10:05:20 -04:00
/// Resolves the storage key to use based on the current flags, config, or main module.
pub fn resolve_storage_key (
& self ,
main_module : & ModuleSpecifier ,
) -> Option < String > {
// use the stored value or fall back to using the path of the main module.
if let Some ( maybe_value ) = & self . 0 {
maybe_value . clone ( )
} else {
Some ( main_module . to_string ( ) )
}
}
}
2023-05-22 21:39:59 -04:00
fn expand_globs ( paths : & [ PathBuf ] ) -> Result < Vec < PathBuf > , AnyError > {
let mut new_paths = vec! [ ] ;
for path in paths {
let path_str = path . to_string_lossy ( ) ;
if path_str . chars ( ) . any ( | c | matches! ( c , '*' | '?' ) ) {
// Escape brackets - we currently don't support them, because with introduction
// of glob expansion paths like "pages/[id].ts" would suddenly start giving
// wrong results. We might want to revisit that in the future.
let escaped_path_str = path_str . replace ( '[' , " [[] " ) . replace ( ']' , " []] " ) ;
let globbed_paths = glob ::glob_with (
& escaped_path_str ,
// Matches what `deno_task_shell` does
glob ::MatchOptions {
// false because it should work the same way on case insensitive file systems
case_sensitive : false ,
// true because it copies what sh does
require_literal_separator : true ,
// true because it copies with sh does—these files are considered "hidden"
require_literal_leading_dot : true ,
} ,
2023-05-23 13:35:12 -04:00
)
. with_context ( | | format! ( " Failed to expand glob: \" {} \" " , path_str ) ) ? ;
2023-05-22 21:39:59 -04:00
for globbed_path_result in globbed_paths {
new_paths . push ( globbed_path_result ? ) ;
}
} else {
new_paths . push ( path . clone ( ) ) ;
}
}
Ok ( new_paths )
}
2023-01-07 15:22:09 -05:00
/// Collect included and ignored files. CLI flags take precedence
/// over config file, i.e. if there's `files.ignore` in config file
/// and `--ignore` CLI flag, only the flag value is taken into account.
fn resolve_files (
maybe_files_config : Option < FilesConfig > ,
maybe_file_flags : Option < FileFlags > ,
2023-05-22 21:39:59 -04:00
) -> Result < FilesConfig , AnyError > {
2023-01-07 15:22:09 -05:00
let mut result = maybe_files_config . unwrap_or_default ( ) ;
if let Some ( file_flags ) = maybe_file_flags {
if ! file_flags . include . is_empty ( ) {
result . include = file_flags . include ;
}
if ! file_flags . ignore . is_empty ( ) {
result . exclude = file_flags . ignore ;
}
}
2023-05-22 21:39:59 -04:00
// Now expand globs if there are any
if ! result . include . is_empty ( ) {
result . include = expand_globs ( & result . include ) ? ;
}
if ! result . exclude . is_empty ( ) {
result . exclude = expand_globs ( & result . exclude ) ? ;
}
Ok ( result )
2023-01-07 15:22:09 -05:00
}
2022-12-08 11:50:09 -05:00
/// Resolves the no_prompt value based on the cli flags and environment.
pub fn resolve_no_prompt ( flags : & Flags ) -> bool {
2023-02-24 14:23:07 -05:00
flags . no_prompt | | has_flag_env_var ( " DENO_NO_PROMPT " )
}
2023-05-22 21:28:36 -04:00
pub fn has_flag_env_var ( name : & str ) -> bool {
2023-02-24 14:23:07 -05:00
let value = env ::var ( name ) ;
matches! ( value . as_ref ( ) . map ( | s | s . as_str ( ) ) , Ok ( " 1 " ) )
2022-12-08 11:50:09 -05:00
}
2023-05-10 20:06:59 -04:00
pub fn npm_pkg_req_ref_to_binary_command (
req_ref : & NpmPackageReqReference ,
) -> String {
let binary_name = req_ref
. sub_path
. as_deref ( )
. unwrap_or ( req_ref . req . name . as_str ( ) ) ;
binary_name . to_string ( )
}
2022-06-28 16:45:55 -04:00
#[ cfg(test) ]
mod test {
use super ::* ;
2023-05-22 21:39:59 -04:00
use pretty_assertions ::assert_eq ;
2022-06-28 16:45:55 -04:00
#[ cfg(not(windows)) ]
#[ test ]
fn resolve_import_map_config_file ( ) {
let config_text = r #" {
" importMap " : " import_map.json "
} " #;
let config_specifier =
ModuleSpecifier ::parse ( " file:///deno/deno.jsonc " ) . unwrap ( ) ;
2023-05-22 21:28:36 -04:00
let config_file = ConfigFile ::new ( config_text , config_specifier ) . unwrap ( ) ;
2023-03-13 21:12:09 -04:00
let actual = resolve_import_map_specifier (
None ,
Some ( & config_file ) ,
& PathBuf ::from ( " / " ) ,
) ;
2022-06-28 16:45:55 -04:00
assert! ( actual . is_ok ( ) ) ;
let actual = actual . unwrap ( ) ;
assert_eq! (
actual ,
2023-01-25 15:13:40 -05:00
Some ( ModuleSpecifier ::parse ( " file:///deno/import_map.json " ) . unwrap ( ) , )
2022-06-28 16:45:55 -04:00
) ;
}
2022-10-13 05:01:11 -04:00
#[ test ]
fn resolve_import_map_remote_config_file_local ( ) {
let config_text = r #" {
" importMap " : " https://example.com/import_map.json "
} " #;
let config_specifier =
ModuleSpecifier ::parse ( " file:///deno/deno.jsonc " ) . unwrap ( ) ;
2023-05-22 21:28:36 -04:00
let config_file = ConfigFile ::new ( config_text , config_specifier ) . unwrap ( ) ;
2023-03-13 21:12:09 -04:00
let actual = resolve_import_map_specifier (
None ,
Some ( & config_file ) ,
& PathBuf ::from ( " / " ) ,
) ;
2022-10-13 05:01:11 -04:00
assert! ( actual . is_ok ( ) ) ;
let actual = actual . unwrap ( ) ;
assert_eq! (
actual ,
Some (
ModuleSpecifier ::parse ( " https://example.com/import_map.json " ) . unwrap ( )
)
) ;
}
2022-06-28 16:45:55 -04:00
#[ test ]
fn resolve_import_map_config_file_remote ( ) {
let config_text = r #" {
" importMap " : " ./import_map.json "
} " #;
let config_specifier =
ModuleSpecifier ::parse ( " https://example.com/deno.jsonc " ) . unwrap ( ) ;
2023-05-22 21:28:36 -04:00
let config_file = ConfigFile ::new ( config_text , config_specifier ) . unwrap ( ) ;
2023-03-13 21:12:09 -04:00
let actual = resolve_import_map_specifier (
None ,
Some ( & config_file ) ,
& PathBuf ::from ( " / " ) ,
) ;
2022-06-28 16:45:55 -04:00
assert! ( actual . is_ok ( ) ) ;
let actual = actual . unwrap ( ) ;
assert_eq! (
actual ,
Some (
ModuleSpecifier ::parse ( " https://example.com/import_map.json " ) . unwrap ( )
)
) ;
}
#[ test ]
fn resolve_import_map_flags_take_precedence ( ) {
let config_text = r #" {
" importMap " : " import_map.json "
} " #;
2023-03-14 07:37:15 -04:00
let cwd = & std ::env ::current_dir ( ) . unwrap ( ) ;
2022-06-28 16:45:55 -04:00
let config_specifier =
ModuleSpecifier ::parse ( " file:///deno/deno.jsonc " ) . unwrap ( ) ;
2023-05-22 21:28:36 -04:00
let config_file = ConfigFile ::new ( config_text , config_specifier ) . unwrap ( ) ;
2023-03-13 21:12:09 -04:00
let actual = resolve_import_map_specifier (
Some ( " import-map.json " ) ,
Some ( & config_file ) ,
cwd ,
) ;
let import_map_path = cwd . join ( " import-map.json " ) ;
2022-06-28 16:45:55 -04:00
let expected_specifier =
2022-12-17 17:20:15 -05:00
ModuleSpecifier ::from_file_path ( import_map_path ) . unwrap ( ) ;
2022-06-28 16:45:55 -04:00
assert! ( actual . is_ok ( ) ) ;
let actual = actual . unwrap ( ) ;
assert_eq! ( actual , Some ( expected_specifier ) ) ;
}
2023-01-25 15:13:40 -05:00
#[ test ]
fn resolve_import_map_embedded_take_precedence ( ) {
let config_text = r #" {
" importMap " : " import_map.json " ,
" imports " : { } ,
} " #;
let config_specifier =
ModuleSpecifier ::parse ( " file:///deno/deno.jsonc " ) . unwrap ( ) ;
2023-05-22 21:28:36 -04:00
let config_file =
ConfigFile ::new ( config_text , config_specifier . clone ( ) ) . unwrap ( ) ;
2023-03-13 21:12:09 -04:00
let actual = resolve_import_map_specifier (
None ,
Some ( & config_file ) ,
& PathBuf ::from ( " / " ) ,
) ;
2023-01-25 15:13:40 -05:00
assert! ( actual . is_ok ( ) ) ;
let actual = actual . unwrap ( ) ;
assert_eq! ( actual , Some ( config_specifier ) ) ;
}
2022-06-28 16:45:55 -04:00
#[ test ]
fn resolve_import_map_none ( ) {
let config_text = r # "{}"# ;
let config_specifier =
ModuleSpecifier ::parse ( " file:///deno/deno.jsonc " ) . unwrap ( ) ;
2023-05-22 21:28:36 -04:00
let config_file = ConfigFile ::new ( config_text , config_specifier ) . unwrap ( ) ;
2023-03-13 21:12:09 -04:00
let actual = resolve_import_map_specifier (
None ,
Some ( & config_file ) ,
& PathBuf ::from ( " / " ) ,
) ;
2022-06-28 16:45:55 -04:00
assert! ( actual . is_ok ( ) ) ;
let actual = actual . unwrap ( ) ;
assert_eq! ( actual , None ) ;
}
#[ test ]
fn resolve_import_map_no_config ( ) {
2023-03-13 21:12:09 -04:00
let actual = resolve_import_map_specifier ( None , None , & PathBuf ::from ( " / " ) ) ;
2022-06-28 16:45:55 -04:00
assert! ( actual . is_ok ( ) ) ;
let actual = actual . unwrap ( ) ;
assert_eq! ( actual , None ) ;
}
2023-04-27 10:05:20 -04:00
#[ test ]
fn storage_key_resolver_test ( ) {
let resolver = StorageKeyResolver ( None ) ;
let specifier = ModuleSpecifier ::parse ( " file:///a.ts " ) . unwrap ( ) ;
assert_eq! (
resolver . resolve_storage_key ( & specifier ) ,
Some ( specifier . to_string ( ) )
) ;
let resolver = StorageKeyResolver ( Some ( None ) ) ;
assert_eq! ( resolver . resolve_storage_key ( & specifier ) , None ) ;
let resolver = StorageKeyResolver ( Some ( Some ( " value " . to_string ( ) ) ) ) ;
assert_eq! (
resolver . resolve_storage_key ( & specifier ) ,
Some ( " value " . to_string ( ) )
) ;
2023-05-01 08:59:38 -04:00
// test empty
let resolver = StorageKeyResolver ::empty ( ) ;
assert_eq! ( resolver . resolve_storage_key ( & specifier ) , None ) ;
2023-04-27 10:05:20 -04:00
}
2023-05-22 21:39:59 -04:00
#[ test ]
fn resolve_files_test ( ) {
use test_util ::TempDir ;
let temp_dir = TempDir ::new ( ) ;
temp_dir . create_dir_all ( " data " ) ;
temp_dir . create_dir_all ( " nested " ) ;
temp_dir . create_dir_all ( " nested/foo " ) ;
temp_dir . create_dir_all ( " nested/fizz " ) ;
temp_dir . create_dir_all ( " pages " ) ;
temp_dir . write ( " data/tes.ts " , " " ) ;
temp_dir . write ( " data/test1.js " , " " ) ;
temp_dir . write ( " data/test1.ts " , " " ) ;
temp_dir . write ( " data/test12.ts " , " " ) ;
temp_dir . write ( " nested/foo/foo.ts " , " " ) ;
temp_dir . write ( " nested/foo/bar.ts " , " " ) ;
temp_dir . write ( " nested/foo/fizz.ts " , " " ) ;
temp_dir . write ( " nested/foo/bazz.ts " , " " ) ;
temp_dir . write ( " nested/fizz/foo.ts " , " " ) ;
temp_dir . write ( " nested/fizz/bar.ts " , " " ) ;
temp_dir . write ( " nested/fizz/fizz.ts " , " " ) ;
temp_dir . write ( " nested/fizz/bazz.ts " , " " ) ;
temp_dir . write ( " pages/[id].ts " , " " ) ;
2023-05-23 13:35:12 -04:00
let error = resolve_files (
Some ( FilesConfig {
include : vec ! [ temp_dir . path ( ) . join ( " data/**********.ts " ) ] ,
exclude : vec ! [ ] ,
} ) ,
None ,
)
. unwrap_err ( ) ;
assert! ( error . to_string ( ) . starts_with ( " Failed to expand glob " ) ) ;
2023-05-22 21:39:59 -04:00
let resolved_files = resolve_files (
Some ( FilesConfig {
include : vec ! [
temp_dir . path ( ) . join ( " data/test1.?s " ) ,
temp_dir . path ( ) . join ( " nested/foo/*.ts " ) ,
temp_dir . path ( ) . join ( " nested/fizz/*.ts " ) ,
temp_dir . path ( ) . join ( " pages/[id].ts " ) ,
] ,
exclude : vec ! [ temp_dir . path ( ) . join ( " nested/**/*bazz.ts " ) ] ,
} ) ,
None ,
)
. unwrap ( ) ;
assert_eq! (
resolved_files . include ,
vec! [
temp_dir . path ( ) . join ( " data/test1.js " ) ,
temp_dir . path ( ) . join ( " data/test1.ts " ) ,
temp_dir . path ( ) . join ( " nested/foo/bar.ts " ) ,
temp_dir . path ( ) . join ( " nested/foo/bazz.ts " ) ,
temp_dir . path ( ) . join ( " nested/foo/fizz.ts " ) ,
temp_dir . path ( ) . join ( " nested/foo/foo.ts " ) ,
temp_dir . path ( ) . join ( " nested/fizz/bar.ts " ) ,
temp_dir . path ( ) . join ( " nested/fizz/bazz.ts " ) ,
temp_dir . path ( ) . join ( " nested/fizz/fizz.ts " ) ,
temp_dir . path ( ) . join ( " nested/fizz/foo.ts " ) ,
temp_dir . path ( ) . join ( " pages/[id].ts " ) ,
]
) ;
assert_eq! (
resolved_files . exclude ,
vec! [
temp_dir . path ( ) . join ( " nested/fizz/bazz.ts " ) ,
temp_dir . path ( ) . join ( " nested/foo/bazz.ts " ) ,
]
)
}
2022-06-28 16:45:55 -04:00
}