Skip to content

Commit aa887f2

Browse files
committed
refactor: unify LintingResult and Formatter APIs
1 parent 4dd4884 commit aa887f2

File tree

14 files changed

+132
-197
lines changed

14 files changed

+132
-197
lines changed

crates/cli-lib/src/commands_fix.rs

+13-15
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,8 @@ pub(crate) fn run_fix(
1919
let mut linter = linter(config, format, collect_parse_errors);
2020
let result = linter.lint_paths(paths, true, &ignorer);
2121

22-
if result.files.iter().all(|file| file.violations.is_empty()) {
23-
let count_files = result.files.len();
24-
println!("{} files processed, nothing to fix.", count_files);
22+
if !result.has_violations() {
23+
println!("{} files processed, nothing to fix.", result.len());
2524
0
2625
} else {
2726
if !force {
@@ -38,20 +37,19 @@ pub(crate) fn run_fix(
3837
}
3938
}
4039

41-
let any_unfixable_errors = result
42-
.files
43-
.iter()
44-
.any(|file| !file.get_violations(Some(false)).is_empty());
40+
let any_unfixable_errors = result.has_unfixable_violations();
41+
let files = result.len();
4542

46-
for mut file in result.files {
43+
for mut file in result {
4744
let path = std::mem::take(&mut file.path);
48-
let write_buff = file.fix_string();
49-
std::fs::write(path, write_buff).unwrap();
45+
let fixed = file.fix_string();
46+
47+
std::fs::write(path, fixed).unwrap();
5048
}
5149

52-
linter.formatter_mut().unwrap().completion_message();
50+
linter.formatter_mut().unwrap().completion_message(files);
5351

54-
if any_unfixable_errors { 1 } else { 0 }
52+
any_unfixable_errors as i32
5553
}
5654
}
5755

@@ -65,10 +63,10 @@ pub(crate) fn run_fix_stdin(
6563
let linter = linter(config, format, collect_parse_errors);
6664
let result = linter.lint_string(&read_in, None, true);
6765

68-
// print fixed to std out
69-
let violations = result.get_violations(Some(false));
66+
let has_unfixable_errors = result.has_unfixable_violations();
67+
7068
println!("{}", result.fix_string());
7169

7270
// if all fixable violations are fixable, return 0 else return 1
73-
if violations.is_empty() { 0 } else { 1 }
71+
has_unfixable_errors as i32
7472
}

crates/cli-lib/src/commands_lint.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ pub(crate) fn run_lint(
1313
let mut linter = linter(config, format, collect_parse_errors);
1414
let result = linter.lint_paths(paths, false, &ignorer);
1515

16-
linter.formatter().unwrap().completion_message();
16+
linter.formatter().unwrap().completion_message(result.len());
1717

1818
result.has_violations() as i32
1919
}
@@ -28,7 +28,7 @@ pub(crate) fn run_lint_stdin(
2828
let linter = linter(config, format, collect_parse_errors);
2929
let result = linter.lint_string(&read_in, None, false);
3030

31-
linter.formatter().unwrap().completion_message();
31+
linter.formatter().unwrap().completion_message(1);
3232

3333
result.has_violations() as i32
3434
}
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
{"tests/lint/test_fail_whitespace_before_comma.sql":[{"range":{"start":{"line":1,"character":8},"end":{"line":1,"character":8}},"message":"Column expression without alias. Use explicit `AS` clause.","severity":"Warning","source":"sqruff","code":"AL03"},{"range":{"start":{"line":1,"character":11},"end":{"line":1,"character":11}},"message":"Column expression without alias. Use explicit `AS` clause.","severity":"Warning","source":"sqruff","code":"AL03"},{"range":{"start":{"line":1,"character":9},"end":{"line":1,"character":9}},"message":"Unexpected whitespace before comma.","severity":"Warning","source":"sqruff","code":"LT01"},{"range":{"start":{"line":1,"character":11},"end":{"line":1,"character":11}},"message":"Expected single whitespace between \",\" and \"4\".","severity":"Warning","source":"sqruff","code":"LT01"},{"range":{"start":{"line":1,"character":12},"end":{"line":1,"character":12}},"message":"Files must end with a single trailing newline.","severity":"Warning","source":"sqruff","code":"LT12"}]}
1+
{"tests/lint/test_fail_whitespace_before_comma.sql":[{"range":{"start":{"line":1,"character":8},"end":{"line":1,"character":8}},"message":"Column expression without alias. Use explicit `AS` clause.","severity":"Warning","source":"sqruff","code":"AL03"},{"range":{"start":{"line":1,"character":9},"end":{"line":1,"character":9}},"message":"Unexpected whitespace before comma.","severity":"Warning","source":"sqruff","code":"LT01"},{"range":{"start":{"line":1,"character":11},"end":{"line":1,"character":11}},"message":"Column expression without alias. Use explicit `AS` clause.","severity":"Warning","source":"sqruff","code":"AL03"},{"range":{"start":{"line":1,"character":11},"end":{"line":1,"character":11}},"message":"Expected single whitespace between \",\" and \"4\".","severity":"Warning","source":"sqruff","code":"LT01"},{"range":{"start":{"line":1,"character":12},"end":{"line":1,"character":12}},"message":"Files must end with a single trailing newline.","severity":"Warning","source":"sqruff","code":"LT12"}]}
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
{"tests/lint/test_fail_whitespace_before_comma.sql":[{"range":{"start":{"line":1,"character":8},"end":{"line":1,"character":8}},"message":"Column expression without alias. Use explicit `AS` clause.","severity":"Warning","source":"sqruff","code":"AL03"},{"range":{"start":{"line":1,"character":11},"end":{"line":1,"character":11}},"message":"Column expression without alias. Use explicit `AS` clause.","severity":"Warning","source":"sqruff","code":"AL03"},{"range":{"start":{"line":1,"character":9},"end":{"line":1,"character":9}},"message":"Unexpected whitespace before comma.","severity":"Warning","source":"sqruff","code":"LT01"},{"range":{"start":{"line":1,"character":11},"end":{"line":1,"character":11}},"message":"Expected single whitespace between \",\" and \"4\".","severity":"Warning","source":"sqruff","code":"LT01"},{"range":{"start":{"line":1,"character":12},"end":{"line":1,"character":12}},"message":"Files must end with a single trailing newline.","severity":"Warning","source":"sqruff","code":"LT12"}]}
1+
{"tests/lint/test_fail_whitespace_before_comma.sql":[{"range":{"start":{"line":1,"character":8},"end":{"line":1,"character":8}},"message":"Column expression without alias. Use explicit `AS` clause.","severity":"Warning","source":"sqruff","code":"AL03"},{"range":{"start":{"line":1,"character":9},"end":{"line":1,"character":9}},"message":"Unexpected whitespace before comma.","severity":"Warning","source":"sqruff","code":"LT01"},{"range":{"start":{"line":1,"character":11},"end":{"line":1,"character":11}},"message":"Column expression without alias. Use explicit `AS` clause.","severity":"Warning","source":"sqruff","code":"AL03"},{"range":{"start":{"line":1,"character":11},"end":{"line":1,"character":11}},"message":"Expected single whitespace between \",\" and \"4\".","severity":"Warning","source":"sqruff","code":"LT01"},{"range":{"start":{"line":1,"character":12},"end":{"line":1,"character":12}},"message":"Files must end with a single trailing newline.","severity":"Warning","source":"sqruff","code":"LT12"}]}

crates/lib-wasm/src/lib.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -94,17 +94,17 @@ impl Linter {
9494
None
9595
};
9696

97-
let mut result = self.base.lint_parsed(&tables, parsed, tool == Tool::Format);
98-
let violations = &mut result.violations;
97+
let result = self.base.lint_parsed(&tables, parsed, tool == Tool::Format);
98+
let violations = result.violations();
9999

100100
let diagnostics = violations
101-
.iter_mut()
101+
.iter()
102102
.map(|violation| {
103103
let start = line_index.line_col(violation.source_slice.start.try_into().unwrap());
104104
let end = line_index.line_col(violation.source_slice.end.try_into().unwrap());
105105

106106
Diagnostic {
107-
message: std::mem::take(&mut violation.description),
107+
message: violation.description.clone(),
108108
start_line_number: start.line + 1,
109109
start_column: start.col + 1,
110110
end_line_number: end.line + 1,

crates/lib/src/cli/formatters.rs

+23-76
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,18 @@
11
use super::utils::*;
22
use std::borrow::Cow;
33
use std::io::{Stderr, Write};
4-
use std::sync::atomic::AtomicUsize;
54

65
use anstyle::{AnsiColor, Effects, Style};
76
use itertools::enumerate;
87
use sqruff_lib_core::errors::SQLBaseError;
98

10-
use crate::core::config::FluffConfig;
119
use crate::core::linter::linted_file::LintedFile;
1210

1311
const LIGHT_GREY: Style = AnsiColor::Black.on_default().effects(Effects::BOLD);
1412

1513
pub trait Formatter: Send + Sync {
16-
fn dispatch_template_header(
17-
&self,
18-
f_name: String,
19-
linter_config: FluffConfig,
20-
file_config: FluffConfig,
21-
);
22-
23-
fn dispatch_parse_header(&self, f_name: String);
24-
25-
fn dispatch_file_violations(&self, linted_file: &LintedFile, only_fixable: bool);
26-
27-
fn completion_message(&self);
14+
fn dispatch_file_violations(&self, linted_file: &LintedFile);
15+
fn completion_message(&self, count: usize);
2816
}
2917

3018
pub struct OutputStreamFormatter {
@@ -33,48 +21,27 @@ pub struct OutputStreamFormatter {
3321
filter_empty: bool,
3422
verbosity: i32,
3523
output_line_length: usize,
36-
files_dispatched: AtomicUsize,
3724
}
3825

3926
impl Formatter for OutputStreamFormatter {
40-
fn dispatch_file_violations(&self, linted_file: &LintedFile, only_fixable: bool) {
27+
fn dispatch_file_violations(&self, linted_file: &LintedFile) {
4128
if self.verbosity < 0 {
4229
return;
4330
}
4431

45-
let s = self.format_file_violations(
46-
&linted_file.path,
47-
linted_file.get_violations(only_fixable.then_some(true)),
48-
);
32+
let s = self.format_file_violations(linted_file.path(), linted_file.violations());
4933

5034
self.dispatch(&s);
51-
self.files_dispatched
52-
.fetch_add(1, std::sync::atomic::Ordering::SeqCst);
5335
}
5436

55-
fn completion_message(&self) {
56-
let count = self
57-
.files_dispatched
58-
.load(std::sync::atomic::Ordering::SeqCst);
59-
let message = format!("The linter processed {count} file(s).\n");
60-
self.dispatch(&message);
61-
62-
let message = if self.plain_output {
37+
fn completion_message(&self, count: usize) {
38+
self.dispatch(&format!("The linter processed {count} file(s).\n"));
39+
self.dispatch(if self.plain_output {
6340
"All Finished\n"
6441
} else {
6542
"All Finished 📜 🎉\n"
66-
};
67-
self.dispatch(message);
68-
}
69-
fn dispatch_template_header(
70-
&self,
71-
_f_name: String,
72-
_linter_config: FluffConfig,
73-
_file_config: FluffConfig,
74-
) {
43+
});
7544
}
76-
77-
fn dispatch_parse_header(&self, _f_name: String) {}
7845
}
7946

8047
impl OutputStreamFormatter {
@@ -85,7 +52,6 @@ impl OutputStreamFormatter {
8552
filter_empty: true,
8653
verbosity,
8754
output_line_length: 80,
88-
files_dispatched: 0.into(),
8955
}
9056
}
9157

@@ -101,7 +67,7 @@ impl OutputStreamFormatter {
10167
}
10268
}
10369

104-
fn format_file_violations(&self, fname: &str, mut violations: Vec<SQLBaseError>) -> String {
70+
fn format_file_violations(&self, fname: &str, violations: &[SQLBaseError]) -> String {
10571
let mut text_buffer = String::new();
10672

10773
let show = !violations.is_empty();
@@ -113,12 +79,6 @@ impl OutputStreamFormatter {
11379
}
11480

11581
if show {
116-
violations.sort_by(|a, b| {
117-
a.line_no
118-
.cmp(&b.line_no)
119-
.then_with(|| a.line_pos.cmp(&b.line_pos))
120-
});
121-
12282
for violation in violations {
12383
let text = self.format_violation(violation, self.output_line_length);
12484
text_buffer.push_str(&text);
@@ -148,12 +108,7 @@ impl OutputStreamFormatter {
148108
format!("== [{filename}] {status}")
149109
}
150110

151-
fn format_violation(
152-
&self,
153-
violation: impl Into<SQLBaseError>,
154-
max_line_length: usize,
155-
) -> String {
156-
let violation: SQLBaseError = violation.into();
111+
fn format_violation(&self, violation: &SQLBaseError, max_line_length: usize) -> String {
157112
let mut desc = violation.desc().to_string();
158113

159114
let line_elem = format!("{:4}", violation.line_no);
@@ -217,10 +172,7 @@ impl Status {
217172
mod tests {
218173
use anstyle::AnsiColor;
219174
use fancy_regex::Regex;
220-
use sqruff_lib_core::dialects::syntax::SyntaxKind;
221-
use sqruff_lib_core::errors::{ErrorStructRule, SQLLintError};
222-
use sqruff_lib_core::parser::markers::PositionMarker;
223-
use sqruff_lib_core::parser::segments::base::SegmentBuilder;
175+
use sqruff_lib_core::errors::{ErrorStructRule, SQLBaseError};
224176

225177
use super::OutputStreamFormatter;
226178
use crate::cli::formatters::split_string_on_spaces;
@@ -267,24 +219,19 @@ mod tests {
267219
fn test_cli_formatters_violation() {
268220
let formatter = mk_formatter();
269221

270-
let s = SegmentBuilder::token(0, "foobarbar", SyntaxKind::Word)
271-
.with_position(PositionMarker::new(
272-
10..19,
273-
10..19,
274-
" \n\n foobarbar".into(),
275-
None,
276-
None,
277-
))
278-
.finish();
279-
280-
let mut v = SQLLintError::new("DESC", s, false, vec![]);
281-
282-
v.rule = Some(ErrorStructRule {
283-
name: "some-name",
284-
code: "DESC",
285-
});
222+
let v = SQLBaseError {
223+
fixable: false,
224+
line_no: 3,
225+
line_pos: 3,
226+
description: "DESC".into(),
227+
rule: Some(ErrorStructRule {
228+
name: "some-name",
229+
code: "DESC",
230+
}),
231+
source_slice: 0..0,
232+
};
286233

287-
let f = formatter.format_violation(v, 90);
234+
let f = formatter.format_violation(&v, 90);
288235

289236
assert_eq!(escape_ansi(&f), "L: 3 | P: 3 | DESC | DESC [some-name]");
290237
}
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
use crate::core::config::FluffConfig;
21
use crate::core::linter::linted_file::LintedFile;
32
use std::io::{Stderr, Write};
43
use std::sync::atomic::{AtomicBool, Ordering};
@@ -29,39 +28,14 @@ impl GithubAnnotationNativeFormatter {
2928
}
3029

3130
impl Formatter for GithubAnnotationNativeFormatter {
32-
fn dispatch_template_header(
33-
&self,
34-
_f_name: String,
35-
_linter_config: FluffConfig,
36-
_file_config: FluffConfig,
37-
) {
38-
// No-op
39-
}
40-
41-
fn dispatch_parse_header(&self, _f_name: String) {
42-
// No-op
43-
}
44-
45-
fn dispatch_file_violations(&self, linted_file: &LintedFile, _only_fixable: bool) {
46-
let mut violations = linted_file.get_violations(None);
47-
48-
violations.sort_by(|a, b| {
49-
a.line_no
50-
.cmp(&b.line_no)
51-
.then_with(|| a.line_pos.cmp(&b.line_pos))
52-
.then_with(|| {
53-
let b = b.rule.as_ref().unwrap().code;
54-
a.rule.as_ref().unwrap().code.cmp(b)
55-
})
56-
});
57-
58-
for violation in violations {
31+
fn dispatch_file_violations(&self, linted_file: &LintedFile) {
32+
for violation in linted_file.violations() {
5933
let message = format!(
6034
"::error title=sqruff,file={},line={},col={}::{}: {}\n",
61-
linted_file.path,
35+
linted_file.path(),
6236
violation.line_no,
6337
violation.line_pos,
64-
violation.rule.as_ref().unwrap().code,
38+
violation.rule_code(),
6539
violation.description
6640
);
6741

@@ -70,7 +44,7 @@ impl Formatter for GithubAnnotationNativeFormatter {
7044
}
7145
}
7246

73-
fn completion_message(&self) {
47+
fn completion_message(&self, _count: usize) {
7448
// No-op
7549
}
7650
}

crates/lib/src/cli/json.rs

+5-15
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use std::sync::Mutex;
22

3-
use crate::core::{config::FluffConfig, linter::linted_file::LintedFile};
3+
use crate::core::linter::linted_file::LintedFile;
44

55
use super::{
66
formatters::Formatter,
@@ -13,30 +13,20 @@ pub struct JsonFormatter {
1313
}
1414

1515
impl Formatter for JsonFormatter {
16-
fn dispatch_file_violations(&self, linted_file: &LintedFile, only_fixable: bool) {
17-
let violations = linted_file.get_violations(only_fixable.then_some(true));
16+
fn dispatch_file_violations(&self, linted_file: &LintedFile) {
17+
let violations = linted_file.violations();
1818
let mut lock = self.violations.lock().unwrap();
19-
lock.entry(linted_file.path.clone()).or_default().extend(
19+
lock.entry(linted_file.path().into()).or_default().extend(
2020
violations
2121
.iter()
2222
.map(|err| Diagnostic::from(err.clone()))
2323
.collect::<Vec<_>>(),
2424
);
2525
}
2626

27-
fn completion_message(&self) {
27+
fn completion_message(&self, _count: usize) {
2828
let lock = self.violations.lock().unwrap();
2929
let json = serde_json::to_string(&*lock).unwrap();
3030
println!("{}", json);
3131
}
32-
33-
fn dispatch_template_header(
34-
&self,
35-
_f_name: String,
36-
_linter_config: FluffConfig,
37-
_file_config: FluffConfig,
38-
) {
39-
}
40-
41-
fn dispatch_parse_header(&self, _f_name: String) {}
4232
}

0 commit comments

Comments
 (0)