nu_lint/output/
mod.rs

1mod json;
2mod text;
3mod vscode;
4
5use std::{borrow::Cow, fs};
6
7pub use json::{JsonFix, JsonOutput, JsonReplacement, JsonViolation, format_json};
8use serde::Serialize;
9pub use text::format_text;
10pub use vscode::{
11    VsCodeCodeAction, VsCodeDiagnostic, VsCodeJsonOutput, VsCodeLocation, VsCodePosition,
12    VsCodeRange, VsCodeRelatedInformation, VsCodeTextEdit, format_vscode_json,
13};
14
15use crate::{config::LintLevel, violation::Violation};
16
17#[derive(Serialize)]
18pub struct Summary {
19    pub errors: usize,
20    pub warnings: usize,
21    pub info: usize,
22    pub files_checked: usize,
23}
24
25impl Summary {
26    #[must_use]
27    pub fn from_violations(violations: &[Violation]) -> Self {
28        let (errors, warnings, info) = violations.iter().fold(
29            (0, 0, 0),
30            |(errors, warnings, info), violation| match violation.lint_level {
31                LintLevel::Deny => (errors + 1, warnings, info),
32                LintLevel::Warn => (errors, warnings + 1, info),
33                LintLevel::Allow => (errors, warnings, info + 1),
34            },
35        );
36
37        Self {
38            errors,
39            warnings,
40            info,
41            files_checked: 1,
42        }
43    }
44
45    #[must_use]
46    pub fn format_compact(&self) -> String {
47        let parts: Vec<String> = [
48            (self.errors > 0).then(|| format!("{} error(s)", self.errors)),
49            (self.warnings > 0).then(|| format!("{} warning(s)", self.warnings)),
50            (self.info > 0).then(|| format!("{} info", self.info)),
51        ]
52        .into_iter()
53        .flatten()
54        .collect();
55
56        if parts.is_empty() {
57            String::from("0 violations")
58        } else {
59            parts.join(", ")
60        }
61    }
62}
63
64pub(super) fn calculate_line_column(source: &str, offset: usize) -> (usize, usize) {
65    source
66        .char_indices()
67        .take_while(|(pos, _)| *pos < offset)
68        .fold((1, 1), |(line, column), (_, ch)| {
69            if ch == '\n' {
70                (line + 1, 1)
71            } else {
72                (line, column + 1)
73            }
74        })
75}
76
77pub(super) fn read_source_code(file: Option<&Cow<'_, str>>) -> String {
78    file.and_then(|path| fs::read_to_string(path.as_ref()).ok())
79        .unwrap_or_default()
80}