config_linter/
config_linter.rs1use duck_diagnostic::*;
4
5#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
6enum ConfigError {
7 InvalidSyntax,
8 MissingRequiredField,
9 InvalidValue,
10 DuplicateKey,
11 DeprecatedField,
13 UnknownField,
14}
15
16impl DiagnosticCode for ConfigError {
17 fn code(&self) -> &str {
18 match self {
19 Self::InvalidSyntax => "CFG001",
20 Self::MissingRequiredField => "CFG002",
21 Self::InvalidValue => "CFG003",
22 Self::DuplicateKey => "CFG004",
23 Self::DeprecatedField => "CFG-W01",
24 Self::UnknownField => "CFG-W02",
25 }
26 }
27
28 fn severity(&self) -> Severity {
29 match self {
30 Self::DeprecatedField | Self::UnknownField => Severity::Warning,
31 _ => Severity::Error,
32 }
33 }
34}
35
36fn main() {
37 let config = r#"[package]
38name = "my-app"
39version = "1.0"
40edition = "2018"
41authors = ["me"]
42authors = ["you"]
43license = 42"#;
44
45 let mut engine = DiagnosticEngine::<ConfigError>::new();
46
47 engine.emit(
48 Diagnostic::new(ConfigError::DuplicateKey, "duplicate key `authors`")
49 .with_label(Label::primary(
50 Span::new("Cargo.toml", 6, 0, 7),
51 Some("second definition here".into()),
52 ))
53 .with_label(Label::secondary(
54 Span::new("Cargo.toml", 5, 0, 7),
55 Some("first defined here".into()),
56 ))
57 .with_help("remove one of the duplicate entries"),
58 );
59
60 engine.emit(
61 Diagnostic::new(ConfigError::InvalidValue, "expected string for `license`, found integer")
62 .with_label(Label::primary(
63 Span::new("Cargo.toml", 7, 10, 2),
64 Some("expected a string like \"MIT\"".into()),
65 )),
66 );
67
68 engine.emit(
69 Diagnostic::new(ConfigError::DeprecatedField, "`edition = \"2018\"` is outdated").with_label(
70 Label::primary(
71 Span::new("Cargo.toml", 4, 0, 18),
72 Some("consider updating to \"2021\" or \"2024\"".into()),
73 ),
74 ),
75 );
76
77 engine.print_all(config);
78}