diff options
author | CGQAQ <m.jason.liu@outlook.com> | 2021-10-06 05:07:38 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-10-05 23:07:38 +0200 |
commit | c555b31d40bcc374013395bd5805410fe7f77b20 (patch) | |
tree | 659a4182122a923bde884b72e6a02242c68293d9 /cli/tools/lint.rs | |
parent | 22328f87585611ae70e555ad7941cc5093b92544 (diff) |
feat(lint): add support for --watch flag (#11983)
Diffstat (limited to 'cli/tools/lint.rs')
-rw-r--r-- | cli/tools/lint.rs | 140 |
1 files changed, 95 insertions, 45 deletions
diff --git a/cli/tools/lint.rs b/cli/tools/lint.rs index 7448463bd..5630067ae 100644 --- a/cli/tools/lint.rs +++ b/cli/tools/lint.rs @@ -6,11 +6,13 @@ //! At the moment it is only consumed using CLI but in //! the future it can be easily extended to provide //! the same functions as ops available in JS runtime. -use crate::colors; use crate::config_file::LintConfig; +use crate::file_watcher::ResolutionResult; +use crate::flags::LintFlags; use crate::fmt_errors; use crate::fs_util::{collect_files, is_supported_ext}; use crate::tools::fmt::run_parallelized; +use crate::{colors, file_watcher}; use deno_ast::swc::parser::Syntax; use deno_ast::MediaType; use deno_core::error::{anyhow, generic_error, AnyError, JsStackFrame}; @@ -31,6 +33,7 @@ use std::sync::{Arc, Mutex}; static STDIN_FILE_NAME: &str = "_stdin.ts"; +#[derive(Clone, Debug)] pub enum LintReporterKind { Pretty, Json, @@ -43,21 +46,26 @@ fn create_reporter(kind: LintReporterKind) -> Box<dyn LintReporter + Send> { } } -pub async fn lint_files( +pub async fn lint( maybe_lint_config: Option<LintConfig>, - rules_tags: Vec<String>, - rules_include: Vec<String>, - rules_exclude: Vec<String>, - args: Vec<PathBuf>, - ignore: Vec<PathBuf>, - json: bool, + lint_flags: LintFlags, + watch: bool, ) -> Result<(), AnyError> { + let LintFlags { + rules_tags, + rules_include, + rules_exclude, + files: args, + ignore, + json, + .. + } = lint_flags; // 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 = args.clone(); - let mut exclude_files = ignore; + let mut exclude_files = ignore.clone(); if let Some(lint_config) = maybe_lint_config.as_ref() { if include_files.is_empty() { @@ -79,6 +87,13 @@ pub async fn lint_files( } } + let reporter_kind = if json { + LintReporterKind::Json + } else { + 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. @@ -89,27 +104,82 @@ pub async fn lint_files( rules_exclude, )?; - let has_error = Arc::new(AtomicBool::new(false)); - - let reporter_kind = if json { - LintReporterKind::Json - } else { - LintReporterKind::Pretty + let resolver = |changed: Option<Vec<PathBuf>>| { + let files_changed = changed.is_some(); + let result = collect_files( + &*include_files.clone(), + &*exclude_files.clone(), + is_supported_ext, + ) + .map(|files| { + if let Some(paths) = changed { + files + .into_iter() + .filter(|path| paths.contains(path)) + .collect::<Vec<_>>() + } else { + files + } + }); + let paths_to_watch = args.clone(); + async move { + if (files_changed || !watch) + && matches!(result, Ok(ref files) if files.is_empty()) + { + ResolutionResult::Ignore + } else { + ResolutionResult::Restart { + paths_to_watch, + result, + } + } + } }; - let reporter_lock = Arc::new(Mutex::new(create_reporter(reporter_kind))); - let no_of_files_linted = + let operation = |paths: Vec<PathBuf>| async { + let target_files_len = paths.len(); + let reporter_kind = reporter_kind.clone(); + let reporter_lock = Arc::new(Mutex::new(create_reporter(reporter_kind))); + run_parallelized(paths, { + let has_error = has_error.clone(); + let lint_rules = lint_rules.clone(); + let reporter_lock = reporter_lock.clone(); + move |file_path| { + let r = lint_file(file_path.clone(), lint_rules.clone()); + handle_lint_result( + &file_path.to_string_lossy(), + r, + reporter_lock.clone(), + has_error, + ); + + Ok(()) + } + }) + .await?; + reporter_lock.lock().unwrap().close(target_files_len); + + Ok(()) + }; + if watch { if args.len() == 1 && args[0].to_string_lossy() == "-" { + return Err(generic_error( + "Lint watch on standard input is not supported.", + )); + } + file_watcher::watch_func(resolver, operation, "Lint").await?; + } else { + if args.len() == 1 && args[0].to_string_lossy() == "-" { + let reporter_lock = + Arc::new(Mutex::new(create_reporter(reporter_kind.clone()))); let r = lint_stdin(lint_rules); - handle_lint_result( STDIN_FILE_NAME, r, reporter_lock.clone(), has_error.clone(), ); - - 1 + reporter_lock.lock().unwrap().close(1); } else { let target_files = collect_files(&include_files, &exclude_files, is_supported_ext) @@ -121,32 +191,12 @@ pub async fn lint_files( } })?; debug!("Found {} files", target_files.len()); - let target_files_len = target_files.len(); - - run_parallelized(target_files, { - let reporter_lock = reporter_lock.clone(); - let has_error = has_error.clone(); - move |file_path| { - let r = lint_file(file_path.clone(), lint_rules.clone()); - handle_lint_result( - &file_path.to_string_lossy(), - r, - reporter_lock, - has_error, - ); - Ok(()) - } - }) - .await?; - - target_files_len + operation(target_files).await?; }; - - reporter_lock.lock().unwrap().close(no_of_files_linted); - let has_error = has_error.load(Ordering::Relaxed); - - if has_error { - std::process::exit(1); + let has_error = has_error.load(Ordering::Relaxed); + if has_error { + std::process::exit(1); + } } Ok(()) |