mrml_wasm/parser/
mod.rs

1mod memory_include_loader;
2#[cfg(feature = "reqwest-include-loader")]
3mod reqwest_include_loader;
4
5pub use memory_include_loader::*;
6#[cfg(feature = "reqwest-include-loader")]
7pub use reqwest_include_loader::*;
8
9#[derive(Clone, Debug, serde::Deserialize, serde::Serialize, tsify::Tsify)]
10#[serde(tag = "type", rename_all = "camelCase")]
11#[tsify(into_wasm_abi, from_wasm_abi)]
12#[derive(Default)]
13pub enum IncludeLoaderOptions {
14    #[default]
15    Noop,
16    Memory(MemoryIncludeLoaderOptions),
17}
18
19impl IncludeLoaderOptions {
20    pub fn build(
21        self,
22    ) -> Box<dyn mrml::prelude::parser::loader::IncludeLoader + Send + Sync + 'static> {
23        match self {
24            Self::Noop => Box::new(mrml::prelude::parser::noop_loader::NoopIncludeLoader),
25            Self::Memory(inner) => inner.build(),
26        }
27    }
28}
29
30#[derive(Clone, Debug, serde::Deserialize, serde::Serialize, tsify::Tsify)]
31#[serde(rename_all = "camelCase")]
32#[tsify(into_wasm_abi, from_wasm_abi)]
33pub struct ParserOptions {
34    pub include_loader: IncludeLoaderOptions,
35}
36
37impl From<ParserOptions> for mrml::prelude::parser::ParserOptions {
38    fn from(value: ParserOptions) -> Self {
39        mrml::prelude::parser::ParserOptions {
40            include_loader: value.include_loader.build(),
41        }
42    }
43}
44
45// ASYNC RELATED
46#[cfg(feature = "async")]
47#[derive(Clone, Debug, serde::Deserialize, serde::Serialize, tsify::Tsify)]
48#[serde(tag = "type", rename_all = "camelCase")]
49#[tsify(into_wasm_abi, from_wasm_abi)]
50#[derive(Default)]
51pub enum AsyncIncludeLoaderOptions {
52    #[default]
53    Noop,
54    Memory(MemoryIncludeLoaderOptions),
55    #[cfg(feature = "reqwest-include-loader")]
56    Reqwest(ReqwestIncludeLoaderOptions),
57}
58
59#[cfg(feature = "async")]
60impl AsyncIncludeLoaderOptions {
61    pub fn build_async(
62        self,
63    ) -> Box<dyn mrml::prelude::parser::loader::AsyncIncludeLoader + Send + Sync + 'static> {
64        match self {
65            Self::Noop => Box::new(mrml::prelude::parser::noop_loader::NoopIncludeLoader),
66            Self::Memory(inner) => inner.build_async(),
67            #[cfg(feature = "reqwest-include-loader")]
68            Self::Reqwest(inner) => inner.build_async(),
69        }
70    }
71}
72
73#[cfg(feature = "async")]
74#[derive(Clone, Debug, serde::Deserialize, serde::Serialize, tsify::Tsify)]
75#[serde(rename_all = "camelCase")]
76#[tsify(into_wasm_abi, from_wasm_abi)]
77pub struct AsyncParserOptions {
78    pub include_loader: AsyncIncludeLoaderOptions,
79}
80
81#[cfg(feature = "async")]
82impl From<AsyncParserOptions> for mrml::prelude::parser::AsyncParserOptions {
83    fn from(value: AsyncParserOptions) -> Self {
84        mrml::prelude::parser::AsyncParserOptions {
85            include_loader: value.include_loader.build_async(),
86        }
87    }
88}
89
90#[derive(Clone, Debug, serde::Deserialize, serde::Serialize, tsify::Tsify)]
91#[serde(rename_all = "kebab-case", tag = "type")]
92#[tsify(into_wasm_abi, from_wasm_abi)]
93pub enum ParserError {
94    UnexpectedElement {
95        origin: super::Origin,
96        position: super::Span,
97    },
98    UnexpectedToken {
99        origin: super::Origin,
100        position: super::Span,
101    },
102    MissingAttribute {
103        name: String,
104        origin: super::Origin,
105        position: super::Span,
106    },
107    InvalidAttribute {
108        origin: super::Origin,
109        position: super::Span,
110    },
111    InvalidFormat {
112        origin: super::Origin,
113        position: super::Span,
114    },
115    EndOfStream {
116        origin: super::Origin,
117    },
118    /// The input string should be smaller than 4GiB.
119    SizeLimit {
120        origin: super::Origin,
121    },
122    /// Errors detected by the `xmlparser` crate.
123    ParserError {
124        origin: super::Origin,
125        source: String,
126    },
127    /// The Mjml document must have at least one element.
128    NoRootNode,
129    IncludeLoaderError {
130        origin: super::Origin,
131        position: super::Span,
132        source: String,
133    },
134}
135
136impl From<mrml::prelude::parser::Error> for ParserError {
137    fn from(value: mrml::prelude::parser::Error) -> Self {
138        use mrml::prelude::parser::Error;
139
140        match value {
141            Error::NoRootNode => Self::NoRootNode,
142            Error::EndOfStream { origin } => Self::EndOfStream {
143                origin: origin.into(),
144            },
145            Error::IncludeLoaderError {
146                origin,
147                position,
148                source,
149            } => Self::IncludeLoaderError {
150                origin: origin.into(),
151                position: position.into(),
152                source: source.to_string(),
153            },
154            Error::InvalidAttribute { origin, position } => Self::InvalidAttribute {
155                origin: origin.into(),
156                position: position.into(),
157            },
158            Error::InvalidFormat { origin, position } => Self::InvalidFormat {
159                origin: origin.into(),
160                position: position.into(),
161            },
162            Error::MissingAttribute {
163                name,
164                origin,
165                position,
166            } => Self::MissingAttribute {
167                name: name.into(),
168                origin: origin.into(),
169                position: position.into(),
170            },
171            Error::ParserError { origin, source } => Self::ParserError {
172                origin: origin.into(),
173                source: source.to_string(),
174            },
175            Error::SizeLimit { origin } => Self::SizeLimit {
176                origin: origin.into(),
177            },
178            Error::UnexpectedElement { origin, position } => Self::UnexpectedElement {
179                origin: origin.into(),
180                position: position.into(),
181            },
182            Error::UnexpectedToken { origin, position } => Self::UnexpectedToken {
183                origin: origin.into(),
184                position: position.into(),
185            },
186        }
187    }
188}
189
190#[derive(Clone, Debug, serde::Deserialize, serde::Serialize, tsify::Tsify)]
191#[serde(rename_all = "kebab-case", tag = "type")]
192#[tsify(into_wasm_abi)]
193pub enum Origin {
194    Root,
195    Include { path: String },
196}
197
198impl From<mrml::prelude::parser::Origin> for Origin {
199    fn from(value: mrml::prelude::parser::Origin) -> Self {
200        match value {
201            mrml::prelude::parser::Origin::Root => Self::Root,
202            mrml::prelude::parser::Origin::Include { path } => Self::Include { path },
203        }
204    }
205}
206
207#[derive(Clone, Debug, serde::Deserialize, serde::Serialize, tsify::Tsify)]
208#[tsify(into_wasm_abi)]
209pub struct Span {
210    start: usize,
211    end: usize,
212}
213
214impl From<mrml::prelude::parser::Span> for Span {
215    fn from(value: mrml::prelude::parser::Span) -> Self {
216        Self {
217            start: value.start,
218            end: value.end,
219        }
220    }
221}
222
223#[derive(Debug, serde::Deserialize, serde::Serialize, tsify::Tsify)]
224#[serde(rename_all = "kebab-case")]
225#[tsify(into_wasm_abi)]
226pub enum WarningKind {
227    UnexpectedAttributes,
228}
229
230impl From<mrml::prelude::parser::WarningKind> for WarningKind {
231    fn from(value: mrml::prelude::parser::WarningKind) -> Self {
232        match value {
233            mrml::prelude::parser::WarningKind::UnexpectedAttribute => Self::UnexpectedAttributes,
234        }
235    }
236}
237
238#[derive(Debug, serde::Deserialize, serde::Serialize, tsify::Tsify)]
239#[tsify(into_wasm_abi)]
240pub struct Warning {
241    kind: WarningKind,
242    origin: Origin,
243    span: Span,
244}
245
246impl Warning {
247    #[inline]
248    pub(crate) fn from_vec(list: Vec<mrml::prelude::parser::Warning>) -> Vec<Warning> {
249        list.into_iter().map(Warning::from).collect()
250    }
251}
252
253impl From<mrml::prelude::parser::Warning> for Warning {
254    fn from(value: mrml::prelude::parser::Warning) -> Self {
255        Self {
256            origin: value.origin.into(),
257            kind: value.kind.into(),
258            span: value.span.into(),
259        }
260    }
261}