1use std::sync::Arc;
2
3use serde::{Deserialize, Serialize};
4
5use crate::ast::common::Span;
6pub use crate::ast::common::{
7 FragmentType, LiteralValue, Loc as ExpressionLoc, SourceRange,
8 Position as ExpressionPoint, RootCommentType, ScriptContext, ScriptType, SnippetHeaderError,
9 SnippetHeaderErrorKind,
10};
11use crate::ast::modern;
12use crate::js::JsProgram;
13use crate::parse::legacy_expression_from_modern_expression;
14
15#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
16pub struct Script {
17 pub r#type: ScriptType,
18 pub start: usize,
19 pub end: usize,
20 pub context: ScriptContext,
21 #[serde(skip_deserializing, default = "empty_parsed_js_program")]
22 pub content: Arc<JsProgram>,
23 #[serde(skip, default)]
24 pub content_start: usize,
25 #[serde(skip, default)]
26 pub content_end: usize,
27 #[serde(skip, default)]
29 pub content_json: Option<Arc<str>>,
30}
31
32impl serde::Serialize for Script {
33 fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
34 use serde::ser::SerializeMap;
35 let mut map = serializer.serialize_map(None)?;
36 map.serialize_entry("type", &self.r#type)?;
37 map.serialize_entry("start", &self.start)?;
38 map.serialize_entry("end", &self.end)?;
39 map.serialize_entry("context", &self.context)?;
40 if let Some(json) = &self.content_json {
41 let raw = serde_json::value::RawValue::from_string(json.to_string())
42 .map_err(serde::ser::Error::custom)?;
43 map.serialize_entry("content", &raw)?;
44 }
45 map.end()
46 }
47}
48
49fn empty_parsed_js_program() -> Arc<JsProgram> {
50 Arc::new(JsProgram::parse("", oxc_span::SourceType::mjs()))
51}
52
53#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
54pub struct Fragment {
55 pub r#type: FragmentType,
56 pub start: Option<usize>,
57 pub end: Option<usize>,
58 pub children: Box<[Node]>,
59}
60
61#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
62pub struct ProgramComment {
63 pub r#type: RootCommentType,
64 pub value: Arc<str>,
65 pub start: usize,
66 pub end: usize,
67 pub loc: ExpressionLoc,
68}
69
70#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
71pub struct Element {
72 pub start: usize,
73 pub end: usize,
74 pub name: Arc<str>,
75 #[serde(skip_serializing_if = "Option::is_none")]
76 pub tag: Option<ElementTag>,
77 pub attributes: Box<[Attribute]>,
78 pub children: Box<[Node]>,
79}
80
81#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
82pub struct Head {
83 pub start: usize,
84 pub end: usize,
85 pub name: Arc<str>,
86 pub attributes: Box<[Attribute]>,
87 pub children: Box<[Node]>,
88}
89
90#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
91pub struct InlineComponent {
92 pub start: usize,
93 pub end: usize,
94 pub name: Arc<str>,
95 #[serde(skip_serializing_if = "Option::is_none")]
96 pub expression: Option<Expression>,
97 pub attributes: Box<[Attribute]>,
98 pub children: Box<[Node]>,
99}
100
101#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
102#[serde(untagged)]
103pub enum ElementTag {
104 String(Arc<str>),
105 Expression(Expression),
106}
107
108#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
109#[serde(tag = "type")]
110pub enum Attribute {
111 Attribute(NamedAttribute),
112 Spread(SpreadAttribute),
113 Transition(TransitionDirective),
114 StyleDirective(StyleDirective),
115 Let(DirectiveAttribute),
116 Action(DirectiveAttribute),
117 Binding(DirectiveAttribute),
118 Class(DirectiveAttribute),
119 Animation(DirectiveAttribute),
120 EventHandler(DirectiveAttribute),
121}
122
123#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
124pub struct NamedAttribute {
125 pub start: usize,
126 pub end: usize,
127 pub name: Arc<str>,
128 pub name_loc: SourceRange,
129 pub value: AttributeValueKind,
130}
131
132#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
133pub struct SpreadAttribute {
134 pub start: usize,
135 pub end: usize,
136 pub expression: Expression,
137}
138
139#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
140pub struct StyleDirective {
141 pub start: usize,
142 pub end: usize,
143 pub name: Arc<str>,
144 pub name_loc: SourceRange,
145 pub modifiers: Box<[Arc<str>]>,
146 pub value: AttributeValueKind,
147}
148
149#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
150pub struct DirectiveAttribute {
151 pub start: usize,
152 pub end: usize,
153 pub name: Arc<str>,
154 pub name_loc: SourceRange,
155 pub expression: Option<Expression>,
156 pub modifiers: Box<[Arc<str>]>,
157}
158
159#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
160pub struct TransitionDirective {
161 pub start: usize,
162 pub end: usize,
163 pub name: Arc<str>,
164 pub name_loc: SourceRange,
165 pub expression: Option<Expression>,
166 pub modifiers: Box<[Arc<str>]>,
167 pub intro: bool,
168 pub outro: bool,
169}
170
171#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
172#[serde(tag = "type")]
173pub enum AttributeValue {
174 Text(Text),
175 MustacheTag(MustacheTag),
176 AttributeShorthand(AttributeShorthand),
177}
178
179#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
180#[serde(untagged)]
181pub enum AttributeValueKind {
182 Boolean(bool),
183 Values(Box<[AttributeValue]>),
184}
185
186#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
187pub struct MustacheTag {
188 pub start: usize,
189 pub end: usize,
190 pub expression: Expression,
191}
192
193#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
194pub struct RawMustacheTag {
195 pub start: usize,
196 pub end: usize,
197 pub expression: Expression,
198}
199
200#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
201pub struct DebugTag {
202 pub start: usize,
203 pub end: usize,
204 pub arguments: Box<[Expression]>,
205 pub identifiers: Box<[IdentifierExpression]>,
206}
207
208#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
209pub struct AttributeShorthand {
210 pub start: usize,
211 pub end: usize,
212 pub expression: Expression,
213}
214
215#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
221#[serde(untagged)]
222pub enum Expression {
223 Identifier(IdentifierExpression),
224 Literal(LiteralExpression),
225 CallExpression(CallExpressionNode),
226 BinaryExpression(BinaryExpressionNode),
227 #[serde(skip)]
231 OtherJson(OtherExpressionJson),
232 Other(modern::Expression),
234}
235
236#[derive(Debug, Clone, PartialEq, Eq)]
239pub struct OtherExpressionJson {
240 pub json: Arc<str>,
241}
242
243impl serde::Serialize for Expression {
244 fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
245 match self {
246 Self::Identifier(v) => v.serialize(serializer),
247 Self::Literal(v) => v.serialize(serializer),
248 Self::CallExpression(v) => v.serialize(serializer),
249 Self::BinaryExpression(v) => v.serialize(serializer),
250 Self::OtherJson(v) => {
251 let raw = serde_json::value::RawValue::from_string(v.json.to_string())
252 .map_err(serde::ser::Error::custom)?;
253 raw.serialize(serializer)
254 }
255 Self::Other(v) => v.serialize(serializer),
256 }
257 }
258}
259
260#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
261pub struct IdentifierExpression {
262 pub r#type: IdentifierType,
263 pub start: usize,
264 pub end: usize,
265 #[serde(skip_serializing_if = "Option::is_none")]
266 pub loc: Option<ExpressionLoc>,
267 pub name: Arc<str>,
268}
269
270#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
272pub enum IdentifierType {
273 Identifier,
274}
275
276#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
277pub struct LiteralExpression {
278 pub r#type: LiteralType,
279 pub start: usize,
280 pub end: usize,
281 #[serde(skip_serializing_if = "Option::is_none")]
282 pub loc: Option<ExpressionLoc>,
283 pub value: LiteralValue,
284 pub raw: Arc<str>,
285}
286
287#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
289pub enum LiteralType {
290 Literal,
291}
292
293#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
294pub struct CallExpressionNode {
295 pub r#type: CallExpressionType,
296 pub start: usize,
297 pub end: usize,
298 #[serde(skip_serializing_if = "Option::is_none")]
299 pub loc: Option<ExpressionLoc>,
300 pub callee: Box<Expression>,
301 pub arguments: Box<[Expression]>,
302 pub optional: bool,
303}
304
305#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
307pub enum CallExpressionType {
308 CallExpression,
309}
310
311#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
312pub struct BinaryExpressionNode {
313 pub r#type: BinaryExpressionType,
314 pub start: usize,
315 pub end: usize,
316 #[serde(skip_serializing_if = "Option::is_none")]
317 pub loc: Option<ExpressionLoc>,
318 pub left: Box<Expression>,
319 pub operator: Arc<str>,
320 pub right: Box<Expression>,
321}
322
323#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
325pub enum BinaryExpressionType {
326 BinaryExpression,
327}
328
329#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
330pub struct Text {
331 pub start: usize,
332 pub end: usize,
333 #[serde(skip_serializing_if = "Option::is_none")]
334 pub raw: Option<Arc<str>>,
335 pub data: Arc<str>,
336}
337
338#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
339pub struct Comment {
340 pub start: usize,
341 pub end: usize,
342 pub data: Arc<str>,
343 pub ignores: Box<[Arc<str>]>,
344}
345
346#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
347pub struct IfBlock {
348 pub start: usize,
349 pub end: usize,
350 pub expression: Expression,
351 pub children: Box<[Node]>,
352 #[serde(rename = "else", skip_serializing_if = "Option::is_none")]
353 pub else_block: Option<ElseBlock>,
354 #[serde(skip_serializing_if = "Option::is_none")]
355 pub elseif: Option<bool>,
356}
357
358#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
359pub struct EachBlock {
360 pub start: usize,
361 pub end: usize,
362 pub children: Box<[Node]>,
363 pub context: Option<Expression>,
364 pub expression: Expression,
365 #[serde(skip_serializing_if = "Option::is_none")]
366 pub index: Option<Arc<str>>,
367 #[serde(skip_serializing_if = "Option::is_none")]
368 pub key: Option<Expression>,
369 #[serde(rename = "else", skip_serializing_if = "Option::is_none")]
370 pub else_block: Option<ElseBlock>,
371}
372
373#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
374pub struct KeyBlock {
375 pub start: usize,
376 pub end: usize,
377 pub expression: Expression,
378 pub children: Box<[Node]>,
379}
380
381#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
382pub struct AwaitBlock {
383 pub start: usize,
384 pub end: usize,
385 pub expression: Expression,
386 pub value: Option<Expression>,
387 pub error: Option<Expression>,
388 pub pending: PendingBlock,
389 pub then: ThenBlock,
390 pub catch: CatchBlock,
391}
392
393#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
394pub struct SnippetBlock {
395 pub start: usize,
396 pub end: usize,
397 pub expression: Expression,
398 #[serde(rename = "typeParams", skip_serializing_if = "Option::is_none")]
399 pub type_params: Option<Arc<str>>,
400 pub parameters: Box<[Expression]>,
401 pub children: Box<[Node]>,
402 #[serde(skip_serializing_if = "Option::is_none")]
403 pub header_error: Option<SnippetHeaderError>,
404}
405
406#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
407pub struct PendingBlock {
408 pub r#type: PendingBlockType,
409 pub start: Option<usize>,
410 pub end: Option<usize>,
411 pub children: Box<[Node]>,
412 pub skip: bool,
413}
414
415#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
416pub struct ThenBlock {
417 pub r#type: ThenBlockType,
418 pub start: Option<usize>,
419 pub end: Option<usize>,
420 pub children: Box<[Node]>,
421 pub skip: bool,
422}
423
424#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
425pub struct CatchBlock {
426 pub r#type: CatchBlockType,
427 pub start: Option<usize>,
428 pub end: Option<usize>,
429 pub children: Box<[Node]>,
430 pub skip: bool,
431}
432
433#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
434pub enum PendingBlockType {
435 PendingBlock,
436}
437
438#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
439pub enum ThenBlockType {
440 ThenBlock,
441}
442
443#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
444pub enum CatchBlockType {
445 CatchBlock,
446}
447
448#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
449pub struct Style {
450 pub r#type: StyleType,
451 pub start: usize,
452 pub end: usize,
453 pub attributes: Box<[crate::ast::modern::Attribute]>,
454 pub children: Box<[StyleNode]>,
455 pub content: crate::ast::modern::CssContent,
456}
457
458#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
459pub enum StyleType {
460 Style,
461}
462
463#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
464#[serde(tag = "type")]
465pub enum StyleNode {
466 Rule(StyleRule),
467 Atrule(StyleAtrule),
468}
469
470#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
471pub struct StyleRule {
472 pub prelude: StyleSelectorList,
473 pub block: crate::ast::modern::CssBlock,
474 pub start: usize,
475 pub end: usize,
476}
477
478#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
479pub struct StyleAtrule {
480 pub start: usize,
481 pub end: usize,
482 pub name: Arc<str>,
483 pub prelude: Arc<str>,
484 pub block: Option<crate::ast::modern::CssBlock>,
485}
486
487#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
488pub struct StyleSelectorList {
489 pub r#type: crate::ast::modern::CssSelectorListType,
490 pub start: usize,
491 pub end: usize,
492 pub children: Box<[StyleSelector]>,
493}
494
495#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
496pub struct StyleSelector {
497 pub r#type: StyleSelectorType,
498 pub start: usize,
499 pub end: usize,
500 pub children: Box<[crate::ast::modern::CssSimpleSelector]>,
501}
502
503#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
504pub enum StyleSelectorType {
505 Selector,
506}
507
508#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
509pub struct ElseBlock {
510 pub r#type: ElseBlockType,
511 pub start: usize,
512 pub end: usize,
513 pub children: Box<[Node]>,
514}
515
516#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
517pub enum ElseBlockType {
518 ElseBlock,
519}
520
521#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
522#[serde(tag = "type")]
523pub enum Node {
524 Element(Element),
525 Head(Head),
526 InlineComponent(InlineComponent),
527 Text(Text),
528 MustacheTag(MustacheTag),
529 RawMustacheTag(RawMustacheTag),
530 DebugTag(DebugTag),
531 Comment(Comment),
532 IfBlock(IfBlock),
533 EachBlock(EachBlock),
534 KeyBlock(KeyBlock),
535 AwaitBlock(AwaitBlock),
536 SnippetBlock(SnippetBlock),
537}
538
539pub fn directive_attribute_from_modern(
540 source: &str,
541 directive: modern::DirectiveAttribute,
542) -> DirectiveAttribute {
543 DirectiveAttribute {
544 start: directive.start,
545 end: directive.end,
546 name: directive.name,
547 name_loc: directive.name_loc,
548 expression: Some(legacy_expression_from_modern_or_empty(
549 source,
550 directive.expression,
551 )),
552 modifiers: directive.modifiers,
553 }
554}
555
556pub fn style_directive_from_modern(
557 source: &str,
558 directive: modern::StyleDirective,
559) -> StyleDirective {
560 StyleDirective {
561 start: directive.start,
562 end: directive.end,
563 name: directive.name,
564 name_loc: directive.name_loc,
565 modifiers: directive.modifiers,
566 value: attribute_value_kind_from_modern(source, directive.value),
567 }
568}
569
570pub fn transition_directive_from_modern(
571 source: &str,
572 directive: modern::TransitionDirective,
573) -> TransitionDirective {
574 TransitionDirective {
575 start: directive.start,
576 end: directive.end,
577 name: directive.name,
578 name_loc: directive.name_loc,
579 expression: Some(legacy_expression_from_modern_or_empty(
580 source,
581 directive.expression,
582 )),
583 modifiers: directive.modifiers,
584 intro: directive.intro,
585 outro: directive.outro,
586 }
587}
588
589pub fn attribute_value_kind_from_modern(
590 source: &str,
591 value: modern::AttributeValueKind,
592) -> AttributeValueKind {
593 match value {
594 modern::AttributeValueKind::Boolean(flag) => AttributeValueKind::Boolean(flag),
595 modern::AttributeValueKind::Values(values) => AttributeValueKind::Values(
596 values
597 .into_vec()
598 .into_iter()
599 .map(|v| attribute_value_from_modern(source, v))
600 .collect::<Vec<_>>()
601 .into_boxed_slice(),
602 ),
603 modern::AttributeValueKind::ExpressionTag(tag) => AttributeValueKind::Values(
604 vec![AttributeValue::MustacheTag(MustacheTag {
605 start: tag.start,
606 end: tag.end,
607 expression: legacy_expression_from_modern_or_empty(source, tag.expression),
608 })]
609 .into_boxed_slice(),
610 ),
611 }
612}
613
614pub fn attribute_value_from_modern(
615 source: &str,
616 value: modern::AttributeValue,
617) -> AttributeValue {
618 match value {
619 modern::AttributeValue::Text(text) => AttributeValue::Text(Text {
620 start: text.start,
621 end: text.end,
622 raw: Some(text.raw),
623 data: text.data,
624 }),
625 modern::AttributeValue::ExpressionTag(tag) => AttributeValue::MustacheTag(MustacheTag {
626 start: tag.start,
627 end: tag.end,
628 expression: legacy_expression_from_modern_or_empty(source, tag.expression),
629 }),
630 }
631}
632
633pub fn script_from_modern(source: &str, script: modern::Script) -> Script {
634 let content_json = if !source.is_empty() {
635 Some(Arc::from(script.content.to_estree_json(source, script.content_start, script.end)))
636 } else {
637 None
638 };
639 Script {
640 r#type: script.r#type,
641 start: script.start,
642 end: script.end,
643 context: script.context,
644 content_start: script.content_start,
645 content_end: script.content_end,
646 content: script.content,
647 content_json,
648 }
649}
650
651fn legacy_expression_from_modern_or_empty(source: &str, expression: modern::Expression) -> Expression {
652 if let Some(converted) = legacy_expression_from_modern_expression(source, expression.clone(), false) {
653 return converted;
654 }
655 let (start, end) = modern_expression_bounds(&expression).unwrap_or((0, 0));
656 legacy_empty_identifier_expression(start, end, None)
657}
658
659fn modern_expression_bounds(expression: &modern::Expression) -> Option<(usize, usize)> {
660 Some((expression.start, expression.end))
661}
662
663fn legacy_empty_identifier_expression(
664 start: usize,
665 end: usize,
666 loc: Option<ExpressionLoc>,
667) -> Expression {
668 Expression::Identifier(IdentifierExpression {
669 r#type: IdentifierType::Identifier,
670 name: Arc::from(""),
671 start,
672 end,
673 loc,
674 })
675}
676
677#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
678pub struct Root {
679 pub html: Fragment,
680 #[serde(skip_serializing_if = "Option::is_none")]
681 pub css: Option<Style>,
682 #[serde(skip_serializing_if = "Option::is_none")]
683 pub instance: Option<Script>,
684 #[serde(skip_serializing_if = "Option::is_none")]
685 pub module: Option<Script>,
686 #[serde(rename = "_comments", skip_serializing_if = "Option::is_none")]
687 pub comments: Option<Box<[ProgramComment]>>,
688}
689
690macro_rules! impl_span_for_struct {
691 ($($ty:ty),* $(,)?) => {
692 $(
693 impl Span for $ty {
694 fn start(&self) -> usize {
695 self.start
696 }
697
698 fn end(&self) -> usize {
699 self.end
700 }
701 }
702 )*
703 };
704}
705
706impl_span_for_struct!(
707 Script,
708 ProgramComment,
709 Element,
710 Head,
711 InlineComponent,
712 NamedAttribute,
713 SpreadAttribute,
714 StyleDirective,
715 DirectiveAttribute,
716 TransitionDirective,
717 MustacheTag,
718 RawMustacheTag,
719 DebugTag,
720 AttributeShorthand,
721 IdentifierExpression,
722 LiteralExpression,
723 CallExpressionNode,
724 BinaryExpressionNode,
725 Text,
726 Comment,
727 IfBlock,
728 EachBlock,
729 KeyBlock,
730 AwaitBlock,
731 SnippetBlock,
732 Style,
733 StyleRule,
734 StyleAtrule,
735 StyleSelectorList,
736 StyleSelector,
737 ElseBlock
738);
739
740impl Span for Node {
741 fn start(&self) -> usize {
742 match self {
743 Node::Element(node) => node.start,
744 Node::Head(node) => node.start,
745 Node::InlineComponent(node) => node.start,
746 Node::Text(node) => node.start,
747 Node::MustacheTag(node) => node.start,
748 Node::RawMustacheTag(node) => node.start,
749 Node::DebugTag(node) => node.start,
750 Node::Comment(node) => node.start,
751 Node::IfBlock(node) => node.start,
752 Node::EachBlock(node) => node.start,
753 Node::KeyBlock(node) => node.start,
754 Node::AwaitBlock(node) => node.start,
755 Node::SnippetBlock(node) => node.start,
756 }
757 }
758
759 fn end(&self) -> usize {
760 match self {
761 Node::Element(node) => node.end,
762 Node::Head(node) => node.end,
763 Node::InlineComponent(node) => node.end,
764 Node::Text(node) => node.end,
765 Node::MustacheTag(node) => node.end,
766 Node::RawMustacheTag(node) => node.end,
767 Node::DebugTag(node) => node.end,
768 Node::Comment(node) => node.end,
769 Node::IfBlock(node) => node.end,
770 Node::EachBlock(node) => node.end,
771 Node::KeyBlock(node) => node.end,
772 Node::AwaitBlock(node) => node.end,
773 Node::SnippetBlock(node) => node.end,
774 }
775 }
776}