extern crate alloc;
use std::collections::HashMap;
use std::fs;
use beancount_importers_generators::compute_checksum_for_files;
use beancount_importers_generators::install_tracing;
use beancount_importers_generators::load_manifest;
use camino::Utf8Path;
use hard_xml::XmlRead;
use miette::IntoDiagnostic as _;
use miette::Result;
use toml_edit::Item;
use crate::passes::codegen;
use crate::passes::dependency_analysis::DependencyGraph;
use crate::passes::type_resolution::resolve_types;
use crate::passes::type_resolution::Type;
use crate::types::cooked;
use crate::types::external_code_sets::ExternalCodeSets;
use crate::types::raw::Repository;
use beancount_importers_generators::save_manifest;
mod passes;
mod types;
pub fn main() -> Result<()> {
install_tracing();
let (manifest_path, mut manifest) = load_manifest()?;
let sources = &mut manifest["package"]["metadata"]["px"]["source"];
let package_directory = manifest_path.parent().expect("absolute path");
run(sources, package_directory)?;
save_manifest(manifest)
}
fn run(sources: &mut Item, package_directory: &Utf8Path) -> Result<()> {
let repository_path = package_directory.join("20220520_ISO20022_2013_eRepository.iso20022");
let codeset_path = package_directory.join("4Q2022_ExternalCodeSets_v1.json");
let current_checksum = compute_checksum_for_files(&[&repository_path, &codeset_path])?;
let old_checksum = &mut sources["checksum"];
if let Some(old_checksum) = old_checksum.as_str() {
if old_checksum == current_checksum {
return Ok(());
}
}
let roots: &[&str] = &[
"_II5S49E-Ed-BzquC8wXy7w_620541391",
"_eYI_SW2PEei3KuUgpx7Xcw",
];
let type_overrides = maplit::hashmap! {
"_bqIp6tp-Ed-ak6NoX_4Aeg_1823330336" => Type { name: "CurrencyCode", needs_lifetime: false },
"_bqIp5tp-Ed-ak6NoX_4Aeg_-1326801359" => Type { name: "CurrencyCode", needs_lifetime: false },
"_YWr8K9p-Ed-ak6NoX_4Aeg_1527093628" => Type { name: "BicIdentifier", needs_lifetime: true },
"_YYB_-9p-Ed-ak6NoX_4Aeg_1297781972" => Type { name: "BicIdentifier", needs_lifetime: true },
"_jp-90kI6EeirV6K70JJQ8Q" => Type { name: "BicIdentifier", needs_lifetime: true },
"_gnK3okI7EeirV6K70JJQ8Q" => Type { name: "BicIdentifier", needs_lifetime: true },
"_bTfEctp-Ed-ak6NoX_4Aeg_-804722522" => Type { name: "CountryCode", needs_lifetime: false },
"_YYxm0dp-Ed-ak6NoX_4Aeg_1226525818" => Type { name: "IbanIdentifier", needs_lifetime: false },
"_YYU64Np-Ed-ak6NoX_4Aeg_-1113170580" => Type { name: "IsinIdentifier", needs_lifetime: false },
"_TUmCIAEcEeCQm6a_G2yO_w_637447613" => Type { name: "IsoLanguageCode", needs_lifetime: false },
"_rMvjUYIXEeWE0I8iABxEQA" => Type { name: "IsinIdentifier", needs_lifetime: false },
"_h7Yn9yjAEeKnA5P_jl2DUw" => Type { name: "LeiIdentifier", needs_lifetime: false },
"_TQIBwHrVEeidVZmeoasaWQ" => Type { name: "UuidV4Identifier", needs_lifetime: false },
};
let source_directory = package_directory.join("src");
generate_external_code_sets(&codeset_path, {
let mut path = source_directory.join("types");
path.push("external_code_sets.rs");
path
})?;
generate_erepository(
&repository_path,
roots,
type_overrides,
source_directory.join("types.rs"),
)?;
*old_checksum = toml_edit::value(current_checksum);
Ok(())
}
fn generate_external_code_sets(
codeset_path: impl AsRef<Utf8Path>,
output_path: impl AsRef<Utf8Path>,
) -> Result<()> {
let external_code_sets = fs::read_to_string(codeset_path.as_ref()).into_diagnostic()?;
let external_code_sets: ExternalCodeSets =
serde_json::de::from_str(&external_code_sets).into_diagnostic()?;
let code = codegen::generate_external_code_sets(&external_code_sets.definitions);
fs::write(output_path.as_ref(), code.to_string()).into_diagnostic()?;
Ok(())
}
fn generate_erepository(
repository_path: impl AsRef<Utf8Path>,
roots: &[&str],
manual_types: HashMap<&str, Type>,
output_path: impl AsRef<Utf8Path>,
) -> Result<()> {
let repo = fs::read_to_string(repository_path.as_ref()).into_diagnostic()?;
let repo = Repository::from_str(&repo).into_diagnostic()?;
let definitions = cooked::cook(repo);
let graph = DependencyGraph::construct_for(&definitions, roots);
let types = resolve_types(&definitions, &graph, &manual_types);
let code = codegen::generate_erepository(&definitions, &graph, &manual_types, &types);
fs::write(output_path.as_ref(), code.to_string()).into_diagnostic()?;
Ok(())
}