Skip to main content

code_baseline/cli/
toml_config.rs

1use crate::config::{RuleConfig, Severity};
2use serde::Deserialize;
3
4/// Top-level TOML config file structure.
5#[derive(Debug, Deserialize)]
6pub struct TomlConfig {
7    pub baseline: BaselineSection,
8    #[serde(default)]
9    pub rule: Vec<TomlRule>,
10}
11
12/// A `[[baseline.scoped]]` entry that applies a preset to a specific directory.
13#[derive(Debug, Clone, Deserialize)]
14pub struct ScopedPreset {
15    pub preset: String,
16    pub path: String,
17    #[serde(default)]
18    pub exclude_rules: Vec<String>,
19}
20
21/// The `[baseline]` section.
22#[derive(Debug, Deserialize)]
23pub struct BaselineSection {
24    #[allow(dead_code)]
25    pub name: Option<String>,
26    #[serde(default)]
27    pub include: Vec<String>,
28    #[serde(default)]
29    pub exclude: Vec<String>,
30    #[serde(default)]
31    pub extends: Vec<String>,
32    /// Paths to plugin TOML files containing additional rules
33    #[serde(default)]
34    pub plugins: Vec<String>,
35    /// Scoped presets: apply a preset only to files under a specific path
36    #[serde(default)]
37    pub scoped: Vec<ScopedPreset>,
38}
39
40/// A single `[[rule]]` entry.
41#[derive(Debug, Clone, Deserialize)]
42pub struct TomlRule {
43    pub id: String,
44    #[serde(rename = "type")]
45    pub rule_type: String,
46    #[serde(default = "default_severity")]
47    pub severity: String,
48    pub glob: Option<String>,
49    #[serde(default)]
50    pub message: String,
51    pub suggest: Option<String>,
52    #[serde(default)]
53    pub allowed_classes: Vec<String>,
54    #[serde(default)]
55    pub token_map: Vec<String>,
56    pub pattern: Option<String>,
57    pub max_count: Option<usize>,
58    #[serde(default)]
59    pub packages: Vec<String>,
60    #[serde(default)]
61    pub regex: bool,
62    pub manifest: Option<String>,
63    #[serde(default)]
64    pub exclude_glob: Vec<String>,
65    pub file_contains: Option<String>,
66    pub file_not_contains: Option<String>,
67    #[serde(default)]
68    pub required_files: Vec<String>,
69    #[serde(default)]
70    pub forbidden_files: Vec<String>,
71    pub condition_pattern: Option<String>,
72    #[serde(default)]
73    pub skip_strings: bool,
74}
75
76fn default_severity() -> String {
77    "warning".into()
78}
79
80impl Default for TomlRule {
81    fn default() -> Self {
82        Self {
83            id: String::new(),
84            rule_type: String::new(),
85            severity: default_severity(),
86            glob: None,
87            message: String::new(),
88            suggest: None,
89            allowed_classes: Vec::new(),
90            token_map: Vec::new(),
91            pattern: None,
92            max_count: None,
93            packages: Vec::new(),
94            regex: false,
95            manifest: None,
96            exclude_glob: Vec::new(),
97            file_contains: None,
98            file_not_contains: None,
99            required_files: Vec::new(),
100            forbidden_files: Vec::new(),
101            condition_pattern: None,
102            skip_strings: false,
103        }
104    }
105}
106
107impl TomlRule {
108    /// Convert to the core `RuleConfig` type.
109    pub fn to_rule_config(&self) -> RuleConfig {
110        let severity = match self.severity.to_lowercase().as_str() {
111            "error" => Severity::Error,
112            _ => Severity::Warning,
113        };
114
115        RuleConfig {
116            id: self.id.clone(),
117            severity,
118            message: self.message.clone(),
119            suggest: self.suggest.clone(),
120            glob: self.glob.clone(),
121            allowed_classes: self.allowed_classes.clone(),
122            token_map: self.token_map.clone(),
123            pattern: self.pattern.clone(),
124            max_count: self.max_count,
125            packages: self.packages.clone(),
126            regex: self.regex,
127            manifest: self.manifest.clone(),
128            exclude_glob: self.exclude_glob.clone(),
129            file_contains: self.file_contains.clone(),
130            file_not_contains: self.file_not_contains.clone(),
131            required_files: self.required_files.clone(),
132            forbidden_files: self.forbidden_files.clone(),
133            condition_pattern: self.condition_pattern.clone(),
134            skip_strings: self.skip_strings,
135        }
136    }
137}