1use std::fmt::Debug;
2
3use crate::{message::Message, result::Violation};
4use serde::{Deserialize, Serialize};
5
6use self::{
7 body_empty::BodyEmpty, body_max_length::BodyMaxLength, description_empty::DescriptionEmpty,
8 description_format::DescriptionFormat, description_max_length::DescriptionMaxLength,
9 footers_empty::FootersEmpty, r#type::Type, scope::Scope, scope_empty::ScopeEmpty,
10 scope_format::ScopeFormat, scope_max_length::ScopeMaxLength, subject_empty::SubjectEmpty,
11 type_empty::TypeEmpty, type_format::TypeFormat, type_max_length::TypeMaxLength,
12};
13
14pub mod body_empty;
15pub mod body_max_length;
16pub mod description_empty;
17pub mod description_format;
18pub mod description_max_length;
19pub mod footers_empty;
20pub mod scope;
21pub mod scope_empty;
22pub mod scope_format;
23pub mod scope_max_length;
24pub mod subject_empty;
25pub mod r#type;
26pub mod type_empty;
27pub mod type_format;
28pub mod type_max_length;
29
30#[derive(Clone, Debug, Deserialize, Serialize)]
33#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
34pub struct Rules {
35 #[serde(rename = "body-empty")]
36 #[serde(skip_serializing_if = "Option::is_none")]
37 pub body_empty: Option<BodyEmpty>,
38
39 #[serde(rename = "body-max-length")]
40 #[serde(skip_serializing_if = "Option::is_none")]
41 pub body_max_length: Option<BodyMaxLength>,
42
43 #[serde(rename = "description-empty")]
44 #[serde(skip_serializing_if = "Option::is_none")]
45 pub description_empty: Option<DescriptionEmpty>,
46
47 #[serde(rename = "description-format")]
48 #[serde(skip_serializing_if = "Option::is_none")]
49 pub description_format: Option<DescriptionFormat>,
50
51 #[serde(rename = "description-max-length")]
52 #[serde(skip_serializing_if = "Option::is_none")]
53 pub description_max_length: Option<DescriptionMaxLength>,
54
55 #[serde(rename = "footers-empty")]
56 #[serde(skip_serializing_if = "Option::is_none")]
57 pub footers_empty: Option<FootersEmpty>,
58
59 #[serde(rename = "scope")]
60 #[serde(skip_serializing_if = "Option::is_none")]
61 pub scope: Option<Scope>,
62
63 #[serde(rename = "scope-empty")]
64 #[serde(skip_serializing_if = "Option::is_none")]
65 pub scope_empty: Option<ScopeEmpty>,
66
67 #[serde(rename = "scope-format")]
68 #[serde(skip_serializing_if = "Option::is_none")]
69 pub scope_format: Option<ScopeFormat>,
70
71 #[serde(rename = "scope-max-length")]
72 #[serde(skip_serializing_if = "Option::is_none")]
73 pub scope_max_length: Option<ScopeMaxLength>,
74
75 #[serde(rename = "subject-empty")]
76 #[serde(skip_serializing_if = "Option::is_none")]
77 pub subject_empty: Option<SubjectEmpty>,
78
79 #[serde(rename = "type")]
80 #[serde(skip_serializing_if = "Option::is_none")]
81 pub r#type: Option<Type>,
82
83 #[serde(rename = "type-empty")]
84 #[serde(skip_serializing_if = "Option::is_none")]
85 pub type_empty: Option<TypeEmpty>,
86
87 #[serde(rename = "type-format")]
88 #[serde(skip_serializing_if = "Option::is_none")]
89 pub type_format: Option<TypeFormat>,
90
91 #[serde(rename = "type-max-length")]
92 #[serde(skip_serializing_if = "Option::is_none")]
93 pub type_max_length: Option<TypeMaxLength>,
94}
95
96impl Rules {
98 pub fn validate(&self, message: &Message) -> Vec<Violation> {
99 let mut results = Vec::new();
100
101 if let Some(rule) = &self.body_empty {
102 if let Some(validation) = rule.validate(message) {
103 results.push(validation);
104 }
105 }
106
107 if let Some(rule) = &self.body_max_length {
108 if let Some(validation) = rule.validate(message) {
109 results.push(validation);
110 }
111 }
112
113 if let Some(rule) = &self.description_empty {
114 if let Some(validation) = rule.validate(message) {
115 results.push(validation);
116 }
117 }
118
119 if let Some(rule) = &self.description_format {
120 if let Some(validation) = rule.validate(message) {
121 results.push(validation);
122 }
123 }
124
125 if let Some(rule) = &self.description_max_length {
126 if let Some(validation) = rule.validate(message) {
127 results.push(validation);
128 }
129 }
130
131 if let Some(rule) = &self.scope {
132 if let Some(validation) = rule.validate(message) {
133 results.push(validation);
134 }
135 }
136
137 if let Some(rule) = &self.scope_empty {
138 if let Some(validation) = rule.validate(message) {
139 results.push(validation);
140 }
141 }
142
143 if let Some(rule) = &self.scope_format {
144 if let Some(validation) = rule.validate(message) {
145 results.push(validation);
146 }
147 }
148
149 if let Some(rule) = &self.scope_max_length {
150 if let Some(validation) = rule.validate(message) {
151 results.push(validation);
152 }
153 }
154
155 if let Some(rule) = &self.subject_empty {
156 if let Some(validation) = rule.validate(message) {
157 results.push(validation);
158 }
159 }
160
161 if let Some(rule) = &self.r#type {
162 if let Some(validation) = rule.validate(message) {
163 results.push(validation);
164 }
165 }
166
167 if let Some(rule) = &self.type_empty {
168 if let Some(validation) = rule.validate(message) {
169 results.push(validation);
170 }
171 }
172
173 if let Some(rule) = &self.type_format {
174 if let Some(validation) = rule.validate(message) {
175 results.push(validation);
176 }
177 }
178
179 if let Some(rule) = &self.type_max_length {
180 if let Some(validation) = rule.validate(message) {
181 results.push(validation);
182 }
183 }
184
185 results
186 }
187}
188
189impl Default for Rules {
192 fn default() -> Self {
193 Self {
194 body_empty: None,
195 body_max_length: None,
196 description_empty: DescriptionEmpty::default().into(),
197 description_format: None,
198 description_max_length: None,
199 footers_empty: None,
200 scope: None,
201 scope_empty: None,
202 scope_format: None,
203 scope_max_length: None,
204 subject_empty: SubjectEmpty::default().into(),
205 r#type: None,
206 type_empty: TypeEmpty::default().into(),
207 type_format: None,
208 type_max_length: None,
209 }
210 }
211}
212
213pub trait Rule: Default {
215 const NAME: &'static str;
218
219 fn message(&self, message: &Message) -> String;
221
222 const LEVEL: Level;
224
225 fn validate(&self, message: &Message) -> Option<Violation>;
227}
228
229#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
231#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
232pub enum Level {
233 #[serde(rename = "error")]
234 Error,
235
236 #[serde(rename = "ignore")]
237 Ignore,
238
239 #[serde(rename = "warning")]
240 Warning,
241}