1use serde::{Deserialize, Serialize};
6
7#[derive(Debug, Clone, Serialize, Deserialize)]
9pub struct DomainSpec {
10 pub project: ProjectSpec,
12
13 #[serde(default)]
15 pub modules: Vec<ModuleSpec>,
16
17 #[serde(default)]
19 pub common_types: Option<CommonTypesSpec>,
20
21 #[serde(default)]
23 pub entities: Vec<EntitySpec>,
24
25 #[serde(default)]
27 pub errors: Vec<ErrorSpec>,
28
29 #[serde(default)]
31 pub implementations: Vec<ImplSpec>,
32
33 #[serde(default)]
35 pub refactors: Vec<RefactorSpec>,
36
37 #[serde(default)]
39 pub verification: Option<VerificationSpec>,
40}
41
42#[derive(Debug, Clone, Serialize, Deserialize)]
44pub struct ProjectSpec {
45 pub name: String,
47
48 #[serde(default)]
50 pub crate_name: Option<String>,
51}
52
53impl ProjectSpec {
54 pub fn crate_name(&self) -> String {
55 self.crate_name
56 .clone()
57 .unwrap_or_else(|| self.name.replace('-', "_"))
58 }
59}
60
61#[derive(Debug, Clone, Serialize, Deserialize)]
63pub struct ModuleSpec {
64 pub name: String,
66
67 #[serde(default)]
69 pub is_pub: bool,
70
71 #[serde(default)]
73 pub children: Vec<ModuleSpec>,
74}
75
76impl ModuleSpec {
77 pub fn flatten(&self, parent_path: &str) -> Vec<(String, bool)> {
79 let mut result = Vec::new();
80 let path = if parent_path.is_empty() {
81 self.name.clone()
82 } else {
83 format!("{}::{}", parent_path, self.name)
84 };
85
86 result.push((path.clone(), self.is_pub));
87
88 for child in &self.children {
89 result.extend(child.flatten(&path));
90 }
91
92 result
93 }
94}
95
96#[derive(Debug, Clone, Default, Serialize, Deserialize)]
98pub struct CommonTypesSpec {
99 #[serde(default)]
101 pub newtypes: Vec<NewtypeSpec>,
102
103 #[serde(default)]
105 pub value_objects: Vec<EntitySpec>,
106}
107
108#[derive(Debug, Clone, Serialize, Deserialize)]
110pub struct NewtypeSpec {
111 pub name: String,
113
114 pub inner: String,
116
117 pub module: String,
119
120 #[serde(default)]
122 pub derives: Vec<String>,
123}
124
125#[derive(Debug, Clone, Serialize, Deserialize)]
127pub struct EntitySpec {
128 pub name: String,
130
131 #[serde(default)]
133 pub module: String,
134
135 #[serde(default)]
137 pub kind: EntityKind,
138
139 #[serde(default)]
141 pub fields: Vec<FieldSpec>,
142
143 #[serde(default)]
145 pub variants: Vec<VariantSpec>,
146
147 #[serde(default)]
149 pub derives: Vec<String>,
150}
151
152#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize)]
154#[serde(rename_all = "lowercase")]
155pub enum EntityKind {
156 #[default]
157 Struct,
158 Enum,
159 Newtype,
160}
161
162#[derive(Debug, Clone, Serialize, Deserialize)]
164pub struct FieldSpec {
165 pub name: String,
167
168 #[serde(rename = "type")]
170 pub ty: String,
171
172 #[serde(default)]
174 pub is_pub: bool,
175}
176
177#[derive(Debug, Clone, Serialize, Deserialize)]
179#[serde(untagged)]
180pub enum VariantSpec {
181 Unit(String),
183
184 Complex {
186 name: String,
187 #[serde(rename = "type", default)]
188 variant_type: Option<String>,
189 },
190}
191
192impl VariantSpec {
193 pub fn name(&self) -> &str {
194 match self {
195 VariantSpec::Unit(name) => name,
196 VariantSpec::Complex { name, .. } => name,
197 }
198 }
199
200 pub fn variant_type(&self) -> Option<&str> {
201 match self {
202 VariantSpec::Unit(_) => None,
203 VariantSpec::Complex { variant_type, .. } => variant_type.as_deref(),
204 }
205 }
206}
207
208#[derive(Debug, Clone, Serialize, Deserialize)]
210pub struct ErrorSpec {
211 pub name: String,
213
214 pub module: String,
216
217 #[serde(default)]
219 pub kind: EntityKind,
220
221 #[serde(default)]
223 pub variants: Vec<VariantSpec>,
224
225 #[serde(default)]
227 pub derives: Vec<String>,
228}
229
230#[derive(Debug, Clone, Serialize, Deserialize)]
232pub struct ImplSpec {
233 pub target: String,
235
236 #[serde(default)]
238 pub trait_name: Option<String>,
239
240 #[serde(default)]
242 pub methods: Vec<MethodSpec>,
243}
244
245#[derive(Debug, Clone, Serialize, Deserialize)]
247pub struct MethodSpec {
248 pub name: String,
250
251 #[serde(default)]
253 pub self_param: Option<SelfParamSpec>,
254
255 #[serde(default)]
257 pub params: Vec<(String, String)>,
258
259 #[serde(default)]
261 pub return_type: Option<String>,
262
263 #[serde(default = "default_body")]
265 pub body: String,
266
267 #[serde(default)]
269 pub is_pub: bool,
270}
271
272fn default_body() -> String {
273 "todo!()".to_string()
274}
275
276#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
278#[serde(rename_all = "lowercase")]
279pub enum SelfParamSpec {
280 Ref,
281 Mut,
282 Owned,
283}
284
285#[derive(Debug, Clone, Serialize, Deserialize)]
287#[serde(tag = "kind")]
288pub enum RefactorSpec {
289 AddBuilderPattern { targets: Vec<String> },
291
292 AddFromInto { pairs: Vec<(String, String)> },
294
295 AddDefault { targets: Vec<String> },
297
298 OrganizeImports {
300 #[serde(default)]
301 target_modules: TargetModules,
302 },
303}
304
305#[derive(Debug, Clone, Default, Serialize)]
307pub enum TargetModules {
308 #[default]
309 All,
310 List(Vec<String>),
311}
312
313impl<'de> Deserialize<'de> for TargetModules {
314 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
315 where
316 D: serde::Deserializer<'de>,
317 {
318 use serde::de::{self, Visitor};
319
320 struct TargetModulesVisitor;
321
322 impl<'de> Visitor<'de> for TargetModulesVisitor {
323 type Value = TargetModules;
324
325 fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
326 formatter.write_str(r#""all" or a list of module names"#)
327 }
328
329 fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
330 where
331 E: de::Error,
332 {
333 if v == "all" {
334 Ok(TargetModules::All)
335 } else {
336 Err(de::Error::custom(format!(
337 "expected 'all' or a list, got '{}'",
338 v
339 )))
340 }
341 }
342
343 fn visit_seq<A>(self, seq: A) -> Result<Self::Value, A::Error>
344 where
345 A: de::SeqAccess<'de>,
346 {
347 let modules = Vec::deserialize(de::value::SeqAccessDeserializer::new(seq))?;
348 Ok(TargetModules::List(modules))
349 }
350
351 fn visit_unit<E>(self) -> Result<Self::Value, E>
352 where
353 E: de::Error,
354 {
355 Ok(TargetModules::All)
356 }
357 }
358
359 deserializer.deserialize_any(TargetModulesVisitor)
360 }
361}
362
363impl TargetModules {
364 pub fn is_all(&self) -> bool {
365 matches!(self, TargetModules::All)
366 }
367}
368
369#[derive(Debug, Clone, Default, Serialize, Deserialize)]
371pub struct VerificationSpec {
372 #[serde(default)]
374 pub phase1: Vec<VerificationPointSpec>,
375
376 #[serde(default)]
378 pub phase2: Vec<VerificationPointSpec>,
379
380 #[serde(default)]
382 pub phase3: Vec<VerificationPointSpec>,
383
384 #[serde(default)]
386 pub phase4: Vec<VerificationPointSpec>,
387
388 #[serde(default)]
390 pub phase5: Vec<VerificationPointSpec>,
391
392 #[serde(default)]
394 pub phase6: Vec<VerificationPointSpec>,
395
396 #[serde(default, rename = "final")]
398 pub final_: Vec<VerificationPointSpec>,
399}
400
401#[derive(Debug, Clone, Serialize, Deserialize)]
403#[serde(tag = "kind")]
404pub enum VerificationPointSpec {
405 ModuleExists { paths: Vec<String> },
407
408 TypeExists { types: Vec<String> },
410
411 HasDerive {
413 #[serde(rename = "type")]
414 ty: String,
415 derives: Vec<String>,
416 },
417
418 HasField {
420 #[serde(rename = "type")]
421 ty: String,
422 field: String,
423 field_type: String,
424 },
425
426 MethodExists {
428 #[serde(rename = "type")]
429 ty: String,
430 method: String,
431 },
432
433 Compiles,
435
436 NoWarnings {
438 #[serde(default)]
439 allowed: Vec<String>,
440 },
441}
442
443#[cfg(test)]
444mod tests {
445 use super::*;
446
447 #[test]
448 fn test_module_flatten() {
449 let module = ModuleSpec {
450 name: "lib".to_string(),
451 is_pub: true,
452 children: vec![
453 ModuleSpec {
454 name: "user".to_string(),
455 is_pub: true,
456 children: vec![],
457 },
458 ModuleSpec {
459 name: "common".to_string(),
460 is_pub: true,
461 children: vec![ModuleSpec {
462 name: "types".to_string(),
463 is_pub: true,
464 children: vec![],
465 }],
466 },
467 ],
468 };
469
470 let flattened = module.flatten("");
471 assert_eq!(flattened.len(), 4);
472 assert!(flattened.iter().any(|(p, _)| p == "lib"));
473 assert!(flattened.iter().any(|(p, _)| p == "lib::user"));
474 assert!(flattened.iter().any(|(p, _)| p == "lib::common"));
475 assert!(flattened.iter().any(|(p, _)| p == "lib::common::types"));
476 }
477
478 #[test]
479 fn test_variant_spec_parsing() {
480 let yaml = r#""Active""#;
482 let variant: VariantSpec = serde_yaml::from_str(yaml).unwrap();
483 assert_eq!(variant.name(), "Active");
484 assert!(variant.variant_type().is_none());
485
486 let yaml = r#"{ name: "NotFound", type: "struct:entity:String" }"#;
488 let variant: VariantSpec = serde_yaml::from_str(yaml).unwrap();
489 assert_eq!(variant.name(), "NotFound");
490 assert_eq!(variant.variant_type(), Some("struct:entity:String"));
491 }
492}