1#![forbid(unsafe_code)]
2
3mod diagnostic;
4mod regex_util;
5mod rule;
6mod rule_set;
7pub mod stdlib;
8mod suppression;
9
10use std::ops::Range;
11
12use mdwright_document::Document;
13
14pub use diagnostic::{DOCS_URL_DEFAULT, Diagnostic, Fix, Severity, Snippet, docs_url, rule_doc_url};
15pub use rule::LintRule;
16pub use rule_set::{DuplicateRuleName, RuleSet};
17
18#[derive(Copy, Clone, Debug)]
20pub struct LintOptions {
21 pub respect_suppressions: bool,
23}
24
25impl Default for LintOptions {
26 fn default() -> Self {
27 Self {
28 respect_suppressions: true,
29 }
30 }
31}
32
33#[must_use]
35pub fn apply_safe_fixes(doc: &Document, diags: &[Diagnostic]) -> (String, usize) {
36 let mut edits: Vec<(Range<usize>, &str)> = diags
37 .iter()
38 .filter_map(|d| {
39 let fix = d.fix.as_ref().filter(|f| f.safe)?;
40 let orig = doc.canonical_to_original_range(d.span.start..d.span.end);
41 Some((orig, fix.replacement.as_str()))
42 })
43 .collect();
44 edits.sort_by_key(|e| std::cmp::Reverse(e.0.start));
45 let mut out = doc.original_source().to_owned();
46 let mut applied = 0usize;
47 let mut last_start = usize::MAX;
48 for (range, replacement) in edits {
49 if range.end > last_start {
50 continue;
51 }
52 out.replace_range(range.clone(), replacement);
53 last_start = range.start;
54 applied = applied.saturating_add(1);
55 }
56 (out, applied)
57}