aam_core/commands/
derive.rs1use crate::aaml::AAML;
23use crate::commands::Command;
24use crate::error::AamlError;
25use crate::pipeline::utils::resolve_relative_path;
26
27#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
29pub struct DeriveCommand;
30
31fn parse_derive_arg(raw: &str) -> (&str, Vec<&str>) {
38 let (path_raw, rest) = if raw.starts_with('"') || raw.starts_with('\'') {
39 let q = raw.chars().next().unwrap();
40 raw[1..].find(q).map_or((raw, ""), |end| {
41 let path = &raw[1..=end];
42 let after = raw[end + 2..].trim_start_matches(':').trim();
43 (path, after)
44 })
45 } else {
46 raw.find("::")
47 .map_or((raw, ""), |pos| (&raw[..pos], &raw[pos + 2..]))
48 };
49
50 let selectors = rest
51 .split("::")
52 .map(str::trim)
53 .filter(|s| !s.is_empty())
54 .collect();
55
56 (path_raw.trim(), selectors)
57}
58
59impl Command for DeriveCommand {
60 fn name(&self) -> &'static str {
61 "derive"
62 }
63
64 fn execute(&self, aaml: &mut AAML, args: &str) -> Result<(), AamlError> {
65 let (path, selectors) = parse_derive_arg(args.trim());
66 let resolved = resolve_relative_path(path, aaml.source_dir.as_deref());
67 let mut base = AAML::load(resolved)?;
68
69 let original_schemas: Vec<String> = aaml.get_schemas().keys().cloned().collect();
70
71 if selectors.is_empty() {
72 let names: Vec<String> = base.get_schemas().keys().cloned().collect();
73 for name in names {
74 aaml.import_schema(&name, &mut base)?;
75 }
76 } else {
77 for name in selectors {
78 aaml.import_schema(name, &mut base)?;
79 }
80 }
81
82 aaml.merge_map_weak(base.get_map_mut());
83
84 let refs: Vec<&str> = original_schemas.iter().map(String::as_str).collect();
85 aaml.validate_schemas_completeness_for(&refs)?;
86
87 Ok(())
88 }
89}