# Emitter Composition

This document describes how [emitters](./architecture.md) can be composed with transformers. For background on the event-driven architecture, see the [architecture documentation](./architecture.md).

```
Base Emitter + Transformer(s) = New Emitter
```

For example:
- `WasotFileEmitter` + `SelectorTransformer` = Filtered emitter
- `SqliteEmitter` + `FilterTransformer` + `EnrichmentTransformer` = Enhanced SQLite emitter

The `transformer_pipeline` function makes this composition easy:
```rust
// Single transformer
let filtered_emitter = apply_transformer(
    WasotFileEmitter::from_file("doc.wasot"),
    SelectorTransformer::new(vec!["paragraph"])
);

// Multiple transformers
let pipeline_emitter = transformer_pipeline(
    WasotFileEmitter::from_file("doc.wasot"),
    vec![
        Box::new(SelectorTransformer::new(vec!["section"])),
        Box::new(ValidationTransformer::new()),
        Box::new(EnrichmentTransformer::new()),
    ]
);
```

For a fluent interface, use the `PipelineBuilder`:
```rust
let events = PipelineBuilder::from_emitter(emitter)
    .apply(SelectorTransformer::new(vec!["section"]))
    .apply(ValidationTransformer::new())
    .build();
```

This composed emitter can be used anywhere an emitter is expected, maintaining the system's composability and flexibility. For an example of this pattern in action, see the [random generator](./random-generator.md) and the [memory analysis](./memory_analysis.md) which examines memory behavior of emitters.