etdl_compiler/codegen/mod.rs
1use etdl_parser::ast::EtlDocument;
2use etdl_parser::asyncapi::AsyncApiRegistry;
3use std::collections::BTreeMap;
4
5use crate::validate::Diagnostic;
6
7mod rust;
8pub use rust::RustCodeGenerator;
9
10/// One file a target generator produces. `relative_path` is relative to the
11/// `--out-dir` the CLI was given — a single-file target (Rust) returns one
12/// entry named from `stem` (e.g. `"order-fulfillment.rs"`); a target whose
13/// ecosystem expects a package/directory layout (Java, Go, ...) returns
14/// several, with `relative_path` encoding that structure (e.g.
15/// `"com/example/OrderFulfillment.java"`). The registry-facing side (the
16/// CLI) never special-cases *how many* files a target produces — it just
17/// writes whatever list comes back, creating parent directories as needed.
18#[derive(Debug, Clone, PartialEq, Eq)]
19pub struct GeneratedFile {
20 pub relative_path: String,
21 pub contents: String,
22}
23
24impl GeneratedFile {
25 pub fn new(relative_path: impl Into<String>, contents: impl Into<String>) -> Self {
26 GeneratedFile {
27 relative_path: relative_path.into(),
28 contents: contents.into(),
29 }
30 }
31}
32
33/// A pluggable code-generation backend (spec-neutral term: "target"). Every
34/// target consumes the *same* validated `EtlDocument` + resolved fault-tree
35/// probabilities + AsyncAPI registry — parsing, semantic validation, and
36/// fault-tree evaluation happen exactly once, upstream of this trait, in
37/// [`crate::Compiler`]; a target implementation only turns that already-
38/// resolved representation into target-language source text. Nothing here
39/// re-parses `.etdl`, re-validates ECEL conditions, or re-evaluates fault
40/// trees — see `docs/architecture/targets.md`.
41pub trait CodeGenerator {
42 /// Short, stable identifier used on the CLI (`--target <name>`) and in
43 /// the target registry (`etdl-cli`'s `TargetRegistry`). Lowercase,
44 /// matches the `--target` value exactly (e.g. `"rust"`, `"java"`).
45 fn target_name(&self) -> &'static str;
46
47 /// Generate this target's output for `doc`. `stem` is the input
48 /// document's filename without extension (what today's Rust target
49 /// already names its single output file after); other targets may use
50 /// it as a package/module root name instead of a literal filename.
51 fn generate_all(
52 &self,
53 doc: &EtlDocument,
54 fault_tree_probs: &BTreeMap<String, f64>,
55 registry: &AsyncApiRegistry,
56 stem: &str,
57 diagnostics: &mut Vec<Diagnostic>,
58 ) -> Result<Vec<GeneratedFile>, String>;
59}