1
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2025-01-21 04:52:26 -05:00

feat: "deno lint" subcommand (#6125)

This commit is contained in:
Bartek Iwańczuk 2020-06-08 14:06:20 +02:00 committed by GitHub
parent 62adc63934
commit 0e9da7e731
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 134 additions and 8 deletions

16
Cargo.lock generated
View file

@ -443,6 +443,7 @@ dependencies = [
"bytes 0.5.4",
"clap",
"deno_core",
"deno_lint",
"deno_typescript",
"dirs",
"dissimilar",
@ -503,6 +504,21 @@ dependencies = [
"url 2.1.1",
]
[[package]]
name = "deno_lint"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "77a3ec96c92609aa121d085f3a1351d3836e55b78a4b8ce79ea771c2ad9bd80b"
dependencies = [
"lazy_static",
"regex",
"swc_atoms",
"swc_common",
"swc_ecma_ast",
"swc_ecma_parser",
"swc_ecma_visit",
]
[[package]]
name = "deno_typescript"
version = "0.47.1"

View file

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

View file

@ -50,6 +50,9 @@ pub enum DenoSubcommand {
root: Option<PathBuf>,
force: bool,
},
Lint {
files: Vec<String>,
},
Repl,
Run {
script: String,
@ -260,6 +263,8 @@ pub fn flags_from_vec_safe(args: Vec<String>) -> clap::Result<Flags> {
upgrade_parse(&mut flags, m);
} else if let Some(m) = matches.subcommand_matches("doc") {
doc_parse(&mut flags, m);
} else if let Some(m) = matches.subcommand_matches("lint") {
lint_parse(&mut flags, m);
} else {
repl_parse(&mut flags, &matches);
}
@ -302,18 +307,19 @@ If the flag is set, restrict these messages to errors.",
.global(true),
)
.subcommand(bundle_subcommand())
.subcommand(completions_subcommand())
.subcommand(eval_subcommand())
.subcommand(cache_subcommand())
.subcommand(completions_subcommand())
.subcommand(doc_subcommand())
.subcommand(eval_subcommand())
.subcommand(fmt_subcommand())
.subcommand(info_subcommand())
.subcommand(install_subcommand())
.subcommand(lint_subcommand())
.subcommand(repl_subcommand())
.subcommand(run_subcommand())
.subcommand(test_subcommand())
.subcommand(types_subcommand())
.subcommand(upgrade_subcommand())
.subcommand(doc_subcommand())
.long_about(DENO_HELP)
.after_help(ENV_VARIABLES_HELP)
}
@ -579,6 +585,16 @@ fn doc_parse(flags: &mut Flags, matches: &clap::ArgMatches) {
};
}
fn lint_parse(flags: &mut Flags, matches: &clap::ArgMatches) {
unstable_arg_parse(flags, matches);
let files = matches
.values_of("files")
.unwrap()
.map(String::from)
.collect();
flags.subcommand = DenoSubcommand::Lint { files };
}
fn types_subcommand<'a, 'b>() -> App<'a, 'b> {
SubCommand::with_name("types")
.arg(unstable_arg())
@ -889,6 +905,25 @@ Show documentation for runtime built-ins:
)
}
fn lint_subcommand<'a, 'b>() -> App<'a, 'b> {
SubCommand::with_name("lint")
.about("Lint source files")
.long_about(
"Lint JavaScript/TypeScript source code.
deno lint myfile1.ts myfile2.js
Ignore diagnostics on next line preceding it with an ignore comment and code:
// deno-lint-ignore no-explicit-any",
)
.arg(unstable_arg())
.arg(
Arg::with_name("files")
.takes_value(true)
.required(true)
.min_values(1),
)
}
fn permission_args<'a, 'b>(app: App<'a, 'b>) -> App<'a, 'b> {
app
.arg(

View file

@ -10,6 +10,15 @@ use std::ops::Deref;
const SOURCE_ABBREV_THRESHOLD: usize = 150;
pub fn format_location(filename: String, line: i64, col: i64) -> String {
format!(
"{}:{}:{}",
colors::cyan(filename),
colors::yellow(line.to_string()),
colors::yellow(col.to_string())
)
}
pub fn format_stack(
is_error: bool,
message_line: String,
@ -137,11 +146,10 @@ impl fmt::Display for JSError {
&& self.0.line_number.is_some()
&& self.0.start_column.is_some()
{
formatted_frames = vec![format!(
"{}:{}:{}",
colors::cyan(self.0.script_resource_name.clone().unwrap()),
colors::yellow(self.0.line_number.unwrap().to_string()),
colors::yellow((self.0.start_column.unwrap() + 1).to_string())
formatted_frames = vec![format_location(
self.0.script_resource_name.clone().unwrap(),
self.0.line_number.unwrap(),
self.0.start_column.unwrap() + 1,
)]
};

View file

@ -314,6 +314,71 @@ async fn install_command(
.map_err(ErrBox::from)
}
async fn lint_command(flags: Flags, files: Vec<String>) -> Result<(), ErrBox> {
let global_state = GlobalState::new(flags)?;
// TODO(bartlomieju): refactor, it's non-sense to create
// state just to perform unstable check...
use crate::state::State;
let state = State::new(
global_state.clone(),
None,
ModuleSpecifier::resolve_url("file:///dummy.ts").unwrap(),
None,
true,
)?;
state.check_unstable("lint");
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 mut linter = deno_lint::linter::Linter::default();
let lint_rules = deno_lint::rules::get_all_rules();
let file_diagnostics = linter.lint(file, source_code, 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> {
let main_module =
ModuleSpecifier::resolve_url_or_path("./__$deno$fetch.ts").unwrap();
@ -657,6 +722,7 @@ pub fn main() {
} => {
install_command(flags, module_url, args, name, root, force).boxed_local()
}
DenoSubcommand::Lint { files } => lint_command(flags, files).boxed_local(),
DenoSubcommand::Repl => run_repl(flags).boxed_local(),
DenoSubcommand::Run { script } => run_command(flags, script).boxed_local(),
DenoSubcommand::Test {