feat(lint): use default globs, upgrade to v0.1.9 (#6222)

This commit:
* added default file globs so "deno lint" can be run
without arguments (just like "deno fmt")
* added test for globs in "deno lint"
* upgrade "deno_lint" crate to v0.1.9
This commit is contained in:
Bartek Iwańczuk 2020-06-10 23:29:48 +02:00 committed by GitHub
parent e53a1b1496
commit e4e332abbb
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 165 additions and 101 deletions

4
Cargo.lock generated
View file

@ -506,9 +506,9 @@ dependencies = [
[[package]] [[package]]
name = "deno_lint" name = "deno_lint"
version = "0.1.8" version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ca00aa150fff66457af99578360267a988b44b3dd0d7d503571b2e98b15094d" checksum = "886dbbba1d26b726e4e6c4c03001b7f21b31384acb2a038e5bce430c42de4190"
dependencies = [ dependencies = [
"lazy_static", "lazy_static",
"regex", "regex",

View file

@ -20,7 +20,7 @@ deno_typescript = { path = "../deno_typescript", version = "0.47.1" }
[dependencies] [dependencies]
deno_core = { path = "../core", version = "0.47.1" } deno_core = { path = "../core", version = "0.47.1" }
deno_lint = { version = "0.1.8" } deno_lint = { version = "0.1.9" }
deno_typescript = { path = "../deno_typescript", version = "0.47.1" } deno_typescript = { path = "../deno_typescript", version = "0.47.1" }
atty = "0.2.14" atty = "0.2.14"

View file

@ -588,11 +588,10 @@ fn doc_parse(flags: &mut Flags, matches: &clap::ArgMatches) {
fn lint_parse(flags: &mut Flags, matches: &clap::ArgMatches) { fn lint_parse(flags: &mut Flags, matches: &clap::ArgMatches) {
unstable_arg_parse(flags, matches); unstable_arg_parse(flags, matches);
let files = matches let files = match matches.values_of("files") {
.values_of("files") Some(f) => f.map(String::from).collect(),
.unwrap() None => vec![],
.map(String::from) };
.collect();
flags.subcommand = DenoSubcommand::Lint { files }; flags.subcommand = DenoSubcommand::Lint { files };
} }
@ -911,6 +910,7 @@ fn lint_subcommand<'a, 'b>() -> App<'a, 'b> {
.about("Lint source files") .about("Lint source files")
.long_about( .long_about(
"Lint JavaScript/TypeScript source code. "Lint JavaScript/TypeScript source code.
deno lint --unstable
deno lint --unstable myfile1.ts myfile2.js deno lint --unstable myfile1.ts myfile2.js
Ignore diagnostics on the next line by preceding it with an ignore comment and Ignore diagnostics on the next line by preceding it with an ignore comment and
@ -927,8 +927,8 @@ Ignore linting a file by adding an ignore comment at the top of the file:
.arg( .arg(
Arg::with_name("files") Arg::with_name("files")
.takes_value(true) .takes_value(true)
.required(true) .multiple(true)
.min_values(1), .required(false),
) )
} }
@ -1640,6 +1640,37 @@ mod tests {
); );
} }
#[test]
fn lint() {
let r = flags_from_vec_safe(svec![
"deno",
"lint",
"--unstable",
"script_1.ts",
"script_2.ts"
]);
assert_eq!(
r.unwrap(),
Flags {
subcommand: DenoSubcommand::Lint {
files: vec!["script_1.ts".to_string(), "script_2.ts".to_string()]
},
unstable: true,
..Flags::default()
}
);
let r = flags_from_vec_safe(svec!["deno", "lint", "--unstable"]);
assert_eq!(
r.unwrap(),
Flags {
subcommand: DenoSubcommand::Lint { files: vec![] },
unstable: true,
..Flags::default()
}
);
}
#[test] #[test]
fn types() { fn types() {
let r = flags_from_vec_safe(svec!["deno", "types"]); let r = flags_from_vec_safe(svec!["deno", "types"]);

View file

@ -34,23 +34,8 @@ pub async fn format(args: Vec<String>, check: bool) -> Result<(), ErrBox> {
return format_stdin(check); return format_stdin(check);
} }
let mut target_files: Vec<PathBuf> = vec![]; let target_files = collect_files(args)?;
if args.is_empty() {
target_files.extend(files_in_subtree(
std::env::current_dir().unwrap(),
is_supported,
));
} else {
for arg in args {
let p = PathBuf::from(arg);
if p.is_dir() {
target_files.extend(files_in_subtree(p, is_supported));
} else {
target_files.push(p);
};
}
}
let config = get_config(); let config = get_config();
if check { if check {
check_source_files(config, target_files).await check_source_files(config, target_files).await
@ -222,6 +207,26 @@ fn is_supported(path: &Path) -> bool {
} }
} }
pub fn collect_files(files: Vec<String>) -> Result<Vec<PathBuf>, ErrBox> {
let mut target_files: Vec<PathBuf> = vec![];
if files.is_empty() {
target_files
.extend(files_in_subtree(std::env::current_dir()?, is_supported));
} else {
for arg in files {
let p = PathBuf::from(arg);
if p.is_dir() {
target_files.extend(files_in_subtree(p, is_supported));
} else {
target_files.push(p);
};
}
}
Ok(target_files)
}
fn get_config() -> dprint::configuration::Configuration { fn get_config() -> dprint::configuration::Configuration {
use dprint::configuration::*; use dprint::configuration::*;
ConfigurationBuilder::new().deno().build() ConfigurationBuilder::new().deno().build()

79
cli/lint.rs Normal file
View file

@ -0,0 +1,79 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
//! This module provides file formating utilities using
//! [`deno_lint`](https://github.com/denoland/deno_lint).
//!
//! 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::file_fetcher::map_file_extension;
use crate::fmt::collect_files;
use crate::fmt_errors;
use crate::swc_util;
use deno_core::ErrBox;
use deno_lint::diagnostic::LintDiagnostic;
use deno_lint::linter::Linter;
use deno_lint::rules;
use std::fs;
use std::path::PathBuf;
pub fn lint_files(args: Vec<String>) -> Result<(), ErrBox> {
let target_files = collect_files(args)?;
let mut error_counts = 0;
for file_path in target_files {
let file_diagnostics = lint_file(file_path)?;
error_counts += file_diagnostics.len();
for d in file_diagnostics.iter() {
let fmt_diagnostic = format_diagnostic(d);
eprintln!("{}\n", fmt_diagnostic);
}
}
if error_counts > 0 {
eprintln!("Found {} problems", error_counts);
std::process::exit(1);
}
Ok(())
}
fn lint_file(file_path: PathBuf) -> Result<Vec<LintDiagnostic>, ErrBox> {
let file_name = file_path.to_string_lossy().to_string();
let source_code = fs::read_to_string(&file_path)?;
let media_type = map_file_extension(&file_path);
let syntax = swc_util::get_syntax_for_media_type(media_type);
let mut linter = Linter::default();
let lint_rules = rules::get_recommended_rules();
let file_diagnostics =
linter.lint(file_name, source_code, syntax, lint_rules)?;
Ok(file_diagnostics)
}
fn format_diagnostic(d: &LintDiagnostic) -> String {
let pretty_message = format!(
"({}) {}",
colors::gray(d.code.to_string()),
d.message.clone()
);
fmt_errors::format_stack(
true,
pretty_message,
Some(d.line_src.clone()),
Some(d.location.col as i64),
Some((d.location.col + d.snippet_length) as i64),
&[fmt_errors::format_location(
d.location.filename.clone(),
d.location.line as i64,
d.location.col as i64,
)],
0,
)
}

View file

@ -42,6 +42,7 @@ mod import_map;
mod inspector; mod inspector;
pub mod installer; pub mod installer;
mod js; mod js;
mod lint;
mod lockfile; mod lockfile;
mod metrics; mod metrics;
mod module_graph; mod module_graph;
@ -321,7 +322,7 @@ async fn lint_command(flags: Flags, files: Vec<String>) -> Result<(), ErrBox> {
// state just to perform unstable check... // state just to perform unstable check...
use crate::state::State; use crate::state::State;
let state = State::new( let state = State::new(
global_state.clone(), global_state,
None, None,
ModuleSpecifier::resolve_url("file:///dummy.ts").unwrap(), ModuleSpecifier::resolve_url("file:///dummy.ts").unwrap(),
None, None,
@ -329,56 +330,7 @@ async fn lint_command(flags: Flags, files: Vec<String>) -> Result<(), ErrBox> {
)?; )?;
state.check_unstable("lint"); state.check_unstable("lint");
lint::lint_files(files)
let mut error_counts = 0;
for file in files {
let specifier = ModuleSpecifier::resolve_url_or_path(&file)?;
let source_file = global_state
.file_fetcher
.fetch_source_file(&specifier, None, Permissions::allow_all())
.await?;
let source_code = String::from_utf8(source_file.source_code)?;
let syntax = swc_util::get_syntax_for_media_type(source_file.media_type);
let mut linter = deno_lint::linter::Linter::default();
let lint_rules = deno_lint::rules::get_all_rules();
let file_diagnostics =
linter.lint(file, source_code, syntax, lint_rules)?;
error_counts += file_diagnostics.len();
for d in file_diagnostics.iter() {
let pretty_message = format!(
"({}) {}",
colors::gray(d.code.to_string()),
d.message.clone()
);
eprintln!(
"{}\n",
fmt_errors::format_stack(
true,
pretty_message,
Some(d.line_src.clone()),
Some(d.location.col as i64),
Some((d.location.col + d.snippet_length) as i64),
&[fmt_errors::format_location(
d.location.filename.clone(),
d.location.line as i64,
d.location.col as i64,
)],
0
)
);
}
}
if error_counts > 0 {
eprintln!("Found {} problems", error_counts);
std::process::exit(1);
}
Ok(())
} }
async fn cache_command(flags: Flags, files: Vec<String>) -> Result<(), ErrBox> { async fn cache_command(flags: Flags, files: Vec<String>) -> Result<(), ErrBox> {

View file

@ -1957,6 +1957,12 @@ itest!(deno_lint {
exit_code: 1, exit_code: 1,
}); });
itest!(deno_lint_glob {
args: "lint --unstable lint/",
output: "lint/expected_glob.out",
exit_code: 1,
});
#[test] #[test]
fn cafile_fetch() { fn cafile_fetch() {
use url::Url; use url::Url;

View file

@ -1,12 +1,12 @@
(no-var) `var` keyword is not allowed (ban-untagged-ignore) Ignore directive requires lint rule code
var a = 1, // deno-lint-ignore
~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~
at [WILDCARD]file1.js:1:0 at [WILDCARD]file1.js:1:0
(single-var-declarator) Multiple variable declarators are not allowed (no-empty) Empty block statement
var a = 1, while (false) {}
~~~~~~~~~~ ~~
at [WILDCARD]file1.js:1:0 at [WILDCARD]file1.js:2:14
(no-empty) Empty block statement (no-empty) Empty block statement
} catch (e) {} } catch (e) {}
@ -23,14 +23,4 @@ function foo(): any {}
~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~
at [WILDCARD]file2.ts:6:0 at [WILDCARD]file2.ts:6:0
(ban-untagged-ignore) Ignore directive requires lint rule code Found 5 problems
// deno-lint-ignore
~~~~~~~~~~~~~~~~~~~
at [WILDCARD]file2.ts:8:0
(no-empty) Empty block statement
while (false) {}
~~
at [WILDCARD]file2.ts:9:14
Found 7 problems

View file

@ -0,0 +1,2 @@
[WILDCARD]
Found 5 problems

View file

@ -1,3 +1,2 @@
var a = 1, // deno-lint-ignore
b = 2, while (false) {}
c = 3;

View file

@ -4,6 +4,3 @@ try {
// deno-lint-ignore no-explicit-any require-await // deno-lint-ignore no-explicit-any require-await
function foo(): any {} function foo(): any {}
// deno-lint-ignore
while (false) {}

3
cli/tests/std_lint.out Normal file
View file

@ -0,0 +1,3 @@
[WILDCARD]
Found [WILDCARD] problems