sql_dialect_fmt_lsp/
lint.rs1use lsp_types::{Diagnostic, DiagnosticSeverity, NumberOrString, Range};
8use sql_dialect_fmt_lint::LintSeverity;
9use sql_dialect_fmt_parser::Dialect;
10use sql_dialect_fmt_text::LineIndex;
11
12use crate::{lsp_position, PositionEncoding};
13
14pub use sql_dialect_fmt_lint::{LintCode, LintOptions};
15
16pub fn diagnostic_lint_code(diagnostic: &Diagnostic) -> Option<LintCode> {
18 match diagnostic.code.as_ref()? {
19 NumberOrString::String(value) => LintCode::from_code(value),
20 NumberOrString::Number(_) => None,
21 }
22}
23
24pub(crate) fn diagnostics_with_encoding(
25 text: &str,
26 dialect: Dialect,
27 index: &LineIndex<'_>,
28 options: LintOptions,
29 encoding: PositionEncoding,
30) -> Vec<Diagnostic> {
31 sql_dialect_fmt_lint::lint_with_dialect(text, dialect, options)
32 .into_iter()
33 .map(|finding| Diagnostic {
34 range: Range::new(
35 lsp_position(index, finding.range.start, encoding),
36 lsp_position(index, finding.range.end, encoding),
37 ),
38 severity: Some(match finding.severity {
39 LintSeverity::Warning => DiagnosticSeverity::WARNING,
40 LintSeverity::Error => DiagnosticSeverity::ERROR,
41 }),
42 code: Some(NumberOrString::String(finding.code.as_str().to_string())),
43 source: Some("sql-dialect-fmt".to_string()),
44 message: finding.message,
45 ..Default::default()
46 })
47 .collect()
48}
49
50#[cfg(test)]
51mod tests {
52 use super::*;
53
54 #[test]
55 fn lint_findings_convert_to_lsp_diagnostics() {
56 let text = "SELECT * FROM t;";
57 let index = LineIndex::new(text);
58 let diagnostics = diagnostics_with_encoding(
59 text,
60 Dialect::Snowflake,
61 &index,
62 LintOptions::default(),
63 PositionEncoding::Utf16,
64 );
65 let wildcard = diagnostics
66 .iter()
67 .find(|diagnostic| diagnostic_lint_code(diagnostic) == Some(LintCode::SelectWildcard))
68 .expect("SDF001 diagnostic");
69 assert_eq!(wildcard.severity, Some(DiagnosticSeverity::WARNING));
70 assert_eq!(wildcard.source.as_deref(), Some("sql-dialect-fmt"));
71 let col = text.find('*').unwrap() as u32;
72 assert_eq!(wildcard.range.start, lsp_types::Position::new(0, col));
73 assert_eq!(wildcard.range.end, lsp_types::Position::new(0, col + 1));
74 }
75
76 #[test]
77 fn suppression_comments_apply_before_conversion() {
78 let text = "-- sql-dialect-fmt: disable-next-line SDF001\nSELECT * FROM t;";
79 let index = LineIndex::new(text);
80 assert!(diagnostics_with_encoding(
81 text,
82 Dialect::Snowflake,
83 &index,
84 LintOptions::default(),
85 PositionEncoding::Utf16,
86 )
87 .is_empty());
88 }
89}