syn_rsx/
config.rs

1use proc_macro2::TokenStream;
2use syn::{parse::ParseStream, Result};
3
4use crate::NodeType;
5
6pub type TransformBlockFn = dyn Fn(ParseStream) -> Result<Option<TokenStream>>;
7
8/// Configures the `Parser` behavior
9#[derive(Default)]
10pub struct ParserConfig {
11    pub(crate) flat_tree: bool,
12    pub(crate) number_of_top_level_nodes: Option<usize>,
13    pub(crate) type_of_top_level_nodes: Option<NodeType>,
14    pub(crate) transform_block: Option<Box<TransformBlockFn>>,
15}
16
17impl ParserConfig {
18    /// Create new `ParserConfig` with default config
19    pub fn new() -> ParserConfig {
20        ParserConfig::default()
21    }
22
23    /// Return flat tree instead of nested tree
24    pub fn flat_tree(mut self) -> Self {
25        self.flat_tree = true;
26        self
27    }
28
29    /// Exact number of required top level nodes
30    pub fn number_of_top_level_nodes(mut self, number: usize) -> Self {
31        self.number_of_top_level_nodes = Some(number);
32        self
33    }
34
35    /// Enforce the `NodeType` of top level nodes
36    pub fn type_of_top_level_nodes(mut self, node_type: NodeType) -> Self {
37        self.type_of_top_level_nodes = Some(node_type);
38        self
39    }
40
41    /// Transforms the `value` of all `NodeType::Block`s with the given closure
42    /// callback. The provided `ParseStream` is the content of the block.
43    ///
44    /// When `Some(TokenStream)` is returned, the `TokenStream` is parsed as
45    /// Rust block content. The `ParseStream` must be completely consumed in
46    /// this case, meaning no tokens can be left in the stream.
47    ///
48    /// If `None` is returned, parsing happens with the original `ParseStream`,
49    /// since the tokens that are passend into the transform callback are a
50    /// fork, which gets only advanced if `Some` is returned.
51    ///
52    /// An example usage might be a custom syntax inside blocks which isn't
53    /// valid Rust. The given example simply translates the `%` character into
54    /// the string `percent`
55    ///
56    /// ```rust
57    /// use quote::quote;
58    /// use syn::Token;
59    /// use syn_rsx::{parse2_with_config, ParserConfig};
60    ///
61    /// let tokens = quote! {
62    ///     <div>{%}</div>
63    /// };
64    ///
65    /// let config = ParserConfig::new().transform_block(|input| {
66    ///     input.parse::<Token![%]>()?;
67    ///     Ok(Some(quote! { "percent" }))
68    /// });
69    ///
70    /// parse2_with_config(tokens, config).unwrap();
71    /// ```
72    pub fn transform_block<F>(mut self, callback: F) -> Self
73    where
74        F: Fn(ParseStream) -> Result<Option<TokenStream>> + 'static,
75    {
76        self.transform_block = Some(Box::new(callback));
77        self
78    }
79}