Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: Linter, Context and more #1218

Merged
merged 19 commits into from
Dec 20, 2023
Merged
29 changes: 15 additions & 14 deletions examples/dlint/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use clap::Command;
use deno_ast::MediaType;
use deno_ast::SourceTextInfo;
use deno_lint::diagnostic::LintDiagnostic;
use deno_lint::linter::LintFileOptions;
use deno_lint::linter::LinterBuilder;
use deno_lint::rules::{get_filtered_rules, get_recommended_rules};
use log::debug;
Expand Down Expand Up @@ -94,25 +95,25 @@ fn run_linter(
get_recommended_rules()
};
let file_diagnostics = Arc::new(Mutex::new(BTreeMap::new()));
let linter_builder = LinterBuilder::default().rules(rules.clone());

let linter = linter_builder.build();
if rules.is_empty() {
bail!("No lint rules configured");
} else {
debug!("Configured rules: {}", rules.len());
}

paths
.par_iter()
.try_for_each(|file_path| -> Result<(), AnyError> {
let source_code = std::fs::read_to_string(file_path)?;

debug!("Configured rules: {}", rules.len());

if rules.is_empty() {
bail!("There's no rule to be run!");
}

let linter_builder = LinterBuilder::default()
.rules(rules.clone())
.media_type(MediaType::from_path(file_path));

let linter = linter_builder.build();

let (parsed_source, diagnostics) =
linter.lint(file_path.to_string_lossy().to_string(), source_code)?;
let (parsed_source, diagnostics) = linter.lint_file(LintFileOptions {
filename: file_path.to_string_lossy().to_string(),
source_code,
media_type: MediaType::from_path(file_path),
})?;

error_counts.fetch_add(diagnostics.len(), Ordering::Relaxed);

Expand Down
7 changes: 4 additions & 3 deletions src/ast_parser.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
// Copyright 2020-2021 the Deno authors. All rights reserved. MIT license.
use deno_ast::swc::parser::Syntax;
use deno_ast::get_syntax;
use deno_ast::Diagnostic;
use deno_ast::MediaType;
use deno_ast::ParsedSource;

pub(crate) fn parse_program(
file_name: &str,
syntax: Syntax,
media_type: MediaType,
source_code: String,
) -> Result<ParsedSource, Diagnostic> {
let syntax = get_syntax(media_type);
deno_ast::parse_program(deno_ast::ParseParams {
specifier: file_name.to_string(),
media_type: MediaType::Unknown,
media_type,
text_info: deno_ast::SourceTextInfo::from_string(source_code),
capture_tokens: true,
maybe_syntax: Some(syntax),
Expand Down
34 changes: 19 additions & 15 deletions src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@
use crate::control_flow::ControlFlow;
use crate::diagnostic::{LintDiagnostic, Position, Range};
use crate::ignore_directives::{
CodeStatus, FileIgnoreDirective, LineIgnoreDirective,
parse_line_ignore_directives, CodeStatus, FileIgnoreDirective,
LineIgnoreDirective,
};
use crate::linter::LinterContext;
use crate::rules::{self, get_all_rules, LintRule};
use deno_ast::swc::common::comments::Comment;
use deno_ast::swc::common::SyntaxContext;
Expand All @@ -14,13 +16,11 @@ use deno_ast::{
view as ast_view, ParsedSource, RootNode, SourcePos, SourceRange,
};
use std::collections::{HashMap, HashSet};

use std::time::Instant;

/// `Context` stores data needed while performing all lint rules to a file.
/// `Context` stores all data needed to perform linting of a particular file.
pub struct Context<'view> {
parsed_source: ParsedSource,
media_type: MediaType,
diagnostics: Vec<LintDiagnostic>,
program: ast_view::Program<'view>,
file_ignore_directive: Option<FileIgnoreDirective>,
Expand All @@ -32,28 +32,30 @@ pub struct Context<'view> {
}

impl<'view> Context<'view> {
#[allow(clippy::too_many_arguments)]
pub(crate) fn new(
linter_ctx: &LinterContext,
parsed_source: ParsedSource,
media_type: MediaType,
program: ast_view::Program<'view>,
file_ignore_directive: Option<FileIgnoreDirective>,
line_ignore_directives: HashMap<usize, LineIgnoreDirective>,
scope: Scope,
control_flow: ControlFlow,
check_unknown_rules: bool,
) -> Self {
Self {
parsed_source,
media_type,
let line_ignore_directives = parse_line_ignore_directives(
&linter_ctx.ignore_diagnostic_directive,
program,
);
let scope = Scope::analyze(program);
let control_flow =
ControlFlow::analyze(program, parsed_source.unresolved_context());

Self {
file_ignore_directive,
line_ignore_directives,
scope,
control_flow,
program,
parsed_source,
diagnostics: Vec::new(),
traverse_flow: TraverseFlow::default(),
check_unknown_rules,
check_unknown_rules: linter_ctx.check_unknown_rules,
}
}

Expand All @@ -65,7 +67,7 @@ impl<'view> Context<'view> {
/// The media type which linter was configured with. Can be used
/// to skip checking some rules.
pub fn media_type(&self) -> MediaType {
self.media_type
self.parsed_source.media_type()
}

/// Stores diagnostics that are generated while linting
Expand Down Expand Up @@ -234,6 +236,8 @@ impl<'view> Context<'view> {
diagnostics
}

// TODO(bartlomieju): this should be a regular lint rule, not a mathod on this
// struct.
/// Lint rule implementation for `ban-unknown-rule-code`.
/// This should be run after all normal rules.
pub(crate) fn ban_unknown_rule_code(&mut self) -> Vec<LintDiagnostic> {
Expand Down
Loading