markup_fmt/
parser.rs

1//! This parser is designed for internal use,
2//! not generating general-purpose AST.
3//!
4//! Also, the parser consumes string then produces AST directly without tokenizing.
5//! For a formal parser, it should be:
6//! `source -> tokens (produced by lexer/tokenizer) -> AST (produced by parser)`.
7//! So, if you're learning or looking for a parser,
8//! this is not a good example and you should look for other projects.
9
10use crate::{
11    ast::*,
12    error::{SyntaxError, SyntaxErrorKind},
13    helpers,
14};
15use std::{cmp::Ordering, iter::Peekable, ops::ControlFlow, str::CharIndices};
16
17#[derive(Clone, Copy, Debug, PartialEq, Eq)]
18/// Supported languages.
19pub enum Language {
20    Html,
21    Vue,
22    Svelte,
23    Astro,
24    Angular,
25    Jinja,
26    Vento,
27    Mustache,
28    Xml,
29}
30
31pub struct Parser<'s> {
32    source: &'s str,
33    language: Language,
34    chars: Peekable<CharIndices<'s>>,
35    state: ParserState,
36}
37
38#[derive(Default)]
39struct ParserState {
40    has_front_matter: bool,
41}
42
43impl<'s> Parser<'s> {
44    pub fn new(source: &'s str, language: Language) -> Self {
45        Self {
46            source,
47            language,
48            chars: source.char_indices().peekable(),
49            state: Default::default(),
50        }
51    }
52
53    fn try_parse<F, R>(&mut self, f: F) -> PResult<R>
54    where
55        F: FnOnce(&mut Self) -> PResult<R>,
56    {
57        let chars = self.chars.clone();
58        let result = f(self);
59        if result.is_err() {
60            self.chars = chars;
61        }
62        result
63    }
64
65    fn emit_error(&mut self, kind: SyntaxErrorKind) -> SyntaxError {
66        let pos = self
67            .chars
68            .peek()
69            .map(|(pos, _)| *pos)
70            .unwrap_or(self.source.len());
71        self.emit_error_with_pos(kind, pos)
72    }
73
74    fn emit_error_with_pos(&self, kind: SyntaxErrorKind, pos: usize) -> SyntaxError {
75        let (line, column) = self.pos_to_line_col(pos);
76        SyntaxError {
77            kind,
78            pos,
79            line,
80            column,
81        }
82    }
83    fn pos_to_line_col(&self, pos: usize) -> (usize, usize) {
84        let search = memchr::memchr_iter(b'\n', self.source.as_bytes()).try_fold(
85            (1, 0),
86            |(line, prev_offset), offset| match pos.cmp(&offset) {
87                Ordering::Less => ControlFlow::Break((line, prev_offset)),
88                Ordering::Equal => ControlFlow::Break((line, prev_offset)),
89                Ordering::Greater => ControlFlow::Continue((line + 1, offset)),
90            },
91        );
92        match search {
93            ControlFlow::Break((line, offset)) => (line, pos - offset + 1),
94            ControlFlow::Continue((line, _)) => (line, 0),
95        }
96    }
97
98    fn skip_ws(&mut self) {
99        while self
100            .chars
101            .next_if(|(_, c)| c.is_ascii_whitespace())
102            .is_some()
103        {}
104    }
105
106    fn with_taken<T, F>(&mut self, parser: F) -> PResult<(T, &'s str)>
107    where
108        F: FnOnce(&mut Self) -> PResult<T>,
109    {
110        let start = self
111            .chars
112            .peek()
113            .map(|(i, _)| *i)
114            .unwrap_or(self.source.len());
115        let parsed = parser(self)?;
116        let end = self
117            .chars
118            .peek()
119            .map(|(i, _)| *i)
120            .unwrap_or(self.source.len());
121        Ok((parsed, unsafe { self.source.get_unchecked(start..end) }))
122    }
123
124    fn parse_angular_control_flow_children(&mut self) -> PResult<Vec<Node<'s>>> {
125        if self.chars.next_if(|(_, c)| *c == '{').is_none() {
126            return Err(self.emit_error(SyntaxErrorKind::ExpectChar('{')));
127        }
128
129        let mut children = vec![];
130        while let Some((_, c)) = self.chars.peek() {
131            if *c == '}' {
132                self.chars.next();
133                break;
134            } else {
135                children.push(self.parse_node()?);
136            }
137        }
138        Ok(children)
139    }
140
141    fn parse_angular_defer(&mut self) -> PResult<Vec<AngularGenericBlock<'s>>> {
142        if self
143            .chars
144            .next_if(|(_, c)| *c == '@')
145            .and_then(|_| self.chars.next_if(|(_, c)| *c == 'd'))
146            .and_then(|_| self.chars.next_if(|(_, c)| *c == 'e'))
147            .and_then(|_| self.chars.next_if(|(_, c)| *c == 'f'))
148            .and_then(|_| self.chars.next_if(|(_, c)| *c == 'e'))
149            .and_then(|_| self.chars.next_if(|(_, c)| *c == 'r'))
150            .is_none()
151        {
152            return Err(self.emit_error(SyntaxErrorKind::ExpectAngularBlock("defer")));
153        }
154        self.skip_ws();
155        let mut blocks = vec![self.parse_angular_generic_block("defer")?];
156
157        loop {
158            let chars = self.chars.clone();
159            self.skip_ws();
160            if self.chars.next_if(|(_, c)| *c == '@').is_some()
161                && let Ok(name) = self.parse_identifier()
162                && matches!(name, "loading" | "error" | "placeholder")
163            {
164                self.skip_ws();
165                blocks.push(self.parse_angular_generic_block(name)?);
166            } else {
167                self.chars = chars;
168                return Ok(blocks);
169            }
170        }
171    }
172
173    fn parse_angular_for(&mut self) -> PResult<AngularFor<'s>> {
174        if self
175            .chars
176            .next_if(|(_, c)| *c == '@')
177            .and_then(|_| self.chars.next_if(|(_, c)| *c == 'f'))
178            .and_then(|_| self.chars.next_if(|(_, c)| *c == 'o'))
179            .and_then(|_| self.chars.next_if(|(_, c)| *c == 'r'))
180            .is_none()
181        {
182            return Err(self.emit_error(SyntaxErrorKind::ExpectAngularBlock("for")));
183        }
184        self.skip_ws();
185
186        let Some((start, _)) = self.chars.next_if(|(_, c)| *c == '(') else {
187            return Err(self.emit_error(SyntaxErrorKind::ExpectChar('(')));
188        };
189
190        let (header, header_start) = self.parse_angular_inline_script(start + 1)?;
191        let Some((binding, expr)) = header.split_once(" of ").map(|(binding, expr)| {
192            (
193                (binding.trim_end(), header_start),
194                (expr.trim_start(), header_start + 4),
195            )
196        }) else {
197            return Err(self.emit_error(SyntaxErrorKind::ExpectKeyword("of")));
198        };
199
200        let mut track = None;
201        if self.chars.next_if(|(_, c)| *c == ';').is_some() {
202            self.skip_ws();
203            if self
204                .chars
205                .next_if(|(_, c)| *c == 't')
206                .and_then(|_| self.chars.next_if(|(_, c)| *c == 'r'))
207                .and_then(|_| self.chars.next_if(|(_, c)| *c == 'a'))
208                .and_then(|_| self.chars.next_if(|(_, c)| *c == 'c'))
209                .and_then(|_| self.chars.next_if(|(_, c)| *c == 'k'))
210                .is_some()
211            {
212                self.skip_ws();
213                if let Some((start, _)) = self.chars.peek() {
214                    let start = *start;
215                    track = Some(self.parse_angular_inline_script(start)?);
216                }
217            }
218        }
219
220        let mut aliases = vec![];
221        while self.chars.next_if(|(_, c)| *c == ';').is_some() {
222            self.skip_ws();
223            let mut chars = self.chars.clone();
224            if chars
225                .next_if(|(_, c)| *c == 'l')
226                .and_then(|_| chars.next_if(|(_, c)| *c == 'e'))
227                .and_then(|_| chars.next_if(|(_, c)| *c == 't'))
228                .is_some()
229                && let Some((start, _)) = self.chars.peek()
230            {
231                let start = *start;
232                aliases.push(self.parse_angular_inline_script(start)?);
233            }
234        }
235
236        self.chars.next_if(|(_, c)| *c == ';');
237        self.skip_ws();
238        if self.chars.next_if(|(_, c)| *c == ')').is_none() {
239            return Err(self.emit_error(SyntaxErrorKind::ExpectChar(')')));
240        };
241        self.skip_ws();
242        let children = self.parse_angular_control_flow_children()?;
243
244        let mut empty = None;
245        let mut chars = self.chars.clone();
246        while chars.next_if(|(_, c)| c.is_ascii_whitespace()).is_some() {}
247        if chars
248            .next_if(|(_, c)| *c == '@')
249            .and_then(|_| chars.next_if(|(_, c)| *c == 'e'))
250            .and_then(|_| chars.next_if(|(_, c)| *c == 'm'))
251            .and_then(|_| chars.next_if(|(_, c)| *c == 'p'))
252            .and_then(|_| chars.next_if(|(_, c)| *c == 't'))
253            .and_then(|_| chars.next_if(|(_, c)| *c == 'y'))
254            .is_some()
255        {
256            self.chars = chars;
257            self.skip_ws();
258            empty = Some(self.parse_angular_control_flow_children()?);
259        }
260
261        Ok(AngularFor {
262            binding,
263            expr,
264            track,
265            aliases,
266            children,
267            empty,
268        })
269    }
270
271    fn parse_angular_generic_block(
272        &mut self,
273        keyword: &'s str,
274    ) -> PResult<AngularGenericBlock<'s>> {
275        let header = if let Some((start, _)) = self.chars.next_if(|(_, c)| *c == '(') {
276            let mut paren_stack = 0u8;
277            loop {
278                match self.chars.next() {
279                    Some((_, '(')) => paren_stack += 1,
280                    Some((i, ')')) => {
281                        if paren_stack == 0 {
282                            break Some(unsafe { self.source.get_unchecked(start..i + 1) });
283                        } else {
284                            paren_stack -= 1;
285                        }
286                    }
287                    Some(..) => {}
288                    None => return Err(self.emit_error(SyntaxErrorKind::ExpectChar(')'))),
289                }
290            }
291        } else {
292            None
293        };
294        self.skip_ws();
295        Ok(AngularGenericBlock {
296            keyword,
297            header,
298            children: self.parse_angular_control_flow_children()?,
299        })
300    }
301
302    fn parse_angular_if(&mut self) -> PResult<AngularIf<'s>> {
303        if self
304            .chars
305            .next_if(|(_, c)| *c == '@')
306            .and_then(|_| self.chars.next_if(|(_, c)| *c == 'i'))
307            .and_then(|_| self.chars.next_if(|(_, c)| *c == 'f'))
308            .is_none()
309        {
310            return Err(self.emit_error(SyntaxErrorKind::ExpectAngularBlock("if")));
311        }
312        self.skip_ws();
313
314        let (expr, reference) = self.parse_angular_if_cond()?;
315        self.skip_ws();
316        let children = self.parse_angular_control_flow_children()?;
317
318        let mut else_if_blocks = vec![];
319        let mut else_children = None;
320        'alter: loop {
321            let mut chars = self.chars.clone();
322            'peek: loop {
323                match chars.next() {
324                    Some((_, c)) if c.is_ascii_whitespace() => continue 'peek,
325                    Some((_, '@')) => {
326                        if chars
327                            .next_if(|(_, c)| *c == 'e')
328                            .and_then(|_| chars.next_if(|(_, c)| *c == 'l'))
329                            .and_then(|_| chars.next_if(|(_, c)| *c == 's'))
330                            .and_then(|_| chars.next_if(|(_, c)| *c == 'e'))
331                            .is_some()
332                        {
333                            self.chars = chars;
334                            break 'peek;
335                        } else {
336                            break 'alter;
337                        }
338                    }
339                    _ => break 'alter,
340                }
341            }
342            self.skip_ws();
343
344            if self
345                .chars
346                .next_if(|(_, c)| *c == 'i')
347                .and_then(|_| self.chars.next_if(|(_, c)| *c == 'f'))
348                .is_some()
349            {
350                self.skip_ws();
351                let (expr, reference) = self.parse_angular_if_cond()?;
352                self.skip_ws();
353                let children = self.parse_angular_control_flow_children()?;
354                else_if_blocks.push(AngularElseIf {
355                    expr,
356                    reference,
357                    children,
358                });
359            } else {
360                else_children = Some(self.parse_angular_control_flow_children()?);
361                break;
362            }
363        }
364
365        Ok(AngularIf {
366            expr,
367            reference,
368            children,
369            else_if_blocks,
370            else_children,
371        })
372    }
373
374    fn parse_angular_if_cond(&mut self) -> PResult<AngularIfCond<'s>> {
375        let Some((start, _)) = self.chars.next_if(|(_, c)| *c == '(') else {
376            return Err(self.emit_error(SyntaxErrorKind::ExpectChar('(')));
377        };
378
379        let expr = self.parse_angular_inline_script(start + 1)?;
380
381        let mut reference = None;
382        if self.chars.next_if(|(_, c)| *c == ';').is_some() {
383            self.skip_ws();
384            if self
385                .chars
386                .next_if(|(_, c)| *c == 'a')
387                .and_then(|_| self.chars.next_if(|(_, c)| *c == 's'))
388                .is_none()
389            {
390                return Err(self.emit_error(SyntaxErrorKind::ExpectKeyword("as")));
391            }
392            self.skip_ws();
393            if let Some((start, _)) = self.chars.peek() {
394                let start = *start;
395                reference = Some(self.parse_angular_inline_script(start)?);
396            }
397        }
398
399        if self.chars.next_if(|(_, c)| *c == ')').is_none() {
400            return Err(self.emit_error(SyntaxErrorKind::ExpectChar(')')));
401        }
402
403        Ok((expr, reference))
404    }
405
406    fn parse_angular_inline_script(&mut self, start: usize) -> PResult<(&'s str, usize)> {
407        let end;
408        let mut chars_stack = vec![];
409        loop {
410            match self.chars.peek() {
411                Some((_, c @ '\'' | c @ '"' | c @ '`')) => {
412                    if chars_stack.last().is_some_and(|last| last == c) {
413                        chars_stack.pop();
414                    } else {
415                        chars_stack.push(*c);
416                    }
417                    self.chars.next();
418                }
419                Some((_, '(')) => {
420                    chars_stack.push('(');
421                    self.chars.next();
422                }
423                Some((i, ')')) => {
424                    if chars_stack.is_empty() {
425                        end = *i;
426                        break;
427                    } else if chars_stack.last().is_some_and(|last| *last == '(') {
428                        chars_stack.pop();
429                        self.chars.next();
430                    }
431                }
432                Some((i, ';')) if chars_stack.is_empty() => {
433                    end = *i;
434                    break;
435                }
436                Some(..) => {
437                    self.chars.next();
438                }
439                None => {
440                    end = start;
441                    break;
442                }
443            }
444        }
445        Ok((unsafe { self.source.get_unchecked(start..end) }, start))
446    }
447
448    fn parse_angular_let(&mut self) -> PResult<AngularLet<'s>> {
449        if self
450            .chars
451            .next_if(|(_, c)| *c == '@')
452            .and_then(|_| self.chars.next_if(|(_, c)| *c == 'l'))
453            .and_then(|_| self.chars.next_if(|(_, c)| *c == 'e'))
454            .and_then(|_| self.chars.next_if(|(_, c)| *c == 't'))
455            .is_none()
456        {
457            return Err(self.emit_error(SyntaxErrorKind::ExpectAngularLet));
458        }
459        self.skip_ws();
460
461        let name = self.parse_identifier()?;
462        self.skip_ws();
463        if self.chars.next_if(|(_, c)| *c == '=').is_none() {
464            return Err(self.emit_error(SyntaxErrorKind::ExpectChar('=')));
465        }
466        self.skip_ws();
467        let start = self
468            .chars
469            .peek()
470            .map(|(i, _)| *i)
471            .unwrap_or(self.source.len());
472        let expr = self.parse_angular_inline_script(start)?;
473        if self.chars.next_if(|(_, c)| *c == ';').is_none() {
474            return Err(self.emit_error(SyntaxErrorKind::ExpectChar(';')));
475        }
476
477        Ok(AngularLet { name, expr })
478    }
479
480    fn parse_angular_switch(&mut self) -> PResult<AngularSwitch<'s>> {
481        if self
482            .chars
483            .next_if(|(_, c)| *c == '@')
484            .and_then(|_| self.chars.next_if(|(_, c)| *c == 's'))
485            .and_then(|_| self.chars.next_if(|(_, c)| *c == 'w'))
486            .and_then(|_| self.chars.next_if(|(_, c)| *c == 'i'))
487            .and_then(|_| self.chars.next_if(|(_, c)| *c == 't'))
488            .and_then(|_| self.chars.next_if(|(_, c)| *c == 'c'))
489            .and_then(|_| self.chars.next_if(|(_, c)| *c == 'h'))
490            .is_none()
491        {
492            return Err(self.emit_error(SyntaxErrorKind::ExpectAngularSwitch));
493        }
494        self.skip_ws();
495
496        let Some((start, _)) = self.chars.next_if(|(_, c)| *c == '(') else {
497            return Err(self.emit_error(SyntaxErrorKind::ExpectChar('(')));
498        };
499        let expr = self.parse_angular_inline_script(start + 1)?;
500        if self.chars.next_if(|(_, c)| *c == ')').is_none() {
501            return Err(self.emit_error(SyntaxErrorKind::ExpectChar(')')));
502        }
503
504        self.skip_ws();
505        if self.chars.next_if(|(_, c)| *c == '{').is_none() {
506            return Err(self.emit_error(SyntaxErrorKind::ExpectChar('{')));
507        }
508        self.skip_ws();
509
510        let mut arms = Vec::with_capacity(2);
511        while let Some((_, '@')) = self.chars.peek() {
512            self.chars.next();
513            match self.chars.peek() {
514                Some((_, 'c')) => {
515                    if self
516                        .chars
517                        .next_if(|(_, c)| *c == 'c')
518                        .and_then(|_| self.chars.next_if(|(_, c)| *c == 'a'))
519                        .and_then(|_| self.chars.next_if(|(_, c)| *c == 's'))
520                        .and_then(|_| self.chars.next_if(|(_, c)| *c == 'e'))
521                        .is_none()
522                    {
523                        return Err(self.emit_error(SyntaxErrorKind::ExpectKeyword("case")));
524                    }
525                    self.skip_ws();
526                    let Some((start, _)) = self.chars.next_if(|(_, c)| *c == '(') else {
527                        return Err(self.emit_error(SyntaxErrorKind::ExpectChar('(')));
528                    };
529                    let expr = self.parse_angular_inline_script(start + 1)?;
530                    if self.chars.next_if(|(_, c)| *c == ')').is_none() {
531                        return Err(self.emit_error(SyntaxErrorKind::ExpectChar(')')));
532                    }
533                    self.skip_ws();
534                    let children = self.parse_angular_control_flow_children()?;
535                    arms.push(AngularSwitchArm {
536                        keyword: "case",
537                        expr: Some(expr),
538                        children,
539                    });
540                    self.skip_ws();
541                }
542                Some((_, 'd')) => {
543                    if self
544                        .chars
545                        .next_if(|(_, c)| *c == 'd')
546                        .and_then(|_| self.chars.next_if(|(_, c)| *c == 'e'))
547                        .and_then(|_| self.chars.next_if(|(_, c)| *c == 'f'))
548                        .and_then(|_| self.chars.next_if(|(_, c)| *c == 'a'))
549                        .and_then(|_| self.chars.next_if(|(_, c)| *c == 'u'))
550                        .and_then(|_| self.chars.next_if(|(_, c)| *c == 'l'))
551                        .and_then(|_| self.chars.next_if(|(_, c)| *c == 't'))
552                        .is_none()
553                    {
554                        return Err(self.emit_error(SyntaxErrorKind::ExpectKeyword("default")));
555                    }
556                    self.skip_ws();
557                    arms.push(AngularSwitchArm {
558                        keyword: "default",
559                        expr: None,
560                        children: self.parse_angular_control_flow_children()?,
561                    });
562                    self.skip_ws();
563                }
564                _ => return Err(self.emit_error(SyntaxErrorKind::ExpectKeyword("case"))),
565            }
566        }
567
568        self.skip_ws();
569        if self.chars.next_if(|(_, c)| *c == '}').is_none() {
570            return Err(self.emit_error(SyntaxErrorKind::ExpectChar('}')));
571        }
572
573        Ok(AngularSwitch { expr, arms })
574    }
575
576    fn parse_astro_attr(&mut self) -> PResult<AstroAttribute<'s>> {
577        let (name, start, first_char) =
578            if let Some((start, first_char)) = self.chars.next_if(|(_, c)| *c == '{') {
579                (None, start, first_char)
580            } else {
581                let name = self.parse_attr_name()?;
582                self.skip_ws();
583                if let Some((start, first_char)) = self
584                    .chars
585                    .next_if(|(_, c)| *c == '=')
586                    .map(|_| self.skip_ws())
587                    .and_then(|_| self.chars.next_if(|(_, c)| matches!(c, '{' | '`')))
588                {
589                    (Some(name), start, first_char)
590                } else {
591                    return Err(self.emit_error(SyntaxErrorKind::ExpectAstroAttr));
592                }
593            };
594
595        if first_char == '`' {
596            while self.chars.next_if(|(_, c)| *c != '`').is_some() {}
597            if let Some((end, _)) = self.chars.next_if(|(_, c)| *c == '`') {
598                Ok(AstroAttribute {
599                    name,
600                    expr: unsafe { (self.source.get_unchecked(start..end + 1), start) },
601                })
602            } else {
603                Err(self.emit_error(SyntaxErrorKind::ExpectAstroAttr))
604            }
605        } else {
606            self.parse_svelte_or_astro_expr()
607                .map(|expr| AstroAttribute { name, expr })
608        }
609    }
610
611    fn parse_astro_expr(&mut self) -> PResult<AstroExpr<'s>> {
612        let Some((start, _)) = self.chars.next_if(|(_, c)| *c == '{') else {
613            return Err(self.emit_error(SyntaxErrorKind::ExpectAstroExpr));
614        };
615
616        let mut children = Vec::with_capacity(1);
617        let mut has_line_comment = false;
618        let mut pair_stack = vec![];
619        let mut pos = self
620            .chars
621            .peek()
622            .map(|(i, _)| *i)
623            .unwrap_or(self.source.len());
624        while let Some((i, c)) = self.chars.peek() {
625            match c {
626                '{' => {
627                    pair_stack.push('{');
628                    self.chars.next();
629                }
630                '}' => {
631                    let i = *i;
632                    self.chars.next();
633                    if pair_stack.is_empty() {
634                        debug_assert!(matches!(
635                            children.last(),
636                            Some(AstroExprChild::Template(..)) | None
637                        ));
638                        children.push(AstroExprChild::Script(unsafe {
639                            self.source.get_unchecked(pos..i)
640                        }));
641                        break;
642                    }
643                    pair_stack.pop();
644                }
645                '<' if !matches!(pair_stack.last(), Some('/' | '*' | '\'' | '"' | '`')) => {
646                    let i = *i;
647                    let mut chars = self.chars.clone();
648                    chars.next();
649                    if chars
650                        .next_if(|(_, c)| is_html_tag_name_char(*c) || *c == '!' || *c == '>')
651                        .is_some()
652                    {
653                        let prev = unsafe { self.source.get_unchecked(pos..i) };
654                        if prev.is_empty() {
655                            // do nothing
656                        } else if prev.chars().all(|c| c.is_ascii_whitespace()) {
657                            if let Some(AstroExprChild::Template(nodes)) = children.last_mut() {
658                                nodes.push(Node {
659                                    kind: NodeKind::Text(TextNode {
660                                        raw: prev,
661                                        line_breaks: prev.chars().filter(|c| *c == '\n').count(),
662                                        start: pos,
663                                    }),
664                                    raw: prev,
665                                });
666                            }
667                        } else {
668                            children.push(AstroExprChild::Script(prev));
669                        }
670
671                        let node = self.parse_node()?;
672                        if let Some(AstroExprChild::Template(nodes)) = children.last_mut() {
673                            nodes.push(node);
674                        } else {
675                            debug_assert!(matches!(
676                                children.last(),
677                                Some(AstroExprChild::Script(..)) | None
678                            ));
679                            children.push(AstroExprChild::Template(vec![node]));
680                        }
681                        pos = self
682                            .chars
683                            .peek()
684                            .map(|(i, _)| *i)
685                            .unwrap_or(self.source.len());
686                    } else {
687                        self.chars.next();
688                    }
689                }
690                '\'' | '"' | '`' => {
691                    let last = pair_stack.last();
692                    if last.is_some_and(|last| last == c) {
693                        pair_stack.pop();
694                    } else if matches!(last, Some('$' | '{') | None) {
695                        pair_stack.push(*c);
696                    }
697                    self.chars.next();
698                }
699                '$' if matches!(pair_stack.last(), Some('`')) => {
700                    self.chars.next();
701                    if self.chars.next_if(|(_, c)| *c == '{').is_some() {
702                        pair_stack.push('$');
703                    }
704                }
705                '/' if !matches!(pair_stack.last(), Some('\'' | '"' | '`' | '/' | '*')) => {
706                    self.chars.next();
707                    match self.chars.peek() {
708                        Some((_, '/')) => {
709                            pair_stack.push('/');
710                            has_line_comment = true;
711                            self.chars.next();
712                        }
713                        Some((_, '*')) => {
714                            pair_stack.push('*');
715                            self.chars.next();
716                        }
717                        _ => {}
718                    }
719                }
720                '\n' => {
721                    self.chars.next();
722                    if let Some('/') = pair_stack.last() {
723                        pair_stack.pop();
724                    }
725                }
726                '*' => {
727                    self.chars.next();
728                    if self
729                        .chars
730                        .next_if(|(_, c)| *c == '/' && matches!(pair_stack.last(), Some('*')))
731                        .is_some()
732                    {
733                        pair_stack.pop();
734                    }
735                }
736                '\\' if matches!(pair_stack.last(), Some('\'' | '"' | '`')) => {
737                    self.chars.next();
738                }
739                _ => {
740                    self.chars.next();
741                }
742            }
743        }
744
745        Ok(AstroExpr {
746            children,
747            has_line_comment,
748            start: start + 1,
749        })
750    }
751
752    fn parse_attr(&mut self) -> PResult<Attribute<'s>> {
753        match self.language {
754            Language::Html | Language::Angular | Language::Mustache | Language::Xml => {
755                self.parse_native_attr().map(Attribute::Native)
756            }
757            Language::Vue => self
758                .try_parse(Parser::parse_vue_directive)
759                .map(Attribute::VueDirective)
760                .or_else(|_| self.parse_native_attr().map(Attribute::Native)),
761            Language::Svelte => self
762                .try_parse(Parser::parse_svelte_attachment)
763                .map(Attribute::SvelteAttachment)
764                .or_else(|_| {
765                    self.try_parse(Parser::parse_svelte_attr)
766                        .map(Attribute::Svelte)
767                })
768                .or_else(|_| self.parse_native_attr().map(Attribute::Native)),
769            Language::Astro => self
770                .try_parse(Parser::parse_astro_attr)
771                .map(Attribute::Astro)
772                .or_else(|_| self.parse_native_attr().map(Attribute::Native)),
773            Language::Jinja => {
774                self.skip_ws();
775                let result = if matches!(self.chars.peek(), Some((_, '{'))) {
776                    let mut chars = self.chars.clone();
777                    chars.next();
778                    match chars.next() {
779                        Some((_, '{')) => self.parse_native_attr().map(Attribute::Native),
780                        Some((_, '#')) => self.parse_jinja_comment().map(Attribute::JinjaComment),
781                        _ => self.parse_jinja_tag_or_block(None, &mut Parser::parse_attr),
782                    }
783                } else {
784                    self.parse_native_attr().map(Attribute::Native)
785                };
786                if result.is_ok() {
787                    self.skip_ws();
788                }
789                result
790            }
791            Language::Vento => self
792                .try_parse(|parser| parser.parse_vento_tag_or_block(None))
793                .map(Attribute::VentoTagOrBlock)
794                .or_else(|_| self.parse_native_attr().map(Attribute::Native)),
795        }
796    }
797
798    fn parse_attr_name(&mut self) -> PResult<&'s str> {
799        if matches!(
800            self.language,
801            Language::Jinja | Language::Vento | Language::Mustache
802        ) {
803            let Some((start, mut end)) = (match self.chars.peek() {
804                Some((i, '{')) => {
805                    let start = *i;
806                    let mut chars = self.chars.clone();
807                    chars.next();
808                    if let Some((_, '{')) = chars.next() {
809                        let end =
810                            start + self.parse_mustache_interpolation()?.0.len() + "{{}}".len();
811                        Some((start, end))
812                    } else {
813                        None
814                    }
815                }
816                Some((_, c)) if is_attr_name_char(*c) => self
817                    .chars
818                    .next()
819                    .map(|(start, c)| (start, start + c.len_utf8())),
820                _ => None,
821            }) else {
822                return Err(self.emit_error(SyntaxErrorKind::ExpectAttrName));
823            };
824
825            while let Some((_, c)) = self.chars.peek() {
826                if is_attr_name_char(*c) && *c != '{' {
827                    end += c.len_utf8();
828                    self.chars.next();
829                } else if *c == '{' {
830                    let mut chars = self.chars.clone();
831                    chars.next();
832                    match chars.next() {
833                        Some((_, '%')) => {
834                            break;
835                        }
836                        Some((_, '{')) => {
837                            end += self.parse_mustache_interpolation()?.0.len() + "{{}}".len();
838                        }
839                        Some((_, c)) => {
840                            end += c.len_utf8();
841                            self.chars.next();
842                        }
843                        None => break,
844                    }
845                } else {
846                    break;
847                }
848            }
849
850            unsafe { Ok(self.source.get_unchecked(start..end)) }
851        } else {
852            let Some((start, start_char)) = self.chars.next_if(|(_, c)| is_attr_name_char(*c))
853            else {
854                return Err(self.emit_error(SyntaxErrorKind::ExpectAttrName));
855            };
856            let mut end = start + start_char.len_utf8();
857
858            while let Some((_, c)) = self.chars.next_if(|(_, c)| is_attr_name_char(*c)) {
859                end += c.len_utf8();
860            }
861
862            unsafe { Ok(self.source.get_unchecked(start..end)) }
863        }
864    }
865
866    fn parse_attr_value(&mut self) -> PResult<(&'s str, usize)> {
867        let quote = self.chars.next_if(|(_, c)| *c == '"' || *c == '\'');
868
869        if let Some((start, quote)) = quote {
870            let can_interpolate = matches!(
871                self.language,
872                Language::Svelte | Language::Jinja | Language::Vento | Language::Mustache
873            );
874            let start = start + 1;
875            let mut end = start;
876            let mut chars_stack = vec![];
877            loop {
878                match self.chars.next() {
879                    Some((i, c)) if c == quote => {
880                        if chars_stack.is_empty() || !can_interpolate {
881                            end = i;
882                            break;
883                        } else if chars_stack.last().is_some_and(|last| *last == c) {
884                            chars_stack.pop();
885                        } else {
886                            chars_stack.push(c);
887                        }
888                    }
889                    Some((_, '{')) if can_interpolate => {
890                        chars_stack.push('{');
891                    }
892                    Some((_, '}'))
893                        if can_interpolate
894                            && chars_stack.last().is_some_and(|last| *last == '{') =>
895                    {
896                        chars_stack.pop();
897                    }
898                    Some(..) => continue,
899                    None => break,
900                }
901            }
902            Ok((unsafe { self.source.get_unchecked(start..end) }, start))
903        } else {
904            fn is_unquoted_attr_value_char(c: char) -> bool {
905                !c.is_ascii_whitespace() && !matches!(c, '"' | '\'' | '=' | '<' | '>' | '`')
906            }
907
908            let start = match self.chars.peek() {
909                Some((i, c)) if is_unquoted_attr_value_char(*c) => *i,
910                _ => return Err(self.emit_error(SyntaxErrorKind::ExpectAttrValue)),
911            };
912
913            let mut end = start;
914            loop {
915                match self.chars.peek() {
916                    Some((i, '{'))
917                        if matches!(
918                            self.language,
919                            Language::Jinja | Language::Vento | Language::Mustache
920                        ) =>
921                    {
922                        end = *i;
923                        let mut chars = self.chars.clone();
924                        chars.next();
925                        match chars.peek() {
926                            Some((_, '%')) => {
927                                if self
928                                    .parse_jinja_tag_or_block(None, &mut Parser::parse_node)
929                                    .is_ok()
930                                {
931                                    end =
932                                        self.chars.peek().map(|(i, _)| i - 1).ok_or_else(|| {
933                                            self.emit_error(SyntaxErrorKind::ExpectAttrValue)
934                                        })?;
935                                } else {
936                                    self.chars.next();
937                                }
938                            }
939                            Some((_, '{')) => {
940                                chars.next();
941                                // We use inclusive range when returning string,
942                                // so we need to substract 1 here.
943                                let (interpolation, _) = self.parse_mustache_interpolation()?;
944                                end += interpolation.len() + "{{}}".len() - 1;
945                            }
946                            _ => {
947                                self.chars.next();
948                            }
949                        }
950                    }
951                    Some((i, c)) if is_unquoted_attr_value_char(*c) => {
952                        end = *i;
953                        self.chars.next();
954                    }
955                    _ => break,
956                }
957            }
958
959            Ok((unsafe { self.source.get_unchecked(start..=end) }, start))
960        }
961    }
962
963    fn parse_cdata(&mut self) -> PResult<Cdata<'s>> {
964        let Some((start, _)) = self
965            .chars
966            .next_if(|(_, c)| *c == '<')
967            .and_then(|_| self.chars.next_if(|(_, c)| *c == '!'))
968            .and_then(|_| self.chars.next_if(|(_, c)| *c == '['))
969            .and_then(|_| self.chars.next_if(|(_, c)| *c == 'C'))
970            .and_then(|_| self.chars.next_if(|(_, c)| *c == 'D'))
971            .and_then(|_| self.chars.next_if(|(_, c)| *c == 'A'))
972            .and_then(|_| self.chars.next_if(|(_, c)| *c == 'T'))
973            .and_then(|_| self.chars.next_if(|(_, c)| *c == 'A'))
974            .and_then(|_| self.chars.next_if(|(_, c)| *c == '['))
975        else {
976            return Err(self.emit_error(SyntaxErrorKind::ExpectCdata));
977        };
978        let start = start + 1;
979
980        let mut end = start;
981        loop {
982            match self.chars.next() {
983                Some((i, ']')) => {
984                    let mut chars = self.chars.clone();
985                    if chars
986                        .next_if(|(_, c)| *c == ']')
987                        .and_then(|_| chars.next_if(|(_, c)| *c == '>'))
988                        .is_some()
989                    {
990                        end = i;
991                        self.chars = chars;
992                        break;
993                    }
994                }
995                Some(..) => continue,
996                None => break,
997            }
998        }
999
1000        Ok(Cdata {
1001            raw: unsafe { self.source.get_unchecked(start..end) },
1002        })
1003    }
1004
1005    fn parse_comment(&mut self) -> PResult<Comment<'s>> {
1006        let Some((start, _)) = self
1007            .chars
1008            .next_if(|(_, c)| *c == '<')
1009            .and_then(|_| self.chars.next_if(|(_, c)| *c == '!'))
1010            .and_then(|_| self.chars.next_if(|(_, c)| *c == '-'))
1011            .and_then(|_| self.chars.next_if(|(_, c)| *c == '-'))
1012        else {
1013            return Err(self.emit_error(SyntaxErrorKind::ExpectComment));
1014        };
1015        let start = start + 1;
1016
1017        let mut end = start;
1018        loop {
1019            match self.chars.next() {
1020                Some((i, '-')) => {
1021                    let mut chars = self.chars.clone();
1022                    if chars
1023                        .next_if(|(_, c)| *c == '-')
1024                        .and_then(|_| chars.next_if(|(_, c)| *c == '>'))
1025                        .is_some()
1026                    {
1027                        end = i;
1028                        self.chars = chars;
1029                        break;
1030                    }
1031                }
1032                Some(..) => continue,
1033                None => break,
1034            }
1035        }
1036
1037        Ok(Comment {
1038            raw: unsafe { self.source.get_unchecked(start..end) },
1039        })
1040    }
1041
1042    fn parse_doctype(&mut self) -> PResult<Doctype<'s>> {
1043        let keyword_start = if let Some((start, _)) = self
1044            .chars
1045            .next_if(|(_, c)| *c == '<')
1046            .and_then(|_| self.chars.next_if(|(_, c)| *c == '!'))
1047        {
1048            start + 1
1049        } else {
1050            return Err(self.emit_error(SyntaxErrorKind::ExpectDoctype));
1051        };
1052        let keyword = if let Some((end, _)) = self
1053            .chars
1054            .next_if(|(_, c)| c.eq_ignore_ascii_case(&'d'))
1055            .and_then(|_| self.chars.next_if(|(_, c)| c.eq_ignore_ascii_case(&'o')))
1056            .and_then(|_| self.chars.next_if(|(_, c)| c.eq_ignore_ascii_case(&'c')))
1057            .and_then(|_| self.chars.next_if(|(_, c)| c.eq_ignore_ascii_case(&'t')))
1058            .and_then(|_| self.chars.next_if(|(_, c)| c.eq_ignore_ascii_case(&'y')))
1059            .and_then(|_| self.chars.next_if(|(_, c)| c.eq_ignore_ascii_case(&'p')))
1060            .and_then(|_| self.chars.next_if(|(_, c)| c.eq_ignore_ascii_case(&'e')))
1061        {
1062            unsafe { self.source.get_unchecked(keyword_start..end + 1) }
1063        } else {
1064            return Err(self.emit_error(SyntaxErrorKind::ExpectDoctype));
1065        };
1066        self.skip_ws();
1067
1068        let value_start = if let Some((start, _)) = self.chars.peek() {
1069            *start
1070        } else {
1071            return Err(self.emit_error(SyntaxErrorKind::ExpectDoctype));
1072        };
1073        while self.chars.next_if(|(_, c)| *c != '>').is_some() {}
1074
1075        if let Some((value_end, _)) = self.chars.next_if(|(_, c)| *c == '>') {
1076            Ok(Doctype {
1077                keyword,
1078                value: unsafe { self.source.get_unchecked(value_start..value_end) }.trim_end(),
1079            })
1080        } else {
1081            Err(self.emit_error(SyntaxErrorKind::ExpectDoctype))
1082        }
1083    }
1084
1085    fn parse_element(&mut self) -> PResult<Element<'s>> {
1086        let Some((element_start, _)) = self.chars.next_if(|(_, c)| *c == '<') else {
1087            return Err(self.emit_error(SyntaxErrorKind::ExpectElement));
1088        };
1089        let tag_name = self.parse_tag_name()?;
1090        let void_element = helpers::is_void_element(tag_name, self.language);
1091
1092        let mut attrs = vec![];
1093        let mut first_attr_same_line = true;
1094        loop {
1095            match self.chars.peek() {
1096                Some((_, '/')) => {
1097                    self.chars.next();
1098                    if self.chars.next_if(|(_, c)| *c == '>').is_some() {
1099                        return Ok(Element {
1100                            tag_name,
1101                            attrs,
1102                            first_attr_same_line,
1103                            children: vec![],
1104                            self_closing: true,
1105                            void_element,
1106                        });
1107                    }
1108                    return Err(self.emit_error(SyntaxErrorKind::ExpectSelfCloseTag));
1109                }
1110                Some((_, '>')) => {
1111                    self.chars.next();
1112                    if void_element {
1113                        return Ok(Element {
1114                            tag_name,
1115                            attrs,
1116                            first_attr_same_line,
1117                            children: vec![],
1118                            self_closing: false,
1119                            void_element,
1120                        });
1121                    }
1122                    break;
1123                }
1124                Some((_, '\n')) => {
1125                    if attrs.is_empty() {
1126                        first_attr_same_line = false;
1127                    }
1128                    self.chars.next();
1129                }
1130                Some((_, c)) if c.is_ascii_whitespace() => {
1131                    self.chars.next();
1132                }
1133                _ => {
1134                    attrs.push(self.parse_attr()?);
1135                }
1136            }
1137        }
1138
1139        let mut children = vec![];
1140        let should_parse_raw = self.language != Language::Xml
1141            && (tag_name.eq_ignore_ascii_case("script")
1142                || tag_name.eq_ignore_ascii_case("style")
1143                || tag_name.eq_ignore_ascii_case("pre")
1144                || tag_name.eq_ignore_ascii_case("textarea"));
1145        if should_parse_raw {
1146            let text_node = self.parse_raw_text_node(tag_name)?;
1147            let raw = text_node.raw;
1148            if !raw.is_empty() {
1149                children.push(Node {
1150                    kind: NodeKind::Text(text_node),
1151                    raw,
1152                });
1153            }
1154        }
1155
1156        loop {
1157            match self.chars.peek() {
1158                Some((_, '<')) => {
1159                    let mut chars = self.chars.clone();
1160                    chars.next();
1161                    if let Some((pos, _)) = chars.next_if(|(_, c)| *c == '/') {
1162                        self.chars = chars;
1163                        let close_tag_name = self.parse_tag_name()?;
1164                        if !close_tag_name.eq_ignore_ascii_case(tag_name) {
1165                            let (line, column) = self.pos_to_line_col(element_start);
1166                            return Err(self.emit_error_with_pos(
1167                                SyntaxErrorKind::ExpectCloseTag {
1168                                    tag_name: tag_name.into(),
1169                                    line,
1170                                    column,
1171                                },
1172                                pos,
1173                            ));
1174                        }
1175                        self.skip_ws();
1176                        if self.chars.next_if(|(_, c)| *c == '>').is_some() {
1177                            break;
1178                        }
1179                        let (line, column) = self.pos_to_line_col(element_start);
1180                        return Err(self.emit_error(SyntaxErrorKind::ExpectCloseTag {
1181                            tag_name: tag_name.into(),
1182                            line,
1183                            column,
1184                        }));
1185                    }
1186                    children.push(self.parse_node()?);
1187                }
1188                Some(..) => {
1189                    if should_parse_raw {
1190                        let text_node = self.parse_raw_text_node(tag_name)?;
1191                        let raw = text_node.raw;
1192                        if !raw.is_empty() {
1193                            children.push(Node {
1194                                kind: NodeKind::Text(text_node),
1195                                raw,
1196                            });
1197                        }
1198                    } else {
1199                        children.push(self.parse_node()?);
1200                    }
1201                }
1202                None => {
1203                    let (line, column) = self.pos_to_line_col(element_start);
1204                    return Err(self.emit_error(SyntaxErrorKind::ExpectCloseTag {
1205                        tag_name: tag_name.into(),
1206                        line,
1207                        column,
1208                    }));
1209                }
1210            }
1211        }
1212
1213        Ok(Element {
1214            tag_name,
1215            attrs,
1216            first_attr_same_line,
1217            children,
1218            self_closing: false,
1219            void_element,
1220        })
1221    }
1222
1223    fn parse_front_matter(&mut self) -> PResult<FrontMatter<'s>> {
1224        let Some((start, _)) = self
1225            .chars
1226            .next_if(|(_, c)| *c == '-')
1227            .and_then(|_| self.chars.next_if(|(_, c)| *c == '-'))
1228            .and_then(|_| self.chars.next_if(|(_, c)| *c == '-'))
1229        else {
1230            return Err(self.emit_error(SyntaxErrorKind::ExpectFrontMatter));
1231        };
1232        let start = start + 1;
1233
1234        let mut pair_stack = vec![];
1235        let mut end = start;
1236        loop {
1237            match self.chars.next() {
1238                Some((i, '-')) if pair_stack.is_empty() => {
1239                    let mut chars = self.chars.clone();
1240                    if chars
1241                        .next_if(|(_, c)| *c == '-')
1242                        .and_then(|_| chars.next_if(|(_, c)| *c == '-'))
1243                        .is_some()
1244                    {
1245                        end = i;
1246                        self.chars = chars;
1247                        break;
1248                    }
1249                }
1250                Some((_, c @ '\'' | c @ '"' | c @ '`')) => {
1251                    let last = pair_stack.last();
1252                    if last.is_some_and(|last| *last == c) {
1253                        pair_stack.pop();
1254                    } else if matches!(last, Some('$' | '{') | None) {
1255                        pair_stack.push(c);
1256                    }
1257                }
1258                Some((_, '$')) if matches!(pair_stack.last(), Some('`')) => {
1259                    if self.chars.next_if(|(_, c)| *c == '{').is_some() {
1260                        pair_stack.push('$');
1261                    }
1262                }
1263                Some((_, '{')) if matches!(pair_stack.last(), Some('$' | '{') | None) => {
1264                    pair_stack.push('{');
1265                }
1266                Some((_, '}')) if matches!(pair_stack.last(), Some('$' | '{')) => {
1267                    pair_stack.pop();
1268                }
1269                Some((_, '/'))
1270                    if !matches!(pair_stack.last(), Some('\'' | '"' | '`' | '/' | '*')) =>
1271                {
1272                    if let Some((_, c)) = self.chars.next_if(|(_, c)| *c == '/' || *c == '*') {
1273                        pair_stack.push(c);
1274                    }
1275                }
1276                Some((_, '\n')) => {
1277                    if let Some('/' | '\'' | '"') = pair_stack.last() {
1278                        pair_stack.pop();
1279                    }
1280                }
1281                Some((_, '*')) => {
1282                    if self
1283                        .chars
1284                        .next_if(|(_, c)| *c == '/' && matches!(pair_stack.last(), Some('*')))
1285                        .is_some()
1286                    {
1287                        pair_stack.pop();
1288                    }
1289                }
1290                Some((_, '\\')) if matches!(pair_stack.last(), Some('\'' | '"' | '`')) => {
1291                    self.chars.next();
1292                }
1293                Some(..) => continue,
1294                None => break,
1295            }
1296        }
1297
1298        self.state.has_front_matter = true;
1299        Ok(FrontMatter {
1300            raw: unsafe { self.source.get_unchecked(start..end) },
1301            start,
1302        })
1303    }
1304
1305    fn parse_identifier(&mut self) -> PResult<&'s str> {
1306        fn is_identifier_char(c: char) -> bool {
1307            c.is_ascii_alphanumeric() || c == '-' || c == '_' || !c.is_ascii() || c == '\\'
1308        }
1309
1310        let Some((start, _)) = self.chars.next_if(|(_, c)| is_identifier_char(*c)) else {
1311            return Err(self.emit_error(SyntaxErrorKind::ExpectIdentifier));
1312        };
1313        let mut end = start;
1314
1315        while let Some((i, _)) = self.chars.next_if(|(_, c)| is_identifier_char(*c)) {
1316            end = i;
1317        }
1318
1319        unsafe { Ok(self.source.get_unchecked(start..=end)) }
1320    }
1321
1322    /// This will consume the open and close char.
1323    fn parse_inside(&mut self, open: char, close: char, inclusive: bool) -> PResult<&'s str> {
1324        let Some(start) = self
1325            .chars
1326            .next_if(|(_, c)| *c == open)
1327            .map(|(i, c)| if inclusive { i } else { i + c.len_utf8() })
1328        else {
1329            return Err(self.emit_error(SyntaxErrorKind::ExpectChar(open)));
1330        };
1331        let mut end = start;
1332        let mut stack = 0u8;
1333        for (i, c) in self.chars.by_ref() {
1334            if c == open {
1335                stack += 1;
1336            } else if c == close {
1337                if stack == 0 {
1338                    end = if inclusive { i + close.len_utf8() } else { i };
1339                    break;
1340                }
1341                stack -= 1;
1342            }
1343        }
1344        Ok(unsafe { self.source.get_unchecked(start..end) })
1345    }
1346
1347    fn parse_jinja_block_children<T, F>(&mut self, children_parser: &mut F) -> PResult<Vec<T>>
1348    where
1349        T: HasJinjaFlowControl<'s>,
1350        F: FnMut(&mut Self) -> PResult<T>,
1351    {
1352        let mut children = vec![];
1353        loop {
1354            match self.chars.peek() {
1355                Some((_, '{')) => {
1356                    let mut chars = self.chars.clone();
1357                    chars.next();
1358                    if chars.next_if(|(_, c)| *c == '%').is_some() {
1359                        break;
1360                    }
1361                    children.push(children_parser(self)?);
1362                }
1363                Some(..) => {
1364                    children.push(children_parser(self)?);
1365                }
1366                None => return Err(self.emit_error(SyntaxErrorKind::ExpectJinjaBlockEnd)),
1367            }
1368        }
1369        Ok(children)
1370    }
1371
1372    fn parse_jinja_comment(&mut self) -> PResult<JinjaComment<'s>> {
1373        let Some((start, _)) = self
1374            .chars
1375            .next_if(|(_, c)| *c == '{')
1376            .and_then(|_| self.chars.next_if(|(_, c)| *c == '#'))
1377        else {
1378            return Err(self.emit_error(SyntaxErrorKind::ExpectComment));
1379        };
1380        let start = start + 1;
1381
1382        let mut end = start;
1383        loop {
1384            match self.chars.next() {
1385                Some((i, '#')) => {
1386                    let mut chars = self.chars.clone();
1387                    if chars.next_if(|(_, c)| *c == '}').is_some() {
1388                        end = i;
1389                        self.chars = chars;
1390                        break;
1391                    }
1392                }
1393                Some(..) => continue,
1394                None => break,
1395            }
1396        }
1397
1398        Ok(JinjaComment {
1399            raw: unsafe { self.source.get_unchecked(start..end) },
1400        })
1401    }
1402
1403    fn parse_jinja_tag(&mut self) -> PResult<JinjaTag<'s>> {
1404        let Some((start, _)) = self
1405            .chars
1406            .next_if(|(_, c)| *c == '{')
1407            .and_then(|_| self.chars.next_if(|(_, c)| *c == '%'))
1408        else {
1409            return Err(self.emit_error(SyntaxErrorKind::ExpectJinjaTag));
1410        };
1411        let start = start + 1;
1412
1413        let mut end = start;
1414        loop {
1415            match self.chars.next() {
1416                Some((i, '%')) => {
1417                    if self.chars.next_if(|(_, c)| *c == '}').is_some() {
1418                        end = i;
1419                        break;
1420                    }
1421                }
1422                Some(..) => continue,
1423                None => break,
1424            }
1425        }
1426
1427        Ok(JinjaTag {
1428            content: unsafe { self.source.get_unchecked(start..end) },
1429            start,
1430        })
1431    }
1432
1433    fn parse_jinja_tag_or_block<T, F>(
1434        &mut self,
1435        first_tag: Option<JinjaTag<'s>>,
1436        children_parser: &mut F,
1437    ) -> PResult<T::Intermediate>
1438    where
1439        T: HasJinjaFlowControl<'s>,
1440        F: FnMut(&mut Self) -> PResult<T>,
1441    {
1442        let first_tag = if let Some(first_tag) = first_tag {
1443            first_tag
1444        } else {
1445            self.parse_jinja_tag()?
1446        };
1447        let tag_name = parse_jinja_tag_name(&first_tag);
1448
1449        if matches!(
1450            tag_name,
1451            "for"
1452                | "if"
1453                | "macro"
1454                | "call"
1455                | "filter"
1456                | "block"
1457                | "apply"
1458                | "autoescape"
1459                | "embed"
1460                | "with"
1461                | "trans"
1462                | "raw"
1463        ) || tag_name == "set" && !first_tag.content.contains('=')
1464        {
1465            let mut body = vec![JinjaTagOrChildren::Tag(first_tag)];
1466
1467            loop {
1468                let mut children = self.parse_jinja_block_children(children_parser)?;
1469                if !children.is_empty() {
1470                    if let Some(JinjaTagOrChildren::Children(nodes)) = body.last_mut() {
1471                        nodes.append(&mut children);
1472                    } else {
1473                        body.push(JinjaTagOrChildren::Children(children));
1474                    }
1475                }
1476                if let Ok(next_tag) = self.parse_jinja_tag() {
1477                    let next_tag_name = parse_jinja_tag_name(&next_tag);
1478                    if next_tag_name
1479                        .strip_prefix("end")
1480                        .is_some_and(|name| name == tag_name)
1481                    {
1482                        body.push(JinjaTagOrChildren::Tag(next_tag));
1483                        break;
1484                    }
1485                    if (tag_name == "if" || tag_name == "for")
1486                        && matches!(next_tag_name, "elif" | "elseif" | "else")
1487                    {
1488                        body.push(JinjaTagOrChildren::Tag(next_tag));
1489                    } else if let Some(JinjaTagOrChildren::Children(nodes)) = body.last_mut() {
1490                        nodes.push(
1491                            self.with_taken(|parser| {
1492                                parser.parse_jinja_tag_or_block(Some(next_tag), children_parser)
1493                            })
1494                            .map(|(kind, raw)| T::build(kind, raw))?,
1495                        );
1496                    } else {
1497                        body.push(JinjaTagOrChildren::Children(vec![
1498                            self.with_taken(|parser| {
1499                                parser.parse_jinja_tag_or_block(Some(next_tag), children_parser)
1500                            })
1501                            .map(|(kind, raw)| T::build(kind, raw))?,
1502                        ]));
1503                    }
1504                } else {
1505                    break;
1506                }
1507            }
1508            Ok(T::from_block(JinjaBlock { body }))
1509        } else {
1510            Ok(T::from_tag(first_tag))
1511        }
1512    }
1513
1514    fn parse_mustache_block_or_interpolation(&mut self) -> PResult<NodeKind<'s>> {
1515        let mut controls = vec![];
1516        let (raw, _) = self.parse_mustache_interpolation()?;
1517        let (content, wc_before, wc_after) = strip_hbs_whitespace_control(raw);
1518        if let Some((prefix, rest)) = content
1519            .split_at_checked(1)
1520            .filter(|(c, _)| matches!(*c, "#" | "^" | "$" | "<"))
1521        {
1522            let (prefix, rest) = if rest.strip_prefix(['>', '*']).is_some() {
1523                content.split_at(2)
1524            } else {
1525                (prefix, rest)
1526            };
1527            let trimmed_rest = rest.trim_ascii();
1528            let (block_name, rest) = if let Some((name, rest)) =
1529                trimmed_rest.split_once(|c: char| c.is_ascii_whitespace())
1530            {
1531                (name, Some(rest))
1532            } else {
1533                (trimmed_rest, None)
1534            };
1535            controls.push(MustacheBlockControl {
1536                name: block_name,
1537                prefix,
1538                content: rest,
1539                wc_before,
1540                wc_after,
1541            });
1542            let mut children = vec![vec![]];
1543            loop {
1544                let chars = self.chars.clone();
1545                if let Some((content, _)) = self.parse_mustache_interpolation().ok()
1546                    && let (content, wc_before, wc_after) = strip_hbs_whitespace_control(content)
1547                    && content
1548                        .strip_prefix('/')
1549                        .is_some_and(|s| s.trim_ascii() == block_name)
1550                {
1551                    controls.push(MustacheBlockControl {
1552                        name: block_name,
1553                        prefix: "/",
1554                        content: None,
1555                        wc_before,
1556                        wc_after,
1557                    });
1558                    break;
1559                } else {
1560                    self.chars = chars;
1561                }
1562                let node = self.parse_node()?;
1563                if let NodeKind::MustacheInterpolation(interpolation) = &node.kind
1564                    && let ("else", wc_before, wc_after) =
1565                        strip_hbs_whitespace_control(interpolation.content)
1566                {
1567                    controls.push(MustacheBlockControl {
1568                        name: "else",
1569                        prefix: "",
1570                        content: None,
1571                        wc_before,
1572                        wc_after,
1573                    });
1574                    children.push(vec![]);
1575                } else if let Some(nodes) = children.last_mut() {
1576                    nodes.push(node);
1577                }
1578            }
1579            Ok(NodeKind::MustacheBlock(MustacheBlock {
1580                controls,
1581                children,
1582            }))
1583        } else {
1584            Ok(NodeKind::MustacheInterpolation(MustacheInterpolation {
1585                content: raw,
1586            }))
1587        }
1588    }
1589
1590    fn parse_mustache_interpolation(&mut self) -> PResult<(&'s str, usize)> {
1591        let Some((start, _)) = self
1592            .chars
1593            .next_if(|(_, c)| *c == '{')
1594            .and_then(|_| self.chars.next_if(|(_, c)| *c == '{'))
1595        else {
1596            return Err(self.emit_error(SyntaxErrorKind::ExpectMustacheInterpolation));
1597        };
1598        let start = start + 1;
1599
1600        let mut braces_stack = 0usize;
1601        let mut end = start;
1602        loop {
1603            match self.chars.next() {
1604                Some((_, '{')) => braces_stack += 1,
1605                Some((i, '}')) => {
1606                    if braces_stack == 0 {
1607                        if self.chars.next_if(|(_, c)| *c == '}').is_some() {
1608                            end = i;
1609                            break;
1610                        }
1611                    } else {
1612                        braces_stack -= 1;
1613                    }
1614                }
1615                Some(..) => continue,
1616                None => break,
1617            }
1618        }
1619
1620        Ok((unsafe { self.source.get_unchecked(start..end) }, start))
1621    }
1622
1623    fn parse_native_attr(&mut self) -> PResult<NativeAttribute<'s>> {
1624        let name = self.parse_attr_name()?;
1625        self.skip_ws();
1626        let mut quote = None;
1627        let value = if self.chars.next_if(|(_, c)| *c == '=').is_some() {
1628            self.skip_ws();
1629            quote = self
1630                .chars
1631                .peek()
1632                .and_then(|(_, c)| (*c == '\'' || *c == '"').then_some(*c));
1633            Some(self.parse_attr_value()?)
1634        } else {
1635            None
1636        };
1637        Ok(NativeAttribute { name, value, quote })
1638    }
1639
1640    fn parse_node(&mut self) -> PResult<Node<'s>> {
1641        let (kind, raw) = self.with_taken(Parser::parse_node_kind)?;
1642        Ok(Node { kind, raw })
1643    }
1644
1645    fn parse_node_kind(&mut self) -> PResult<NodeKind<'s>> {
1646        match self.chars.peek() {
1647            Some((_, '<')) => {
1648                let mut chars = self.chars.clone();
1649                chars.next();
1650                match chars.next() {
1651                    Some((_, c))
1652                        if is_html_tag_name_char(c)
1653                            || is_special_tag_name_char(c, self.language) =>
1654                    {
1655                        self.parse_element().map(NodeKind::Element)
1656                    }
1657                    Some((_, '!')) => {
1658                        if matches!(
1659                            self.language,
1660                            Language::Html
1661                                | Language::Astro
1662                                | Language::Jinja
1663                                | Language::Vento
1664                                | Language::Mustache
1665                                | Language::Xml
1666                        ) {
1667                            self.try_parse(Parser::parse_comment)
1668                                .map(NodeKind::Comment)
1669                                .or_else(|_| {
1670                                    self.try_parse(Parser::parse_doctype).map(NodeKind::Doctype)
1671                                })
1672                                .or_else(|_| {
1673                                    self.try_parse(Parser::parse_cdata).map(NodeKind::Cdata)
1674                                })
1675                                .or_else(|_| self.parse_text_node().map(NodeKind::Text))
1676                        } else {
1677                            self.parse_comment().map(NodeKind::Comment)
1678                        }
1679                    }
1680                    Some((_, '?')) if self.language == Language::Xml => {
1681                        self.parse_xml_decl().map(NodeKind::XmlDecl)
1682                    }
1683                    _ => self.parse_text_node().map(NodeKind::Text),
1684                }
1685            }
1686            Some((_, '{')) => {
1687                let mut chars = self.chars.clone();
1688                chars.next();
1689                match chars.next() {
1690                    Some((_, '{')) => {
1691                        match self.language {
1692                            Language::Html | Language::Xml => {
1693                                self.parse_text_node().map(NodeKind::Text)
1694                            }
1695                            Language::Vue | Language::Jinja => self
1696                                .parse_mustache_interpolation()
1697                                .map(|(expr, start)| match self.language {
1698                                    Language::Vue => {
1699                                        NodeKind::VueInterpolation(VueInterpolation { expr, start })
1700                                    }
1701                                    Language::Jinja => {
1702                                        NodeKind::JinjaInterpolation(JinjaInterpolation {
1703                                            expr,
1704                                            start,
1705                                        })
1706                                    }
1707                                    _ => unreachable!(),
1708                                }),
1709                            Language::Svelte => self
1710                                .parse_svelte_interpolation()
1711                                .map(NodeKind::SvelteInterpolation),
1712                            Language::Astro => self.parse_astro_expr().map(NodeKind::AstroExpr),
1713                            Language::Angular => self
1714                                .try_parse(|parser| {
1715                                    parser.parse_mustache_interpolation().map(|(expr, start)| {
1716                                        NodeKind::AngularInterpolation(AngularInterpolation {
1717                                            expr,
1718                                            start,
1719                                        })
1720                                    })
1721                                })
1722                                .or_else(|_| self.parse_text_node().map(NodeKind::Text)),
1723                            Language::Vento => self.parse_vento_tag_or_block(None),
1724                            Language::Mustache => self.parse_mustache_block_or_interpolation(),
1725                        }
1726                    }
1727                    Some((_, '#')) if matches!(self.language, Language::Svelte) => {
1728                        match chars.next() {
1729                            Some((_, 'i')) => {
1730                                self.parse_svelte_if_block().map(NodeKind::SvelteIfBlock)
1731                            }
1732                            Some((_, 'e')) => self
1733                                .parse_svelte_each_block()
1734                                .map(NodeKind::SvelteEachBlock),
1735                            Some((_, 'a')) => self
1736                                .parse_svelte_await_block()
1737                                .map(NodeKind::SvelteAwaitBlock),
1738                            Some((_, 'k')) => {
1739                                self.parse_svelte_key_block().map(NodeKind::SvelteKeyBlock)
1740                            }
1741                            Some((_, 's')) => self
1742                                .parse_svelte_snippet_block()
1743                                .map(NodeKind::SvelteSnippetBlock),
1744                            _ => self.parse_text_node().map(NodeKind::Text),
1745                        }
1746                    }
1747                    Some((_, '#')) if matches!(self.language, Language::Jinja) => {
1748                        self.parse_jinja_comment().map(NodeKind::JinjaComment)
1749                    }
1750                    Some((_, '@')) => self.parse_svelte_at_tag().map(NodeKind::SvelteAtTag),
1751                    Some((_, '%')) if matches!(self.language, Language::Jinja) => {
1752                        self.parse_jinja_tag_or_block(None, &mut Parser::parse_node)
1753                    }
1754                    _ => match self.language {
1755                        Language::Svelte => self
1756                            .parse_svelte_interpolation()
1757                            .map(NodeKind::SvelteInterpolation),
1758                        Language::Astro => self.parse_astro_expr().map(NodeKind::AstroExpr),
1759                        _ => self.parse_text_node().map(NodeKind::Text),
1760                    },
1761                }
1762            }
1763            Some((_, '-'))
1764                if matches!(
1765                    self.language,
1766                    Language::Astro | Language::Jinja | Language::Vento | Language::Mustache
1767                ) && !self.state.has_front_matter =>
1768            {
1769                let mut chars = self.chars.clone();
1770                chars.next();
1771                if let Some(((_, '-'), (_, '-'))) = chars.next().zip(chars.next()) {
1772                    self.parse_front_matter().map(NodeKind::FrontMatter)
1773                } else {
1774                    self.parse_text_node().map(NodeKind::Text)
1775                }
1776            }
1777            Some((_, '@')) if matches!(self.language, Language::Angular) => {
1778                let mut chars = self.chars.clone();
1779                chars.next();
1780                match chars.next() {
1781                    Some((_, 'i')) => self.parse_angular_if().map(NodeKind::AngularIf),
1782                    Some((_, 'f')) => self.parse_angular_for().map(NodeKind::AngularFor),
1783                    Some((_, 's')) => self.parse_angular_switch().map(NodeKind::AngularSwitch),
1784                    Some((_, 'l')) => self.parse_angular_let().map(NodeKind::AngularLet),
1785                    Some((_, 'd')) => self
1786                        .parse_angular_defer()
1787                        .map(NodeKind::AngularGenericBlocks),
1788                    _ => self.parse_text_node().map(NodeKind::Text),
1789                }
1790            }
1791            Some(..) => self.parse_text_node().map(NodeKind::Text),
1792            None => Err(self.emit_error(SyntaxErrorKind::ExpectElement)),
1793        }
1794    }
1795
1796    fn parse_raw_text_node(&mut self, tag_name: &str) -> PResult<TextNode<'s>> {
1797        let start = self
1798            .chars
1799            .peek()
1800            .map(|(i, _)| *i)
1801            .unwrap_or(self.source.len());
1802
1803        let allow_nested = tag_name.eq_ignore_ascii_case("pre");
1804        let mut nested = 0u16;
1805        let mut line_breaks = 0;
1806        let end;
1807        loop {
1808            match self.chars.peek() {
1809                Some((i, '<')) => {
1810                    let i = *i;
1811                    let mut chars = self.chars.clone();
1812                    chars.next();
1813                    if chars.next_if(|(_, c)| *c == '/').is_some()
1814                        && chars
1815                            .by_ref()
1816                            .zip(tag_name.chars())
1817                            .all(|((_, a), b)| a.eq_ignore_ascii_case(&b))
1818                    {
1819                        if nested == 0 {
1820                            end = i;
1821                            break;
1822                        } else {
1823                            nested -= 1;
1824                            self.chars = chars;
1825                            continue;
1826                        }
1827                    } else if allow_nested
1828                        && chars
1829                            .by_ref()
1830                            .zip(tag_name.chars())
1831                            .all(|((_, a), b)| a.eq_ignore_ascii_case(&b))
1832                    {
1833                        nested += 1;
1834                        self.chars = chars;
1835                        continue;
1836                    }
1837                    self.chars.next();
1838                }
1839                Some((_, c)) => {
1840                    if *c == '\n' {
1841                        line_breaks += 1;
1842                    }
1843                    self.chars.next();
1844                }
1845                None => {
1846                    end = self.source.len();
1847                    break;
1848                }
1849            }
1850        }
1851
1852        Ok(TextNode {
1853            raw: unsafe { self.source.get_unchecked(start..end) },
1854            line_breaks,
1855            start,
1856        })
1857    }
1858
1859    pub fn parse_root(&mut self) -> PResult<Root<'s>> {
1860        let mut children = vec![];
1861        while self.chars.peek().is_some() {
1862            children.push(self.parse_node()?);
1863        }
1864
1865        Ok(Root { children })
1866    }
1867
1868    fn parse_svelte_at_tag(&mut self) -> PResult<SvelteAtTag<'s>> {
1869        if self
1870            .chars
1871            .next_if(|(_, c)| *c == '{')
1872            .and_then(|_| self.chars.next_if(|(_, c)| *c == '@'))
1873            .is_none()
1874        {
1875            return Err(self.emit_error(SyntaxErrorKind::ExpectSvelteAtTag));
1876        };
1877        let name = self.parse_identifier()?;
1878        self.skip_ws();
1879        let expr = self.parse_svelte_or_astro_expr()?;
1880        Ok(SvelteAtTag { name, expr })
1881    }
1882
1883    fn parse_svelte_attachment(&mut self) -> PResult<SvelteAttachment<'s>> {
1884        if self
1885            .chars
1886            .next_if(|(_, c)| *c == '{')
1887            .map(|_| self.skip_ws())
1888            .and_then(|_| self.chars.next_if(|(_, c)| *c == '@'))
1889            .and_then(|_| self.chars.next_if(|(_, c)| *c == 'a'))
1890            .and_then(|_| self.chars.next_if(|(_, c)| *c == 't'))
1891            .and_then(|_| self.chars.next_if(|(_, c)| *c == 't'))
1892            .and_then(|_| self.chars.next_if(|(_, c)| *c == 'a'))
1893            .and_then(|_| self.chars.next_if(|(_, c)| *c == 'c'))
1894            .and_then(|_| self.chars.next_if(|(_, c)| *c == 'h'))
1895            .is_some()
1896        {
1897            self.parse_svelte_or_astro_expr()
1898                .map(|expr| SvelteAttachment { expr })
1899        } else {
1900            Err(self.emit_error(SyntaxErrorKind::ExpectSvelteAttachment))
1901        }
1902    }
1903
1904    fn parse_svelte_attr(&mut self) -> PResult<SvelteAttribute<'s>> {
1905        let name = if self.chars.next_if(|(_, c)| *c == '{').is_some() {
1906            None
1907        } else {
1908            let name = self.parse_attr_name()?;
1909            self.skip_ws();
1910            if self
1911                .chars
1912                .next_if(|(_, c)| *c == '=')
1913                .map(|_| self.skip_ws())
1914                .and_then(|_| self.chars.next_if(|(_, c)| *c == '{'))
1915                .is_some()
1916            {
1917                Some(name)
1918            } else {
1919                return Err(self.emit_error(SyntaxErrorKind::ExpectSvelteAttr));
1920            }
1921        };
1922
1923        self.parse_svelte_or_astro_expr()
1924            .map(|expr| SvelteAttribute { name, expr })
1925    }
1926
1927    fn parse_svelte_await_block(&mut self) -> PResult<Box<SvelteAwaitBlock<'s>>> {
1928        if self
1929            .chars
1930            .next_if(|(_, c)| *c == '{')
1931            .and_then(|_| self.chars.next_if(|(_, c)| *c == '#'))
1932            .and_then(|_| self.chars.next_if(|(_, c)| *c == 'a'))
1933            .and_then(|_| self.chars.next_if(|(_, c)| *c == 'w'))
1934            .and_then(|_| self.chars.next_if(|(_, c)| *c == 'a'))
1935            .and_then(|_| self.chars.next_if(|(_, c)| *c == 'i'))
1936            .and_then(|_| self.chars.next_if(|(_, c)| *c == 't'))
1937            .and_then(|_| self.chars.next_if(|(_, c)| c.is_ascii_whitespace()))
1938            .is_none()
1939        {
1940            return Err(self.emit_error(SyntaxErrorKind::ExpectSvelteIfBlock));
1941        };
1942        self.skip_ws();
1943
1944        let expr = {
1945            let start = self
1946                .chars
1947                .peek()
1948                .map(|(i, _)| *i)
1949                .unwrap_or(self.source.len());
1950            let mut end = start;
1951            let mut braces_stack = 0u8;
1952            loop {
1953                match self.chars.peek() {
1954                    Some((i, c)) if c.is_ascii_whitespace() => {
1955                        let i = *i;
1956                        self.skip_ws();
1957                        let mut chars = self.chars.clone();
1958                        match chars.next() {
1959                            Some((_, 't')) => {
1960                                if chars
1961                                    .next_if(|(_, c)| *c == 'h')
1962                                    .and_then(|_| chars.next_if(|(_, c)| *c == 'e'))
1963                                    .and_then(|_| chars.next_if(|(_, c)| *c == 'n'))
1964                                    .is_some()
1965                                {
1966                                    end = i;
1967                                    break;
1968                                }
1969                            }
1970                            Some((_, 'c')) => {
1971                                if chars
1972                                    .next_if(|(_, c)| *c == 'a')
1973                                    .and_then(|_| chars.next_if(|(_, c)| *c == 't'))
1974                                    .and_then(|_| chars.next_if(|(_, c)| *c == 'c'))
1975                                    .and_then(|_| chars.next_if(|(_, c)| *c == 'h'))
1976                                    .is_some()
1977                                {
1978                                    end = i;
1979                                    break;
1980                                }
1981                            }
1982                            _ => {}
1983                        }
1984                    }
1985                    Some((i, '{')) => {
1986                        braces_stack += 1;
1987                        end = *i;
1988                        self.chars.next();
1989                    }
1990                    Some((i, '}')) => {
1991                        end = *i;
1992                        if braces_stack == 0 {
1993                            break;
1994                        }
1995                        self.chars.next();
1996                        braces_stack -= 1;
1997                    }
1998                    Some((i, _)) => {
1999                        end = *i;
2000                        self.chars.next();
2001                    }
2002                    None => break,
2003                }
2004            }
2005            (unsafe { self.source.get_unchecked(start..end) }, start)
2006        };
2007
2008        self.skip_ws();
2009        let then_binding = if self
2010            .chars
2011            .next_if(|(_, c)| *c == 't')
2012            .and_then(|_| self.chars.next_if(|(_, c)| *c == 'h'))
2013            .and_then(|_| self.chars.next_if(|(_, c)| *c == 'e'))
2014            .and_then(|_| self.chars.next_if(|(_, c)| *c == 'n'))
2015            .is_some()
2016        {
2017            self.skip_ws();
2018            Some(match self.chars.peek() {
2019                Some((_, '}')) => None,
2020                _ => Some(self.parse_svelte_binding()?),
2021            })
2022        } else {
2023            None
2024        };
2025
2026        self.skip_ws();
2027        let catch_binding = if self
2028            .chars
2029            .next_if(|(_, c)| *c == 'c')
2030            .and_then(|_| self.chars.next_if(|(_, c)| *c == 'a'))
2031            .and_then(|_| self.chars.next_if(|(_, c)| *c == 't'))
2032            .and_then(|_| self.chars.next_if(|(_, c)| *c == 'c'))
2033            .and_then(|_| self.chars.next_if(|(_, c)| *c == 'h'))
2034            .is_some()
2035        {
2036            self.skip_ws();
2037            Some(match self.chars.peek() {
2038                Some((_, '}')) => None,
2039                _ => Some(self.parse_svelte_binding()?),
2040            })
2041        } else {
2042            None
2043        };
2044
2045        self.skip_ws();
2046        if self.chars.next_if(|(_, c)| *c == '}').is_none() {
2047            return Err(self.emit_error(SyntaxErrorKind::ExpectChar('}')));
2048        }
2049
2050        let children = self.parse_svelte_block_children()?;
2051
2052        let then_block = if self
2053            .try_parse(|parser| {
2054                parser
2055                    .chars
2056                    .next_if(|(_, c)| *c == '{')
2057                    .and_then(|_| parser.chars.next_if(|(_, c)| *c == ':'))
2058                    .and_then(|_| parser.chars.next_if(|(_, c)| *c == 't'))
2059                    .and_then(|_| parser.chars.next_if(|(_, c)| *c == 'h'))
2060                    .and_then(|_| parser.chars.next_if(|(_, c)| *c == 'e'))
2061                    .and_then(|_| parser.chars.next_if(|(_, c)| *c == 'n'))
2062                    .ok_or_else(|| parser.emit_error(SyntaxErrorKind::ExpectSvelteThenBlock))
2063            })
2064            .is_ok()
2065        {
2066            self.skip_ws();
2067            let binding = match self.chars.peek() {
2068                Some((_, '}')) => None,
2069                _ => {
2070                    let binding = self.parse_svelte_binding()?;
2071                    self.skip_ws();
2072                    Some(binding)
2073                }
2074            };
2075            if self.chars.next_if(|(_, c)| *c == '}').is_none() {
2076                return Err(self.emit_error(SyntaxErrorKind::ExpectSvelteThenBlock));
2077            }
2078            let children = self.parse_svelte_block_children()?;
2079            Some(SvelteThenBlock { binding, children })
2080        } else {
2081            None
2082        };
2083
2084        let catch_block = if self
2085            .try_parse(|parser| {
2086                parser
2087                    .chars
2088                    .next_if(|(_, c)| *c == '{')
2089                    .and_then(|_| parser.chars.next_if(|(_, c)| *c == ':'))
2090                    .and_then(|_| parser.chars.next_if(|(_, c)| *c == 'c'))
2091                    .and_then(|_| parser.chars.next_if(|(_, c)| *c == 'a'))
2092                    .and_then(|_| parser.chars.next_if(|(_, c)| *c == 't'))
2093                    .and_then(|_| parser.chars.next_if(|(_, c)| *c == 'c'))
2094                    .and_then(|_| parser.chars.next_if(|(_, c)| *c == 'h'))
2095                    .ok_or_else(|| parser.emit_error(SyntaxErrorKind::ExpectSvelteCatchBlock))
2096            })
2097            .is_ok()
2098        {
2099            self.skip_ws();
2100            let binding = match self.chars.peek() {
2101                Some((_, '}')) => None,
2102                _ => {
2103                    let binding = self.parse_svelte_binding()?;
2104                    self.skip_ws();
2105                    Some(binding)
2106                }
2107            };
2108            if self.chars.next_if(|(_, c)| *c == '}').is_none() {
2109                return Err(self.emit_error(SyntaxErrorKind::ExpectSvelteCatchBlock));
2110            }
2111            let children = self.parse_svelte_block_children()?;
2112            Some(SvelteCatchBlock { binding, children })
2113        } else {
2114            None
2115        };
2116
2117        if self
2118            .chars
2119            .next_if(|(_, c)| *c == '{')
2120            .map(|_| self.skip_ws())
2121            .and_then(|_| self.chars.next_if(|(_, c)| *c == '/'))
2122            .and_then(|_| self.chars.next_if(|(_, c)| *c == 'a'))
2123            .and_then(|_| self.chars.next_if(|(_, c)| *c == 'w'))
2124            .and_then(|_| self.chars.next_if(|(_, c)| *c == 'a'))
2125            .and_then(|_| self.chars.next_if(|(_, c)| *c == 'i'))
2126            .and_then(|_| self.chars.next_if(|(_, c)| *c == 't'))
2127            .map(|_| self.skip_ws())
2128            .and_then(|_| self.chars.next_if(|(_, c)| *c == '}'))
2129            .is_some()
2130        {
2131            Ok(Box::new(SvelteAwaitBlock {
2132                expr,
2133                then_binding,
2134                catch_binding,
2135                children,
2136                then_block,
2137                catch_block,
2138            }))
2139        } else {
2140            Err(self.emit_error(SyntaxErrorKind::ExpectSvelteBlockEnd))
2141        }
2142    }
2143
2144    fn parse_svelte_binding(&mut self) -> PResult<(&'s str, usize)> {
2145        match self.chars.peek() {
2146            Some((start, '{')) => {
2147                let start = start + 1;
2148                self.parse_inside('{', '}', true)
2149                    .map(|binding| (binding, start))
2150            }
2151            Some((start, '[')) => {
2152                let start = start + 1;
2153                self.parse_inside('[', ']', true)
2154                    .map(|binding| (binding, start))
2155            }
2156            Some((start, _)) => {
2157                let start = *start;
2158                self.parse_identifier().map(|ident| (ident, start))
2159            }
2160            _ => Err(self.emit_error(SyntaxErrorKind::ExpectIdentifier)),
2161        }
2162    }
2163
2164    fn parse_svelte_block_children(&mut self) -> PResult<Vec<Node<'s>>> {
2165        let mut children = vec![];
2166        loop {
2167            match self.chars.peek() {
2168                Some((_, '{')) => {
2169                    let mut chars = self.chars.clone();
2170                    chars.next();
2171                    while chars.next_if(|(_, c)| c.is_ascii_whitespace()).is_some() {}
2172                    if chars.next_if(|(_, c)| *c == '/' || *c == ':').is_some() {
2173                        break;
2174                    }
2175                    children.push(self.parse_node()?);
2176                }
2177                Some(..) => {
2178                    children.push(self.parse_node()?);
2179                }
2180                None => return Err(self.emit_error(SyntaxErrorKind::ExpectSvelteBlockEnd)),
2181            }
2182        }
2183        Ok(children)
2184    }
2185
2186    fn parse_svelte_each_block(&mut self) -> PResult<SvelteEachBlock<'s>> {
2187        if self
2188            .chars
2189            .next_if(|(_, c)| *c == '{')
2190            .and_then(|_| self.chars.next_if(|(_, c)| *c == '#'))
2191            .and_then(|_| self.chars.next_if(|(_, c)| *c == 'e'))
2192            .and_then(|_| self.chars.next_if(|(_, c)| *c == 'a'))
2193            .and_then(|_| self.chars.next_if(|(_, c)| *c == 'c'))
2194            .and_then(|_| self.chars.next_if(|(_, c)| *c == 'h'))
2195            .and_then(|_| self.chars.next_if(|(_, c)| c.is_ascii_whitespace()))
2196            .is_none()
2197        {
2198            return Err(self.emit_error(SyntaxErrorKind::ExpectSvelteIfBlock));
2199        };
2200        self.skip_ws();
2201
2202        let mut binding = None;
2203        let expr = {
2204            let start = self
2205                .chars
2206                .peek()
2207                .map(|(i, _)| *i)
2208                .unwrap_or(self.source.len());
2209            let mut end = start;
2210            let mut pair_stack = vec![];
2211            loop {
2212                match self.chars.peek() {
2213                    Some((i, c)) if c.is_ascii_whitespace() => {
2214                        end = *i;
2215                        self.skip_ws();
2216                        let mut chars = self.chars.clone();
2217                        if chars
2218                            .next_if(|(_, c)| *c == 'a')
2219                            .and_then(|_| chars.next_if(|(_, c)| *c == 's'))
2220                            .and_then(|_| chars.next_if(|(_, c)| c.is_ascii_whitespace()))
2221                            .is_some()
2222                        {
2223                            self.chars = chars;
2224                            self.skip_ws();
2225                            binding = Some(self.parse_svelte_binding()?);
2226
2227                            // fix for #127
2228                            let mut chars = self.chars.clone();
2229                            while chars.next_if(|(_, c)| c.is_ascii_whitespace()).is_some() {}
2230                            if matches!(chars.peek(), Some((_, '}' | '(' | ','))) {
2231                                break;
2232                            }
2233                        }
2234                    }
2235                    Some((_, '(')) => {
2236                        pair_stack.push('(');
2237                        self.chars.next();
2238                    }
2239                    Some((i, ')')) if matches!(pair_stack.last(), Some('(')) => {
2240                        pair_stack.pop();
2241                        end = *i;
2242                        self.chars.next();
2243                    }
2244                    Some((_, '[')) => {
2245                        pair_stack.push('[');
2246                        self.chars.next();
2247                    }
2248                    Some((i, ']')) if matches!(pair_stack.last(), Some('[')) => {
2249                        pair_stack.pop();
2250                        end = *i;
2251                        self.chars.next();
2252                    }
2253                    Some((_, '{')) => {
2254                        pair_stack.push('{');
2255                        self.chars.next();
2256                    }
2257                    Some((i, '}')) => {
2258                        end = *i;
2259                        if matches!(pair_stack.last(), Some('{')) {
2260                            pair_stack.pop();
2261                            self.chars.next();
2262                        } else {
2263                            break;
2264                        }
2265                    }
2266                    Some((i, ',')) => {
2267                        end = *i;
2268                        if pair_stack.is_empty() {
2269                            break;
2270                        } else {
2271                            self.chars.next();
2272                        }
2273                    }
2274                    Some((i, _)) => {
2275                        end = *i;
2276                        self.chars.next();
2277                    }
2278                    None => break,
2279                }
2280            }
2281            (unsafe { self.source.get_unchecked(start..end) }, start)
2282        };
2283
2284        self.skip_ws();
2285        let index = if self.chars.next_if(|(_, c)| *c == ',').is_some() {
2286            self.skip_ws();
2287            Some(self.parse_identifier()?)
2288        } else {
2289            None
2290        };
2291
2292        self.skip_ws();
2293        let key = if let Some((start, '(')) = self.chars.peek() {
2294            let start = start + 1;
2295            Some((self.parse_inside('(', ')', false)?, start))
2296        } else {
2297            None
2298        };
2299
2300        self.skip_ws();
2301        if self.chars.next_if(|(_, c)| *c == '}').is_none() {
2302            return Err(self.emit_error(SyntaxErrorKind::ExpectSvelteEachBlock));
2303        }
2304
2305        let children = self.parse_svelte_block_children()?;
2306
2307        let else_children = if self
2308            .try_parse(|parser| {
2309                parser
2310                    .chars
2311                    .next_if(|(_, c)| *c == '{')
2312                    .and_then(|_| parser.chars.next_if(|(_, c)| *c == ':'))
2313                    .and_then(|_| parser.chars.next_if(|(_, c)| *c == 'e'))
2314                    .and_then(|_| parser.chars.next_if(|(_, c)| *c == 'l'))
2315                    .and_then(|_| parser.chars.next_if(|(_, c)| *c == 's'))
2316                    .and_then(|_| parser.chars.next_if(|(_, c)| *c == 'e'))
2317                    .and_then(|_| {
2318                        parser.skip_ws();
2319                        parser.chars.next_if(|(_, c)| *c == '}')
2320                    })
2321                    .ok_or_else(|| parser.emit_error(SyntaxErrorKind::ExpectSvelteEachBlock))
2322            })
2323            .is_ok()
2324        {
2325            Some(self.parse_svelte_block_children()?)
2326        } else {
2327            None
2328        };
2329
2330        if self
2331            .chars
2332            .next_if(|(_, c)| *c == '{')
2333            .map(|_| self.skip_ws())
2334            .and_then(|_| self.chars.next_if(|(_, c)| *c == '/'))
2335            .and_then(|_| self.chars.next_if(|(_, c)| *c == 'e'))
2336            .and_then(|_| self.chars.next_if(|(_, c)| *c == 'a'))
2337            .and_then(|_| self.chars.next_if(|(_, c)| *c == 'c'))
2338            .and_then(|_| self.chars.next_if(|(_, c)| *c == 'h'))
2339            .map(|_| self.skip_ws())
2340            .and_then(|_| self.chars.next_if(|(_, c)| *c == '}'))
2341            .is_some()
2342        {
2343            Ok(SvelteEachBlock {
2344                expr,
2345                binding,
2346                index,
2347                key,
2348                children,
2349                else_children,
2350            })
2351        } else {
2352            Err(self.emit_error(SyntaxErrorKind::ExpectSvelteBlockEnd))
2353        }
2354    }
2355
2356    fn parse_svelte_if_block(&mut self) -> PResult<SvelteIfBlock<'s>> {
2357        if self
2358            .chars
2359            .next_if(|(_, c)| *c == '{')
2360            .and_then(|_| self.chars.next_if(|(_, c)| *c == '#'))
2361            .and_then(|_| self.chars.next_if(|(_, c)| *c == 'i'))
2362            .and_then(|_| self.chars.next_if(|(_, c)| *c == 'f'))
2363            .and_then(|_| self.chars.next_if(|(_, c)| c.is_ascii_whitespace()))
2364            .is_none()
2365        {
2366            return Err(self.emit_error(SyntaxErrorKind::ExpectSvelteIfBlock));
2367        };
2368
2369        let expr = self.parse_svelte_or_astro_expr()?;
2370        let children = self.parse_svelte_block_children()?;
2371
2372        let mut else_if_blocks = vec![];
2373        let mut else_children = None;
2374        loop {
2375            if self.chars.next_if(|(_, c)| *c == '{').is_none() {
2376                return Err(self.emit_error(SyntaxErrorKind::ExpectSvelteBlockEnd));
2377            }
2378            self.skip_ws();
2379            match self.chars.next() {
2380                Some((_, ':')) => {
2381                    if self
2382                        .chars
2383                        .next_if(|(_, c)| *c == 'e')
2384                        .and_then(|_| self.chars.next_if(|(_, c)| *c == 'l'))
2385                        .and_then(|_| self.chars.next_if(|(_, c)| *c == 's'))
2386                        .and_then(|_| self.chars.next_if(|(_, c)| *c == 'e'))
2387                        .is_none()
2388                    {
2389                        return Err(self.emit_error(SyntaxErrorKind::ExpectSvelteElseIfBlock));
2390                    }
2391                    self.skip_ws();
2392                    match self.chars.next() {
2393                        Some((_, 'i')) => {
2394                            if self.chars.next_if(|(_, c)| *c == 'f').is_none() {
2395                                return Err(
2396                                    self.emit_error(SyntaxErrorKind::ExpectSvelteElseIfBlock)
2397                                );
2398                            }
2399                            let expr = self.parse_svelte_or_astro_expr()?;
2400                            let children = self.parse_svelte_block_children()?;
2401                            else_if_blocks.push(SvelteElseIfBlock { expr, children });
2402                        }
2403                        Some((_, '}')) => {
2404                            else_children = Some(self.parse_svelte_block_children()?);
2405                        }
2406                        _ => return Err(self.emit_error(SyntaxErrorKind::ExpectSvelteElseIfBlock)),
2407                    }
2408                }
2409                Some((_, '/')) => break,
2410                _ => return Err(self.emit_error(SyntaxErrorKind::ExpectSvelteBlockEnd)),
2411            }
2412        }
2413        if self
2414            .chars
2415            .next_if(|(_, c)| *c == 'i')
2416            .and_then(|_| self.chars.next_if(|(_, c)| *c == 'f'))
2417            .map(|_| self.skip_ws())
2418            .and_then(|_| self.chars.next_if(|(_, c)| *c == '}'))
2419            .is_some()
2420        {
2421            Ok(SvelteIfBlock {
2422                expr,
2423                children,
2424                else_if_blocks,
2425                else_children,
2426            })
2427        } else {
2428            Err(self.emit_error(SyntaxErrorKind::ExpectSvelteBlockEnd))
2429        }
2430    }
2431
2432    fn parse_svelte_interpolation(&mut self) -> PResult<SvelteInterpolation<'s>> {
2433        if self.chars.next_if(|(_, c)| *c == '{').is_some() {
2434            Ok(SvelteInterpolation {
2435                expr: self.parse_svelte_or_astro_expr()?,
2436            })
2437        } else {
2438            Err(self.emit_error(SyntaxErrorKind::ExpectSvelteInterpolation))
2439        }
2440    }
2441
2442    fn parse_svelte_key_block(&mut self) -> PResult<SvelteKeyBlock<'s>> {
2443        if self
2444            .chars
2445            .next_if(|(_, c)| *c == '{')
2446            .and_then(|_| self.chars.next_if(|(_, c)| *c == '#'))
2447            .and_then(|_| self.chars.next_if(|(_, c)| *c == 'k'))
2448            .and_then(|_| self.chars.next_if(|(_, c)| *c == 'e'))
2449            .and_then(|_| self.chars.next_if(|(_, c)| *c == 'y'))
2450            .and_then(|_| self.chars.next_if(|(_, c)| c.is_ascii_whitespace()))
2451            .is_none()
2452        {
2453            return Err(self.emit_error(SyntaxErrorKind::ExpectSvelteKeyBlock));
2454        };
2455
2456        let expr = self.parse_svelte_or_astro_expr()?;
2457        let children = self.parse_svelte_block_children()?;
2458
2459        if self
2460            .chars
2461            .next_if(|(_, c)| *c == '{')
2462            .map(|_| self.skip_ws())
2463            .and_then(|_| self.chars.next_if(|(_, c)| *c == '/'))
2464            .and_then(|_| self.chars.next_if(|(_, c)| *c == 'k'))
2465            .and_then(|_| self.chars.next_if(|(_, c)| *c == 'e'))
2466            .and_then(|_| self.chars.next_if(|(_, c)| *c == 'y'))
2467            .map(|_| self.skip_ws())
2468            .and_then(|_| self.chars.next_if(|(_, c)| *c == '}'))
2469            .is_some()
2470        {
2471            Ok(SvelteKeyBlock { expr, children })
2472        } else {
2473            Err(self.emit_error(SyntaxErrorKind::ExpectSvelteBlockEnd))
2474        }
2475    }
2476
2477    /// This will consume `}`.
2478    fn parse_svelte_or_astro_expr(&mut self) -> PResult<(&'s str, usize)> {
2479        self.skip_ws();
2480
2481        let start = self
2482            .chars
2483            .peek()
2484            .map(|(i, _)| *i)
2485            .unwrap_or(self.source.len());
2486        let mut end = start;
2487        let mut braces_stack = 0u8;
2488        loop {
2489            match self.chars.next() {
2490                Some((_, '{')) => {
2491                    braces_stack += 1;
2492                }
2493                Some((i, '}')) => {
2494                    if braces_stack == 0 {
2495                        end = i;
2496                        break;
2497                    }
2498                    braces_stack -= 1;
2499                }
2500                Some(..) => continue,
2501                None => break,
2502            }
2503        }
2504        Ok((unsafe { self.source.get_unchecked(start..end) }, start))
2505    }
2506
2507    fn parse_svelte_snippet_block(&mut self) -> PResult<SvelteSnippetBlock<'s>> {
2508        if self
2509            .chars
2510            .next_if(|(_, c)| *c == '{')
2511            .and_then(|_| self.chars.next_if(|(_, c)| *c == '#'))
2512            .and_then(|_| self.chars.next_if(|(_, c)| *c == 's'))
2513            .and_then(|_| self.chars.next_if(|(_, c)| *c == 'n'))
2514            .and_then(|_| self.chars.next_if(|(_, c)| *c == 'i'))
2515            .and_then(|_| self.chars.next_if(|(_, c)| *c == 'p'))
2516            .and_then(|_| self.chars.next_if(|(_, c)| *c == 'p'))
2517            .and_then(|_| self.chars.next_if(|(_, c)| *c == 'e'))
2518            .and_then(|_| self.chars.next_if(|(_, c)| *c == 't'))
2519            .and_then(|_| self.chars.next_if(|(_, c)| c.is_ascii_whitespace()))
2520            .is_none()
2521        {
2522            return Err(self.emit_error(SyntaxErrorKind::ExpectSvelteSnippetBlock));
2523        };
2524
2525        let signature = self.parse_svelte_or_astro_expr()?;
2526        let children = self.parse_svelte_block_children()?;
2527
2528        if self
2529            .chars
2530            .next_if(|(_, c)| *c == '{')
2531            .map(|_| self.skip_ws())
2532            .and_then(|_| self.chars.next_if(|(_, c)| *c == '/'))
2533            .and_then(|_| self.chars.next_if(|(_, c)| *c == 's'))
2534            .and_then(|_| self.chars.next_if(|(_, c)| *c == 'n'))
2535            .and_then(|_| self.chars.next_if(|(_, c)| *c == 'i'))
2536            .and_then(|_| self.chars.next_if(|(_, c)| *c == 'p'))
2537            .and_then(|_| self.chars.next_if(|(_, c)| *c == 'p'))
2538            .and_then(|_| self.chars.next_if(|(_, c)| *c == 'e'))
2539            .and_then(|_| self.chars.next_if(|(_, c)| *c == 't'))
2540            .map(|_| self.skip_ws())
2541            .and_then(|_| self.chars.next_if(|(_, c)| *c == '}'))
2542            .is_some()
2543        {
2544            Ok(SvelteSnippetBlock {
2545                signature,
2546                children,
2547            })
2548        } else {
2549            Err(self.emit_error(SyntaxErrorKind::ExpectSvelteBlockEnd))
2550        }
2551    }
2552
2553    fn parse_tag_name(&mut self) -> PResult<&'s str> {
2554        let (start, mut end) = match self.chars.peek() {
2555            Some((i, c)) if is_html_tag_name_char(*c) => {
2556                let c = *c;
2557                let start = *i;
2558                self.chars.next();
2559                (start, start + c.len_utf8())
2560            }
2561            Some((i, '{')) if matches!(self.language, Language::Jinja) => (*i, *i + 1),
2562            Some((_, '>')) if matches!(self.language, Language::Astro) => {
2563                // Astro allows fragment
2564                return Ok("");
2565            }
2566            _ => return Err(self.emit_error(SyntaxErrorKind::ExpectTagName)),
2567        };
2568
2569        while let Some((i, c)) = self.chars.peek() {
2570            if is_html_tag_name_char(*c) {
2571                end = *i + c.len_utf8();
2572                self.chars.next();
2573            } else if *c == '{' && matches!(self.language, Language::Jinja) {
2574                let current_i = *i;
2575                let mut chars = self.chars.clone();
2576                chars.next();
2577                if chars.next_if(|(_, c)| *c == '{').is_some() {
2578                    end = current_i + self.parse_mustache_interpolation()?.0.len() + "{{}}".len();
2579                } else {
2580                    break;
2581                }
2582            } else {
2583                break;
2584            }
2585        }
2586
2587        unsafe { Ok(self.source.get_unchecked(start..end)) }
2588    }
2589
2590    fn parse_text_node(&mut self) -> PResult<TextNode<'s>> {
2591        let Some((start, first_char)) = self.chars.next() else {
2592            return Err(self.emit_error(SyntaxErrorKind::ExpectTextNode));
2593        };
2594
2595        let mut line_breaks = if first_char == '\n' { 1 } else { 0 };
2596        let end;
2597        loop {
2598            match self.chars.peek() {
2599                Some((i, '{')) => match self.language {
2600                    Language::Html | Language::Xml => {
2601                        self.chars.next();
2602                    }
2603                    Language::Vue | Language::Vento | Language::Mustache => {
2604                        let i = *i;
2605                        let mut chars = self.chars.clone();
2606                        chars.next();
2607                        if chars.next_if(|(_, c)| *c == '{').is_some() {
2608                            end = i;
2609                            break;
2610                        }
2611                        self.chars.next();
2612                    }
2613                    Language::Svelte | Language::Astro => {
2614                        end = *i;
2615                        break;
2616                    }
2617                    Language::Jinja => {
2618                        let i = *i;
2619                        let mut chars = self.chars.clone();
2620                        chars.next();
2621                        if chars
2622                            .next_if(|(_, c)| *c == '%' || *c == '{' || *c == '#')
2623                            .is_some()
2624                        {
2625                            end = i;
2626                            break;
2627                        }
2628                        self.chars.next();
2629                    }
2630                    Language::Angular => {
2631                        let i = *i;
2632                        let mut chars = self.chars.clone();
2633                        chars.next();
2634                        // there can be interpolation inside ICU expression, so there will be three `{`,
2635                        // and the first one is for ICU expression, while the second one and third one are for interpolation.
2636                        if chars.next_if(|(_, c)| *c == '{').is_some()
2637                            && chars.next_if(|(_, c)| *c == '{').is_none()
2638                        {
2639                            end = i;
2640                            break;
2641                        }
2642                        self.chars.next();
2643                    }
2644                },
2645                Some((i, '<')) => {
2646                    let i = *i;
2647                    let mut chars = self.chars.clone();
2648                    chars.next();
2649                    match chars.next() {
2650                        Some((_, c))
2651                            if is_html_tag_name_char(c)
2652                                || is_special_tag_name_char(c, self.language)
2653                                || c == '/'
2654                                || c == '!' =>
2655                        {
2656                            end = i;
2657                            break;
2658                        }
2659                        _ => {
2660                            self.chars.next();
2661                        }
2662                    }
2663                }
2664                Some((i, '-'))
2665                    if matches!(self.language, Language::Astro) && !self.state.has_front_matter =>
2666                {
2667                    let i = *i;
2668                    let mut chars = self.chars.clone();
2669                    chars.next();
2670                    if let Some(((_, '-'), (_, '-'))) = chars.next().zip(chars.next()) {
2671                        end = i;
2672                        break;
2673                    }
2674                    self.chars.next();
2675                }
2676                Some((i, '}' | '@')) if matches!(self.language, Language::Angular) => {
2677                    end = *i;
2678                    break;
2679                }
2680                Some((_, c)) => {
2681                    if *c == '\n' {
2682                        line_breaks += 1;
2683                    }
2684                    self.chars.next();
2685                }
2686                None => {
2687                    end = self.source.len();
2688                    break;
2689                }
2690            }
2691        }
2692
2693        Ok(TextNode {
2694            raw: unsafe { self.source.get_unchecked(start..end) },
2695            line_breaks,
2696            start,
2697        })
2698    }
2699
2700    fn parse_vento_block_children(&mut self) -> PResult<Vec<Node<'s>>> {
2701        let mut children = vec![];
2702        loop {
2703            match self.chars.peek() {
2704                Some((_, '{')) => {
2705                    let mut chars = self.chars.clone();
2706                    chars.next();
2707                    if chars.next_if(|(_, c)| *c == '{').is_some() {
2708                        break;
2709                    }
2710                    children.push(self.parse_node()?);
2711                }
2712                Some(..) => {
2713                    children.push(self.parse_node()?);
2714                }
2715                None => return Err(self.emit_error(SyntaxErrorKind::ExpectVentoBlockEnd)),
2716            }
2717        }
2718        Ok(children)
2719    }
2720
2721    fn parse_vento_tag_or_block(
2722        &mut self,
2723        first_tag: Option<(&'s str, bool, bool, usize)>,
2724    ) -> PResult<NodeKind<'s>> {
2725        let (first_tag, trim_prev, trim_next, first_tag_start) = if let Some(first_tag) = first_tag
2726        {
2727            first_tag
2728        } else {
2729            let (mut first_tag, mut start) = self.parse_mustache_interpolation()?;
2730            let mut trim_prev = false;
2731            let mut trim_next = false;
2732            if let Some(tag) = first_tag.strip_prefix('-') {
2733                first_tag = tag;
2734                trim_prev = true;
2735                start += 1;
2736            }
2737            if let Some(tag) = first_tag.strip_suffix('-') {
2738                first_tag = tag;
2739                trim_next = true;
2740            }
2741            (first_tag, trim_prev, trim_next, start)
2742        };
2743
2744        if let Some(raw) = first_tag
2745            .strip_prefix('#')
2746            .and_then(|s| s.strip_suffix('#'))
2747        {
2748            return Ok(NodeKind::VentoComment(VentoComment { raw }));
2749        } else if let Some(raw) = first_tag.strip_prefix('>') {
2750            return Ok(NodeKind::VentoEval(VentoEval {
2751                raw,
2752                start: first_tag_start,
2753            }));
2754        }
2755
2756        let (tag_name, tag_rest) = helpers::parse_vento_tag(first_tag);
2757
2758        let is_function = tag_name == "function"
2759            || matches!(tag_name, "async" | "export") && tag_rest.starts_with("function");
2760        if matches!(tag_name, "for" | "if" | "layout")
2761            || matches!(tag_name, "set" | "export") && !first_tag.contains('=')
2762            || is_function
2763        {
2764            let mut body = vec![VentoTagOrChildren::Tag(VentoTag {
2765                tag: first_tag,
2766                trim_prev,
2767                trim_next,
2768            })];
2769
2770            loop {
2771                let mut children = self.parse_vento_block_children()?;
2772                if !children.is_empty() {
2773                    if let Some(VentoTagOrChildren::Children(nodes)) = body.last_mut() {
2774                        nodes.append(&mut children);
2775                    } else {
2776                        body.push(VentoTagOrChildren::Children(children));
2777                    }
2778                }
2779                if let Ok((mut next_tag, mut next_tag_start)) = self.parse_mustache_interpolation()
2780                {
2781                    let mut trim_prev = false;
2782                    let mut trim_next = false;
2783                    if let Some(tag) = next_tag.strip_prefix('-') {
2784                        next_tag = tag;
2785                        trim_prev = true;
2786                        next_tag_start += 1;
2787                    };
2788                    if let Some(tag) = next_tag.strip_suffix('-') {
2789                        next_tag = tag;
2790                        trim_next = true;
2791                    };
2792                    let (next_tag_name, _) = helpers::parse_vento_tag(next_tag);
2793                    if next_tag_name
2794                        .trim()
2795                        .strip_prefix('/')
2796                        .is_some_and(|name| name == tag_name || is_function && name == "function")
2797                    {
2798                        body.push(VentoTagOrChildren::Tag(VentoTag {
2799                            tag: next_tag,
2800                            trim_prev,
2801                            trim_next,
2802                        }));
2803                        break;
2804                    }
2805                    if tag_name == "if" && next_tag_name == "else" {
2806                        body.push(VentoTagOrChildren::Tag(VentoTag {
2807                            tag: next_tag,
2808                            trim_prev,
2809                            trim_next,
2810                        }));
2811                    } else {
2812                        let node = self
2813                            .with_taken(|parser| {
2814                                parser.parse_vento_tag_or_block(Some((
2815                                    next_tag,
2816                                    trim_prev,
2817                                    trim_next,
2818                                    next_tag_start,
2819                                )))
2820                            })
2821                            .map(|(kind, raw)| Node { kind, raw })?;
2822                        if let Some(VentoTagOrChildren::Children(nodes)) = body.last_mut() {
2823                            nodes.push(node);
2824                        } else {
2825                            body.push(VentoTagOrChildren::Children(vec![node]));
2826                        }
2827                    }
2828                } else {
2829                    break;
2830                }
2831            }
2832            Ok(NodeKind::VentoBlock(VentoBlock { body }))
2833        } else if is_vento_interpolation(tag_name) {
2834            Ok(NodeKind::VentoInterpolation(VentoInterpolation {
2835                expr: first_tag,
2836                start: first_tag_start,
2837            }))
2838        } else {
2839            Ok(NodeKind::VentoTag(VentoTag {
2840                tag: first_tag,
2841                trim_prev,
2842                trim_next,
2843            }))
2844        }
2845    }
2846
2847    fn parse_vue_directive(&mut self) -> PResult<VueDirective<'s>> {
2848        let name = match self.chars.peek() {
2849            Some((_, ':')) => {
2850                self.chars.next();
2851                ":"
2852            }
2853            Some((_, '@')) => {
2854                self.chars.next();
2855                "@"
2856            }
2857            Some((_, '#')) => {
2858                self.chars.next();
2859                "#"
2860            }
2861            Some((_, 'v')) => {
2862                let mut chars = self.chars.clone();
2863                chars.next();
2864                if chars.next_if(|(_, c)| *c == '-').is_some() {
2865                    self.chars = chars;
2866                    self.parse_identifier()?
2867                } else {
2868                    return Err(self.emit_error(SyntaxErrorKind::ExpectVueDirective));
2869                }
2870            }
2871            _ => return Err(self.emit_error(SyntaxErrorKind::ExpectVueDirective)),
2872        };
2873
2874        let arg_and_modifiers = if matches!(name, ":" | "@" | "#")
2875            || self
2876                .chars
2877                .peek()
2878                .is_some_and(|(_, c)| is_attr_name_char(*c))
2879        {
2880            Some(self.parse_attr_name()?)
2881        } else {
2882            None
2883        };
2884
2885        self.skip_ws();
2886        let value = if self.chars.next_if(|(_, c)| *c == '=').is_some() {
2887            self.skip_ws();
2888            Some(self.parse_attr_value()?)
2889        } else {
2890            None
2891        };
2892
2893        Ok(VueDirective {
2894            name,
2895            arg_and_modifiers,
2896            value,
2897        })
2898    }
2899
2900    fn parse_xml_decl(&mut self) -> PResult<XmlDecl<'s>> {
2901        if self
2902            .chars
2903            .next_if(|(_, c)| *c == '<')
2904            .and_then(|_| self.chars.next_if(|(_, c)| *c == '?'))
2905            .and_then(|_| self.chars.next_if(|(_, c)| *c == 'x'))
2906            .and_then(|_| self.chars.next_if(|(_, c)| *c == 'm'))
2907            .and_then(|_| self.chars.next_if(|(_, c)| *c == 'l'))
2908            .and_then(|_| self.chars.next_if(|(_, c)| c.is_ascii_whitespace()))
2909            .is_none()
2910        {
2911            return Err(self.emit_error(SyntaxErrorKind::ExpectXmlDecl));
2912        };
2913
2914        let mut attrs = vec![];
2915        loop {
2916            match self.chars.peek() {
2917                Some((_, '?')) => {
2918                    self.chars.next();
2919                    if self.chars.next_if(|(_, c)| *c == '>').is_some() {
2920                        break;
2921                    }
2922                    return Err(self.emit_error(SyntaxErrorKind::ExpectChar('>')));
2923                }
2924                Some((_, c)) if c.is_ascii_whitespace() => {
2925                    self.chars.next();
2926                }
2927                _ => {
2928                    attrs.push(self.parse_native_attr()?);
2929                }
2930            }
2931        }
2932        Ok(XmlDecl { attrs })
2933    }
2934}
2935
2936/// Returns true if the provided character is a valid HTML tag name character.
2937fn is_html_tag_name_char(c: char) -> bool {
2938    c.is_ascii_alphanumeric()
2939        || c == '-'
2940        || c == '_'
2941        || c == '.'
2942        || c == ':'
2943        || !c.is_ascii()
2944        || c == '\\'
2945}
2946
2947/// Checks whether a character is valid in an HTML tag name, for specific template languages.
2948///
2949/// For example:
2950/// - Astro allows '>' in tag names (for fragments)
2951/// - Jinja allows '{' for template expressions like <{{ tag_name }}>
2952fn is_special_tag_name_char(c: char, language: Language) -> bool {
2953    match language {
2954        Language::Astro => c == '>',
2955        Language::Jinja => c == '{',
2956        _ => false,
2957    }
2958}
2959
2960fn is_attr_name_char(c: char) -> bool {
2961    !matches!(c, '"' | '\'' | '>' | '/' | '=') && !c.is_ascii_whitespace()
2962}
2963
2964fn parse_jinja_tag_name<'s>(tag: &JinjaTag<'s>) -> &'s str {
2965    let trimmed = tag.content.trim_start_matches(['+', '-']).trim_start();
2966    trimmed
2967        .split_once(|c: char| c.is_ascii_whitespace())
2968        .map(|(name, _)| name)
2969        .unwrap_or(trimmed)
2970}
2971
2972fn is_vento_interpolation(tag_name: &str) -> bool {
2973    !matches!(
2974        tag_name,
2975        "if" | "else"
2976            | "for"
2977            | "set"
2978            | "include"
2979            | "layout"
2980            | "async"
2981            | "function"
2982            | "import"
2983            | "export"
2984    )
2985}
2986
2987fn strip_hbs_whitespace_control(text: &str) -> (&str, bool, bool) {
2988    let (text, before) = if let Some(stripped) = text.strip_prefix('~') {
2989        (stripped, true)
2990    } else {
2991        (text, false)
2992    };
2993    let (text, after) = if let Some(stripped) = text.strip_suffix('~') {
2994        (stripped, true)
2995    } else {
2996        (text, false)
2997    };
2998    (text, before, after)
2999}
3000
3001pub type PResult<T> = Result<T, SyntaxError>;
3002type AngularIfCond<'s> = ((&'s str, usize), Option<(&'s str, usize)>);
3003
3004trait HasJinjaFlowControl<'s>: Sized {
3005    type Intermediate;
3006
3007    fn build(intermediate: Self::Intermediate, raw: &'s str) -> Self;
3008    fn from_tag(tag: JinjaTag<'s>) -> Self::Intermediate;
3009    fn from_block(block: JinjaBlock<'s, Self>) -> Self::Intermediate;
3010}
3011
3012impl<'s> HasJinjaFlowControl<'s> for Node<'s> {
3013    type Intermediate = NodeKind<'s>;
3014
3015    fn build(intermediate: Self::Intermediate, raw: &'s str) -> Self {
3016        Node {
3017            kind: intermediate,
3018            raw,
3019        }
3020    }
3021
3022    fn from_tag(tag: JinjaTag<'s>) -> Self::Intermediate {
3023        NodeKind::JinjaTag(tag)
3024    }
3025
3026    fn from_block(block: JinjaBlock<'s, Self>) -> Self::Intermediate {
3027        NodeKind::JinjaBlock(block)
3028    }
3029}
3030
3031impl<'s> HasJinjaFlowControl<'s> for Attribute<'s> {
3032    type Intermediate = Attribute<'s>;
3033
3034    fn build(intermediate: Self::Intermediate, _: &'s str) -> Self {
3035        intermediate
3036    }
3037
3038    fn from_tag(tag: JinjaTag<'s>) -> Self::Intermediate {
3039        Attribute::JinjaTag(tag)
3040    }
3041
3042    fn from_block(block: JinjaBlock<'s, Self>) -> Self::Intermediate {
3043        Attribute::JinjaBlock(block)
3044    }
3045}
3046
3047pub fn parse_as_interpolated(
3048    text: &'_ str,
3049    base_start: usize,
3050    language: Language,
3051    attr: bool,
3052) -> (Vec<&'_ str>, Vec<(&'_ str, usize)>) {
3053    let mut statics = Vec::with_capacity(1);
3054    let mut dynamics = Vec::new();
3055    let mut chars = text.char_indices().peekable();
3056    let mut pos = 0;
3057    let mut brace_stack = 0u8;
3058    while let Some((i, c)) = chars.next() {
3059        match c {
3060            '{' => {
3061                if brace_stack > 0 {
3062                    brace_stack += 1;
3063                    continue;
3064                }
3065                match language {
3066                    Language::Svelte if attr => {
3067                        statics.push(unsafe { text.get_unchecked(pos..i) });
3068                        pos = i;
3069                        brace_stack += 1;
3070                    }
3071                    Language::Jinja | Language::Vento | Language::Mustache => {
3072                        if chars.next_if(|(_, c)| *c == '{').is_some() {
3073                            statics.push(unsafe { text.get_unchecked(pos..i) });
3074                            pos = i;
3075                            brace_stack += 1;
3076                        }
3077                    }
3078                    _ => {}
3079                }
3080            }
3081            '}' => {
3082                if brace_stack > 1 {
3083                    brace_stack -= 1;
3084                    continue;
3085                }
3086                match language {
3087                    Language::Svelte if attr => {
3088                        dynamics.push((
3089                            unsafe { text.get_unchecked(pos + 1..i) },
3090                            base_start + pos + 1,
3091                        ));
3092                        pos = i + 1;
3093                        brace_stack = 0;
3094                    }
3095                    Language::Jinja | Language::Vento | Language::Mustache => {
3096                        if chars.next_if(|(_, c)| *c == '}').is_some() {
3097                            dynamics.push((
3098                                unsafe { text.get_unchecked(pos + 2..i) },
3099                                base_start + pos + 2,
3100                            ));
3101                            pos = i + 2;
3102                            brace_stack = 0;
3103                        }
3104                    }
3105                    _ => {}
3106                }
3107            }
3108            _ => {}
3109        }
3110    }
3111    statics.push(unsafe { text.get_unchecked(pos..) });
3112    (statics, dynamics)
3113}