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