libhanzzok/codegen/walker/
decorator_chain.rs

1use v_htmlescape::escape;
2
3use crate::{
4    codegen::{Context, HtmlNode},
5    core::ast::{DecoratorChainNode, InlineObjectNode, Raw, TextNode},
6    syntax::{Token, TokenKind},
7};
8
9use super::Walker;
10
11impl Walker<DecoratorChainNode> for Context<'_> {
12    fn walk(&mut self, node: DecoratorChainNode) -> Vec<crate::codegen::HtmlNode> {
13        let should_be_raw_until = node
14            .decorators
15            .iter()
16            .enumerate()
17            .find(|(_, node)| {
18                self.compiler
19                    .decorator_rules
20                    .get(&node.name)
21                    .map(|rule| rule.accept_raw_text())
22                    .unwrap_or(false)
23            })
24            .map(|(index, _)| index + 1)
25            .unwrap_or(0);
26        let should_be_raw = should_be_raw_until > 0;
27        let should_be_raw_until = if should_be_raw {
28            should_be_raw_until - 1
29        } else {
30            should_be_raw_until
31        };
32        let mut nodes = if should_be_raw {
33            vec![HtmlNode::create_text(
34                escape(
35                    &node
36                        .main_text
37                        .raw()
38                        .into_iter()
39                        .chain(
40                            node.decorators
41                                .iter()
42                                .take(should_be_raw_until)
43                                .flat_map(|node| node.raw()),
44                        )
45                        .map(|t| t.text.clone())
46                        .collect::<String>()
47                        .trim_end(),
48                )
49                .to_string(),
50            )]
51        } else {
52            let node = match *node.main_text {
53                InlineObjectNode::Text(text) => {
54                    let mut tokens = text.tokens;
55                    while let Some((
56                        (
57                            Token {
58                                kind: TokenKind::HorizontalSpace,
59                                ..
60                            },
61                            _,
62                        ),
63                        elements,
64                    )) = tokens.split_last_mut()
65                    {
66                        if let Some((
67                            Token {
68                                kind: TokenKind::PunctuationReverseSolidus,
69                                ..
70                            },
71                            _,
72                        )) = elements.last()
73                        {
74                            break;
75                        }
76
77                        tokens = elements.to_vec();
78                    }
79                    InlineObjectNode::Text(TextNode { tokens })
80                }
81                a @ _ => a,
82            };
83
84            self.walk(node)
85        };
86        let mut is_first = true;
87        for decorator in node.decorators.into_iter().skip(should_be_raw_until) {
88            let rule = match self.compiler.decorator_rules.get(&decorator.name) {
89                Some(rule) => rule,
90                None => continue,
91            };
92            if !is_first && rule.accept_raw_text() {
93                continue;
94            }
95            is_first = false;
96            nodes = rule.apply(
97                self,
98                nodes,
99                decorator
100                    .params
101                    .and_then(|s| serde_hzdata::from_str(&s).ok()),
102            );
103        }
104        nodes
105    }
106}