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;
33pub mod semantic;
34pub mod spanned;
35
36use ast::EtlDocument;
37use asyncapi::AsyncApiRegistry;
38use std::path::Path;
39
40pub fn parse_document(yaml_str: &str) -> Result<EtlDocument, String> {
41 let doc: EtlDocument =
42 serde_yaml::from_str(yaml_str).map_err(|e| format!("YAML parse error: {}", e))?;
43 Ok(doc)
44}
45
46/// Like [`parse_document`] but preserves the underlying `serde_yaml` error so
47/// callers can recover a source position via [`serde_yaml::Error::location`].
48pub fn parse_document_raw(yaml_str: &str) -> Result<EtlDocument, serde_yaml::Error> {
49 serde_yaml::from_str(yaml_str)
50}
51
52pub fn parse_document_from_file(path: &Path) -> Result<EtlDocument, String> {
53 let content = std::fs::read_to_string(path).map_err(|e| format!("cannot read file: {}", e))?;
54
55 if content.starts_with('\u{feff}') {
56 return Err("E-102: document contains a byte-order mark (BOM)".to_string());
57 }
58
59 parse_document(&content)
60}
61
62pub fn load_asyncapi_imports(
63 doc: &EtlDocument,
64 base_dir: &Path,
65) -> Result<AsyncApiRegistry, String> {
66 let mut registry = AsyncApiRegistry::new();
67 for (alias, location) in &doc.asyncapi_imports {
68 registry.load(alias, location, base_dir)?;
69 }
70 Ok(registry)
71}