1use crate::types::LineLength;
2use indexmap::IndexMap;
3use std::collections::{BTreeMap, HashMap};
4use std::marker::PhantomData;
5
6use super::flavor::{ConfigLoaded, MarkdownFlavor};
7
8#[derive(Debug, Clone, Copy, PartialEq, Eq)]
17pub enum ConfigSource {
18 Default,
20 UserConfig,
22 PyprojectToml,
24 ProjectConfig,
26 Cli,
28}
29
30fn source_precedence(src: ConfigSource) -> u8 {
31 match src {
32 ConfigSource::Default => 0,
33 ConfigSource::UserConfig => 1,
34 ConfigSource::PyprojectToml => 2,
35 ConfigSource::ProjectConfig => 3,
36 ConfigSource::Cli => 4,
37 }
38}
39
40#[derive(Debug, Clone)]
45pub struct SourcedValue<T> {
46 pub value: T,
47 pub source: ConfigSource,
48 pub origin: Option<String>,
51}
52
53impl<T: Clone> SourcedValue<T> {
54 pub fn new(value: T, source: ConfigSource) -> Self {
55 Self {
56 value,
57 source,
58 origin: None,
59 }
60 }
61
62 pub fn merge_override(&mut self, new_value: T, new_source: ConfigSource, new_origin: Option<String>) {
66 if source_precedence(new_source) >= source_precedence(self.source) {
67 self.value = new_value;
68 self.source = new_source;
69 self.origin = new_origin;
70 }
71 }
72
73 pub fn merge_from(&mut self, other: SourcedValue<T>) {
75 self.merge_override(other.value, other.source, other.origin);
76 }
77
78 pub fn push_override(&mut self, value: T, source: ConfigSource, origin: Option<String>) {
82 self.value = value;
83 self.source = source;
84 self.origin = origin;
85 }
86}
87
88impl<T: Clone + Eq + std::hash::Hash> SourcedValue<Vec<T>> {
89 pub fn merge_union(&mut self, new_value: Vec<T>, new_source: ConfigSource, new_origin: Option<String>) {
93 if source_precedence(new_source) >= source_precedence(self.source) {
94 for item in new_value {
95 if !self.value.contains(&item) {
96 self.value.push(item);
97 }
98 }
99 self.source = new_source;
100 self.origin = new_origin;
101 }
102 }
103
104 pub fn merge_union_from(&mut self, other: SourcedValue<Vec<T>>) {
106 self.merge_union(other.value, other.source, other.origin);
107 }
108}
109
110#[derive(Debug, Clone)]
111pub struct SourcedGlobalConfig {
112 pub enable: SourcedValue<Vec<String>>,
113 pub disable: SourcedValue<Vec<String>>,
114 pub exclude: SourcedValue<Vec<String>>,
115 pub include: SourcedValue<Vec<String>>,
116 pub respect_gitignore: SourcedValue<bool>,
117 pub line_length: SourcedValue<LineLength>,
118 pub output_format: Option<SourcedValue<String>>,
119 pub fixable: SourcedValue<Vec<String>>,
120 pub unfixable: SourcedValue<Vec<String>>,
121 pub flavor: SourcedValue<MarkdownFlavor>,
122 pub force_exclude: SourcedValue<bool>,
123 pub cache_dir: Option<SourcedValue<String>>,
124 pub cache: SourcedValue<bool>,
125 pub extend_enable: SourcedValue<Vec<String>>,
126 pub extend_disable: SourcedValue<Vec<String>>,
127}
128
129impl Default for SourcedGlobalConfig {
130 fn default() -> Self {
131 SourcedGlobalConfig {
132 enable: SourcedValue::new(Vec::new(), ConfigSource::Default),
133 disable: SourcedValue::new(Vec::new(), ConfigSource::Default),
134 exclude: SourcedValue::new(Vec::new(), ConfigSource::Default),
135 include: SourcedValue::new(Vec::new(), ConfigSource::Default),
136 respect_gitignore: SourcedValue::new(true, ConfigSource::Default),
137 line_length: SourcedValue::new(LineLength::default(), ConfigSource::Default),
138 output_format: None,
139 fixable: SourcedValue::new(Vec::new(), ConfigSource::Default),
140 unfixable: SourcedValue::new(Vec::new(), ConfigSource::Default),
141 flavor: SourcedValue::new(MarkdownFlavor::default(), ConfigSource::Default),
142 force_exclude: SourcedValue::new(false, ConfigSource::Default),
143 cache_dir: None,
144 cache: SourcedValue::new(true, ConfigSource::Default),
145 extend_enable: SourcedValue::new(Vec::new(), ConfigSource::Default),
146 extend_disable: SourcedValue::new(Vec::new(), ConfigSource::Default),
147 }
148 }
149}
150
151#[derive(Debug, Default, Clone)]
152pub struct SourcedRuleConfig {
153 pub severity: Option<SourcedValue<crate::rule::Severity>>,
154 pub values: BTreeMap<String, SourcedValue<toml::Value>>,
155}
156
157#[derive(Debug, Clone)]
160pub struct SourcedConfigFragment {
161 pub extends: Option<String>,
163 pub global: SourcedGlobalConfig,
164 pub per_file_ignores: SourcedValue<BTreeMap<String, Vec<String>>>,
165 pub per_file_flavor: SourcedValue<IndexMap<String, MarkdownFlavor>>,
166 pub code_block_tools: SourcedValue<crate::code_block_tools::CodeBlockToolsConfig>,
167 pub rules: BTreeMap<String, SourcedRuleConfig>,
168 pub rule_display_names: HashMap<String, String>,
172 pub unknown_keys: Vec<(String, String, Option<String>)>, }
175
176impl Default for SourcedConfigFragment {
177 fn default() -> Self {
178 Self {
179 extends: None,
180 global: SourcedGlobalConfig::default(),
181 per_file_ignores: SourcedValue::new(BTreeMap::new(), ConfigSource::Default),
182 per_file_flavor: SourcedValue::new(IndexMap::new(), ConfigSource::Default),
183 code_block_tools: SourcedValue::new(
184 crate::code_block_tools::CodeBlockToolsConfig::default(),
185 ConfigSource::Default,
186 ),
187 rules: BTreeMap::new(),
188 rule_display_names: HashMap::new(),
189 unknown_keys: Vec::new(),
190 }
191 }
192}
193
194#[derive(Debug, Clone)]
196pub struct ConfigValidationWarning {
197 pub message: String,
198 pub rule: Option<String>,
199 pub key: Option<String>,
200}
201
202#[derive(Debug, Clone)]
220pub struct SourcedConfig<State = ConfigLoaded> {
221 pub global: SourcedGlobalConfig,
222 pub per_file_ignores: SourcedValue<BTreeMap<String, Vec<String>>>,
223 pub per_file_flavor: SourcedValue<IndexMap<String, MarkdownFlavor>>,
224 pub code_block_tools: SourcedValue<crate::code_block_tools::CodeBlockToolsConfig>,
225 pub rules: BTreeMap<String, SourcedRuleConfig>,
226 pub loaded_files: Vec<String>,
227 pub unknown_keys: Vec<(String, String, Option<String>)>, pub project_root: Option<std::path::PathBuf>,
230 pub discovery_warnings: Vec<String>,
234 pub validation_warnings: Vec<ConfigValidationWarning>,
236 pub(super) _state: PhantomData<State>,
238}
239
240impl Default for SourcedConfig<ConfigLoaded> {
241 fn default() -> Self {
242 Self {
243 global: SourcedGlobalConfig::default(),
244 per_file_ignores: SourcedValue::new(BTreeMap::new(), ConfigSource::Default),
245 per_file_flavor: SourcedValue::new(IndexMap::new(), ConfigSource::Default),
246 code_block_tools: SourcedValue::new(
247 crate::code_block_tools::CodeBlockToolsConfig::default(),
248 ConfigSource::Default,
249 ),
250 rules: BTreeMap::new(),
251 loaded_files: Vec::new(),
252 unknown_keys: Vec::new(),
253 project_root: None,
254 discovery_warnings: Vec::new(),
255 validation_warnings: Vec::new(),
256 _state: PhantomData,
257 }
258 }
259}