summaryrefslogtreecommitdiff
path: root/cli/tools/lint/mod.rs
diff options
context:
space:
mode:
authorDavid Sherret <dsherret@users.noreply.github.com>2024-07-25 09:07:59 -0400
committerGitHub <noreply@github.com>2024-07-25 09:07:59 -0400
commit763f05e74dfd0032b238603f625893a52e363591 (patch)
treec6a71559472755919358afa53eecac206cad80a9 /cli/tools/lint/mod.rs
parentef78d317f084ffe633253acd138a48a425113fa7 (diff)
fix(unstable): move sloppy-import warnings to lint rule (#24710)
Adds a new `no-sloppy-imports` lint rule and cleans up the lint code. Closes #22844 Closes https://github.com/denoland/deno_lint/issues/1293
Diffstat (limited to 'cli/tools/lint/mod.rs')
-rw-r--r--cli/tools/lint/mod.rs584
1 files changed, 125 insertions, 459 deletions
diff --git a/cli/tools/lint/mod.rs b/cli/tools/lint/mod.rs
index 942129120..e01b38430 100644
--- a/cli/tools/lint/mod.rs
+++ b/cli/tools/lint/mod.rs
@@ -3,18 +3,13 @@
//! This module provides file linting utilities using
//! [`deno_lint`](https://github.com/denoland/deno_lint).
use deno_ast::diagnostics::Diagnostic;
-use deno_ast::MediaType;
use deno_ast::ModuleSpecifier;
use deno_ast::ParsedSource;
-use deno_ast::SourceRange;
-use deno_ast::SourceTextInfo;
-use deno_config::deno_json::ConfigFile;
+use deno_config::deno_json::LintRulesConfig;
use deno_config::glob::FileCollector;
use deno_config::glob::FilePatterns;
use deno_config::workspace::WorkspaceDirectory;
use deno_core::anyhow::anyhow;
-use deno_core::anyhow::bail;
-use deno_core::anyhow::Context;
use deno_core::error::generic_error;
use deno_core::error::AnyError;
use deno_core::futures::future::LocalBoxFuture;
@@ -23,19 +18,12 @@ use deno_core::parking_lot::Mutex;
use deno_core::serde_json;
use deno_core::unsync::future::LocalFutureExt;
use deno_core::unsync::future::SharedLocal;
-use deno_graph::FastCheckDiagnostic;
use deno_graph::ModuleGraph;
use deno_lint::diagnostic::LintDiagnostic;
use deno_lint::linter::LintConfig;
-use deno_lint::linter::LintFileOptions;
-use deno_lint::linter::Linter;
-use deno_lint::linter::LinterBuilder;
-use deno_lint::rules;
-use deno_lint::rules::LintRule;
use log::debug;
use log::info;
use serde::Serialize;
-use std::borrow::Cow;
use std::collections::HashSet;
use std::fs;
use std::io::stdin;
@@ -50,7 +38,6 @@ use crate::args::Flags;
use crate::args::LintFlags;
use crate::args::LintOptions;
use crate::args::LintReporterKind;
-use crate::args::LintRulesConfig;
use crate::args::WorkspaceLintOptions;
use crate::cache::Caches;
use crate::cache::IncrementalCache;
@@ -60,11 +47,17 @@ use crate::graph_util::ModuleGraphCreator;
use crate::tools::fmt::run_parallelized;
use crate::util::file_watcher;
use crate::util::fs::canonicalize_path;
-use crate::util::fs::specifier_from_file_path;
use crate::util::path::is_script_ext;
use crate::util::sync::AtomicFlag;
-pub mod no_slow_types;
+mod linter;
+mod rules;
+
+pub use linter::CliLinter;
+pub use linter::CliLinterOptions;
+pub use rules::collect_no_slow_type_diagnostics;
+pub use rules::ConfiguredRules;
+pub use rules::LintRuleProvider;
static STDIN_FILE_NAME: &str = "$deno$stdin.ts";
@@ -120,6 +113,7 @@ pub async fn lint(
let mut linter = WorkspaceLinter::new(
factory.caches()?.clone(),
+ factory.lint_rule_provider().await?,
factory.module_graph_creator().await?.clone(),
cli_options.start_dir.clone(),
&cli_options.resolve_workspace_lint_options(&lint_flags)?,
@@ -157,12 +151,15 @@ pub async fn lint(
let lint_config = start_dir
.to_lint_config(FilePatterns::new_with_base(start_dir.dir_path()))?;
let lint_options = LintOptions::resolve(lint_config, &lint_flags);
- let lint_rules = get_config_rules_err_empty(
- lint_options.rules,
- start_dir.maybe_deno_json().map(|c| c.as_ref()),
- )?;
+ let lint_rules = factory
+ .lint_rule_provider()
+ .await?
+ .resolve_lint_rules_err_empty(
+ lint_options.rules,
+ start_dir.maybe_deno_json().map(|c| c.as_ref()),
+ )?;
let file_path = cli_options.initial_cwd().join(STDIN_FILE_NAME);
- let r = lint_stdin(&file_path, lint_rules.rules, deno_lint_config);
+ let r = lint_stdin(&file_path, lint_rules, deno_lint_config);
let success = handle_lint_result(
&file_path.to_string_lossy(),
r,
@@ -173,6 +170,7 @@ pub async fn lint(
} else {
let mut linter = WorkspaceLinter::new(
factory.caches()?.clone(),
+ factory.lint_rule_provider().await?,
factory.module_graph_creator().await?.clone(),
cli_options.start_dir.clone(),
&workspace_lint_options,
@@ -234,6 +232,7 @@ type WorkspaceModuleGraphFuture =
struct WorkspaceLinter {
caches: Arc<Caches>,
+ lint_rule_provider: LintRuleProvider,
module_graph_creator: Arc<ModuleGraphCreator>,
workspace_dir: Arc<WorkspaceDirectory>,
reporter_lock: Arc<Mutex<Box<dyn LintReporter + Send>>>,
@@ -245,6 +244,7 @@ struct WorkspaceLinter {
impl WorkspaceLinter {
pub fn new(
caches: Arc<Caches>,
+ lint_rule_provider: LintRuleProvider,
module_graph_creator: Arc<ModuleGraphCreator>,
workspace_dir: Arc<WorkspaceDirectory>,
workspace_options: &WorkspaceLintOptions,
@@ -253,6 +253,7 @@ impl WorkspaceLinter {
Arc::new(Mutex::new(create_reporter(workspace_options.reporter_kind)));
Self {
caches,
+ lint_rule_provider,
module_graph_creator,
workspace_dir,
reporter_lock,
@@ -271,18 +272,27 @@ impl WorkspaceLinter {
) -> Result<(), AnyError> {
self.file_count += paths.len();
- let lint_rules = get_config_rules_err_empty(
+ let lint_rules = self.lint_rule_provider.resolve_lint_rules_err_empty(
lint_options.rules,
member_dir.maybe_deno_json().map(|c| c.as_ref()),
)?;
- let incremental_cache = Arc::new(IncrementalCache::new(
- self.caches.lint_incremental_cache_db(),
- &lint_rules.incremental_cache_state(),
- &paths,
- ));
+ let maybe_incremental_cache =
+ lint_rules.incremental_cache_state().map(|state| {
+ Arc::new(IncrementalCache::new(
+ self.caches.lint_incremental_cache_db(),
+ &state,
+ &paths,
+ ))
+ });
+
+ let linter = Arc::new(CliLinter::new(CliLinterOptions {
+ configured_rules: lint_rules,
+ fix: lint_options.fix,
+ deno_lint_config: lint_config,
+ }));
let mut futures = Vec::with_capacity(2);
- if lint_rules.no_slow_types {
+ if linter.has_package_rules() {
if self.workspace_module_graph.is_none() {
let module_graph_creator = self.module_graph_creator.clone();
let packages = self.workspace_dir.jsr_packages_for_publish();
@@ -304,6 +314,7 @@ impl WorkspaceLinter {
if let Some(publish_config) = publish_config {
let has_error = self.has_error.clone();
let reporter_lock = self.reporter_lock.clone();
+ let linter = linter.clone();
let path_urls = paths
.iter()
.filter_map(|p| ModuleSpecifier::from_file_path(p).ok())
@@ -318,16 +329,12 @@ impl WorkspaceLinter {
if !export_urls.iter().any(|url| path_urls.contains(url)) {
return Ok(()); // entrypoint is not specified, so skip
}
- let diagnostics = no_slow_types::collect_no_slow_type_diagnostics(
- &export_urls,
- &graph,
- );
+ let diagnostics = linter.lint_package(&graph, &export_urls);
if !diagnostics.is_empty() {
has_error.raise();
let mut reporter = reporter_lock.lock();
for diagnostic in &diagnostics {
- reporter
- .visit_diagnostic(LintOrCliDiagnostic::FastCheck(diagnostic));
+ reporter.visit_diagnostic(diagnostic);
}
}
Ok(())
@@ -339,11 +346,9 @@ impl WorkspaceLinter {
futures.push({
let has_error = self.has_error.clone();
- let linter = create_linter(lint_rules.rules);
let reporter_lock = self.reporter_lock.clone();
- let incremental_cache = incremental_cache.clone();
- let lint_config = lint_config.clone();
- let fix = lint_options.fix;
+ let maybe_incremental_cache = maybe_incremental_cache.clone();
+ let linter = linter.clone();
async move {
run_parallelized(paths, {
move |file_path| {
@@ -351,19 +356,23 @@ impl WorkspaceLinter {
deno_ast::strip_bom(fs::read_to_string(&file_path)?);
// don't bother rechecking this file if it didn't have any diagnostics before
- if incremental_cache.is_file_same(&file_path, &file_text) {
- return Ok(());
+ if let Some(incremental_cache) = &maybe_incremental_cache {
+ if incremental_cache.is_file_same(&file_path, &file_text) {
+ return Ok(());
+ }
}
- let r = lint_file(&linter, &file_path, file_text, lint_config, fix);
+ let r = linter.lint_file(&file_path, file_text);
if let Ok((file_source, file_diagnostics)) = &r {
- if file_diagnostics.is_empty() {
- // update the incremental cache if there were no diagnostics
- incremental_cache.update_file(
- &file_path,
- // ensure the returned text is used here as it may have been modified via --fix
- file_source.text(),
- )
+ if let Some(incremental_cache) = &maybe_incremental_cache {
+ if file_diagnostics.is_empty() {
+ // update the incremental cache if there were no diagnostics
+ incremental_cache.update_file(
+ &file_path,
+ // ensure the returned text is used here as it may have been modified via --fix
+ file_source.text(),
+ )
+ }
}
}
@@ -384,9 +393,21 @@ impl WorkspaceLinter {
.boxed_local()
});
- deno_core::futures::future::try_join_all(futures).await?;
+ if lint_options.fix {
+ // run sequentially when using `--fix` to lower the chances of weird
+ // bugs where a file level fix affects a package level diagnostic though
+ // it probably will happen anyway
+ for future in futures {
+ future.await?;
+ }
+ } else {
+ deno_core::futures::future::try_join_all(futures).await?;
+ }
+
+ if let Some(incremental_cache) = &maybe_incremental_cache {
+ incremental_cache.wait_completion().await;
+ }
- incremental_cache.wait_completion().await;
Ok(())
}
@@ -410,11 +431,17 @@ fn collect_lint_files(
#[allow(clippy::print_stdout)]
pub fn print_rules_list(json: bool, maybe_rules_tags: Option<Vec<String>>) {
- let lint_rules = if maybe_rules_tags.is_none() {
- rules::get_all_rules()
- } else {
- rules::get_filtered_rules(maybe_rules_tags, None, None)
- };
+ let rule_provider = LintRuleProvider::new(None, None);
+ let lint_rules = rule_provider
+ .resolve_lint_rules(
+ LintRulesConfig {
+ tags: maybe_rules_tags.clone(),
+ include: None,
+ exclude: None,
+ },
+ None,
+ )
+ .rules;
if json {
let json_rules: Vec<serde_json::Value> = lint_rules
@@ -442,186 +469,19 @@ pub fn print_rules_list(json: bool, maybe_rules_tags: Option<Vec<String>>) {
}
println!(
"{}",
- colors::gray(format!(
- " help: https://lint.deno.land/#{}",
- rule.code()
- ))
+ colors::gray(format!(" help: {}", rule.help_docs_url()))
);
println!();
}
}
}
-pub fn create_linter(rules: Vec<&'static dyn LintRule>) -> Linter {
- LinterBuilder::default()
- .ignore_file_directive("deno-lint-ignore-file")
- .ignore_diagnostic_directive("deno-lint-ignore")
- .rules(rules)
- .build()
-}
-
-fn lint_file(
- linter: &Linter,
- file_path: &Path,
- source_code: String,
- config: LintConfig,
- fix: bool,
-) -> Result<(ParsedSource, Vec<LintDiagnostic>), AnyError> {
- let specifier = specifier_from_file_path(file_path)?;
- let media_type = MediaType::from_specifier(&specifier);
-
- if fix {
- lint_file_and_fix(
- linter,
- &specifier,
- media_type,
- source_code,
- file_path,
- config,
- )
- } else {
- linter
- .lint_file(LintFileOptions {
- specifier,
- media_type,
- source_code,
- config,
- })
- .map_err(AnyError::from)
- }
-}
-
-fn lint_file_and_fix(
- linter: &Linter,
- specifier: &ModuleSpecifier,
- media_type: MediaType,
- source_code: String,
- file_path: &Path,
- config: LintConfig,
-) -> Result<(ParsedSource, Vec<LintDiagnostic>), deno_core::anyhow::Error> {
- // initial lint
- let (source, diagnostics) = linter.lint_file(LintFileOptions {
- specifier: specifier.clone(),
- media_type,
- source_code,
- config: config.clone(),
- })?;
-
- // Try applying fixes repeatedly until the file has none left or
- // a maximum number of iterations is reached. This is necessary
- // because lint fixes may overlap and so we can't always apply
- // them in one pass.
- let mut source = source;
- let mut diagnostics = diagnostics;
- let mut fix_iterations = 0;
- loop {
- let change = apply_lint_fixes_and_relint(
- specifier,
- media_type,
- linter,
- config.clone(),
- source.text_info_lazy(),
- &diagnostics,
- )?;
- match change {
- Some(change) => {
- source = change.0;
- diagnostics = change.1;
- }
- None => {
- break;
- }
- }
- fix_iterations += 1;
- if fix_iterations > 5 {
- log::warn!(
- concat!(
- "Reached maximum number of fix iterations for '{}'. There's ",
- "probably a bug in Deno. Please fix this file manually.",
- ),
- specifier,
- );
- break;
- }
- }
-
- if fix_iterations > 0 {
- // everything looks good and the file still parses, so write it out
- fs::write(file_path, source.text().as_ref())
- .context("Failed writing fix to file.")?;
- }
-
- Ok((source, diagnostics))
-}
-
-fn apply_lint_fixes_and_relint(
- specifier: &ModuleSpecifier,
- media_type: MediaType,
- linter: &Linter,
- config: LintConfig,
- text_info: &SourceTextInfo,
- diagnostics: &[LintDiagnostic],
-) -> Result<Option<(ParsedSource, Vec<LintDiagnostic>)>, AnyError> {
- let Some(new_text) = apply_lint_fixes(text_info, diagnostics) else {
- return Ok(None);
- };
- linter
- .lint_file(LintFileOptions {
- specifier: specifier.clone(),
- source_code: new_text,
- media_type,
- config,
- })
- .map(Some)
- .context(
- "An applied lint fix caused a syntax error. Please report this bug.",
- )
-}
-
-fn apply_lint_fixes(
- text_info: &SourceTextInfo,
- diagnostics: &[LintDiagnostic],
-) -> Option<String> {
- if diagnostics.is_empty() {
- return None;
- }
-
- let file_start = text_info.range().start;
- let mut quick_fixes = diagnostics
- .iter()
- // use the first quick fix
- .filter_map(|d| d.fixes.first())
- .flat_map(|fix| fix.changes.iter())
- .map(|change| deno_ast::TextChange {
- range: change.range.as_byte_range(file_start),
- new_text: change.new_text.to_string(),
- })
- .collect::<Vec<_>>();
- if quick_fixes.is_empty() {
- return None;
- }
- // remove any overlapping text changes, we'll circle
- // back for another pass to fix the remaining
- quick_fixes.sort_by_key(|change| change.range.start);
- for i in (1..quick_fixes.len()).rev() {
- let cur = &quick_fixes[i];
- let previous = &quick_fixes[i - 1];
- let is_overlapping = cur.range.start < previous.range.end;
- if is_overlapping {
- quick_fixes.remove(i);
- }
- }
- let new_text =
- deno_ast::apply_text_changes(text_info.text_str(), quick_fixes);
- Some(new_text)
-}
-
/// Lint stdin and write result to stdout.
/// Treats input as TypeScript.
/// Compatible with `--json` flag.
fn lint_stdin(
file_path: &Path,
- lint_rules: Vec<&'static dyn LintRule>,
+ configured_rules: ConfiguredRules,
deno_lint_config: LintConfig,
) -> Result<(ParsedSource, Vec<LintDiagnostic>), AnyError> {
let mut source_code = String::new();
@@ -629,15 +489,14 @@ fn lint_stdin(
return Err(generic_error("Failed to read from stdin"));
}
- let linter = create_linter(lint_rules);
+ let linter = CliLinter::new(CliLinterOptions {
+ fix: false,
+ configured_rules,
+ deno_lint_config,
+ });
linter
- .lint_file(LintFileOptions {
- specifier: specifier_from_file_path(file_path)?,
- source_code: deno_ast::strip_bom(source_code),
- media_type: MediaType::TypeScript,
- config: deno_lint_config,
- })
+ .lint_file(file_path, deno_ast::strip_bom(source_code))
.map_err(AnyError::from)
}
@@ -656,11 +515,18 @@ fn handle_lint_result(
}
}
file_diagnostics.sort_by(|a, b| match a.specifier.cmp(&b.specifier) {
- std::cmp::Ordering::Equal => a.range.start.cmp(&b.range.start),
+ std::cmp::Ordering::Equal => {
+ let a_start = a.range.as_ref().map(|r| r.range.start);
+ let b_start = b.range.as_ref().map(|r| r.range.start);
+ match a_start.cmp(&b_start) {
+ std::cmp::Ordering::Equal => a.details.code.cmp(&b.details.code),
+ other => other,
+ }
+ }
file_order => file_order,
});
for d in &file_diagnostics {
- reporter.visit_diagnostic(LintOrCliDiagnostic::Lint(d));
+ reporter.visit_diagnostic(d);
}
file_diagnostics.is_empty()
}
@@ -671,99 +537,8 @@ fn handle_lint_result(
}
}
-#[derive(Clone, Copy)]
-pub enum LintOrCliDiagnostic<'a> {
- Lint(&'a LintDiagnostic),
- FastCheck(&'a FastCheckDiagnostic),
-}
-
-impl<'a> LintOrCliDiagnostic<'a> {
- pub fn specifier(&self) -> &ModuleSpecifier {
- match self {
- LintOrCliDiagnostic::Lint(d) => &d.specifier,
- LintOrCliDiagnostic::FastCheck(d) => d.specifier(),
- }
- }
-
- pub fn range(&self) -> Option<(&SourceTextInfo, SourceRange)> {
- match self {
- LintOrCliDiagnostic::Lint(d) => Some((&d.text_info, d.range)),
- LintOrCliDiagnostic::FastCheck(d) => {
- d.range().map(|r| (&r.text_info, r.range))
- }
- }
- }
-}
-
-impl<'a> deno_ast::diagnostics::Diagnostic for LintOrCliDiagnostic<'a> {
- fn level(&self) -> deno_ast::diagnostics::DiagnosticLevel {
- match self {
- LintOrCliDiagnostic::Lint(d) => d.level(),
- LintOrCliDiagnostic::FastCheck(d) => d.level(),
- }
- }
-
- fn code(&self) -> Cow<'_, str> {
- match self {
- LintOrCliDiagnostic::Lint(d) => d.code(),
- LintOrCliDiagnostic::FastCheck(_) => Cow::Borrowed("no-slow-types"),
- }
- }
-
- fn message(&self) -> Cow<'_, str> {
- match self {
- LintOrCliDiagnostic::Lint(d) => d.message(),
- LintOrCliDiagnostic::FastCheck(d) => d.message(),
- }
- }
-
- fn location(&self) -> deno_ast::diagnostics::DiagnosticLocation {
- match self {
- LintOrCliDiagnostic::Lint(d) => d.location(),
- LintOrCliDiagnostic::FastCheck(d) => d.location(),
- }
- }
-
- fn snippet(&self) -> Option<deno_ast::diagnostics::DiagnosticSnippet<'_>> {
- match self {
- LintOrCliDiagnostic::Lint(d) => d.snippet(),
- LintOrCliDiagnostic::FastCheck(d) => d.snippet(),
- }
- }
-
- fn hint(&self) -> Option<Cow<'_, str>> {
- match self {
- LintOrCliDiagnostic::Lint(d) => d.hint(),
- LintOrCliDiagnostic::FastCheck(d) => d.hint(),
- }
- }
-
- fn snippet_fixed(
- &self,
- ) -> Option<deno_ast::diagnostics::DiagnosticSnippet<'_>> {
- match self {
- LintOrCliDiagnostic::Lint(d) => d.snippet_fixed(),
- LintOrCliDiagnostic::FastCheck(d) => d.snippet_fixed(),
- }
- }
-
- fn info(&self) -> Cow<'_, [Cow<'_, str>]> {
- match self {
- LintOrCliDiagnostic::Lint(d) => d.info(),
- LintOrCliDiagnostic::FastCheck(d) => d.info(),
- }
- }
-
- fn docs_url(&self) -> Option<Cow<'_, str>> {
- match self {
- LintOrCliDiagnostic::Lint(d) => d.docs_url(),
- LintOrCliDiagnostic::FastCheck(d) => d.docs_url(),
- }
- }
-}
-
trait LintReporter {
- fn visit_diagnostic(&mut self, d: LintOrCliDiagnostic);
+ fn visit_diagnostic(&mut self, d: &LintDiagnostic);
fn visit_error(&mut self, file_path: &str, err: &AnyError);
fn close(&mut self, check_count: usize);
}
@@ -789,12 +564,10 @@ impl PrettyLintReporter {
}
impl LintReporter for PrettyLintReporter {
- fn visit_diagnostic(&mut self, d: LintOrCliDiagnostic) {
+ fn visit_diagnostic(&mut self, d: &LintDiagnostic) {
self.lint_count += 1;
- if let LintOrCliDiagnostic::Lint(d) = d {
- if !d.fixes.is_empty() {
- self.fixable_diagnostics += 1;
- }
+ if !d.details.fixes.is_empty() {
+ self.fixable_diagnostics += 1;
}
log::error!("{}\n", d.display());
@@ -838,15 +611,17 @@ impl CompactLintReporter {
}
impl LintReporter for CompactLintReporter {
- fn visit_diagnostic(&mut self, d: LintOrCliDiagnostic) {
+ fn visit_diagnostic(&mut self, d: &LintDiagnostic) {
self.lint_count += 1;
- match d.range() {
- Some((text_info, range)) => {
+ match &d.range {
+ Some(range) => {
+ let text_info = &range.text_info;
+ let range = &range.range;
let line_and_column = text_info.line_and_column_display(range.start);
log::error!(
"{}: line {}, col {} - {} ({})",
- d.specifier(),
+ d.specifier,
line_and_column.line_number,
line_and_column.column_number,
d.message(),
@@ -854,7 +629,7 @@ impl LintReporter for CompactLintReporter {
)
}
None => {
- log::error!("{}: {} ({})", d.specifier(), d.message(), d.code())
+ log::error!("{}: {} ({})", d.specifier, d.message(), d.code())
}
}
}
@@ -932,18 +707,22 @@ impl JsonLintReporter {
}
impl LintReporter for JsonLintReporter {
- fn visit_diagnostic(&mut self, d: LintOrCliDiagnostic) {
+ fn visit_diagnostic(&mut self, d: &LintDiagnostic) {
self.diagnostics.push(JsonLintDiagnostic {
- filename: d.specifier().to_string(),
- range: d.range().map(|(text_info, range)| JsonLintDiagnosticRange {
- start: JsonDiagnosticLintPosition::new(
- range.start.as_byte_index(text_info.range().start),
- text_info.line_and_column_index(range.start),
- ),
- end: JsonDiagnosticLintPosition::new(
- range.end.as_byte_index(text_info.range().start),
- text_info.line_and_column_index(range.end),
- ),
+ filename: d.specifier.to_string(),
+ range: d.range.as_ref().map(|range| {
+ let text_info = &range.text_info;
+ let range = range.range;
+ JsonLintDiagnosticRange {
+ start: JsonDiagnosticLintPosition::new(
+ range.start.as_byte_index(text_info.range().start),
+ text_info.line_and_column_index(range.start),
+ ),
+ end: JsonDiagnosticLintPosition::new(
+ range.end.as_byte_index(text_info.range().start),
+ text_info.line_and_column_index(range.end),
+ ),
+ }
}),
message: d.message().to_string(),
code: d.code().to_string(),
@@ -994,116 +773,3 @@ fn sort_diagnostics(diagnostics: &mut [JsonLintDiagnostic]) {
}
});
}
-
-fn get_config_rules_err_empty(
- rules: LintRulesConfig,
- maybe_config_file: Option<&ConfigFile>,
-) -> Result<ConfiguredRules, AnyError> {
- let lint_rules = get_configured_rules(rules, maybe_config_file);
- if lint_rules.rules.is_empty() {
- bail!("No rules have been configured")
- }
- Ok(lint_rules)
-}
-
-#[derive(Debug, Clone)]
-pub struct ConfiguredRules {
- pub rules: Vec<&'static dyn LintRule>,
- // cli specific rules
- pub no_slow_types: bool,
-}
-
-impl Default for ConfiguredRules {
- fn default() -> Self {
- get_configured_rules(Default::default(), None)
- }
-}
-
-impl ConfiguredRules {
- fn incremental_cache_state(&self) -> Vec<&str> {
- // use a hash of the rule names in order to bust the cache
- let mut names = self.rules.iter().map(|r| r.code()).collect::<Vec<_>>();
- // ensure this is stable by sorting it
- names.sort_unstable();
- if self.no_slow_types {
- names.push("no-slow-types");
- }
- names
- }
-}
-
-pub fn get_configured_rules(
- rules: LintRulesConfig,
- maybe_config_file: Option<&ConfigFile>,
-) -> ConfiguredRules {
- const NO_SLOW_TYPES_NAME: &str = "no-slow-types";
- let implicit_no_slow_types =
- maybe_config_file.map(|c| c.is_package()).unwrap_or(false);
- let no_slow_types = implicit_no_slow_types
- && !rules
- .exclude
- .as_ref()
- .map(|exclude| exclude.iter().any(|i| i == NO_SLOW_TYPES_NAME))
- .unwrap_or(false);
- let rules = rules::get_filtered_rules(
- rules
- .tags
- .or_else(|| Some(get_default_tags(maybe_config_file))),
- rules.exclude.map(|exclude| {
- exclude
- .into_iter()
- .filter(|c| c != NO_SLOW_TYPES_NAME)
- .collect()
- }),
- rules.include.map(|include| {
- include
- .into_iter()
- .filter(|c| c != NO_SLOW_TYPES_NAME)
- .collect()
- }),
- );
- ConfiguredRules {
- rules,
- no_slow_types,
- }
-}
-
-fn get_default_tags(maybe_config_file: Option<&ConfigFile>) -> Vec<String> {
- let mut tags = Vec::with_capacity(2);
- tags.push("recommended".to_string());
- if maybe_config_file.map(|c| c.is_package()).unwrap_or(false) {
- tags.push("jsr".to_string());
- }
- tags
-}
-
-#[cfg(test)]
-mod test {
- use deno_lint::rules::get_recommended_rules;
-
- use super::*;
- use crate::args::LintRulesConfig;
-
- #[test]
- fn recommended_rules_when_no_tags_in_config() {
- let rules_config = LintRulesConfig {
- exclude: Some(vec!["no-debugger".to_string()]),
- include: None,
- tags: None,
- };
- let rules = get_configured_rules(rules_config, None);
- let mut rule_names = rules
- .rules
- .into_iter()
- .map(|r| r.code().to_string())
- .collect::<Vec<_>>();
- rule_names.sort();
- let mut recommended_rule_names = get_recommended_rules()
- .into_iter()
- .map(|r| r.code().to_string())
- .filter(|n| n != "no-debugger")
- .collect::<Vec<_>>();
- recommended_rule_names.sort();
- assert_eq!(rule_names, recommended_rule_names);
- }
-}