1
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2024-12-25 16:49:18 -05:00

refactor(cli/tools): move flag and config logic to CliOptions (#17008)

Co-authored-by: David Sherret <dsherret@gmail.com>
This commit is contained in:
Geert-Jan Zwiers 2023-01-07 21:22:09 +01:00 committed by GitHub
parent fac6447815
commit 84ef26ac9b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
15 changed files with 914 additions and 772 deletions

View file

@ -295,43 +295,45 @@ impl SerializedFilesConfig {
include: self include: self
.include .include
.into_iter() .into_iter()
.map(|p| config_dir.join(&p)) .map(|p| {
.collect::<Result<Vec<ModuleSpecifier>, _>>()?, let url = config_dir.join(&p)?;
specifier_to_file_path(&url)
})
.collect::<Result<Vec<_>, _>>()?,
exclude: self exclude: self
.exclude .exclude
.into_iter() .into_iter()
.map(|p| config_dir.join(&p)) .map(|p| {
.collect::<Result<Vec<ModuleSpecifier>, _>>()?, let url = config_dir.join(&p)?;
specifier_to_file_path(&url)
})
.collect::<Result<Vec<_>, _>>()?,
}) })
} }
} }
#[derive(Clone, Debug, Default)] #[derive(Clone, Debug, Default, Eq, PartialEq)]
pub struct FilesConfig { pub struct FilesConfig {
pub include: Vec<ModuleSpecifier>, pub include: Vec<PathBuf>,
pub exclude: Vec<ModuleSpecifier>, pub exclude: Vec<PathBuf>,
} }
impl FilesConfig { impl FilesConfig {
/// Gets if the provided specifier is allowed based on the includes /// Gets if the provided specifier is allowed based on the includes
/// and excludes in the configuration file. /// and excludes in the configuration file.
pub fn matches_specifier(&self, specifier: &ModuleSpecifier) -> bool { pub fn matches_specifier(&self, specifier: &ModuleSpecifier) -> bool {
let file_path = match specifier_to_file_path(specifier) {
Ok(file_path) => file_path,
Err(_) => return false,
};
// Skip files which is in the exclude list. // Skip files which is in the exclude list.
let specifier_text = specifier.as_str(); if self.exclude.iter().any(|i| file_path.starts_with(i)) {
if self
.exclude
.iter()
.any(|i| specifier_text.starts_with(i.as_str()))
{
return false; return false;
} }
// Ignore files not in the include list if it's not empty. // Ignore files not in the include list if it's not empty.
self.include.is_empty() self.include.is_empty()
|| self || self.include.iter().any(|i| file_path.starts_with(i))
.include
.iter()
.any(|i| specifier_text.starts_with(i.as_str()))
} }
} }
@ -663,6 +665,16 @@ impl ConfigFile {
self.json.import_map.clone() self.json.import_map.clone()
} }
pub fn to_fmt_config(&self) -> Result<Option<FmtConfig>, AnyError> {
if let Some(config) = self.json.fmt.clone() {
let fmt_config: SerializedFmtConfig = serde_json::from_value(config)
.context("Failed to parse \"fmt\" configuration")?;
Ok(Some(fmt_config.into_resolved(&self.specifier)?))
} else {
Ok(None)
}
}
pub fn to_lint_config(&self) -> Result<Option<LintConfig>, AnyError> { pub fn to_lint_config(&self) -> Result<Option<LintConfig>, AnyError> {
if let Some(config) = self.json.lint.clone() { if let Some(config) = self.json.lint.clone() {
let lint_config: SerializedLintConfig = serde_json::from_value(config) let lint_config: SerializedLintConfig = serde_json::from_value(config)
@ -767,16 +779,6 @@ impl ConfigFile {
}) })
} }
pub fn to_fmt_config(&self) -> Result<Option<FmtConfig>, AnyError> {
if let Some(config) = self.json.fmt.clone() {
let fmt_config: SerializedFmtConfig = serde_json::from_value(config)
.context("Failed to parse \"fmt\" configuration")?;
Ok(Some(fmt_config.into_resolved(&self.specifier)?))
} else {
Ok(None)
}
}
pub fn resolve_tasks_config( pub fn resolve_tasks_config(
&self, &self,
) -> Result<BTreeMap<String, String>, AnyError> { ) -> Result<BTreeMap<String, String>, AnyError> {
@ -1068,13 +1070,10 @@ mod tests {
.to_lint_config() .to_lint_config()
.expect("error parsing lint object") .expect("error parsing lint object")
.expect("lint object should be defined"); .expect("lint object should be defined");
assert_eq!( assert_eq!(lint_config.files.include, vec![PathBuf::from("/deno/src/")]);
lint_config.files.include,
vec![config_dir.join("src/").unwrap()]
);
assert_eq!( assert_eq!(
lint_config.files.exclude, lint_config.files.exclude,
vec![config_dir.join("src/testdata/").unwrap()] vec![PathBuf::from("/deno/src/testdata/")]
); );
assert_eq!( assert_eq!(
lint_config.rules.include, lint_config.rules.include,
@ -1090,13 +1089,10 @@ mod tests {
.to_fmt_config() .to_fmt_config()
.expect("error parsing fmt object") .expect("error parsing fmt object")
.expect("fmt object should be defined"); .expect("fmt object should be defined");
assert_eq!( assert_eq!(fmt_config.files.include, vec![PathBuf::from("/deno/src/")]);
fmt_config.files.include,
vec![config_dir.join("src/").unwrap()]
);
assert_eq!( assert_eq!(
fmt_config.files.exclude, fmt_config.files.exclude,
vec![config_dir.join("src/testdata/").unwrap()] vec![PathBuf::from("/deno/src/testdata/")],
); );
assert_eq!(fmt_config.options.use_tabs, Some(true)); assert_eq!(fmt_config.options.use_tabs, Some(true));
assert_eq!(fmt_config.options.line_width, Some(80)); assert_eq!(fmt_config.options.line_width, Some(80));
@ -1190,6 +1186,8 @@ mod tests {
let expected_exclude = ModuleSpecifier::from_file_path( let expected_exclude = ModuleSpecifier::from_file_path(
testdata.join("fmt/with_config/subdir/b.ts"), testdata.join("fmt/with_config/subdir/b.ts"),
) )
.unwrap()
.to_file_path()
.unwrap(); .unwrap();
assert_eq!(fmt_config.files.exclude, vec![expected_exclude]); assert_eq!(fmt_config.files.exclude, vec![expected_exclude]);

View file

@ -6,8 +6,6 @@ use clap::ColorChoice;
use clap::Command; use clap::Command;
use clap::ValueHint; use clap::ValueHint;
use deno_core::error::AnyError; use deno_core::error::AnyError;
use deno_core::serde::Deserialize;
use deno_core::serde::Serialize;
use deno_core::url::Url; use deno_core::url::Url;
use deno_runtime::permissions::parse_sys_kind; use deno_runtime::permissions::parse_sys_kind;
use log::debug; use log::debug;
@ -46,30 +44,35 @@ static SHORT_VERSION: Lazy<String> = Lazy::new(|| {
.to_string() .to_string()
}); });
#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)] #[derive(Clone, Debug, Default, Eq, PartialEq)]
pub struct BenchFlags { pub struct FileFlags {
pub ignore: Vec<PathBuf>, pub ignore: Vec<PathBuf>,
pub include: Option<Vec<String>>, pub include: Vec<PathBuf>,
}
#[derive(Clone, Debug, Default, Eq, PartialEq)]
pub struct BenchFlags {
pub files: FileFlags,
pub filter: Option<String>, pub filter: Option<String>,
} }
#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)] #[derive(Clone, Debug, Eq, PartialEq)]
pub struct BundleFlags { pub struct BundleFlags {
pub source_file: String, pub source_file: String,
pub out_file: Option<PathBuf>, pub out_file: Option<PathBuf>,
} }
#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)] #[derive(Clone, Debug, Eq, PartialEq)]
pub struct CacheFlags { pub struct CacheFlags {
pub files: Vec<String>, pub files: Vec<String>,
} }
#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)] #[derive(Clone, Debug, Eq, PartialEq)]
pub struct CheckFlags { pub struct CheckFlags {
pub files: Vec<String>, pub files: Vec<String>,
} }
#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)] #[derive(Clone, Debug, Eq, PartialEq)]
pub struct CompileFlags { pub struct CompileFlags {
pub source_file: String, pub source_file: String,
pub output: Option<PathBuf>, pub output: Option<PathBuf>,
@ -77,12 +80,12 @@ pub struct CompileFlags {
pub target: Option<String>, pub target: Option<String>,
} }
#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)] #[derive(Clone, Debug, Eq, PartialEq)]
pub struct CompletionsFlags { pub struct CompletionsFlags {
pub buf: Box<[u8]>, pub buf: Box<[u8]>,
} }
#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)] #[derive(Clone, Debug, Eq, PartialEq)]
pub struct CoverageFlags { pub struct CoverageFlags {
pub files: Vec<PathBuf>, pub files: Vec<PathBuf>,
pub output: Option<PathBuf>, pub output: Option<PathBuf>,
@ -92,7 +95,7 @@ pub struct CoverageFlags {
pub lcov: bool, pub lcov: bool,
} }
#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)] #[derive(Clone, Debug, Eq, PartialEq)]
pub struct DocFlags { pub struct DocFlags {
pub private: bool, pub private: bool,
pub json: bool, pub json: bool,
@ -100,19 +103,18 @@ pub struct DocFlags {
pub filter: Option<String>, pub filter: Option<String>,
} }
#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)] #[derive(Clone, Debug, Eq, PartialEq)]
pub struct EvalFlags { pub struct EvalFlags {
pub print: bool, pub print: bool,
pub code: String, pub code: String,
pub ext: String, pub ext: String,
} }
#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)] #[derive(Clone, Debug, Eq, PartialEq)]
pub struct FmtFlags { pub struct FmtFlags {
pub check: bool, pub check: bool,
pub files: Vec<PathBuf>,
pub ignore: Vec<PathBuf>,
pub ext: String, pub ext: String,
pub files: FileFlags,
pub use_tabs: Option<bool>, pub use_tabs: Option<bool>,
pub line_width: Option<NonZeroU32>, pub line_width: Option<NonZeroU32>,
pub indent_width: Option<NonZeroU8>, pub indent_width: Option<NonZeroU8>,
@ -120,18 +122,18 @@ pub struct FmtFlags {
pub prose_wrap: Option<String>, pub prose_wrap: Option<String>,
} }
#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)] #[derive(Clone, Debug, Eq, PartialEq)]
pub struct InitFlags { pub struct InitFlags {
pub dir: Option<String>, pub dir: Option<String>,
} }
#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)] #[derive(Clone, Debug, Eq, PartialEq)]
pub struct InfoFlags { pub struct InfoFlags {
pub json: bool, pub json: bool,
pub file: Option<String>, pub file: Option<String>,
} }
#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)] #[derive(Clone, Debug, Eq, PartialEq)]
pub struct InstallFlags { pub struct InstallFlags {
pub module_url: String, pub module_url: String,
pub args: Vec<String>, pub args: Vec<String>,
@ -140,16 +142,15 @@ pub struct InstallFlags {
pub force: bool, pub force: bool,
} }
#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)] #[derive(Clone, Debug, Eq, PartialEq)]
pub struct UninstallFlags { pub struct UninstallFlags {
pub name: String, pub name: String,
pub root: Option<PathBuf>, pub root: Option<PathBuf>,
} }
#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)] #[derive(Clone, Debug, Eq, PartialEq)]
pub struct LintFlags { pub struct LintFlags {
pub files: Vec<PathBuf>, pub files: FileFlags,
pub ignore: Vec<PathBuf>,
pub rules: bool, pub rules: bool,
pub maybe_rules_tags: Option<Vec<String>>, pub maybe_rules_tags: Option<Vec<String>>,
pub maybe_rules_include: Option<Vec<String>>, pub maybe_rules_include: Option<Vec<String>>,
@ -158,14 +159,14 @@ pub struct LintFlags {
pub compact: bool, pub compact: bool,
} }
#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)] #[derive(Clone, Debug, Eq, PartialEq)]
pub struct ReplFlags { pub struct ReplFlags {
pub eval_files: Option<Vec<String>>, pub eval_files: Option<Vec<String>>,
pub eval: Option<String>, pub eval: Option<String>,
pub is_default_command: bool, pub is_default_command: bool,
} }
#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)] #[derive(Clone, Debug, Eq, PartialEq)]
pub struct RunFlags { pub struct RunFlags {
pub script: String, pub script: String,
} }
@ -176,27 +177,26 @@ impl RunFlags {
} }
} }
#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)] #[derive(Clone, Debug, Eq, PartialEq)]
pub struct TaskFlags { pub struct TaskFlags {
pub cwd: Option<String>, pub cwd: Option<String>,
pub task: String, pub task: String,
} }
#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)] #[derive(Clone, Debug, Default, Eq, PartialEq)]
pub struct TestFlags { pub struct TestFlags {
pub ignore: Vec<PathBuf>,
pub doc: bool, pub doc: bool,
pub no_run: bool, pub no_run: bool,
pub fail_fast: Option<NonZeroUsize>, pub fail_fast: Option<NonZeroUsize>,
pub files: FileFlags,
pub allow_none: bool, pub allow_none: bool,
pub include: Vec<String>,
pub filter: Option<String>, pub filter: Option<String>,
pub shuffle: Option<u64>, pub shuffle: Option<u64>,
pub concurrent_jobs: NonZeroUsize, pub concurrent_jobs: Option<NonZeroUsize>,
pub trace_ops: bool, pub trace_ops: bool,
} }
#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)] #[derive(Clone, Debug, Eq, PartialEq)]
pub struct UpgradeFlags { pub struct UpgradeFlags {
pub dry_run: bool, pub dry_run: bool,
pub force: bool, pub force: bool,
@ -205,14 +205,14 @@ pub struct UpgradeFlags {
pub output: Option<PathBuf>, pub output: Option<PathBuf>,
} }
#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)] #[derive(Clone, Debug, Eq, PartialEq)]
pub struct VendorFlags { pub struct VendorFlags {
pub specifiers: Vec<String>, pub specifiers: Vec<String>,
pub output_path: Option<PathBuf>, pub output_path: Option<PathBuf>,
pub force: bool, pub force: bool,
} }
#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)] #[derive(Clone, Debug, Eq, PartialEq)]
pub enum DenoSubcommand { pub enum DenoSubcommand {
Bench(BenchFlags), Bench(BenchFlags),
Bundle(BundleFlags), Bundle(BundleFlags),
@ -455,9 +455,9 @@ impl Flags {
pub fn config_path_args(&self) -> Option<Vec<PathBuf>> { pub fn config_path_args(&self) -> Option<Vec<PathBuf>> {
use DenoSubcommand::*; use DenoSubcommand::*;
if let Fmt(FmtFlags { files, .. }) = &self.subcommand { if let Fmt(FmtFlags { files, .. }) = &self.subcommand {
Some(files.clone()) Some(files.include.clone())
} else if let Lint(LintFlags { files, .. }) = &self.subcommand { } else if let Lint(LintFlags { files, .. }) = &self.subcommand {
Some(files.clone()) Some(files.include.clone())
} else if let Run(RunFlags { script }) = &self.subcommand { } else if let Run(RunFlags { script }) = &self.subcommand {
if let Ok(module_specifier) = deno_core::resolve_url_or_path(script) { if let Ok(module_specifier) = deno_core::resolve_url_or_path(script) {
if module_specifier.scheme() == "file" if module_specifier.scheme() == "file"
@ -2298,20 +2298,19 @@ fn bench_parse(flags: &mut Flags, matches: &clap::ArgMatches) {
} }
let include = if matches.is_present("files") { let include = if matches.is_present("files") {
let files: Vec<String> = matches let files = matches
.values_of("files") .values_of("files")
.unwrap() .unwrap()
.map(String::from) .map(PathBuf::from)
.collect(); .collect();
Some(files) files
} else { } else {
None Vec::new()
}; };
watch_arg_parse(flags, matches, false); watch_arg_parse(flags, matches, false);
flags.subcommand = DenoSubcommand::Bench(BenchFlags { flags.subcommand = DenoSubcommand::Bench(BenchFlags {
include, files: FileFlags { include, ignore },
ignore,
filter, filter,
}); });
} }
@ -2493,7 +2492,7 @@ fn fmt_parse(flags: &mut Flags, matches: &clap::ArgMatches) {
config_args_parse(flags, matches); config_args_parse(flags, matches);
watch_arg_parse(flags, matches, false); watch_arg_parse(flags, matches, false);
let files = match matches.values_of("files") { let include = match matches.values_of("files") {
Some(f) => f.map(PathBuf::from).collect(), Some(f) => f.map(PathBuf::from).collect(),
None => vec![], None => vec![],
}; };
@ -2544,8 +2543,7 @@ fn fmt_parse(flags: &mut Flags, matches: &clap::ArgMatches) {
flags.subcommand = DenoSubcommand::Fmt(FmtFlags { flags.subcommand = DenoSubcommand::Fmt(FmtFlags {
check: matches.is_present("check"), check: matches.is_present("check"),
ext, ext,
files, files: FileFlags { include, ignore },
ignore,
use_tabs, use_tabs,
line_width, line_width,
indent_width, indent_width,
@ -2647,12 +2645,15 @@ fn lint_parse(flags: &mut Flags, matches: &clap::ArgMatches) {
let json = matches.is_present("json"); let json = matches.is_present("json");
let compact = matches.is_present("compact"); let compact = matches.is_present("compact");
flags.subcommand = DenoSubcommand::Lint(LintFlags { flags.subcommand = DenoSubcommand::Lint(LintFlags {
files, files: FileFlags {
include: files,
ignore,
},
rules, rules,
maybe_rules_tags, maybe_rules_tags,
maybe_rules_include, maybe_rules_include,
maybe_rules_exclude, maybe_rules_exclude,
ignore,
json, json,
compact, compact,
}); });
@ -2811,12 +2812,9 @@ fn test_parse(flags: &mut Flags, matches: &clap::ArgMatches) {
let concurrent_jobs = if matches.is_present("parallel") { let concurrent_jobs = if matches.is_present("parallel") {
if let Ok(value) = env::var("DENO_JOBS") { if let Ok(value) = env::var("DENO_JOBS") {
value value.parse::<NonZeroUsize>().ok()
.parse::<NonZeroUsize>()
.unwrap_or(NonZeroUsize::new(1).unwrap())
} else { } else {
std::thread::available_parallelism() std::thread::available_parallelism().ok()
.unwrap_or(NonZeroUsize::new(1).unwrap())
} }
} else if matches.is_present("jobs") { } else if matches.is_present("jobs") {
// We can't change this to use the log crate because its not configured // We can't change this to use the log crate because its not configured
@ -2828,20 +2826,19 @@ fn test_parse(flags: &mut Flags, matches: &clap::ArgMatches) {
crate::colors::yellow("Warning: --jobs flag is deprecated. Use the --parallel flag with possibly the 'DENO_JOBS' environment variable."), crate::colors::yellow("Warning: --jobs flag is deprecated. Use the --parallel flag with possibly the 'DENO_JOBS' environment variable."),
); );
if let Some(value) = matches.value_of("jobs") { if let Some(value) = matches.value_of("jobs") {
value.parse().unwrap() Some(value.parse().unwrap())
} else { } else {
std::thread::available_parallelism() std::thread::available_parallelism().ok()
.unwrap_or(NonZeroUsize::new(1).unwrap())
} }
} else { } else {
NonZeroUsize::new(1).unwrap() None
}; };
let include: Vec<String> = if matches.is_present("files") { let include = if matches.is_present("files") {
matches matches
.values_of("files") .values_of("files")
.unwrap() .unwrap()
.map(String::from) .map(PathBuf::from)
.collect::<Vec<_>>() .collect::<Vec<_>>()
} else { } else {
Vec::new() Vec::new()
@ -2853,8 +2850,7 @@ fn test_parse(flags: &mut Flags, matches: &clap::ArgMatches) {
no_run, no_run,
doc, doc,
fail_fast, fail_fast,
include, files: FileFlags { include, ignore },
ignore,
filter, filter,
shuffle, shuffle,
allow_none, allow_none,
@ -3267,6 +3263,7 @@ mod tests {
fn global_flags() { fn global_flags() {
#[rustfmt::skip] #[rustfmt::skip]
let r = flags_from_vec(svec!["deno", "--unstable", "--log-level", "debug", "--quiet", "run", "script.ts"]); let r = flags_from_vec(svec!["deno", "--unstable", "--log-level", "debug", "--quiet", "run", "script.ts"]);
let flags = r.unwrap(); let flags = r.unwrap();
assert_eq!( assert_eq!(
flags, flags,
@ -3562,13 +3559,15 @@ mod tests {
r.unwrap(), r.unwrap(),
Flags { Flags {
subcommand: DenoSubcommand::Fmt(FmtFlags { subcommand: DenoSubcommand::Fmt(FmtFlags {
ignore: vec![],
check: false, check: false,
files: vec![ ext: "ts".to_string(),
files: FileFlags {
include: vec![
PathBuf::from("script_1.ts"), PathBuf::from("script_1.ts"),
PathBuf::from("script_2.ts") PathBuf::from("script_2.ts")
], ],
ext: "ts".to_string(), ignore: vec![],
},
use_tabs: None, use_tabs: None,
line_width: None, line_width: None,
indent_width: None, indent_width: None,
@ -3584,10 +3583,12 @@ mod tests {
r.unwrap(), r.unwrap(),
Flags { Flags {
subcommand: DenoSubcommand::Fmt(FmtFlags { subcommand: DenoSubcommand::Fmt(FmtFlags {
ignore: vec![],
check: true, check: true,
files: vec![],
ext: "ts".to_string(), ext: "ts".to_string(),
files: FileFlags {
include: vec![],
ignore: vec![],
},
use_tabs: None, use_tabs: None,
line_width: None, line_width: None,
indent_width: None, indent_width: None,
@ -3603,10 +3604,12 @@ mod tests {
r.unwrap(), r.unwrap(),
Flags { Flags {
subcommand: DenoSubcommand::Fmt(FmtFlags { subcommand: DenoSubcommand::Fmt(FmtFlags {
ignore: vec![],
check: false, check: false,
files: vec![],
ext: "ts".to_string(), ext: "ts".to_string(),
files: FileFlags {
include: vec![],
ignore: vec![],
},
use_tabs: None, use_tabs: None,
line_width: None, line_width: None,
indent_width: None, indent_width: None,
@ -3622,10 +3625,12 @@ mod tests {
r.unwrap(), r.unwrap(),
Flags { Flags {
subcommand: DenoSubcommand::Fmt(FmtFlags { subcommand: DenoSubcommand::Fmt(FmtFlags {
ignore: vec![],
check: false, check: false,
files: vec![],
ext: "ts".to_string(), ext: "ts".to_string(),
files: FileFlags {
include: vec![],
ignore: vec![],
},
use_tabs: None, use_tabs: None,
line_width: None, line_width: None,
indent_width: None, indent_width: None,
@ -3643,10 +3648,12 @@ mod tests {
r.unwrap(), r.unwrap(),
Flags { Flags {
subcommand: DenoSubcommand::Fmt(FmtFlags { subcommand: DenoSubcommand::Fmt(FmtFlags {
ignore: vec![],
check: false, check: false,
files: vec![],
ext: "ts".to_string(), ext: "ts".to_string(),
files: FileFlags {
include: vec![],
ignore: vec![],
},
use_tabs: None, use_tabs: None,
line_width: None, line_width: None,
indent_width: None, indent_width: None,
@ -3671,10 +3678,12 @@ mod tests {
r.unwrap(), r.unwrap(),
Flags { Flags {
subcommand: DenoSubcommand::Fmt(FmtFlags { subcommand: DenoSubcommand::Fmt(FmtFlags {
ignore: vec![PathBuf::from("bar.js")],
check: true, check: true,
files: vec![PathBuf::from("foo.ts")],
ext: "ts".to_string(), ext: "ts".to_string(),
files: FileFlags {
include: vec![PathBuf::from("foo.ts")],
ignore: vec![PathBuf::from("bar.js")],
},
use_tabs: None, use_tabs: None,
line_width: None, line_width: None,
indent_width: None, indent_width: None,
@ -3691,10 +3700,12 @@ mod tests {
r.unwrap(), r.unwrap(),
Flags { Flags {
subcommand: DenoSubcommand::Fmt(FmtFlags { subcommand: DenoSubcommand::Fmt(FmtFlags {
ignore: vec![],
check: false, check: false,
files: vec![],
ext: "ts".to_string(), ext: "ts".to_string(),
files: FileFlags {
include: vec![],
ignore: vec![],
},
use_tabs: None, use_tabs: None,
line_width: None, line_width: None,
indent_width: None, indent_width: None,
@ -3718,10 +3729,12 @@ mod tests {
r.unwrap(), r.unwrap(),
Flags { Flags {
subcommand: DenoSubcommand::Fmt(FmtFlags { subcommand: DenoSubcommand::Fmt(FmtFlags {
ignore: vec![],
check: false, check: false,
files: vec![PathBuf::from("foo.ts")],
ext: "ts".to_string(), ext: "ts".to_string(),
files: FileFlags {
include: vec![PathBuf::from("foo.ts")],
ignore: vec![],
},
use_tabs: None, use_tabs: None,
line_width: None, line_width: None,
indent_width: None, indent_width: None,
@ -3750,10 +3763,12 @@ mod tests {
r.unwrap(), r.unwrap(),
Flags { Flags {
subcommand: DenoSubcommand::Fmt(FmtFlags { subcommand: DenoSubcommand::Fmt(FmtFlags {
ignore: vec![],
check: false, check: false,
files: vec![],
ext: "ts".to_string(), ext: "ts".to_string(),
files: FileFlags {
include: vec![],
ignore: vec![],
},
use_tabs: Some(true), use_tabs: Some(true),
line_width: Some(NonZeroU32::new(60).unwrap()), line_width: Some(NonZeroU32::new(60).unwrap()),
indent_width: Some(NonZeroU8::new(4).unwrap()), indent_width: Some(NonZeroU8::new(4).unwrap()),
@ -3772,17 +3787,19 @@ mod tests {
r.unwrap(), r.unwrap(),
Flags { Flags {
subcommand: DenoSubcommand::Lint(LintFlags { subcommand: DenoSubcommand::Lint(LintFlags {
files: vec![ files: FileFlags {
include: vec![
PathBuf::from("script_1.ts"), PathBuf::from("script_1.ts"),
PathBuf::from("script_2.ts") PathBuf::from("script_2.ts")
], ],
ignore: vec![],
},
rules: false, rules: false,
maybe_rules_tags: None, maybe_rules_tags: None,
maybe_rules_include: None, maybe_rules_include: None,
maybe_rules_exclude: None, maybe_rules_exclude: None,
json: false, json: false,
compact: false, compact: false,
ignore: vec![],
}), }),
..Flags::default() ..Flags::default()
} }
@ -3799,17 +3816,19 @@ mod tests {
r.unwrap(), r.unwrap(),
Flags { Flags {
subcommand: DenoSubcommand::Lint(LintFlags { subcommand: DenoSubcommand::Lint(LintFlags {
files: vec![ files: FileFlags {
include: vec![
PathBuf::from("script_1.ts"), PathBuf::from("script_1.ts"),
PathBuf::from("script_2.ts") PathBuf::from("script_2.ts")
], ],
ignore: vec![],
},
rules: false, rules: false,
maybe_rules_tags: None, maybe_rules_tags: None,
maybe_rules_include: None, maybe_rules_include: None,
maybe_rules_exclude: None, maybe_rules_exclude: None,
json: false, json: false,
compact: false, compact: false,
ignore: vec![],
}), }),
watch: Some(vec![]), watch: Some(vec![]),
..Flags::default() ..Flags::default()
@ -3828,17 +3847,19 @@ mod tests {
r.unwrap(), r.unwrap(),
Flags { Flags {
subcommand: DenoSubcommand::Lint(LintFlags { subcommand: DenoSubcommand::Lint(LintFlags {
files: vec![ files: FileFlags {
include: vec![
PathBuf::from("script_1.ts"), PathBuf::from("script_1.ts"),
PathBuf::from("script_2.ts") PathBuf::from("script_2.ts")
], ],
ignore: vec![],
},
rules: false, rules: false,
maybe_rules_tags: None, maybe_rules_tags: None,
maybe_rules_include: None, maybe_rules_include: None,
maybe_rules_exclude: None, maybe_rules_exclude: None,
json: false, json: false,
compact: false, compact: false,
ignore: vec![],
}), }),
watch: Some(vec![]), watch: Some(vec![]),
no_clear_screen: true, no_clear_screen: true,
@ -3852,17 +3873,19 @@ mod tests {
r.unwrap(), r.unwrap(),
Flags { Flags {
subcommand: DenoSubcommand::Lint(LintFlags { subcommand: DenoSubcommand::Lint(LintFlags {
files: vec![], files: FileFlags {
include: vec![],
ignore: vec![
PathBuf::from("script_1.ts"),
PathBuf::from("script_2.ts")
],
},
rules: false, rules: false,
maybe_rules_tags: None, maybe_rules_tags: None,
maybe_rules_include: None, maybe_rules_include: None,
maybe_rules_exclude: None, maybe_rules_exclude: None,
json: false, json: false,
compact: false, compact: false,
ignore: vec![
PathBuf::from("script_1.ts"),
PathBuf::from("script_2.ts")
],
}), }),
..Flags::default() ..Flags::default()
} }
@ -3873,14 +3896,16 @@ mod tests {
r.unwrap(), r.unwrap(),
Flags { Flags {
subcommand: DenoSubcommand::Lint(LintFlags { subcommand: DenoSubcommand::Lint(LintFlags {
files: vec![], files: FileFlags {
include: vec![],
ignore: vec![],
},
rules: true, rules: true,
maybe_rules_tags: None, maybe_rules_tags: None,
maybe_rules_include: None, maybe_rules_include: None,
maybe_rules_exclude: None, maybe_rules_exclude: None,
json: false, json: false,
compact: false, compact: false,
ignore: vec![],
}), }),
..Flags::default() ..Flags::default()
} }
@ -3897,14 +3922,16 @@ mod tests {
r.unwrap(), r.unwrap(),
Flags { Flags {
subcommand: DenoSubcommand::Lint(LintFlags { subcommand: DenoSubcommand::Lint(LintFlags {
files: vec![], files: FileFlags {
include: vec![],
ignore: vec![],
},
rules: false, rules: false,
maybe_rules_tags: Some(svec![""]), maybe_rules_tags: Some(svec![""]),
maybe_rules_include: Some(svec!["ban-untagged-todo", "no-undef"]), maybe_rules_include: Some(svec!["ban-untagged-todo", "no-undef"]),
maybe_rules_exclude: Some(svec!["no-const-assign"]), maybe_rules_exclude: Some(svec!["no-const-assign"]),
json: false, json: false,
compact: false, compact: false,
ignore: vec![],
}), }),
..Flags::default() ..Flags::default()
} }
@ -3915,14 +3942,16 @@ mod tests {
r.unwrap(), r.unwrap(),
Flags { Flags {
subcommand: DenoSubcommand::Lint(LintFlags { subcommand: DenoSubcommand::Lint(LintFlags {
files: vec![PathBuf::from("script_1.ts")], files: FileFlags {
include: vec![PathBuf::from("script_1.ts")],
ignore: vec![],
},
rules: false, rules: false,
maybe_rules_tags: None, maybe_rules_tags: None,
maybe_rules_include: None, maybe_rules_include: None,
maybe_rules_exclude: None, maybe_rules_exclude: None,
json: true, json: true,
compact: false, compact: false,
ignore: vec![],
}), }),
..Flags::default() ..Flags::default()
} }
@ -3940,14 +3969,16 @@ mod tests {
r.unwrap(), r.unwrap(),
Flags { Flags {
subcommand: DenoSubcommand::Lint(LintFlags { subcommand: DenoSubcommand::Lint(LintFlags {
files: vec![PathBuf::from("script_1.ts")], files: FileFlags {
include: vec![PathBuf::from("script_1.ts")],
ignore: vec![],
},
rules: false, rules: false,
maybe_rules_tags: None, maybe_rules_tags: None,
maybe_rules_include: None, maybe_rules_include: None,
maybe_rules_exclude: None, maybe_rules_exclude: None,
json: true, json: true,
compact: false, compact: false,
ignore: vec![],
}), }),
config_flag: ConfigFlag::Path("Deno.jsonc".to_string()), config_flag: ConfigFlag::Path("Deno.jsonc".to_string()),
..Flags::default() ..Flags::default()
@ -3966,14 +3997,16 @@ mod tests {
r.unwrap(), r.unwrap(),
Flags { Flags {
subcommand: DenoSubcommand::Lint(LintFlags { subcommand: DenoSubcommand::Lint(LintFlags {
files: vec![PathBuf::from("script_1.ts")], files: FileFlags {
include: vec![PathBuf::from("script_1.ts")],
ignore: vec![],
},
rules: false, rules: false,
maybe_rules_tags: None, maybe_rules_tags: None,
maybe_rules_include: None, maybe_rules_include: None,
maybe_rules_exclude: None, maybe_rules_exclude: None,
json: false, json: false,
compact: true, compact: true,
ignore: vec![],
}), }),
config_flag: ConfigFlag::Path("Deno.jsonc".to_string()), config_flag: ConfigFlag::Path("Deno.jsonc".to_string()),
..Flags::default() ..Flags::default()
@ -5510,10 +5543,12 @@ mod tests {
fail_fast: None, fail_fast: None,
filter: Some("- foo".to_string()), filter: Some("- foo".to_string()),
allow_none: true, allow_none: true,
include: svec!["dir1/", "dir2/"], files: FileFlags {
include: vec![PathBuf::from("dir1/"), PathBuf::from("dir2/")],
ignore: vec![], ignore: vec![],
},
shuffle: None, shuffle: None,
concurrent_jobs: NonZeroUsize::new(1).unwrap(), concurrent_jobs: None,
trace_ops: true, trace_ops: true,
}), }),
unstable: true, unstable: true,
@ -5582,9 +5617,11 @@ mod tests {
filter: None, filter: None,
allow_none: false, allow_none: false,
shuffle: None, shuffle: None,
files: FileFlags {
include: vec![], include: vec![],
ignore: vec![], ignore: vec![],
concurrent_jobs: NonZeroUsize::new(4).unwrap(), },
concurrent_jobs: Some(NonZeroUsize::new(4).unwrap()),
trace_ops: false, trace_ops: false,
}), }),
type_check_mode: TypeCheckMode::Local, type_check_mode: TypeCheckMode::Local,
@ -5610,9 +5647,11 @@ mod tests {
filter: None, filter: None,
allow_none: false, allow_none: false,
shuffle: None, shuffle: None,
files: FileFlags {
include: vec![], include: vec![],
ignore: vec![], ignore: vec![],
concurrent_jobs: NonZeroUsize::new(1).unwrap(), },
concurrent_jobs: None,
trace_ops: false, trace_ops: false,
}), }),
type_check_mode: TypeCheckMode::Local, type_check_mode: TypeCheckMode::Local,
@ -5642,9 +5681,11 @@ mod tests {
filter: None, filter: None,
allow_none: false, allow_none: false,
shuffle: None, shuffle: None,
files: FileFlags {
include: vec![], include: vec![],
ignore: vec![], ignore: vec![],
concurrent_jobs: NonZeroUsize::new(1).unwrap(), },
concurrent_jobs: None,
trace_ops: false, trace_ops: false,
}), }),
no_prompt: true, no_prompt: true,
@ -5668,9 +5709,11 @@ mod tests {
filter: None, filter: None,
allow_none: false, allow_none: false,
shuffle: Some(1), shuffle: Some(1),
files: FileFlags {
include: vec![], include: vec![],
ignore: vec![], ignore: vec![],
concurrent_jobs: NonZeroUsize::new(1).unwrap(), },
concurrent_jobs: None,
trace_ops: false, trace_ops: false,
}), }),
no_prompt: true, no_prompt: true,
@ -5694,9 +5737,38 @@ mod tests {
filter: None, filter: None,
allow_none: false, allow_none: false,
shuffle: None, shuffle: None,
files: FileFlags {
include: vec![], include: vec![],
ignore: vec![], ignore: vec![],
concurrent_jobs: NonZeroUsize::new(1).unwrap(), },
concurrent_jobs: None,
trace_ops: false,
}),
no_prompt: true,
type_check_mode: TypeCheckMode::Local,
watch: Some(vec![]),
..Flags::default()
}
);
}
#[test]
fn test_watch_explicit_cwd() {
let r = flags_from_vec(svec!["deno", "test", "--watch", "./"]);
assert_eq!(
r.unwrap(),
Flags {
subcommand: DenoSubcommand::Test(TestFlags {
no_run: false,
doc: false,
fail_fast: None,
filter: None,
allow_none: false,
shuffle: None,
files: FileFlags {
include: vec![PathBuf::from("./")],
ignore: vec![],
},
concurrent_jobs: None,
trace_ops: false, trace_ops: false,
}), }),
no_prompt: true, no_prompt: true,
@ -5721,9 +5793,11 @@ mod tests {
filter: None, filter: None,
allow_none: false, allow_none: false,
shuffle: None, shuffle: None,
files: FileFlags {
include: vec![], include: vec![],
ignore: vec![], ignore: vec![],
concurrent_jobs: NonZeroUsize::new(1).unwrap(), },
concurrent_jobs: None,
trace_ops: false, trace_ops: false,
}), }),
watch: Some(vec![]), watch: Some(vec![]),
@ -6372,8 +6446,10 @@ mod tests {
Flags { Flags {
subcommand: DenoSubcommand::Bench(BenchFlags { subcommand: DenoSubcommand::Bench(BenchFlags {
filter: Some("- foo".to_string()), filter: Some("- foo".to_string()),
include: Some(svec!["dir1/", "dir2/"]), files: FileFlags {
include: vec![PathBuf::from("dir1/"), PathBuf::from("dir2/")],
ignore: vec![], ignore: vec![],
},
}), }),
unstable: true, unstable: true,
type_check_mode: TypeCheckMode::Local, type_check_mode: TypeCheckMode::Local,
@ -6386,6 +6462,27 @@ mod tests {
); );
} }
#[test]
fn bench_watch() {
let r = flags_from_vec(svec!["deno", "bench", "--watch"]);
assert_eq!(
r.unwrap(),
Flags {
subcommand: DenoSubcommand::Bench(BenchFlags {
filter: None,
files: FileFlags {
include: vec![],
ignore: vec![],
},
}),
no_prompt: true,
type_check_mode: TypeCheckMode::Local,
watch: Some(vec![]),
..Flags::default()
}
);
}
#[test] #[test]
fn run_with_check() { fn run_with_check() {
let r = flags_from_vec(svec!["deno", "run", "--check", "script.ts",]); let r = flags_from_vec(svec!["deno", "run", "--check", "script.ts",]);

View file

@ -10,23 +10,15 @@ pub use config_file::BenchConfig;
pub use config_file::CompilerOptions; pub use config_file::CompilerOptions;
pub use config_file::ConfigFile; pub use config_file::ConfigFile;
pub use config_file::EmitConfigOptions; pub use config_file::EmitConfigOptions;
pub use config_file::FmtConfig; pub use config_file::FilesConfig;
pub use config_file::FmtOptionsConfig; pub use config_file::FmtOptionsConfig;
pub use config_file::IgnoredCompilerOptions;
pub use config_file::JsxImportSourceConfig; pub use config_file::JsxImportSourceConfig;
pub use config_file::LintConfig;
pub use config_file::LintRulesConfig; pub use config_file::LintRulesConfig;
pub use config_file::MaybeImportsResult;
pub use config_file::ProseWrap; pub use config_file::ProseWrap;
pub use config_file::TestConfig;
pub use config_file::TsConfig; pub use config_file::TsConfig;
pub use config_file::TsConfigForEmit; pub use config_file::TsConfigForEmit;
pub use config_file::TsConfigType; pub use config_file::TsConfigType;
pub use config_file::TsTypeLib; pub use config_file::TsTypeLib;
use deno_runtime::deno_tls::rustls;
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;
pub use flags::*; pub use flags::*;
pub use lockfile::Lockfile; pub use lockfile::Lockfile;
pub use lockfile::LockfileError; pub use lockfile::LockfileError;
@ -40,13 +32,18 @@ use deno_core::normalize_path;
use deno_core::parking_lot::Mutex; use deno_core::parking_lot::Mutex;
use deno_core::url::Url; use deno_core::url::Url;
use deno_runtime::colors; use deno_runtime::colors;
use deno_runtime::deno_tls::rustls;
use deno_runtime::deno_tls::rustls::RootCertStore; use deno_runtime::deno_tls::rustls::RootCertStore;
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;
use deno_runtime::inspector_server::InspectorServer; use deno_runtime::inspector_server::InspectorServer;
use deno_runtime::permissions::PermissionsOptions; use deno_runtime::permissions::PermissionsOptions;
use std::collections::BTreeMap; use std::collections::BTreeMap;
use std::env; use std::env;
use std::io::BufReader; use std::io::BufReader;
use std::net::SocketAddr; use std::net::SocketAddr;
use std::num::NonZeroUsize;
use std::path::PathBuf; use std::path::PathBuf;
use std::sync::Arc; use std::sync::Arc;
@ -54,6 +51,11 @@ use crate::cache::DenoDir;
use crate::util::fs::canonicalize_path_maybe_not_exists; use crate::util::fs::canonicalize_path_maybe_not_exists;
use crate::version; use crate::version;
use self::config_file::FmtConfig;
use self::config_file::LintConfig;
use self::config_file::MaybeImportsResult;
use self::config_file::TestConfig;
/// Indicates how cached source files should be handled. /// Indicates how cached source files should be handled.
#[derive(Debug, Clone, Eq, PartialEq)] #[derive(Debug, Clone, Eq, PartialEq)]
pub enum CacheSetting { pub enum CacheSetting {
@ -95,6 +97,274 @@ impl CacheSetting {
} }
} }
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct BenchOptions {
pub files: FilesConfig,
pub filter: Option<String>,
}
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),
),
filter: bench_flags.filter,
})
}
}
#[derive(Clone, Debug, Default)]
pub struct FmtOptions {
pub is_stdin: bool,
pub check: bool,
pub ext: String,
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),
ext: maybe_fmt_flags
.as_ref()
.map(|f| f.ext.to_string())
.unwrap_or_else(|| "ts".to_string()),
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),
),
})
}
}
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!(),
});
}
}
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),
),
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,
})
}
}
#[derive(Clone, Debug)]
pub enum LintReporterKind {
Pretty,
Json,
Compact,
}
impl Default for LintReporterKind {
fn default() -> Self {
LintReporterKind::Pretty
}
}
#[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,
files: resolve_files(maybe_config_files, Some(maybe_file_flags)),
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,
}
}
/// Create and populate a root cert store based on the passed options and /// Create and populate a root cert store based on the passed options and
/// environment. /// environment.
pub fn get_root_cert_store( pub fn get_root_cert_store(
@ -394,36 +664,57 @@ impl CliOptions {
} }
} }
pub fn to_lint_config(&self) -> Result<Option<LintConfig>, AnyError> { pub fn get_maybe_config_file(&self) -> &Option<ConfigFile> {
if let Some(config_file) = &self.maybe_config_file { &self.maybe_config_file
config_file.to_lint_config()
} else {
Ok(None)
}
} }
pub fn to_test_config(&self) -> Result<Option<TestConfig>, AnyError> { pub fn resolve_fmt_options(
if let Some(config_file) = &self.maybe_config_file { &self,
config_file.to_test_config() fmt_flags: FmtFlags,
) -> Result<FmtOptions, AnyError> {
let maybe_fmt_config = if let Some(config_file) = &self.maybe_config_file {
config_file.to_fmt_config()?
} else { } else {
Ok(None) None
} };
FmtOptions::resolve(maybe_fmt_config, Some(fmt_flags))
} }
pub fn to_bench_config(&self) -> Result<Option<BenchConfig>, AnyError> { pub fn resolve_lint_options(
if let Some(config_file) = &self.maybe_config_file { &self,
config_file.to_bench_config() lint_flags: LintFlags,
) -> Result<LintOptions, AnyError> {
let maybe_lint_config = if let Some(config_file) = &self.maybe_config_file {
config_file.to_lint_config()?
} else { } else {
Ok(None) None
} };
LintOptions::resolve(maybe_lint_config, Some(lint_flags))
} }
pub fn to_fmt_config(&self) -> Result<Option<FmtConfig>, AnyError> { pub fn resolve_test_options(
if let Some(config) = &self.maybe_config_file { &self,
config.to_fmt_config() test_flags: TestFlags,
) -> Result<TestOptions, AnyError> {
let maybe_test_config = if let Some(config_file) = &self.maybe_config_file {
config_file.to_test_config()?
} else { } else {
Ok(None) None
};
TestOptions::resolve(maybe_test_config, Some(test_flags))
} }
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()?
} else {
None
};
BenchOptions::resolve(maybe_bench_config, Some(bench_flags))
} }
/// Vector of user script CLI arguments. /// Vector of user script CLI arguments.
@ -639,6 +930,25 @@ fn resolve_import_map_specifier(
Ok(None) Ok(None)
} }
/// 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>,
) -> FilesConfig {
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;
}
}
result
}
/// Resolves the no_prompt value based on the cli flags and environment. /// Resolves the no_prompt value based on the cli flags and environment.
pub fn resolve_no_prompt(flags: &Flags) -> bool { pub fn resolve_no_prompt(flags: &Flags) -> bool {
flags.no_prompt || { flags.no_prompt || {

View file

@ -5,9 +5,7 @@ use super::documents::Documents;
use super::language_server; use super::language_server;
use super::tsc; use super::tsc;
use crate::args::LintConfig;
use crate::tools::lint::create_linter; use crate::tools::lint::create_linter;
use crate::tools::lint::get_configured_rules;
use deno_ast::SourceRange; use deno_ast::SourceRange;
use deno_ast::SourceRangedForSpanned; use deno_ast::SourceRangedForSpanned;
@ -18,10 +16,12 @@ use deno_core::error::AnyError;
use deno_core::serde::Deserialize; use deno_core::serde::Deserialize;
use deno_core::serde_json::json; use deno_core::serde_json::json;
use deno_core::ModuleSpecifier; use deno_core::ModuleSpecifier;
use deno_lint::rules::LintRule;
use once_cell::sync::Lazy; use once_cell::sync::Lazy;
use regex::Regex; use regex::Regex;
use std::cmp::Ordering; use std::cmp::Ordering;
use std::collections::HashMap; use std::collections::HashMap;
use std::sync::Arc;
use tower_lsp::lsp_types as lsp; use tower_lsp::lsp_types as lsp;
use tower_lsp::lsp_types::Position; use tower_lsp::lsp_types::Position;
use tower_lsp::lsp_types::Range; use tower_lsp::lsp_types::Range;
@ -127,9 +127,8 @@ fn as_lsp_range(range: &deno_lint::diagnostic::Range) -> Range {
pub fn get_lint_references( pub fn get_lint_references(
parsed_source: &deno_ast::ParsedSource, parsed_source: &deno_ast::ParsedSource,
maybe_lint_config: Option<&LintConfig>, lint_rules: Vec<Arc<dyn LintRule>>,
) -> Result<Vec<Reference>, AnyError> { ) -> Result<Vec<Reference>, AnyError> {
let lint_rules = get_configured_rules(maybe_lint_config, None, None, None)?;
let linter = create_linter(parsed_source.media_type(), lint_rules); let linter = create_linter(parsed_source.media_type(), lint_rules);
let lint_diagnostics = linter.lint_with_ast(parsed_source); let lint_diagnostics = linter.lint_with_ast(parsed_source);

View file

@ -12,8 +12,9 @@ use super::performance::Performance;
use super::tsc; use super::tsc;
use super::tsc::TsServer; use super::tsc::TsServer;
use crate::args::LintConfig; use crate::args::LintOptions;
use crate::npm::NpmPackageReference; use crate::npm::NpmPackageReference;
use crate::tools::lint::get_configured_rules;
use deno_ast::MediaType; use deno_ast::MediaType;
use deno_core::anyhow::anyhow; use deno_core::anyhow::anyhow;
@ -24,6 +25,7 @@ use deno_core::serde_json;
use deno_core::serde_json::json; use deno_core::serde_json::json;
use deno_core::ModuleSpecifier; use deno_core::ModuleSpecifier;
use deno_graph::Resolved; use deno_graph::Resolved;
use deno_lint::rules::LintRule;
use deno_runtime::tokio_util::create_basic_runtime; use deno_runtime::tokio_util::create_basic_runtime;
use log::error; use log::error;
use std::collections::HashMap; use std::collections::HashMap;
@ -36,7 +38,7 @@ use tokio_util::sync::CancellationToken;
use tower_lsp::lsp_types as lsp; use tower_lsp::lsp_types as lsp;
pub type SnapshotForDiagnostics = pub type SnapshotForDiagnostics =
(Arc<StateSnapshot>, Arc<ConfigSnapshot>, Option<LintConfig>); (Arc<StateSnapshot>, Arc<ConfigSnapshot>, LintOptions);
pub type DiagnosticRecord = pub type DiagnosticRecord =
(ModuleSpecifier, Option<i32>, Vec<lsp::Diagnostic>); (ModuleSpecifier, Option<i32>, Vec<lsp::Diagnostic>);
pub type DiagnosticVec = Vec<DiagnosticRecord>; pub type DiagnosticVec = Vec<DiagnosticRecord>;
@ -198,7 +200,7 @@ impl DiagnosticsServer {
match rx.recv().await { match rx.recv().await {
// channel has closed // channel has closed
None => break, None => break,
Some((snapshot, config, maybe_lint_config)) => { Some((snapshot, config, lint_options)) => {
// cancel the previous run // cancel the previous run
token.cancel(); token.cancel();
token = CancellationToken::new(); token = CancellationToken::new();
@ -300,7 +302,7 @@ impl DiagnosticsServer {
let diagnostics = generate_lint_diagnostics( let diagnostics = generate_lint_diagnostics(
&snapshot, &snapshot,
&config, &config,
maybe_lint_config, &lint_options,
token.clone(), token.clone(),
) )
.await; .await;
@ -443,12 +445,12 @@ fn ts_json_to_diagnostics(
async fn generate_lint_diagnostics( async fn generate_lint_diagnostics(
snapshot: &language_server::StateSnapshot, snapshot: &language_server::StateSnapshot,
config: &ConfigSnapshot, config: &ConfigSnapshot,
maybe_lint_config: Option<LintConfig>, lint_options: &LintOptions,
token: CancellationToken, token: CancellationToken,
) -> DiagnosticVec { ) -> DiagnosticVec {
let documents = snapshot.documents.documents(true, true); let documents = snapshot.documents.documents(true, true);
let workspace_settings = config.settings.workspace.clone(); let workspace_settings = config.settings.workspace.clone();
let lint_rules = get_configured_rules(lint_options.rules.clone());
let mut diagnostics_vec = Vec::new(); let mut diagnostics_vec = Vec::new();
if workspace_settings.lint { if workspace_settings.lint {
for document in documents { for document in documents {
@ -470,7 +472,8 @@ async fn generate_lint_diagnostics(
version, version,
generate_document_lint_diagnostics( generate_document_lint_diagnostics(
config, config,
&maybe_lint_config, lint_options,
lint_rules.clone(),
&document, &document,
), ),
)); ));
@ -481,23 +484,21 @@ async fn generate_lint_diagnostics(
fn generate_document_lint_diagnostics( fn generate_document_lint_diagnostics(
config: &ConfigSnapshot, config: &ConfigSnapshot,
maybe_lint_config: &Option<LintConfig>, lint_options: &LintOptions,
lint_rules: Vec<Arc<dyn LintRule>>,
document: &Document, document: &Document,
) -> Vec<lsp::Diagnostic> { ) -> Vec<lsp::Diagnostic> {
if !config.specifier_enabled(document.specifier()) { if !config.specifier_enabled(document.specifier()) {
return Vec::new(); return Vec::new();
} }
if let Some(lint_config) = &maybe_lint_config { if !lint_options.files.matches_specifier(document.specifier()) {
if !lint_config.files.matches_specifier(document.specifier()) {
return Vec::new(); return Vec::new();
} }
}
match document.maybe_parsed_source() { match document.maybe_parsed_source() {
Some(Ok(parsed_source)) => { Some(Ok(parsed_source)) => {
if let Ok(references) = analysis::get_lint_references( if let Ok(references) =
&parsed_source, analysis::get_lint_references(&parsed_source, lint_rules)
maybe_lint_config.as_ref(), {
) {
references references
.into_iter() .into_iter()
.map(|r| r.to_diagnostic()) .map(|r| r.to_diagnostic())
@ -1080,7 +1081,7 @@ let c: number = "a";
let diagnostics = generate_lint_diagnostics( let diagnostics = generate_lint_diagnostics(
&snapshot, &snapshot,
&enabled_config, &enabled_config,
None, &Default::default(),
Default::default(), Default::default(),
) )
.await; .await;
@ -1121,7 +1122,7 @@ let c: number = "a";
let diagnostics = generate_lint_diagnostics( let diagnostics = generate_lint_diagnostics(
&snapshot, &snapshot,
&disabled_config, &disabled_config,
None, &Default::default(),
Default::default(), Default::default(),
) )
.await; .await;

View file

@ -62,8 +62,8 @@ use crate::args::CacheSetting;
use crate::args::CliOptions; use crate::args::CliOptions;
use crate::args::ConfigFile; use crate::args::ConfigFile;
use crate::args::Flags; use crate::args::Flags;
use crate::args::FmtConfig; use crate::args::FmtOptions;
use crate::args::LintConfig; use crate::args::LintOptions;
use crate::args::TsConfig; use crate::args::TsConfig;
use crate::cache::DenoDir; use crate::cache::DenoDir;
use crate::file_fetcher::get_source_from_data_url; use crate::file_fetcher::get_source_from_data_url;
@ -122,14 +122,14 @@ pub struct Inner {
/// An optional configuration file which has been specified in the client /// An optional configuration file which has been specified in the client
/// options. /// options.
maybe_config_file: Option<ConfigFile>, maybe_config_file: Option<ConfigFile>,
/// An optional configuration for formatter which has been taken from specified config file.
maybe_fmt_config: Option<FmtConfig>,
/// An optional import map which is used to resolve modules. /// An optional import map which is used to resolve modules.
pub maybe_import_map: Option<Arc<ImportMap>>, pub maybe_import_map: Option<Arc<ImportMap>>,
/// The URL for the import map which is used to determine relative imports. /// The URL for the import map which is used to determine relative imports.
maybe_import_map_uri: Option<Url>, maybe_import_map_uri: Option<Url>,
/// Configuration for formatter which has been taken from specified config file.
fmt_options: FmtOptions,
/// An optional configuration for linter which has been taken from specified config file. /// An optional configuration for linter which has been taken from specified config file.
pub maybe_lint_config: Option<LintConfig>, lint_options: LintOptions,
/// A lazily create "server" for handling test run requests. /// A lazily create "server" for handling test run requests.
maybe_testing_server: Option<testing::TestServer>, maybe_testing_server: Option<testing::TestServer>,
/// Resolver for npm packages. /// Resolver for npm packages.
@ -347,8 +347,8 @@ impl Inner {
maybe_config_file: None, maybe_config_file: None,
maybe_import_map: None, maybe_import_map: None,
maybe_import_map_uri: None, maybe_import_map_uri: None,
maybe_lint_config: None, fmt_options: Default::default(),
maybe_fmt_config: None, lint_options: Default::default(),
maybe_testing_server: None, maybe_testing_server: None,
module_registries, module_registries,
module_registries_location, module_registries_location,
@ -713,26 +713,30 @@ impl Inner {
fn update_config_file(&mut self) -> Result<(), AnyError> { fn update_config_file(&mut self) -> Result<(), AnyError> {
self.maybe_config_file = None; self.maybe_config_file = None;
self.maybe_fmt_config = None; self.fmt_options = Default::default();
self.maybe_lint_config = None; self.lint_options = Default::default();
if let Some(config_file) = self.get_config_file()? { if let Some(config_file) = self.get_config_file()? {
let lint_config = config_file let lint_options = config_file
.to_lint_config() .to_lint_config()
.and_then(|maybe_lint_config| {
LintOptions::resolve(maybe_lint_config, None)
})
.map_err(|err| { .map_err(|err| {
anyhow!("Unable to update lint configuration: {:?}", err) anyhow!("Unable to update lint configuration: {:?}", err)
})? })?;
.unwrap_or_default(); let fmt_options = config_file
let fmt_config = config_file
.to_fmt_config() .to_fmt_config()
.and_then(|maybe_fmt_config| {
FmtOptions::resolve(maybe_fmt_config, None)
})
.map_err(|err| { .map_err(|err| {
anyhow!("Unable to update formatter configuration: {:?}", err) anyhow!("Unable to update formatter configuration: {:?}", err)
})? })?;
.unwrap_or_default();
self.maybe_config_file = Some(config_file); self.maybe_config_file = Some(config_file);
self.maybe_lint_config = Some(lint_config); self.lint_options = lint_options;
self.maybe_fmt_config = Some(fmt_config); self.fmt_options = fmt_options;
} }
Ok(()) Ok(())
@ -1196,19 +1200,14 @@ impl Inner {
LspError::invalid_request() LspError::invalid_request()
})?; })?;
let fmt_options = if let Some(fmt_config) = self.maybe_fmt_config.as_ref() {
// skip formatting any files ignored by the config file // skip formatting any files ignored by the config file
if !fmt_config.files.matches_specifier(&specifier) { if !self.fmt_options.files.matches_specifier(&specifier) {
return Ok(None); return Ok(None);
} }
fmt_config.options.clone()
} else {
Default::default()
};
let format_result = match document.maybe_parsed_source() { let format_result = match document.maybe_parsed_source() {
Some(Ok(parsed_source)) => { Some(Ok(parsed_source)) => {
format_parsed_source(&parsed_source, fmt_options) format_parsed_source(&parsed_source, &self.fmt_options.options)
} }
Some(Err(err)) => Err(anyhow!("{}", err)), Some(Err(err)) => Err(anyhow!("{}", err)),
None => { None => {
@ -1221,7 +1220,7 @@ impl Inner {
.map(|ext| file_path.with_extension(ext)) .map(|ext| file_path.with_extension(ext))
.unwrap_or(file_path); .unwrap_or(file_path);
// it's not a js/ts file, so attempt to format its contents // it's not a js/ts file, so attempt to format its contents
format_file(&file_path, &document.content(), &fmt_options) format_file(&file_path, &document.content(), &self.fmt_options.options)
} }
}; };
@ -2521,7 +2520,7 @@ impl Inner {
let snapshot = ( let snapshot = (
self.snapshot(), self.snapshot(),
self.config.snapshot(), self.config.snapshot(),
self.maybe_lint_config.clone(), self.lint_options.clone(),
); );
if let Err(err) = self.diagnostics_server.update(snapshot) { if let Err(err) = self.diagnostics_server.update(snapshot) {
error!("Cannot update diagnostics: {}", err); error!("Cannot update diagnostics: {}", err);

View file

@ -35,6 +35,7 @@ use deno_runtime::tokio_util::run_local;
use indexmap::IndexMap; use indexmap::IndexMap;
use std::collections::HashMap; use std::collections::HashMap;
use std::collections::HashSet; use std::collections::HashSet;
use std::num::NonZeroUsize;
use std::sync::Arc; use std::sync::Arc;
use std::time::Duration; use std::time::Duration;
use std::time::Instant; use std::time::Instant;
@ -273,7 +274,13 @@ impl TestRun {
let (concurrent_jobs, fail_fast) = let (concurrent_jobs, fail_fast) =
if let DenoSubcommand::Test(test_flags) = ps.options.sub_command() { if let DenoSubcommand::Test(test_flags) = ps.options.sub_command() {
(test_flags.concurrent_jobs.into(), test_flags.fail_fast) (
test_flags
.concurrent_jobs
.unwrap_or_else(|| NonZeroUsize::new(1).unwrap())
.into(),
test_flags.fail_fast,
)
} else { } else {
unreachable!("Should always be Test subcommand."); unreachable!("Should always be Test subcommand.");
}; };

View file

@ -71,10 +71,13 @@ fn init_v8_flags(v8_flags: &[String]) {
async fn run_subcommand(flags: Flags) -> Result<i32, AnyError> { async fn run_subcommand(flags: Flags) -> Result<i32, AnyError> {
match flags.subcommand.clone() { match flags.subcommand.clone() {
DenoSubcommand::Bench(bench_flags) => { DenoSubcommand::Bench(bench_flags) => {
if flags.watch.is_some() { let cli_options = CliOptions::from_flags(flags)?;
tools::bench::run_benchmarks_with_watch(flags, bench_flags).await?; let bench_options = cli_options.resolve_bench_options(bench_flags)?;
if cli_options.watch_paths().is_some() {
tools::bench::run_benchmarks_with_watch(cli_options, bench_options)
.await?;
} else { } else {
tools::bench::run_benchmarks(flags, bench_flags).await?; tools::bench::run_benchmarks(cli_options, bench_options).await?;
} }
Ok(0) Ok(0)
} }
@ -109,19 +112,9 @@ async fn run_subcommand(flags: Flags) -> Result<i32, AnyError> {
Ok(0) Ok(0)
} }
DenoSubcommand::Fmt(fmt_flags) => { DenoSubcommand::Fmt(fmt_flags) => {
let config = CliOptions::from_flags(flags)?; let cli_options = CliOptions::from_flags(flags)?;
let fmt_options = cli_options.resolve_fmt_options(fmt_flags)?;
if fmt_flags.files.len() == 1 tools::fmt::format(cli_options, fmt_options).await?;
&& fmt_flags.files[0].to_string_lossy() == "-"
{
let maybe_fmt_config = config.to_fmt_config()?;
tools::fmt::format_stdin(
fmt_flags,
maybe_fmt_config.map(|c| c.options).unwrap_or_default(),
)?;
} else {
tools::fmt::format(&config, fmt_flags).await?;
}
Ok(0) Ok(0)
} }
DenoSubcommand::Init(init_flags) => { DenoSubcommand::Init(init_flags) => {
@ -148,7 +141,9 @@ async fn run_subcommand(flags: Flags) -> Result<i32, AnyError> {
if lint_flags.rules { if lint_flags.rules {
tools::lint::print_rules_list(lint_flags.json); tools::lint::print_rules_list(lint_flags.json);
} else { } else {
tools::lint::lint(flags, lint_flags).await?; let cli_options = CliOptions::from_flags(flags)?;
let lint_options = cli_options.resolve_lint_options(lint_flags)?;
tools::lint::lint(cli_options, lint_options).await?;
} }
Ok(0) Ok(0)
} }
@ -176,11 +171,13 @@ async fn run_subcommand(flags: Flags) -> Result<i32, AnyError> {
PathBuf::from(coverage_dir).canonicalize()?, PathBuf::from(coverage_dir).canonicalize()?,
); );
} }
let cli_options = CliOptions::from_flags(flags)?;
let test_options = cli_options.resolve_test_options(test_flags)?;
if flags.watch.is_some() { if cli_options.watch_paths().is_some() {
tools::test::run_tests_with_watch(flags, test_flags).await?; tools::test::run_tests_with_watch(cli_options, test_options).await?;
} else { } else {
tools::test::run_tests(flags, test_flags).await?; tools::test::run_tests(cli_options, test_options).await?;
} }
Ok(0) Ok(0)

View file

@ -1,8 +1,7 @@
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license. // Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
use crate::args::BenchConfig; use crate::args::BenchOptions;
use crate::args::BenchFlags; use crate::args::CliOptions;
use crate::args::Flags;
use crate::args::TypeCheckMode; use crate::args::TypeCheckMode;
use crate::colors; use crate::colors;
use crate::graph_util::contains_specifier; use crate::graph_util::contains_specifier;
@ -15,7 +14,6 @@ use crate::util::file_watcher;
use crate::util::file_watcher::ResolutionResult; use crate::util::file_watcher::ResolutionResult;
use crate::util::fs::collect_specifiers; use crate::util::fs::collect_specifiers;
use crate::util::path::is_supported_ext; use crate::util::path::is_supported_ext;
use crate::util::path::specifier_to_file_path;
use crate::worker::create_main_worker_for_test_or_bench; use crate::worker::create_main_worker_for_test_or_bench;
use deno_core::error::generic_error; use deno_core::error::generic_error;
@ -37,6 +35,7 @@ use serde::Serialize;
use std::collections::HashSet; use std::collections::HashSet;
use std::path::Path; use std::path::Path;
use std::path::PathBuf; use std::path::PathBuf;
use std::sync::Arc;
use tokio::sync::mpsc::unbounded_channel; use tokio::sync::mpsc::unbounded_channel;
use tokio::sync::mpsc::UnboundedSender; use tokio::sync::mpsc::UnboundedSender;
@ -487,24 +486,18 @@ fn is_supported_bench_path(path: &Path) -> bool {
} }
pub async fn run_benchmarks( pub async fn run_benchmarks(
flags: Flags, cli_options: CliOptions,
bench_flags: BenchFlags, bench_options: BenchOptions,
) -> Result<(), AnyError> { ) -> Result<(), AnyError> {
let ps = ProcState::build(flags).await?; let ps = ProcState::from_options(Arc::new(cli_options)).await?;
// Various bench files should not share the same permissions in terms of // Various bench files should not share the same permissions in terms of
// `PermissionsContainer` - otherwise granting/revoking permissions in one // `PermissionsContainer` - otherwise granting/revoking permissions in one
// file would have impact on other files, which is undesirable. // file would have impact on other files, which is undesirable.
let permissions = let permissions =
Permissions::from_options(&ps.options.permissions_options())?; Permissions::from_options(&ps.options.permissions_options())?;
let selection = let specifiers =
collect_include_ignore(&bench_flags, ps.options.to_bench_config()?); collect_specifiers(&bench_options.files, is_supported_bench_path)?;
let specifiers = collect_specifiers(
selection.include,
&selection.ignore,
is_supported_bench_path,
)?;
if specifiers.is_empty() { if specifiers.is_empty() {
return Err(generic_error("No bench modules found")); return Err(generic_error("No bench modules found"));
@ -517,7 +510,7 @@ pub async fn run_benchmarks(
permissions, permissions,
specifiers, specifiers,
BenchSpecifierOptions { BenchSpecifierOptions {
filter: bench_flags.filter, filter: bench_options.filter,
}, },
) )
.await?; .await?;
@ -527,21 +520,22 @@ pub async fn run_benchmarks(
// TODO(bartlomieju): heavy duplication of code with `cli/tools/test.rs` // TODO(bartlomieju): heavy duplication of code with `cli/tools/test.rs`
pub async fn run_benchmarks_with_watch( pub async fn run_benchmarks_with_watch(
flags: Flags, cli_options: CliOptions,
bench_flags: BenchFlags, bench_options: BenchOptions,
) -> Result<(), AnyError> { ) -> Result<(), AnyError> {
let ps = ProcState::build(flags).await?; let ps = ProcState::from_options(Arc::new(cli_options)).await?;
// Various bench files should not share the same permissions in terms of // Various bench files should not share the same permissions in terms of
// `PermissionsContainer` - otherwise granting/revoking permissions in one // `PermissionsContainer` - otherwise granting/revoking permissions in one
// file would have impact on other files, which is undesirable. // file would have impact on other files, which is undesirable.
let permissions = let permissions =
Permissions::from_options(&ps.options.permissions_options())?; Permissions::from_options(&ps.options.permissions_options())?;
let selection = let paths_to_watch: Vec<_> = bench_options
collect_include_ignore(&bench_flags, ps.options.to_bench_config()?); .files
.include
let paths_to_watch: Vec<_> = .iter()
selection.include.iter().map(PathBuf::from).collect(); .map(PathBuf::from)
.collect();
let no_check = ps.options.type_check_mode() == TypeCheckMode::None; let no_check = ps.options.type_check_mode() == TypeCheckMode::None;
let resolver = |changed: Option<Vec<PathBuf>>| { let resolver = |changed: Option<Vec<PathBuf>>| {
@ -549,13 +543,11 @@ pub async fn run_benchmarks_with_watch(
let paths_to_watch_clone = paths_to_watch.clone(); let paths_to_watch_clone = paths_to_watch.clone();
let files_changed = changed.is_some(); let files_changed = changed.is_some();
let include = selection.include.clone(); let files = bench_options.files.clone();
let ignore = selection.ignore.clone();
let ps = ps.clone(); let ps = ps.clone();
async move { async move {
let bench_modules = let bench_modules = collect_specifiers(&files, is_supported_bench_path)?;
collect_specifiers(include.clone(), &ignore, is_supported_bench_path)?;
let mut paths_to_watch = paths_to_watch_clone; let mut paths_to_watch = paths_to_watch_clone;
let mut modules_to_reload = if files_changed { let mut modules_to_reload = if files_changed {
@ -615,7 +607,6 @@ pub async fn run_benchmarks_with_watch(
} }
} }
} }
// This bench module and all it's dependencies // This bench module and all it's dependencies
let mut modules = HashSet::new(); let mut modules = HashSet::new();
modules.insert(&specifier); modules.insert(&specifier);
@ -664,15 +655,13 @@ pub async fn run_benchmarks_with_watch(
}; };
let operation = |modules_to_reload: Vec<(ModuleSpecifier, ModuleKind)>| { let operation = |modules_to_reload: Vec<(ModuleSpecifier, ModuleKind)>| {
let filter = bench_flags.filter.clone();
let include = selection.include.clone();
let ignore = selection.ignore.clone();
let permissions = permissions.clone(); let permissions = permissions.clone();
let ps = ps.clone(); let ps = ps.clone();
let filter = bench_options.filter.clone();
let files = bench_options.files.clone();
async move { async move {
let specifiers = let specifiers = collect_specifiers(&files, is_supported_bench_path)?
collect_specifiers(include.clone(), &ignore, is_supported_bench_path)?
.iter() .iter()
.filter(|specifier| contains_specifier(&modules_to_reload, specifier)) .filter(|specifier| contains_specifier(&modules_to_reload, specifier))
.cloned() .cloned()
@ -680,10 +669,12 @@ pub async fn run_benchmarks_with_watch(
check_specifiers(&ps, permissions.clone(), specifiers.clone()).await?; check_specifiers(&ps, permissions.clone(), specifiers.clone()).await?;
let specifier_options = BenchSpecifierOptions { bench_specifiers(
filter: filter.clone(), ps,
}; permissions.clone(),
bench_specifiers(ps, permissions.clone(), specifiers, specifier_options) specifiers,
BenchSpecifierOptions { filter },
)
.await?; .await?;
Ok(()) Ok(())
@ -702,42 +693,3 @@ pub async fn run_benchmarks_with_watch(
Ok(()) Ok(())
} }
struct IncludeIgnoreCollection {
include: Vec<String>,
ignore: Vec<PathBuf>,
}
fn collect_include_ignore(
bench_flags: &BenchFlags,
maybe_bench_config: Option<BenchConfig>,
) -> IncludeIgnoreCollection {
let mut include = bench_flags.include.clone().unwrap_or_default();
let mut ignore = bench_flags.ignore.clone();
if let Some(bench_config) = maybe_bench_config {
if include.is_empty() {
include = bench_config
.files
.include
.iter()
.map(|s| s.to_string())
.collect::<Vec<_>>();
}
if ignore.is_empty() {
ignore = bench_config
.files
.exclude
.iter()
.filter_map(|s| specifier_to_file_path(s).ok())
.collect::<Vec<_>>();
}
}
if include.is_empty() {
include.push(".".to_string());
}
IncludeIgnoreCollection { include, ignore }
}

View file

@ -8,7 +8,8 @@
//! the same functions as ops available in JS runtime. //! the same functions as ops available in JS runtime.
use crate::args::CliOptions; use crate::args::CliOptions;
use crate::args::FmtFlags; use crate::args::FilesConfig;
use crate::args::FmtOptions;
use crate::args::FmtOptionsConfig; use crate::args::FmtOptionsConfig;
use crate::args::ProseWrap; use crate::args::ProseWrap;
use crate::colors; use crate::colors;
@ -17,7 +18,6 @@ use crate::util::file_watcher;
use crate::util::file_watcher::ResolutionResult; use crate::util::file_watcher::ResolutionResult;
use crate::util::fs::FileCollector; use crate::util::fs::FileCollector;
use crate::util::path::get_extension; use crate::util::path::get_extension;
use crate::util::path::specifier_to_file_path;
use crate::util::text_encoding; use crate::util::text_encoding;
use deno_ast::ParsedSource; use deno_ast::ParsedSource;
use deno_core::anyhow::bail; use deno_core::anyhow::bail;
@ -44,60 +44,21 @@ use crate::cache::IncrementalCache;
/// Format JavaScript/TypeScript files. /// Format JavaScript/TypeScript files.
pub async fn format( pub async fn format(
config: &CliOptions, cli_options: CliOptions,
fmt_flags: FmtFlags, fmt_options: FmtOptions,
) -> Result<(), AnyError> { ) -> Result<(), AnyError> {
let maybe_fmt_config = config.to_fmt_config()?; if fmt_options.is_stdin {
let deno_dir = config.resolve_deno_dir()?; return format_stdin(fmt_options);
let FmtFlags {
files,
ignore,
check,
..
} = fmt_flags.clone();
// First, prepare final configuration.
// Collect included and ignored files. CLI flags take precendence
// over config file, ie. if there's `files.ignore` in config file
// and `--ignore` CLI flag, only the flag value is taken into account.
let mut include_files = files.clone();
let mut exclude_files = ignore;
if let Some(fmt_config) = maybe_fmt_config.as_ref() {
if include_files.is_empty() {
include_files = fmt_config
.files
.include
.iter()
.filter_map(|s| specifier_to_file_path(s).ok())
.collect::<Vec<_>>();
} }
if exclude_files.is_empty() { let files = fmt_options.files;
exclude_files = fmt_config let check = fmt_options.check;
.files let fmt_config_options = fmt_options.options;
.exclude
.iter()
.filter_map(|s| specifier_to_file_path(s).ok())
.collect::<Vec<_>>();
}
}
if include_files.is_empty() {
include_files = [std::env::current_dir()?].to_vec();
}
// Now do the same for options
let fmt_options = resolve_fmt_options(
&fmt_flags,
maybe_fmt_config.map(|c| c.options).unwrap_or_default(),
);
let resolver = |changed: Option<Vec<PathBuf>>| { let resolver = |changed: Option<Vec<PathBuf>>| {
let files_changed = changed.is_some(); let files_changed = changed.is_some();
let result = let result = collect_fmt_files(&files).map(|files| {
collect_fmt_files(&include_files, &exclude_files).map(|files| {
let refmt_files = if let Some(paths) = changed { let refmt_files = if let Some(paths) = changed {
if check { if check {
files files
@ -114,10 +75,10 @@ pub async fn format(
} else { } else {
files files
}; };
(refmt_files, fmt_options.clone()) (refmt_files, fmt_config_options.clone())
}); });
let paths_to_watch = include_files.clone(); let paths_to_watch = files.include.clone();
async move { async move {
if files_changed if files_changed
&& matches!(result, Ok((ref files, _)) if files.is_empty()) && matches!(result, Ok((ref files, _)) if files.is_empty())
@ -131,6 +92,7 @@ pub async fn format(
} }
} }
}; };
let deno_dir = cli_options.resolve_deno_dir()?;
let deno_dir = &deno_dir; let deno_dir = &deno_dir;
let operation = |(paths, fmt_options): (Vec<PathBuf>, FmtOptionsConfig)| async move { let operation = |(paths, fmt_options): (Vec<PathBuf>, FmtOptionsConfig)| async move {
let incremental_cache = Arc::new(IncrementalCache::new( let incremental_cache = Arc::new(IncrementalCache::new(
@ -148,40 +110,36 @@ pub async fn format(
Ok(()) Ok(())
}; };
if config.watch_paths().is_some() { if cli_options.watch_paths().is_some() {
file_watcher::watch_func( file_watcher::watch_func(
resolver, resolver,
operation, operation,
file_watcher::PrintConfig { file_watcher::PrintConfig {
job_name: "Fmt".to_string(), job_name: "Fmt".to_string(),
clear_screen: !config.no_clear_screen(), clear_screen: !cli_options.no_clear_screen(),
}, },
) )
.await?; .await?;
} else { } else {
let files = let files = collect_fmt_files(&files).and_then(|files| {
collect_fmt_files(&include_files, &exclude_files).and_then(|files| {
if files.is_empty() { if files.is_empty() {
Err(generic_error("No target files found.")) Err(generic_error("No target files found."))
} else { } else {
Ok(files) Ok(files)
} }
})?; })?;
operation((files, fmt_options.clone())).await?; operation((files, fmt_config_options)).await?;
} }
Ok(()) Ok(())
} }
fn collect_fmt_files( fn collect_fmt_files(files: &FilesConfig) -> Result<Vec<PathBuf>, AnyError> {
include_files: &[PathBuf],
exclude_files: &[PathBuf],
) -> Result<Vec<PathBuf>, AnyError> {
FileCollector::new(is_supported_ext_fmt) FileCollector::new(is_supported_ext_fmt)
.ignore_git_folder() .ignore_git_folder()
.ignore_node_modules() .ignore_node_modules()
.add_ignore_paths(exclude_files) .add_ignore_paths(&files.exclude)
.collect_files(include_files) .collect_files(&files.include)
} }
/// Formats markdown (using <https://github.com/dprint/dprint-plugin-markdown>) and its code blocks /// Formats markdown (using <https://github.com/dprint/dprint-plugin-markdown>) and its code blocks
@ -275,11 +233,11 @@ pub fn format_file(
pub fn format_parsed_source( pub fn format_parsed_source(
parsed_source: &ParsedSource, parsed_source: &ParsedSource,
fmt_options: FmtOptionsConfig, fmt_options: &FmtOptionsConfig,
) -> Result<Option<String>, AnyError> { ) -> Result<Option<String>, AnyError> {
dprint_plugin_typescript::format_parsed_source( dprint_plugin_typescript::format_parsed_source(
parsed_source, parsed_source,
&get_resolved_typescript_config(&fmt_options), &get_resolved_typescript_config(fmt_options),
) )
} }
@ -501,19 +459,14 @@ fn format_ensure_stable(
/// Format stdin and write result to stdout. /// Format stdin and write result to stdout.
/// Treats input as TypeScript or as set by `--ext` flag. /// Treats input as TypeScript or as set by `--ext` flag.
/// Compatible with `--check` flag. /// Compatible with `--check` flag.
pub fn format_stdin( fn format_stdin(fmt_options: FmtOptions) -> Result<(), AnyError> {
fmt_flags: FmtFlags,
fmt_options: FmtOptionsConfig,
) -> Result<(), AnyError> {
let mut source = String::new(); let mut source = String::new();
if stdin().read_to_string(&mut source).is_err() { if stdin().read_to_string(&mut source).is_err() {
bail!("Failed to read from stdin"); bail!("Failed to read from stdin");
} }
let file_path = PathBuf::from(format!("_stdin.{}", fmt_flags.ext)); let file_path = PathBuf::from(format!("_stdin.{}", fmt_options.ext));
let fmt_options = resolve_fmt_options(&fmt_flags, fmt_options); let formatted_text = format_file(&file_path, &source, &fmt_options.options)?;
if fmt_options.check {
let formatted_text = format_file(&file_path, &source, &fmt_options)?;
if fmt_flags.check {
if formatted_text.is_some() { if formatted_text.is_some() {
println!("Not formatted stdin"); println!("Not formatted stdin");
} }
@ -531,41 +484,6 @@ fn files_str(len: usize) -> &'static str {
} }
} }
fn resolve_fmt_options(
fmt_flags: &FmtFlags,
options: FmtOptionsConfig,
) -> FmtOptionsConfig {
let mut options = options;
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!(),
});
}
options
}
fn get_resolved_typescript_config( fn get_resolved_typescript_config(
options: &FmtOptionsConfig, options: &FmtOptionsConfig,
) -> dprint_plugin_typescript::configuration::Configuration { ) -> dprint_plugin_typescript::configuration::Configuration {

View file

@ -6,19 +6,19 @@
//! At the moment it is only consumed using CLI but in //! At the moment it is only consumed using CLI but in
//! the future it can be easily extended to provide //! the future it can be easily extended to provide
//! the same functions as ops available in JS runtime. //! the same functions as ops available in JS runtime.
use crate::args::Flags; use crate::args::CliOptions;
use crate::args::LintConfig; use crate::args::FilesConfig;
use crate::args::LintFlags; use crate::args::LintOptions;
use crate::args::LintReporterKind;
use crate::args::LintRulesConfig;
use crate::colors; use crate::colors;
use crate::proc_state::ProcState;
use crate::tools::fmt::run_parallelized; use crate::tools::fmt::run_parallelized;
use crate::util::file_watcher; use crate::util::file_watcher;
use crate::util::file_watcher::ResolutionResult; use crate::util::file_watcher::ResolutionResult;
use crate::util::fs::FileCollector; use crate::util::fs::FileCollector;
use crate::util::path::is_supported_ext; use crate::util::path::is_supported_ext;
use crate::util::path::specifier_to_file_path;
use deno_ast::MediaType; use deno_ast::MediaType;
use deno_core::anyhow::anyhow; use deno_core::anyhow::bail;
use deno_core::error::generic_error; use deno_core::error::generic_error;
use deno_core::error::AnyError; use deno_core::error::AnyError;
use deno_core::error::JsStackFrame; use deno_core::error::JsStackFrame;
@ -45,13 +45,6 @@ use crate::cache::IncrementalCache;
static STDIN_FILE_NAME: &str = "_stdin.ts"; static STDIN_FILE_NAME: &str = "_stdin.ts";
#[derive(Clone, Debug)]
pub enum LintReporterKind {
Pretty,
Json,
Compact,
}
fn create_reporter(kind: LintReporterKind) -> Box<dyn LintReporter + Send> { fn create_reporter(kind: LintReporterKind) -> Box<dyn LintReporter + Send> {
match kind { match kind {
LintReporterKind::Pretty => Box::new(PrettyLintReporter::new()), LintReporterKind::Pretty => Box::new(PrettyLintReporter::new()),
@ -60,90 +53,23 @@ fn create_reporter(kind: LintReporterKind) -> Box<dyn LintReporter + Send> {
} }
} }
pub async fn lint(flags: Flags, lint_flags: LintFlags) -> Result<(), AnyError> { pub async fn lint(
let LintFlags { cli_options: CliOptions,
maybe_rules_tags, lint_options: LintOptions,
maybe_rules_include, ) -> Result<(), AnyError> {
maybe_rules_exclude, // Try to get lint rules. If none were set use recommended rules.
files: args, let lint_rules = get_configured_rules(lint_options.rules);
ignore,
json,
compact,
..
} = lint_flags;
// First, prepare final configuration.
// Collect included and ignored files. CLI flags take precendence
// 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.
let mut include_files = args.clone();
let mut exclude_files = ignore.clone();
let mut maybe_reporter_kind = if json {
Some(LintReporterKind::Json)
} else if compact {
Some(LintReporterKind::Compact)
} else {
None
};
let ps = ProcState::build(flags).await?; if lint_rules.is_empty() {
let maybe_lint_config = ps.options.to_lint_config()?; bail!("No rules have been configured")
if let Some(lint_config) = maybe_lint_config.as_ref() {
if include_files.is_empty() {
include_files = lint_config
.files
.include
.iter()
.filter_map(|s| specifier_to_file_path(s).ok())
.collect::<Vec<_>>();
} }
if exclude_files.is_empty() { let files = lint_options.files;
exclude_files = lint_config let reporter_kind = lint_options.reporter_kind;
.files
.exclude
.iter()
.filter_map(|s| specifier_to_file_path(s).ok())
.collect::<Vec<_>>();
}
if maybe_reporter_kind.is_none() {
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(_) => {
return Err(anyhow!("Invalid lint report type in config file"))
}
None => Some(LintReporterKind::Pretty),
}
}
}
if include_files.is_empty() {
include_files = [std::env::current_dir()?].to_vec();
}
let reporter_kind = match maybe_reporter_kind {
Some(report) => report,
None => LintReporterKind::Pretty,
};
let has_error = Arc::new(AtomicBool::new(false));
// Try to get configured rules. CLI flags take precendence
// over config file, ie. if there's `rules.include` in config file
// and `--rules-include` CLI flag, only the flag value is taken into account.
let lint_rules = get_configured_rules(
maybe_lint_config.as_ref(),
maybe_rules_tags,
maybe_rules_include,
maybe_rules_exclude,
)?;
let resolver = |changed: Option<Vec<PathBuf>>| { let resolver = |changed: Option<Vec<PathBuf>>| {
let files_changed = changed.is_some(); let files_changed = changed.is_some();
let result = let result = collect_lint_files(&files).map(|files| {
collect_lint_files(&include_files, &exclude_files).map(|files| {
if let Some(paths) = changed { if let Some(paths) = changed {
files files
.iter() .iter()
@ -155,7 +81,7 @@ pub async fn lint(flags: Flags, lint_flags: LintFlags) -> Result<(), AnyError> {
} }
}); });
let paths_to_watch = include_files.clone(); let paths_to_watch = files.include.clone();
async move { async move {
if files_changed && matches!(result, Ok(ref files) if files.is_empty()) { if files_changed && matches!(result, Ok(ref files) if files.is_empty()) {
@ -169,9 +95,12 @@ pub async fn lint(flags: Flags, lint_flags: LintFlags) -> Result<(), AnyError> {
} }
}; };
let has_error = Arc::new(AtomicBool::new(false));
let deno_dir = cli_options.resolve_deno_dir()?;
let operation = |paths: Vec<PathBuf>| async { let operation = |paths: Vec<PathBuf>| async {
let incremental_cache = Arc::new(IncrementalCache::new( let incremental_cache = Arc::new(IncrementalCache::new(
&ps.dir.lint_incremental_cache_db_file_path(), &deno_dir.lint_incremental_cache_db_file_path(),
// use a hash of the rule names in order to bust the cache // use a hash of the rule names in order to bust the cache
&{ &{
// ensure this is stable by sorting it // ensure this is stable by sorting it
@ -221,8 +150,8 @@ pub async fn lint(flags: Flags, lint_flags: LintFlags) -> Result<(), AnyError> {
Ok(()) Ok(())
}; };
if ps.options.watch_paths().is_some() { if cli_options.watch_paths().is_some() {
if args.len() == 1 && args[0].to_string_lossy() == "-" { if lint_options.is_stdin {
return Err(generic_error( return Err(generic_error(
"Lint watch on standard input is not supported.", "Lint watch on standard input is not supported.",
)); ));
@ -232,12 +161,12 @@ pub async fn lint(flags: Flags, lint_flags: LintFlags) -> Result<(), AnyError> {
operation, operation,
file_watcher::PrintConfig { file_watcher::PrintConfig {
job_name: "Lint".to_string(), job_name: "Lint".to_string(),
clear_screen: !ps.options.no_clear_screen(), clear_screen: !cli_options.no_clear_screen(),
}, },
) )
.await?; .await?;
} else { } else {
if args.len() == 1 && args[0].to_string_lossy() == "-" { if lint_options.is_stdin {
let reporter_lock = let reporter_lock =
Arc::new(Mutex::new(create_reporter(reporter_kind.clone()))); Arc::new(Mutex::new(create_reporter(reporter_kind.clone())));
let r = lint_stdin(lint_rules); let r = lint_stdin(lint_rules);
@ -249,8 +178,7 @@ pub async fn lint(flags: Flags, lint_flags: LintFlags) -> Result<(), AnyError> {
); );
reporter_lock.lock().unwrap().close(1); reporter_lock.lock().unwrap().close(1);
} else { } else {
let target_files = collect_lint_files(&include_files, &exclude_files) let target_files = collect_lint_files(&files).and_then(|files| {
.and_then(|files| {
if files.is_empty() { if files.is_empty() {
Err(generic_error("No target files found.")) Err(generic_error("No target files found."))
} else { } else {
@ -269,15 +197,12 @@ pub async fn lint(flags: Flags, lint_flags: LintFlags) -> Result<(), AnyError> {
Ok(()) Ok(())
} }
fn collect_lint_files( fn collect_lint_files(files: &FilesConfig) -> Result<Vec<PathBuf>, AnyError> {
include_files: &[PathBuf],
exclude_files: &[PathBuf],
) -> Result<Vec<PathBuf>, AnyError> {
FileCollector::new(is_supported_ext) FileCollector::new(is_supported_ext)
.ignore_git_folder() .ignore_git_folder()
.ignore_node_modules() .ignore_node_modules()
.add_ignore_paths(exclude_files) .add_ignore_paths(&files.exclude)
.collect_files(include_files) .collect_files(&files.include)
} }
pub fn print_rules_list(json: bool) { pub fn print_rules_list(json: bool) {
@ -606,60 +531,17 @@ fn sort_diagnostics(diagnostics: &mut [LintDiagnostic]) {
}); });
} }
pub fn get_configured_rules( pub fn get_configured_rules(rules: LintRulesConfig) -> Vec<Arc<dyn LintRule>> {
maybe_lint_config: Option<&LintConfig>, if rules.tags.is_none() && rules.include.is_none() && rules.exclude.is_none()
maybe_rules_tags: Option<Vec<String>>,
maybe_rules_include: Option<Vec<String>>,
maybe_rules_exclude: Option<Vec<String>>,
) -> Result<Vec<Arc<dyn LintRule>>, AnyError> {
if maybe_lint_config.is_none()
&& maybe_rules_tags.is_none()
&& maybe_rules_include.is_none()
&& maybe_rules_exclude.is_none()
{ {
return Ok(rules::get_recommended_rules()); rules::get_recommended_rules()
} } else {
rules::get_filtered_rules(
let (config_file_tags, config_file_include, config_file_exclude) = rules.tags.or_else(|| Some(vec!["recommended".to_string()])),
if let Some(lint_config) = maybe_lint_config { rules.exclude,
( rules.include,
lint_config.rules.tags.clone(),
lint_config.rules.include.clone(),
lint_config.rules.exclude.clone(),
) )
} else {
(None, None, None)
};
let maybe_configured_include = if maybe_rules_include.is_some() {
maybe_rules_include
} else {
config_file_include
};
let maybe_configured_exclude = if maybe_rules_exclude.is_some() {
maybe_rules_exclude
} else {
config_file_exclude
};
let maybe_configured_tags = if maybe_rules_tags.is_some() {
maybe_rules_tags
} else {
config_file_tags
};
let configured_rules = rules::get_filtered_rules(
maybe_configured_tags.or_else(|| Some(vec!["recommended".to_string()])),
maybe_configured_exclude,
maybe_configured_include,
);
if configured_rules.is_empty() {
return Err(anyhow!("No rules have been configured"));
} }
Ok(configured_rules)
} }
#[cfg(test)] #[cfg(test)]
@ -671,15 +553,12 @@ mod test {
#[test] #[test]
fn recommended_rules_when_no_tags_in_config() { fn recommended_rules_when_no_tags_in_config() {
let lint_config = LintConfig { let rules_config = LintRulesConfig {
rules: LintRulesConfig {
exclude: Some(vec!["no-debugger".to_string()]), exclude: Some(vec!["no-debugger".to_string()]),
..Default::default() include: None,
}, tags: None,
..Default::default()
}; };
let rules = let rules = get_configured_rules(rules_config);
get_configured_rules(Some(&lint_config), None, None, None).unwrap();
let mut rule_names = rules let mut rule_names = rules
.into_iter() .into_iter()
.map(|r| r.code().to_string()) .map(|r| r.code().to_string())

View file

@ -1,7 +1,8 @@
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license. // Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
use crate::args::Flags; use crate::args::CliOptions;
use crate::args::TestFlags; use crate::args::FilesConfig;
use crate::args::TestOptions;
use crate::args::TypeCheckMode; use crate::args::TypeCheckMode;
use crate::colors; use crate::colors;
use crate::display; use crate::display;
@ -16,7 +17,6 @@ use crate::util::file_watcher::ResolutionResult;
use crate::util::fs::collect_specifiers; use crate::util::fs::collect_specifiers;
use crate::util::path::get_extension; use crate::util::path::get_extension;
use crate::util::path::is_supported_ext; use crate::util::path::is_supported_ext;
use crate::util::path::specifier_to_file_path;
use crate::worker::create_main_worker_for_test_or_bench; use crate::worker::create_main_worker_for_test_or_bench;
use deno_ast::swc::common::comments::CommentKind; use deno_ast::swc::common::comments::CommentKind;
@ -1237,15 +1237,13 @@ fn is_supported_test_ext(path: &Path) -> bool {
/// - Specifiers matching the `is_supported_test_path` are marked as `TestMode::Executable`. /// - Specifiers matching the `is_supported_test_path` are marked as `TestMode::Executable`.
/// - Specifiers matching both predicates are marked as `TestMode::Both` /// - Specifiers matching both predicates are marked as `TestMode::Both`
fn collect_specifiers_with_test_mode( fn collect_specifiers_with_test_mode(
include: Vec<String>, files: FilesConfig,
ignore: Vec<PathBuf>,
include_inline: bool, include_inline: bool,
) -> Result<Vec<(ModuleSpecifier, TestMode)>, AnyError> { ) -> Result<Vec<(ModuleSpecifier, TestMode)>, AnyError> {
let module_specifiers = let module_specifiers = collect_specifiers(&files, is_supported_test_path)?;
collect_specifiers(include.clone(), &ignore, is_supported_test_path)?;
if include_inline { if include_inline {
return collect_specifiers(include, &ignore, is_supported_test_ext).map( return collect_specifiers(&files, is_supported_test_ext).map(
|specifiers| { |specifiers| {
specifiers specifiers
.into_iter() .into_iter()
@ -1281,44 +1279,10 @@ fn collect_specifiers_with_test_mode(
/// as well. /// as well.
async fn fetch_specifiers_with_test_mode( async fn fetch_specifiers_with_test_mode(
ps: &ProcState, ps: &ProcState,
include: Vec<String>, files: FilesConfig,
ignore: Vec<PathBuf>, doc: bool,
include_inline: bool,
) -> Result<Vec<(ModuleSpecifier, TestMode)>, AnyError> { ) -> Result<Vec<(ModuleSpecifier, TestMode)>, AnyError> {
let maybe_test_config = ps.options.to_test_config()?; let mut specifiers_with_mode = collect_specifiers_with_test_mode(files, doc)?;
let mut include_files = include.clone();
let mut exclude_files = ignore.clone();
if let Some(test_config) = maybe_test_config.as_ref() {
if include_files.is_empty() {
include_files = test_config
.files
.include
.iter()
.map(|s| s.to_string())
.collect::<Vec<_>>();
}
if exclude_files.is_empty() {
exclude_files = test_config
.files
.exclude
.iter()
.filter_map(|s| specifier_to_file_path(s).ok())
.collect::<Vec<_>>();
}
}
if include_files.is_empty() {
include_files.push(".".to_string());
}
let mut specifiers_with_mode = collect_specifiers_with_test_mode(
include_files,
exclude_files,
include_inline,
)?;
for (specifier, mode) in &mut specifiers_with_mode { for (specifier, mode) in &mut specifiers_with_mode {
let file = ps let file = ps
.file_fetcher .file_fetcher
@ -1336,31 +1300,28 @@ async fn fetch_specifiers_with_test_mode(
} }
pub async fn run_tests( pub async fn run_tests(
flags: Flags, cli_options: CliOptions,
test_flags: TestFlags, test_options: TestOptions,
) -> Result<(), AnyError> { ) -> Result<(), AnyError> {
let ps = ProcState::build(flags).await?; let ps = ProcState::from_options(Arc::new(cli_options)).await?;
// Various test files should not share the same permissions in terms of // Various test files should not share the same permissions in terms of
// `PermissionsContainer` - otherwise granting/revoking permissions in one // `PermissionsContainer` - otherwise granting/revoking permissions in one
// file would have impact on other files, which is undesirable. // file would have impact on other files, which is undesirable.
let permissions = let permissions =
Permissions::from_options(&ps.options.permissions_options())?; Permissions::from_options(&ps.options.permissions_options())?;
let specifiers_with_mode = fetch_specifiers_with_test_mode(
&ps, let specifiers_with_mode =
test_flags.include, fetch_specifiers_with_test_mode(&ps, test_options.files, test_options.doc)
test_flags.ignore.clone(),
test_flags.doc,
)
.await?; .await?;
if !test_flags.allow_none && specifiers_with_mode.is_empty() { if !test_options.allow_none && specifiers_with_mode.is_empty() {
return Err(generic_error("No test modules found")); return Err(generic_error("No test modules found"));
} }
check_specifiers(&ps, permissions.clone(), specifiers_with_mode.clone()) check_specifiers(&ps, permissions.clone(), specifiers_with_mode.clone())
.await?; .await?;
if test_flags.no_run { if test_options.no_run {
return Ok(()); return Ok(());
} }
@ -1369,9 +1330,9 @@ pub async fn run_tests(
permissions, permissions,
specifiers_with_mode, specifiers_with_mode,
TestSpecifierOptions { TestSpecifierOptions {
concurrent_jobs: test_flags.concurrent_jobs, concurrent_jobs: test_options.concurrent_jobs,
fail_fast: test_flags.fail_fast, fail_fast: test_options.fail_fast,
filter: TestFilter::from_flag(&test_flags.filter), filter: TestFilter::from_flag(&test_options.filter),
}, },
) )
.await?; .await?;
@ -1380,35 +1341,32 @@ pub async fn run_tests(
} }
pub async fn run_tests_with_watch( pub async fn run_tests_with_watch(
flags: Flags, cli_options: CliOptions,
test_flags: TestFlags, test_options: TestOptions,
) -> Result<(), AnyError> { ) -> Result<(), AnyError> {
let ps = ProcState::build(flags).await?; let ps = ProcState::from_options(Arc::new(cli_options)).await?;
// Various test files should not share the same permissions in terms of // Various test files should not share the same permissions in terms of
// `PermissionsContainer` - otherwise granting/revoking permissions in one // `PermissionsContainer` - otherwise granting/revoking permissions in one
// file would have impact on other files, which is undesirable. // file would have impact on other files, which is undesirable.
let permissions = let permissions =
Permissions::from_options(&ps.options.permissions_options())?; Permissions::from_options(&ps.options.permissions_options())?;
let include = test_flags.include; let paths_to_watch: Vec<_> = test_options.files.include.clone();
let ignore = test_flags.ignore.clone();
let paths_to_watch: Vec<_> = include.iter().map(PathBuf::from).collect();
let no_check = ps.options.type_check_mode() == TypeCheckMode::None; let no_check = ps.options.type_check_mode() == TypeCheckMode::None;
let test_options = &test_options;
let resolver = |changed: Option<Vec<PathBuf>>| { let resolver = |changed: Option<Vec<PathBuf>>| {
let paths_to_watch = paths_to_watch.clone(); let paths_to_watch = paths_to_watch.clone();
let paths_to_watch_clone = paths_to_watch.clone(); let paths_to_watch_clone = paths_to_watch.clone();
let files_changed = changed.is_some(); let files_changed = changed.is_some();
let include = include.clone();
let ignore = ignore.clone();
let ps = ps.clone(); let ps = ps.clone();
async move { async move {
let test_modules = if test_flags.doc { let test_modules = if test_options.doc {
collect_specifiers(include.clone(), &ignore, is_supported_test_ext) collect_specifiers(&test_options.files, is_supported_test_ext)
} else { } else {
collect_specifiers(include.clone(), &ignore, is_supported_test_path) collect_specifiers(&test_options.files, is_supported_test_path)
}?; }?;
let mut paths_to_watch = paths_to_watch_clone; let mut paths_to_watch = paths_to_watch_clone;
@ -1517,20 +1475,16 @@ pub async fn run_tests_with_watch(
}) })
}; };
let cli_options = ps.options.clone();
let operation = |modules_to_reload: Vec<(ModuleSpecifier, ModuleKind)>| { let operation = |modules_to_reload: Vec<(ModuleSpecifier, ModuleKind)>| {
let filter = test_flags.filter.clone();
let include = include.clone();
let ignore = ignore.clone();
let permissions = permissions.clone(); let permissions = permissions.clone();
let ps = ps.clone(); let ps = ps.clone();
let test_options = test_options.clone();
async move { async move {
let specifiers_with_mode = fetch_specifiers_with_test_mode( let specifiers_with_mode = fetch_specifiers_with_test_mode(
&ps, &ps,
include.clone(), test_options.files,
ignore.clone(), test_options.doc,
test_flags.doc,
) )
.await? .await?
.iter() .iter()
@ -1543,7 +1497,7 @@ pub async fn run_tests_with_watch(
check_specifiers(&ps, permissions.clone(), specifiers_with_mode.clone()) check_specifiers(&ps, permissions.clone(), specifiers_with_mode.clone())
.await?; .await?;
if test_flags.no_run { if test_options.no_run {
return Ok(()); return Ok(());
} }
@ -1552,9 +1506,9 @@ pub async fn run_tests_with_watch(
permissions.clone(), permissions.clone(),
specifiers_with_mode, specifiers_with_mode,
TestSpecifierOptions { TestSpecifierOptions {
concurrent_jobs: test_flags.concurrent_jobs, concurrent_jobs: test_options.concurrent_jobs,
fail_fast: test_flags.fail_fast, fail_fast: test_options.fail_fast,
filter: TestFilter::from_flag(&filter), filter: TestFilter::from_flag(&test_options.filter),
}, },
) )
.await?; .await?;
@ -1568,7 +1522,7 @@ pub async fn run_tests_with_watch(
operation, operation,
file_watcher::PrintConfig { file_watcher::PrintConfig {
job_name: "Test".to_string(), job_name: "Test".to_string(),
clear_screen: !cli_options.no_clear_screen(), clear_screen: !ps.options.no_clear_screen(),
}, },
) )
.await?; .await?;

View file

@ -153,9 +153,12 @@ fn maybe_update_config_file(output_dir: &Path, ps: &ProcState) -> bool {
Some(f) => f, Some(f) => f,
None => return false, None => return false,
}; };
let fmt_config = ps let fmt_config = ps
.options .options
.to_fmt_config() .get_maybe_config_file()
.as_ref()
.and_then(|config| config.to_fmt_config().ok())
.unwrap_or_default() .unwrap_or_default()
.unwrap_or_default(); .unwrap_or_default();
let result = update_config_file( let result = update_config_file(

View file

@ -107,9 +107,13 @@ where
log::debug!("File change ignored") log::debug!("File change ignored")
} }
ResolutionResult::Restart { ResolutionResult::Restart {
paths_to_watch, mut paths_to_watch,
result, result,
} => { } => {
// watch the current directory when empty
if paths_to_watch.is_empty() {
paths_to_watch.push(PathBuf::from("."));
}
return (paths_to_watch, result); return (paths_to_watch, result);
} }
} }
@ -190,9 +194,13 @@ where
print_after_restart(); print_after_restart();
} }
ResolutionResult::Restart { ResolutionResult::Restart {
paths_to_watch: paths, paths_to_watch: mut paths,
result, result,
} => { } => {
// watch the current directory when empty
if paths.is_empty() {
paths.push(PathBuf::from("."));
}
paths_to_watch = paths; paths_to_watch = paths;
resolution_result = result; resolution_result = result;
} }

View file

@ -6,6 +6,7 @@ pub use deno_core::normalize_path;
use deno_core::ModuleSpecifier; use deno_core::ModuleSpecifier;
use deno_runtime::deno_crypto::rand; use deno_runtime::deno_crypto::rand;
use deno_runtime::deno_node::PathClean; use deno_runtime::deno_node::PathClean;
use std::borrow::Cow;
use std::env::current_dir; use std::env::current_dir;
use std::fs::OpenOptions; use std::fs::OpenOptions;
use std::io::Error; use std::io::Error;
@ -16,6 +17,8 @@ use std::path::PathBuf;
use std::time::Duration; use std::time::Duration;
use walkdir::WalkDir; use walkdir::WalkDir;
use crate::args::FilesConfig;
use super::path::specifier_to_file_path; use super::path::specifier_to_file_path;
pub fn atomic_write_file<T: AsRef<[u8]>>( pub fn atomic_write_file<T: AsRef<[u8]>>(
@ -181,6 +184,7 @@ impl<TFilter: Fn(&Path) -> bool> FileCollector<TFilter> {
ignore_node_modules: false, ignore_node_modules: false,
} }
} }
pub fn add_ignore_paths(mut self, paths: &[PathBuf]) -> Self { pub fn add_ignore_paths(mut self, paths: &[PathBuf]) -> Self {
// retain only the paths which exist and ignore the rest // retain only the paths which exist and ignore the rest
self self
@ -204,7 +208,13 @@ impl<TFilter: Fn(&Path) -> bool> FileCollector<TFilter> {
files: &[PathBuf], files: &[PathBuf],
) -> Result<Vec<PathBuf>, AnyError> { ) -> Result<Vec<PathBuf>, AnyError> {
let mut target_files = Vec::new(); let mut target_files = Vec::new();
for file in files { let files = if files.is_empty() {
// collect files in the current directory when empty
Cow::Owned(vec![PathBuf::from(".")])
} else {
Cow::Borrowed(files)
};
for file in files.iter() {
if let Ok(file) = canonicalize_path(file) { if let Ok(file) = canonicalize_path(file) {
// use an iterator like this in order to minimize the number of file system operations // use an iterator like this in order to minimize the number of file system operations
let mut iterator = WalkDir::new(&file).into_iter(); let mut iterator = WalkDir::new(&file).into_iter();
@ -254,18 +264,24 @@ impl<TFilter: Fn(&Path) -> bool> FileCollector<TFilter> {
/// Specifiers that start with http and https are left intact. /// Specifiers that start with http and https are left intact.
/// Note: This ignores all .git and node_modules folders. /// Note: This ignores all .git and node_modules folders.
pub fn collect_specifiers( pub fn collect_specifiers(
include: Vec<String>, files: &FilesConfig,
ignore: &[PathBuf],
predicate: impl Fn(&Path) -> bool, predicate: impl Fn(&Path) -> bool,
) -> Result<Vec<ModuleSpecifier>, AnyError> { ) -> Result<Vec<ModuleSpecifier>, AnyError> {
let mut prepared = vec![]; let mut prepared = vec![];
let file_collector = FileCollector::new(predicate) let file_collector = FileCollector::new(predicate)
.add_ignore_paths(ignore) .add_ignore_paths(&files.exclude)
.ignore_git_folder() .ignore_git_folder()
.ignore_node_modules(); .ignore_node_modules();
let root_path = current_dir()?; let root_path = current_dir()?;
for path in include { let include_files = if files.include.is_empty() {
// collect files in the current directory when empty
Cow::Owned(vec![root_path.clone()])
} else {
Cow::Borrowed(&files.include)
};
for path in include_files.iter() {
let path = path.to_string_lossy();
let lowercase_path = path.to_lowercase(); let lowercase_path = path.to_lowercase();
if lowercase_path.starts_with("http://") if lowercase_path.starts_with("http://")
|| lowercase_path.starts_with("https://") || lowercase_path.starts_with("https://")
@ -278,7 +294,7 @@ pub fn collect_specifiers(
let p = if lowercase_path.starts_with("file://") { let p = if lowercase_path.starts_with("file://") {
specifier_to_file_path(&ModuleSpecifier::parse(&path)?)? specifier_to_file_path(&ModuleSpecifier::parse(&path)?)?
} else { } else {
root_path.join(path) root_path.join(path.as_ref())
}; };
let p = normalize_path(p); let p = normalize_path(p);
if p.is_dir() { if p.is_dir() {
@ -675,12 +691,14 @@ mod tests {
}; };
let result = collect_specifiers( let result = collect_specifiers(
vec![ &FilesConfig {
"http://localhost:8080".to_string(), include: vec![
root_dir_path.to_str().unwrap().to_string(), PathBuf::from("http://localhost:8080"),
"https://localhost:8080".to_string(), root_dir_path.clone(),
PathBuf::from("https://localhost:8080".to_string()),
], ],
&[ignore_dir_path], exclude: vec![ignore_dir_path],
},
predicate, predicate,
) )
.unwrap(); .unwrap();
@ -713,7 +731,8 @@ mod tests {
"file://" "file://"
}; };
let result = collect_specifiers( let result = collect_specifiers(
vec![format!( &FilesConfig {
include: vec![PathBuf::from(format!(
"{}{}", "{}{}",
scheme, scheme,
root_dir_path root_dir_path
@ -721,8 +740,9 @@ mod tests {
.to_str() .to_str()
.unwrap() .unwrap()
.replace('\\', "/") .replace('\\', "/")
)], ))],
&[], exclude: vec![],
},
predicate, predicate,
) )
.unwrap(); .unwrap();