aam_core/commands/import.rs
1//! `@import` directive — merges another `.aam` file into the current document.
2//!
3//! # Syntax
4//! ```text
5//! @import path/to/file.aam
6//! @import "path/to/file.aam"
7//! ```
8//!
9//! # Semantics
10//! Unlike `@derive`, `@import` uses `merge_content` which means **later** values
11//! overwrite earlier ones. If the same key appears in both the current document
12//! and the imported file, the imported value **wins** (last-write semantics).
13
14use crate::aaml::AAML;
15use crate::commands::Command;
16use crate::error::AamlError;
17use crate::pipeline::utils::resolve_relative_path;
18
19/// Command handler for the `@import` directive.
20#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
21pub struct ImportCommand;
22
23impl Command for ImportCommand {
24 fn name(&self) -> &'static str {
25 "import"
26 }
27
28 /// Reads the file at the given path and merges its content into `aaml`.
29 ///
30 /// # Errors
31 /// - [`AamlError::ParseError`] — path argument is empty.
32 /// - [`AamlError::IoError`] — a file cannot be read.
33 /// - Any parse error from the imported file.
34 fn execute(&self, aaml: &mut AAML, args: &str) -> Result<(), AamlError> {
35 let raw_path = args.trim();
36 if raw_path.is_empty() {
37 return Err(AamlError::ParseError {
38 line: 0,
39 content: args.to_string(),
40 details: "Import path cannot be empty".to_string(),
41 diagnostics: Some(Box::new(crate::error::ErrorDiagnostics::new(
42 "Missing import path",
43 "@import directive requires a file path",
44 "Use format: @import \"path/to/file.aam\"",
45 ))),
46 });
47 }
48
49 let path = AAML::unwrap_quotes(raw_path);
50 let resolved = resolve_relative_path(path, aaml.source_dir.as_deref());
51 aaml.merge_file(resolved)
52 }
53}