mirror of
https://github.com/denoland/deno.git
synced 2025-03-04 01:44:26 -05:00
feat: "deno lint" subcommand (#6125)
This commit is contained in:
parent
62adc63934
commit
0e9da7e731
5 changed files with 134 additions and 8 deletions
16
Cargo.lock
generated
16
Cargo.lock
generated
|
@ -443,6 +443,7 @@ dependencies = [
|
||||||
"bytes 0.5.4",
|
"bytes 0.5.4",
|
||||||
"clap",
|
"clap",
|
||||||
"deno_core",
|
"deno_core",
|
||||||
|
"deno_lint",
|
||||||
"deno_typescript",
|
"deno_typescript",
|
||||||
"dirs",
|
"dirs",
|
||||||
"dissimilar",
|
"dissimilar",
|
||||||
|
@ -503,6 +504,21 @@ dependencies = [
|
||||||
"url 2.1.1",
|
"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]]
|
[[package]]
|
||||||
name = "deno_typescript"
|
name = "deno_typescript"
|
||||||
version = "0.47.1"
|
version = "0.47.1"
|
||||||
|
|
|
@ -20,6 +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.7" }
|
||||||
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"
|
||||||
|
|
41
cli/flags.rs
41
cli/flags.rs
|
@ -50,6 +50,9 @@ pub enum DenoSubcommand {
|
||||||
root: Option<PathBuf>,
|
root: Option<PathBuf>,
|
||||||
force: bool,
|
force: bool,
|
||||||
},
|
},
|
||||||
|
Lint {
|
||||||
|
files: Vec<String>,
|
||||||
|
},
|
||||||
Repl,
|
Repl,
|
||||||
Run {
|
Run {
|
||||||
script: String,
|
script: String,
|
||||||
|
@ -260,6 +263,8 @@ pub fn flags_from_vec_safe(args: Vec<String>) -> clap::Result<Flags> {
|
||||||
upgrade_parse(&mut flags, m);
|
upgrade_parse(&mut flags, m);
|
||||||
} else if let Some(m) = matches.subcommand_matches("doc") {
|
} else if let Some(m) = matches.subcommand_matches("doc") {
|
||||||
doc_parse(&mut flags, m);
|
doc_parse(&mut flags, m);
|
||||||
|
} else if let Some(m) = matches.subcommand_matches("lint") {
|
||||||
|
lint_parse(&mut flags, m);
|
||||||
} else {
|
} else {
|
||||||
repl_parse(&mut flags, &matches);
|
repl_parse(&mut flags, &matches);
|
||||||
}
|
}
|
||||||
|
@ -302,18 +307,19 @@ If the flag is set, restrict these messages to errors.",
|
||||||
.global(true),
|
.global(true),
|
||||||
)
|
)
|
||||||
.subcommand(bundle_subcommand())
|
.subcommand(bundle_subcommand())
|
||||||
.subcommand(completions_subcommand())
|
|
||||||
.subcommand(eval_subcommand())
|
|
||||||
.subcommand(cache_subcommand())
|
.subcommand(cache_subcommand())
|
||||||
|
.subcommand(completions_subcommand())
|
||||||
|
.subcommand(doc_subcommand())
|
||||||
|
.subcommand(eval_subcommand())
|
||||||
.subcommand(fmt_subcommand())
|
.subcommand(fmt_subcommand())
|
||||||
.subcommand(info_subcommand())
|
.subcommand(info_subcommand())
|
||||||
.subcommand(install_subcommand())
|
.subcommand(install_subcommand())
|
||||||
|
.subcommand(lint_subcommand())
|
||||||
.subcommand(repl_subcommand())
|
.subcommand(repl_subcommand())
|
||||||
.subcommand(run_subcommand())
|
.subcommand(run_subcommand())
|
||||||
.subcommand(test_subcommand())
|
.subcommand(test_subcommand())
|
||||||
.subcommand(types_subcommand())
|
.subcommand(types_subcommand())
|
||||||
.subcommand(upgrade_subcommand())
|
.subcommand(upgrade_subcommand())
|
||||||
.subcommand(doc_subcommand())
|
|
||||||
.long_about(DENO_HELP)
|
.long_about(DENO_HELP)
|
||||||
.after_help(ENV_VARIABLES_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> {
|
fn types_subcommand<'a, 'b>() -> App<'a, 'b> {
|
||||||
SubCommand::with_name("types")
|
SubCommand::with_name("types")
|
||||||
.arg(unstable_arg())
|
.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> {
|
fn permission_args<'a, 'b>(app: App<'a, 'b>) -> App<'a, 'b> {
|
||||||
app
|
app
|
||||||
.arg(
|
.arg(
|
||||||
|
|
|
@ -10,6 +10,15 @@ use std::ops::Deref;
|
||||||
|
|
||||||
const SOURCE_ABBREV_THRESHOLD: usize = 150;
|
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(
|
pub fn format_stack(
|
||||||
is_error: bool,
|
is_error: bool,
|
||||||
message_line: String,
|
message_line: String,
|
||||||
|
@ -137,11 +146,10 @@ impl fmt::Display for JSError {
|
||||||
&& self.0.line_number.is_some()
|
&& self.0.line_number.is_some()
|
||||||
&& self.0.start_column.is_some()
|
&& self.0.start_column.is_some()
|
||||||
{
|
{
|
||||||
formatted_frames = vec![format!(
|
formatted_frames = vec![format_location(
|
||||||
"{}:{}:{}",
|
self.0.script_resource_name.clone().unwrap(),
|
||||||
colors::cyan(self.0.script_resource_name.clone().unwrap()),
|
self.0.line_number.unwrap(),
|
||||||
colors::yellow(self.0.line_number.unwrap().to_string()),
|
self.0.start_column.unwrap() + 1,
|
||||||
colors::yellow((self.0.start_column.unwrap() + 1).to_string())
|
|
||||||
)]
|
)]
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
66
cli/main.rs
66
cli/main.rs
|
@ -314,6 +314,71 @@ async fn install_command(
|
||||||
.map_err(ErrBox::from)
|
.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> {
|
async fn cache_command(flags: Flags, files: Vec<String>) -> Result<(), ErrBox> {
|
||||||
let main_module =
|
let main_module =
|
||||||
ModuleSpecifier::resolve_url_or_path("./__$deno$fetch.ts").unwrap();
|
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()
|
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::Repl => run_repl(flags).boxed_local(),
|
||||||
DenoSubcommand::Run { script } => run_command(flags, script).boxed_local(),
|
DenoSubcommand::Run { script } => run_command(flags, script).boxed_local(),
|
||||||
DenoSubcommand::Test {
|
DenoSubcommand::Test {
|
||||||
|
|
Loading…
Add table
Reference in a new issue