helm-schema-ir 0.0.4

Generate an accurate JSON schema for any helm chart
Documentation
use color_eyre::eyre::{self, WrapErr as _};
use helm_schema_ast::DefineIndex;
use helm_schema_ir::SymbolicIrContext;
use serde_json::Value;
use test_util::prelude::sim_assert_eq;

pub mod cases;

#[derive(Clone, Copy)]
pub struct IrCorpusCase<'a> {
    pub template_path: &'a str,
    pub expected_fixture: &'a str,
    pub define_sources: test_util::DefineSourceSpec<'a>,
    pub dump_env: &'a str,
}

pub fn build_define_index(spec: test_util::DefineSourceSpec<'_>) -> eyre::Result<DefineIndex> {
    let mut idx = DefineIndex::new();
    for source in spec.load()? {
        idx.add_file_source(&source.path, &source.source);
    }
    Ok(idx)
}

pub fn render_ir_case(case: &IrCorpusCase<'_>) -> eyre::Result<Value> {
    let src = test_util::read_testdata(case.template_path)?;
    let idx = build_define_index(case.define_sources)?;
    let ir = SymbolicIrContext::new(&idx)
        .generate_contract_ir(&src)
        .finalize()
        .document();

    let actual = serde_json::to_value(ir).wrap_err("serialize contract IR")?;
    if std::env::var(case.dump_env).is_ok() {
        eprintln!("{}", serde_json::to_string_pretty(&actual)?);
        let dump_stem = case
            .template_path
            .chars()
            .map(|c| if c.is_ascii_alphanumeric() { c } else { '-' })
            .collect::<String>();
        let path = std::env::temp_dir().join(format!("helm-schema-ir.{dump_stem}.ir.json"));
        std::fs::write(&path, serde_json::to_vec_pretty(&actual)?)
            .wrap_err_with(|| format!("write IR dump to {}", path.display()))?;
    }
    Ok(actual)
}

pub fn assert_ir_fixture(case: &IrCorpusCase<'_>) -> eyre::Result<()> {
    let actual = render_ir_case(case)?;
    if std::env::var(case.dump_env).is_ok() {
        return Ok(());
    }
    let expected: Value = serde_json::from_str(case.expected_fixture)
        .wrap_err("parse expected contract IR fixture")?;

    sim_assert_eq!(have: actual, want: expected);
    Ok(())
}