dmc_transform/
pipeline.rs1use crate::config::PipelineConfig;
2use dmc_diagnostic::{Code, metadata::SourceMeta};
3use dmc_parser::ast::Document;
4use duck_diagnostic::DiagnosticEngine;
5
6pub trait Transformer {
9 fn name(&self) -> &str {
11 "anonymous"
12 }
13 fn transform(&self, doc: &mut Document, meta: &SourceMeta, diag_engine: &mut DiagnosticEngine<Code>);
16}
17
18#[derive(Default)]
21pub struct Pipeline {
22 transformers: Vec<Box<dyn Transformer + Send + Sync>>,
23}
24
25impl Pipeline {
26 pub fn new() -> Self {
27 Self { transformers: Vec::new() }
28 }
29
30 #[allow(clippy::should_implement_trait)]
32 pub fn add<T: Transformer + Send + Sync + 'static>(mut self, t: T) -> Self {
33 self.transformers.push(Box::new(t));
34 self
35 }
36
37 pub fn with_defaults() -> Self {
39 Self::with_defaults_for(&PipelineConfig::default())
40 }
41
42 pub fn with_defaults_for(cfg: &PipelineConfig) -> Self {
46 #[allow(unused_mut)]
47 let mut p = Self::new()
48 .add(crate::AssignHeadingIds::new())
52 .add(crate::CodeImport::new())
53 .add(crate::BareUrlAutolink);
54 if cfg.autolink_headings != Some(false) {
55 p = p.add(crate::AutolinkHeadings::new());
56 }
57
58 if cfg.markdown_gfm == Some(false) {
59 p = p.add(crate::DisableGfm);
60 }
61
62 #[cfg(feature = "npm-command")]
63 {
64 p = p.add(crate::NpmCommand::new());
65 }
66
67 #[cfg(feature = "mermaid")]
68 {
69 if cfg.mermaid_enabled != Some(false) {
70 let m = cfg.mermaid.clone().map(crate::Mermaid::from_options).unwrap_or_default();
71 p = p.add(m);
72 }
73 }
74
75 #[cfg(feature = "emoji")]
76 {
77 if cfg.emoji != Some(false) {
78 p = p.add(crate::Emoji);
79 }
80 }
81
82 #[cfg(feature = "math")]
83 {
84 if let Some(engine) = cfg.math_engine {
85 crate::Math::set_engine(engine);
86 }
87 if cfg.math != Some(false) {
88 p = p.add(crate::Math);
89 }
90 }
91
92 #[cfg(feature = "pretty-code")]
93 {
94 if cfg.pretty_code_enabled != Some(false) {
95 let pc = cfg.pretty_code.as_ref().map(crate::PrettyCode::from_options).unwrap_or_default();
96 p = p.add(pc);
97 }
98 }
99
100 #[cfg(feature = "assets")]
101 if let Some(opts) = &cfg.copy_linked_files {
102 p =
103 p.add(crate::CopyLinkedFiles::new(opts.source_dir.clone(), opts.assets_dir.clone(), opts.public_base.clone()));
104 }
105
106 p
107 }
108
109 pub fn run(&self, doc: &mut Document, meta: &SourceMeta, engine: &'_ mut DiagnosticEngine<Code>) {
111 for t in &self.transformers {
112 t.transform(doc, meta, engine);
113 }
114 }
115
116 pub fn run_silent(&self, doc: &mut Document) {
119 use dmc_diagnostic::metadata::Origin;
120 use std::sync::Arc;
121 let meta = SourceMeta { path: Arc::from("<test>"), origin: Origin::Inline("<test>") };
122 let mut engine = DiagnosticEngine::new();
123 self.run(doc, &meta, &mut engine);
124 }
125}