1use crate::file::{AbiFile, AbiMetadata};
2use crate::resolver::ImportResolver;
3use abi_types::{TypeDef, TypeKind};
4use std::path::{Path, PathBuf};
5
6pub fn flatten(file_path: &Path, include_dirs: &[PathBuf]) -> anyhow::Result<AbiFile> {
9 flatten_with_options(file_path, include_dirs, false)
10}
11
12pub fn flatten_with_options(
14 file_path: &Path,
15 include_dirs: &[PathBuf],
16 verbose: bool,
17) -> anyhow::Result<AbiFile> {
18 let mut resolver = ImportResolver::new(include_dirs.to_vec());
20 resolver.load_file_with_imports(file_path, verbose)?;
21
22 let all_files = resolver.get_all_files();
23 if all_files.is_empty() {
24 anyhow::bail!("No ABI files loaded");
25 }
26
27 let root_file = all_files.last().unwrap();
29
30 let mut all_types: Vec<TypeDef> = resolver.get_all_types().to_vec();
32
33 normalize_type_refs(&mut all_types, &resolver);
35
36 let flattened = AbiFile {
38 abi: AbiMetadata {
39 package: root_file.abi.package.clone(),
40 name: root_file.abi.name.clone(),
41 abi_version: root_file.abi.abi_version,
42 package_version: root_file.abi.package_version.clone(),
43 description: root_file.abi.description.clone(),
44 imports: Vec::new(), options: root_file.abi.options.clone(),
46 },
47 types: all_types,
48 };
49
50 if verbose {
51 println!(
52 "[~] Flattened {} files into {} types",
53 resolver.loaded_file_count(),
54 flattened.types.len()
55 );
56 }
57
58 Ok(flattened)
59}
60
61pub fn flatten_to_yaml(file_path: &Path, include_dirs: &[PathBuf]) -> anyhow::Result<String> {
63 let flattened = flatten(file_path, include_dirs)?;
64 let yaml = serde_yml::to_string(&flattened)?;
65 Ok(yaml)
66}
67
68pub fn normalize_type_refs(typedefs: &mut [TypeDef], resolver: &ImportResolver) {
70 for typedef in typedefs.iter_mut() {
71 normalize_type_kind(&mut typedef.kind, resolver);
72 }
73}
74
75fn normalize_type_kind(kind: &mut TypeKind, resolver: &ImportResolver) {
76 match kind {
77 TypeKind::TypeRef(type_ref) => {
78 if let Some(simple_name) = resolver.resolve_type_name(&type_ref.name) {
80 type_ref.name = simple_name;
81 }
82 type_ref.package = None;
84 }
85 TypeKind::Struct(struct_type) => {
86 for field in &mut struct_type.fields {
87 normalize_type_kind(&mut field.field_type, resolver);
88 }
89 }
90 TypeKind::Union(union_type) => {
91 for variant in &mut union_type.variants {
92 normalize_type_kind(&mut variant.variant_type, resolver);
93 }
94 }
95 TypeKind::Enum(enum_type) => {
96 for variant in &mut enum_type.variants {
97 normalize_type_kind(&mut variant.variant_type, resolver);
98 }
99 }
100 TypeKind::Array(array_type) => {
101 normalize_type_kind(&mut array_type.element_type, resolver);
102 }
103 TypeKind::SizeDiscriminatedUnion(sdu_type) => {
104 for variant in &mut sdu_type.variants {
105 normalize_type_kind(&mut variant.variant_type, resolver);
106 }
107 }
108 TypeKind::Primitive(_) => { }
109 }
110}