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:
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",
|
||||
"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"
|
||||
|
|
|
@ -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"
|
||||
|
|
41
cli/flags.rs
41
cli/flags.rs
|
@ -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(
|
||||
|
|
|
@ -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,
|
||||
)]
|
||||
};
|
||||
|
||||
|
|
66
cli/main.rs
66
cli/main.rs
|
@ -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 {
|
||||
|
|
Loading…
Add table
Reference in a new issue