use crate::cli::CliResult;
use crate::AasAction;
use oxirs_samm::metamodel::ModelElement;
use std::path::PathBuf;
pub async fn run(action: AasAction) -> CliResult<()> {
match action {
AasAction::ToAspect {
file,
output_directory,
submodel_templates,
} => to_aspect(file, output_directory, submodel_templates).await,
AasAction::List { file } => list(file).await,
}
}
async fn to_aspect(
file: PathBuf,
output_directory: Option<PathBuf>,
submodel_templates: Vec<usize>,
) -> CliResult<()> {
let format = detect_aas_format(&file)?;
println!("Converting AAS file to Aspect Models...");
println!(" File: {}", file.display());
println!(" Format: {}", format);
if let Some(ref dir) = output_directory {
println!(" Output Directory: {}", dir.display());
} else {
println!(" Output Directory: (current directory)");
}
if !submodel_templates.is_empty() {
println!(" Selected Submodels: {:?}", submodel_templates);
} else {
println!(" Selected Submodels: (all)");
}
if !file.exists() {
return Err(format!("AAS file not found: {}", file.display()).into());
}
let env = oxirs_samm::aas_parser::parse_aas_file(&file)
.await
.map_err(|e| format!("Failed to parse AAS file: {}", e))?;
println!("\n✓ Successfully parsed AAS file");
println!(" Found {} submodel(s)", env.submodels.len());
let aspects = oxirs_samm::aas_parser::convert_to_aspects(&env, submodel_templates)
.map_err(|e| format!("Failed to convert to Aspect Models: {}", e))?;
println!(" Converted {} Aspect Model(s)", aspects.len());
let output_dir = output_directory
.unwrap_or_else(|| std::env::current_dir().expect("failed to get current directory"));
if !output_dir.exists() {
std::fs::create_dir_all(&output_dir)
.map_err(|e| format!("Failed to create output directory: {}", e))?;
}
println!("\nGenerating Aspect Model files:");
for (idx, aspect) in aspects.iter().enumerate() {
let filename = format!("{}.ttl", aspect.name());
let filepath = output_dir.join(&filename);
oxirs_samm::serializer::serialize_aspect_to_file(aspect, &filepath)
.await
.map_err(|e| format!("Failed to serialize aspect {}: {}", aspect.name(), e))?;
println!(
" {}. {} ({})",
idx + 1,
aspect.name(),
aspect.metadata().urn
);
println!(" Properties: {}", aspect.properties().len());
println!(" Operations: {}", aspect.operations().len());
println!(" Output: {}", filepath.display());
}
println!(
"\n✓ Successfully generated {} Turtle file(s) in {}",
aspects.len(),
output_dir.display()
);
Ok(())
}
async fn list(file: PathBuf) -> CliResult<()> {
let format = detect_aas_format(&file)?;
println!("Listing submodel templates in AAS file...");
println!(" File: {}", file.display());
println!(" Format: {}", format);
println!();
if !file.exists() {
return Err(format!("AAS file not found: {}", file.display()).into());
}
let env = oxirs_samm::aas_parser::parse_aas_file(&file)
.await
.map_err(|e| format!("Failed to parse AAS file: {}", e))?;
let submodels = oxirs_samm::aas_parser::list_submodels(&env);
println!("✓ Found {} submodel template(s):\n", submodels.len());
if submodels.is_empty() {
println!(" (No submodel templates found in this AAS file)");
} else {
for (idx, id, name, description) in submodels {
println!(" [{}] {}", idx, name.as_ref().unwrap_or(&id));
println!(" ID: {}", id);
if let Some(desc) = description {
let display_desc = if desc.len() > 80 {
format!("{}...", &desc[..77])
} else {
desc
};
println!(" Description: {}", display_desc);
}
println!();
}
println!("Use `-s <index>` with `to-aspect` to convert specific submodels.");
println!(
"Example: oxirs aas to-aspect {} -s 0 -s 1 -d output/",
file.display()
);
}
Ok(())
}
fn detect_aas_format(file: &std::path::Path) -> CliResult<&'static str> {
let extension = file
.extension()
.and_then(|ext| ext.to_str())
.ok_or_else(|| format!("Unable to determine file format from: {}", file.display()))?;
match extension.to_lowercase().as_str() {
"xml" => Ok("XML"),
"json" => Ok("JSON"),
"aasx" => Ok("AASX"),
other => Err(format!(
"Unsupported AAS file format: .{}\n\
Supported formats: .xml, .json, .aasx",
other
)
.into()),
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::path::PathBuf;
#[test]
fn test_detect_aas_format_xml() {
let file = PathBuf::from("test.xml");
assert_eq!(detect_aas_format(&file).unwrap(), "XML");
}
#[test]
fn test_detect_aas_format_json() {
let file = PathBuf::from("test.json");
assert_eq!(detect_aas_format(&file).unwrap(), "JSON");
}
#[test]
fn test_detect_aas_format_aasx() {
let file = PathBuf::from("test.aasx");
assert_eq!(detect_aas_format(&file).unwrap(), "AASX");
}
#[test]
fn test_detect_aas_format_case_insensitive() {
let file = PathBuf::from("test.AASX");
assert_eq!(detect_aas_format(&file).unwrap(), "AASX");
}
#[test]
fn test_detect_aas_format_unsupported() {
let file = PathBuf::from("test.txt");
assert!(detect_aas_format(&file).is_err());
}
#[test]
fn test_detect_aas_format_no_extension() {
let file = PathBuf::from("test");
assert!(detect_aas_format(&file).is_err());
}
}