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}