Skip to main content

etdl_parser/
lib.rs

1//! Parsing for the Event Tree Definition Language (ETDL).
2//!
3//! `etdl-parser` reads `.etdl` documents — the declarative, design-time DSL for
4//! reliability-aware event-driven microservices defined by
5//! [IEC 62502:2010 (event tree analysis)](https://github.com/usamassem/etdl-specification)
6//! and [IEC 61025:2006 (fault tree analysis)](https://github.com/usamassem/etdl-specification) —
7//! and resolves their references into AsyncAPI 3.0 contracts.
8//!
9//! # Features
10//!
11//! - [`ast`] — full document AST with manual `Deserialize` (supports legacy
12//!   `eventTree` and `x-*` extension fields)
13//! - [`ecel`] — the Event-tree Condition Expression Language (ECEL), a typed,
14//!   side-effect-free expression language for barrier branch conditions
15//! - [`asyncapi`] — AsyncAPI 3.0 document loading and a schema-introspecting registry
16//! - [`jsonptr`] — RFC 6901 JSON Pointer resolution for `onFailureProbabilitySource`
17//!   and other in-document references
18//!
19//! # Example
20//!
21//! ```no_run
22//! use etdl_parser::parse_document_from_file;
23//! use std::path::Path;
24//!
25//! let doc = parse_document_from_file(Path::new("order-fulfillment.etdl"))?;
26//! # Ok::<(), String>(())
27//! ```
28
29pub mod ast;
30pub mod asyncapi;
31pub mod ecel;
32pub mod jsonptr;
33
34use ast::EtlDocument;
35use asyncapi::AsyncApiRegistry;
36use std::path::Path;
37
38pub fn parse_document(yaml_str: &str) -> Result<EtlDocument, String> {
39    let doc: EtlDocument =
40        serde_yaml::from_str(yaml_str).map_err(|e| format!("YAML parse error: {}", e))?;
41    Ok(doc)
42}
43
44pub fn parse_document_from_file(path: &Path) -> Result<EtlDocument, String> {
45    let content =
46        std::fs::read_to_string(path).map_err(|e| format!("cannot read file: {}", e))?;
47
48    if content.starts_with('\u{feff}') {
49        return Err("E-102: document contains a byte-order mark (BOM)".to_string());
50    }
51
52    parse_document(&content)
53}
54
55pub fn load_asyncapi_imports(
56    doc: &EtlDocument,
57    base_dir: &Path,
58) -> Result<AsyncApiRegistry, String> {
59    let mut registry = AsyncApiRegistry::new();
60    for (alias, location) in &doc.asyncapi_imports {
61        registry.load(alias, location, base_dir)?;
62    }
63    Ok(registry)
64}