Skip to main content

svelte_syntax/ast/
legacy.rs

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    /// Pre-serialized ESTree JSON for the content Program AST.
28    #[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/// Legacy expression representation.
216///
217/// Typed variants exist for the handful of expression shapes that legacy tests
218/// and consumers inspect structurally. All other expression types are
219/// represented via `Other`, which wraps the modern `Expression` (OXC-backed).
220#[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    /// Any expression type not covered above.
228    /// Stores a pre-serialized JSON string (with `loc` fields injected)
229    /// so that serialization is self-contained.
230    #[serde(skip)]
231    OtherJson(OtherExpressionJson),
232    /// Fallback for deserialization — wraps the modern Expression directly.
233    Other(modern::Expression),
234}
235
236/// Pre-serialized ESTree JSON for expression types not covered by typed variants.
237/// The JSON string already contains `loc` fields computed from source at construction time.
238#[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/// Serde discriminant for `"type": "Identifier"`.
271#[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/// Serde discriminant for `"type": "Literal"`.
288#[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/// Serde discriminant for `"type": "CallExpression"`.
306#[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/// Serde discriminant for `"type": "BinaryExpression"`.
324#[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}