automapper-validation 0.1.66

AHB condition expression parsing, evaluation, and EDIFACT validation
Documentation
//! Full raw-EDIFACT validation pipeline, shared by the v2 API route
//! (`automapper-api`'s `run_validation`) and the `edifact-mapper` library entry
//! point (`Mapper::validate_edifact`), so both produce byte-identical findings.

use mig_assembly::assembler::{Assembler, AssemblerConfig};
use mig_assembly::navigator::AssembledTreeNavigator;
use mig_types::schema::mig::MigSchema;
use mig_types::segment::OwnedSegment;

use crate::eval::{ConditionEvaluator, ExternalConditionProvider};
use crate::{
    build_validated_tree, validate_unt_segment_count, AhbWorkflow, EdifactValidator, IssueKind,
    Severity, ValidationIssue, ValidationLevel, ValidationReport,
};

/// Validate one message's assembled segments against its AHB workflow.
///
/// Callers resolve `filtered_mig`, `workflow`, and `evaluator` from wherever they
/// hold the data (the API from its `MigServiceRegistry`, `edifact-mapper` from the
/// data bundle) and pass the already-collected `all_segments` (message body plus
/// envelope for MIGs that cover it). Assembly config, validated-tree construction,
/// UNT-count and structure diagnostics all live here so the two entry points can
/// never drift.
pub fn validate_edifact_message<E: ConditionEvaluator>(
    all_segments: &[OwnedSegment],
    filtered_mig: &MigSchema,
    workflow: &AhbWorkflow,
    evaluator: E,
    external: &dyn ExternalConditionProvider,
    level: ValidationLevel,
) -> ValidationReport {
    // `skip_unknown_segments` lets the assembler advance past AHB-foreign segments
    // (surfaced once as diagnostics below) instead of stalling; `strict_code_matching`
    // disambiguates merged sibling slots. Mirrors the v2 route's config exactly.
    let assembler = Assembler::with_config(
        filtered_mig,
        AssemblerConfig {
            strict_code_matching: true,
            skip_unknown_segments: true,
            ..Default::default()
        },
    );
    let (tree, structure_diagnostics) = assembler.assemble_with_diagnostics(all_segments);

    let validated_tree = build_validated_tree(workflow, &tree);
    let navigator = AssembledTreeNavigator::new(&tree);
    let validator = EdifactValidator::new(evaluator);
    let mut report = validator.validate_tree(
        &validated_tree,
        all_segments,
        external,
        level,
        Some(&navigator),
    );

    if let Some(issue) = validate_unt_segment_count(all_segments) {
        report.add_issue(issue);
    }

    for diag in structure_diagnostics {
        let kind = IssueKind::StructureDiagnostic {
            kind: diag.kind,
            segment_id: diag.segment_id.clone(),
            position: diag.position,
            detail: diag.message,
        };
        report.add_issue(ValidationIssue::new(Severity::Warning, kind));
    }

    report
}