1use std::ops::ControlFlow;
2use std::sync::Arc;
3
4use oxc_ast::ast::{
5 BindingIdentifier, BindingPattern, Expression as OxcExpression, FormalParameter,
6 FormalParameterRest, Program as OxcProgram, Statement as OxcStatement,
7 VariableDeclaration as OxcVariableDeclaration,
8};
9use oxc_span::GetSpan;
10use serde::{Deserialize, Serialize, ser::SerializeMap};
11
12use crate::ast::common::Span;
13pub use crate::ast::common::{
14 AttrError, AttrErrorKind, AttributeValueSyntax, DirectiveValueSyntax,
15 FragmentType, LiteralValue, Loc, SourceRange, ParseError, Position, RootCommentType,
16 ScriptContext, ScriptType, SnippetHeaderError, SnippetHeaderErrorKind,
17};
18use crate::js::{JsExpression, JsParameters, JsPattern, JsProgram};
19
20fn empty_parsed_js_program() -> Arc<JsProgram> {
21 Arc::new(JsProgram::parse("", oxc_span::SourceType::mjs()))
22}
23
24#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
26pub enum RootType {
27 Root,
28}
29
30#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
31pub struct Fragment {
32 pub r#type: FragmentType,
33 pub nodes: Box<[Node]>,
34}
35
36impl Fragment {
37 pub fn empty() -> Self {
38 Self {
39 r#type: FragmentType::Fragment,
40 nodes: Box::new([]),
41 }
42 }
43}
44
45impl Default for Fragment {
46 fn default() -> Self {
47 Self::empty()
48 }
49}
50
51pub enum Search<T> {
52 Continue,
53 Skip,
54 Found(T),
55}
56
57#[derive(Clone, Copy)]
58pub enum Entry<'a> {
59 Node(&'a Node),
60 IfBlock(&'a IfBlock),
61}
62
63impl<'a> Entry<'a> {
64 pub fn as_node(self) -> Option<&'a Node> {
65 match self {
66 Self::Node(node) => Some(node),
67 Self::IfBlock(_) => None,
68 }
69 }
70
71 pub fn as_if_block(self) -> Option<&'a IfBlock> {
72 match self {
73 Self::Node(Node::IfBlock(block)) | Self::IfBlock(block) => Some(block),
74 Self::Node(_) => None,
75 }
76 }
77}
78
79impl Fragment {
80 pub fn walk<'a, T, S, E, L>(&'a self, state: &mut S, enter: E, leave: L) -> Option<T>
82 where
83 E: FnMut(Entry<'a>, &mut S) -> Search<T>,
84 L: FnMut(Entry<'a>, &mut S),
85 {
86 fn walk_fragment<'a, T, S, E, L>(
87 fragment: &'a Fragment,
88 state: &mut S,
89 enter: &mut E,
90 leave: &mut L,
91 ) -> Option<T>
92 where
93 E: FnMut(Entry<'a>, &mut S) -> Search<T>,
94 L: FnMut(Entry<'a>, &mut S),
95 {
96 for node in fragment.nodes.iter() {
97 if let Some(found) = walk_node(node, state, enter, leave) {
98 return Some(found);
99 }
100 }
101 None
102 }
103
104 fn walk_entry<'a, T, S, E, L>(
105 entry: Entry<'a>,
106 state: &mut S,
107 enter: &mut E,
108 leave: &mut L,
109 ) -> Option<T>
110 where
111 E: FnMut(Entry<'a>, &mut S) -> Search<T>,
112 L: FnMut(Entry<'a>, &mut S),
113 {
114 match enter(entry, state) {
115 Search::Found(found) => return Some(found),
116 Search::Skip => {
117 leave(entry, state);
118 return None;
119 }
120 Search::Continue => {}
121 }
122
123 let found = match entry {
124 Entry::Node(node) => walk_node_children(node, state, enter, leave),
125 Entry::IfBlock(block) => walk_if_block_children(block, state, enter, leave),
126 };
127 if found.is_none() {
128 leave(entry, state);
129 }
130 found
131 }
132
133 fn walk_alternate<'a, T, S, E, L>(
134 alternate: &'a Alternate,
135 state: &mut S,
136 enter: &mut E,
137 leave: &mut L,
138 ) -> Option<T>
139 where
140 E: FnMut(Entry<'a>, &mut S) -> Search<T>,
141 L: FnMut(Entry<'a>, &mut S),
142 {
143 match alternate {
144 Alternate::Fragment(fragment) => walk_fragment(fragment, state, enter, leave),
145 Alternate::IfBlock(block) => walk_entry(Entry::IfBlock(block), state, enter, leave),
146 }
147 }
148
149 fn walk_if_block_children<'a, T, S, E, L>(
150 block: &'a IfBlock,
151 state: &mut S,
152 enter: &mut E,
153 leave: &mut L,
154 ) -> Option<T>
155 where
156 E: FnMut(Entry<'a>, &mut S) -> Search<T>,
157 L: FnMut(Entry<'a>, &mut S),
158 {
159 walk_fragment(&block.consequent, state, enter, leave).or_else(|| {
160 block
161 .alternate
162 .as_deref()
163 .and_then(|alternate| walk_alternate(alternate, state, enter, leave))
164 })
165 }
166
167 fn walk_node<'a, T, S, E, L>(
168 node: &'a Node,
169 state: &mut S,
170 enter: &mut E,
171 leave: &mut L,
172 ) -> Option<T>
173 where
174 E: FnMut(Entry<'a>, &mut S) -> Search<T>,
175 L: FnMut(Entry<'a>, &mut S),
176 {
177 walk_entry(Entry::Node(node), state, enter, leave)
178 }
179
180 fn walk_node_children<'a, T, S, E, L>(
181 node: &'a Node,
182 state: &mut S,
183 enter: &mut E,
184 leave: &mut L,
185 ) -> Option<T>
186 where
187 E: FnMut(Entry<'a>, &mut S) -> Search<T>,
188 L: FnMut(Entry<'a>, &mut S),
189 {
190 match node {
191 Node::IfBlock(block) => walk_if_block_children(block, state, enter, leave),
192 Node::EachBlock(block) => {
193 walk_fragment(&block.body, state, enter, leave).or_else(|| {
194 block
195 .fallback
196 .as_ref()
197 .and_then(|fragment| walk_fragment(fragment, state, enter, leave))
198 })
199 }
200 Node::KeyBlock(block) => walk_fragment(&block.fragment, state, enter, leave),
201 Node::AwaitBlock(block) => {
202 for fragment in [
203 block.pending.as_ref(),
204 block.then.as_ref(),
205 block.catch.as_ref(),
206 ] {
207 if let Some(fragment) = fragment
208 && let Some(found) = walk_fragment(fragment, state, enter, leave)
209 {
210 return Some(found);
211 }
212 }
213 None
214 }
215 Node::SnippetBlock(block) => walk_fragment(&block.body, state, enter, leave),
216 _ => node
217 .as_element()
218 .and_then(|element| walk_fragment(element.fragment(), state, enter, leave)),
219 }
220 }
221
222 let mut enter = enter;
223 let mut leave = leave;
224 walk_fragment(self, state, &mut enter, &mut leave)
225 }
226
227 pub fn search<'a, T, F>(&'a self, visit: F) -> Option<T>
228 where
229 F: FnMut(Entry<'a>, &mut ()) -> Search<T>,
230 {
231 self.walk(&mut (), visit, |_, _| {})
232 }
233
234 pub fn find_map<'a, T, F>(&'a self, mut find: F) -> Option<T>
235 where
236 F: FnMut(Entry<'a>) -> Option<T>,
237 {
238 self.search(|entry, _| match find(entry) {
239 Some(found) => Search::Found(found),
240 None => Search::Continue,
241 })
242 }
243}
244
245#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
246pub struct Script {
247 pub r#type: ScriptType,
248 pub start: usize,
249 pub end: usize,
250 #[serde(skip_serializing, default)]
252 pub content_start: usize,
253 #[serde(skip_serializing, default)]
254 pub content_end: usize,
255 pub context: ScriptContext,
256 #[serde(
257 skip_serializing,
258 skip_deserializing,
259 default = "empty_parsed_js_program"
260 )]
261 pub content: Arc<JsProgram>,
262 pub attributes: Box<[Attribute]>,
263}
264
265impl Script {
266 pub fn parsed_program(&self) -> &JsProgram {
267 &self.content
268 }
269
270 pub fn oxc_program(&self) -> &OxcProgram<'_> {
271 self.parsed_program().program()
272 }
273}
274
275#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
276pub struct EachBlock {
277 pub start: usize,
278 pub end: usize,
279 pub expression: Expression,
280 pub body: Fragment,
281 #[serde(skip_serializing, default)]
282 pub has_as_clause: bool,
283 #[serde(skip_serializing, default)]
284 pub invalid_key_without_as: bool,
285 pub context: Option<Expression>,
286 #[serde(skip_serializing, default)]
287 pub context_error: Option<ParseError>,
288 #[serde(skip_serializing_if = "Option::is_none")]
289 pub index: Option<Arc<str>>,
290 #[serde(skip_serializing_if = "Option::is_none")]
291 pub key: Option<Expression>,
292 #[serde(skip_serializing_if = "Option::is_none")]
293 pub fallback: Option<Fragment>,
294}
295
296#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
297pub struct KeyBlock {
298 pub start: usize,
299 pub end: usize,
300 pub expression: Expression,
301 pub fragment: Fragment,
302}
303
304#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
305pub struct AwaitBlock {
306 pub start: usize,
307 pub end: usize,
308 pub expression: Expression,
309 pub value: Option<Expression>,
310 pub error: Option<Expression>,
311 pub pending: Option<Fragment>,
312 pub then: Option<Fragment>,
313 pub catch: Option<Fragment>,
314}
315
316#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
317pub struct SnippetBlock {
318 pub start: usize,
319 pub end: usize,
320 pub expression: Expression,
321 #[serde(rename = "typeParams", skip_serializing_if = "Option::is_none")]
322 pub type_params: Option<Arc<str>>,
323 pub parameters: Box<[Expression]>,
324 pub body: Fragment,
325 #[serde(skip_serializing_if = "Option::is_none")]
326 pub header_error: Option<SnippetHeaderError>,
327}
328
329#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
330pub struct RenderTag {
331 pub start: usize,
332 pub end: usize,
333 pub expression: Expression,
334}
335
336#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
337pub struct HtmlTag {
338 pub start: usize,
339 pub end: usize,
340 pub expression: Expression,
341}
342
343#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
344pub struct ConstTag {
345 pub start: usize,
346 pub end: usize,
347 pub declaration: Expression,
348}
349
350#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
351pub struct DebugTag {
352 pub start: usize,
353 pub end: usize,
354 pub arguments: Box<[Expression]>,
355 pub identifiers: Box<[Identifier]>,
356}
357
358#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
359pub struct ExpressionTag {
360 pub r#type: ExpressionTagType,
361 pub start: usize,
362 pub end: usize,
363 pub expression: Expression,
364}
365
366#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
368pub enum ExpressionTagType {
369 ExpressionTag,
370}
371
372#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
373pub struct Comment {
374 pub start: usize,
375 pub end: usize,
376 pub data: Arc<str>,
377}
378
379#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
380pub struct RegularElement {
381 pub start: usize,
382 pub end: usize,
383 pub name: Arc<str>,
384 pub name_loc: SourceRange,
385 #[serde(skip_serializing, default)]
386 pub self_closing: bool,
387 #[serde(skip_serializing, default)]
388 pub has_end_tag: bool,
389 pub attributes: Box<[Attribute]>,
390 pub fragment: Fragment,
391}
392
393#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
394pub struct Component {
395 pub start: usize,
396 pub end: usize,
397 pub name: Arc<str>,
398 pub name_loc: SourceRange,
399 pub attributes: Box<[Attribute]>,
400 pub fragment: Fragment,
401}
402
403#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
404pub struct SlotElement {
405 pub start: usize,
406 pub end: usize,
407 pub name: Arc<str>,
408 pub name_loc: SourceRange,
409 pub attributes: Box<[Attribute]>,
410 pub fragment: Fragment,
411}
412
413#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
414pub struct SvelteHead {
415 pub start: usize,
416 pub end: usize,
417 pub name: Arc<str>,
418 pub name_loc: SourceRange,
419 pub attributes: Box<[Attribute]>,
420 pub fragment: Fragment,
421}
422
423#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
424pub struct SvelteBody {
425 pub start: usize,
426 pub end: usize,
427 pub name: Arc<str>,
428 pub name_loc: SourceRange,
429 pub attributes: Box<[Attribute]>,
430 pub fragment: Fragment,
431}
432
433#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
434pub struct SvelteWindow {
435 pub start: usize,
436 pub end: usize,
437 pub name: Arc<str>,
438 pub name_loc: SourceRange,
439 pub attributes: Box<[Attribute]>,
440 pub fragment: Fragment,
441}
442
443#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
444pub struct SvelteDocument {
445 pub start: usize,
446 pub end: usize,
447 pub name: Arc<str>,
448 pub name_loc: SourceRange,
449 pub attributes: Box<[Attribute]>,
450 pub fragment: Fragment,
451}
452
453#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
454pub struct SvelteComponent {
455 pub start: usize,
456 pub end: usize,
457 pub name: Arc<str>,
458 pub name_loc: SourceRange,
459 pub attributes: Box<[Attribute]>,
460 pub fragment: Fragment,
461 #[serde(skip_serializing_if = "Option::is_none")]
462 pub expression: Option<Expression>,
463}
464
465#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
466pub struct SvelteElement {
467 pub start: usize,
468 pub end: usize,
469 pub name: Arc<str>,
470 pub name_loc: SourceRange,
471 pub attributes: Box<[Attribute]>,
472 pub fragment: Fragment,
473 #[serde(skip_serializing_if = "Option::is_none")]
474 pub expression: Option<Expression>,
475}
476
477#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
478pub struct SvelteSelf {
479 pub start: usize,
480 pub end: usize,
481 pub name: Arc<str>,
482 pub name_loc: SourceRange,
483 pub attributes: Box<[Attribute]>,
484 pub fragment: Fragment,
485}
486
487#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
488pub struct SvelteFragment {
489 pub start: usize,
490 pub end: usize,
491 pub name: Arc<str>,
492 pub name_loc: SourceRange,
493 pub attributes: Box<[Attribute]>,
494 pub fragment: Fragment,
495}
496
497#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
498pub struct SvelteBoundary {
499 pub start: usize,
500 pub end: usize,
501 pub name: Arc<str>,
502 pub name_loc: SourceRange,
503 pub attributes: Box<[Attribute]>,
504 pub fragment: Fragment,
505}
506
507#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
508pub struct TitleElement {
509 pub start: usize,
510 pub end: usize,
511 pub name: Arc<str>,
512 pub name_loc: SourceRange,
513 pub attributes: Box<[Attribute]>,
514 pub fragment: Fragment,
515}
516
517#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
518#[serde(tag = "type")]
519pub enum Attribute {
520 Attribute(NamedAttribute),
521 SpreadAttribute(SpreadAttribute),
522 BindDirective(DirectiveAttribute),
523 OnDirective(DirectiveAttribute),
524 ClassDirective(DirectiveAttribute),
525 LetDirective(DirectiveAttribute),
526 StyleDirective(StyleDirective),
527 TransitionDirective(TransitionDirective),
528 AnimateDirective(DirectiveAttribute),
529 UseDirective(DirectiveAttribute),
530 AttachTag(AttachTag),
531}
532
533#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
534pub struct SpreadAttribute {
535 pub start: usize,
536 pub end: usize,
537 pub expression: Expression,
538}
539
540#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
541pub struct NamedAttribute {
542 pub start: usize,
543 pub end: usize,
544 pub name: Arc<str>,
545 pub name_loc: SourceRange,
546 pub value: AttributeValueKind,
547 #[serde(skip_serializing, default)]
548 pub value_syntax: AttributeValueSyntax,
549 #[serde(skip_serializing, default)]
550 pub error: Option<AttrError>,
551}
552
553#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
554#[serde(untagged)]
555pub enum AttributeValueKind {
556 Boolean(bool),
557 Values(Box<[AttributeValue]>),
558 ExpressionTag(ExpressionTag),
559}
560
561#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
562#[serde(tag = "type")]
563pub enum AttributeValue {
564 Text(Text),
565 ExpressionTag(ExpressionTag),
566}
567
568#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
569pub struct DirectiveAttribute {
570 pub start: usize,
571 pub end: usize,
572 pub name: Arc<str>,
573 pub name_loc: SourceRange,
574 pub expression: Expression,
575 pub modifiers: Box<[Arc<str>]>,
576 #[serde(skip_serializing, default)]
577 pub value_syntax: DirectiveValueSyntax,
578 #[serde(skip_serializing, default)]
579 pub value_start: usize,
580}
581
582#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
583pub struct StyleDirective {
584 pub start: usize,
585 pub end: usize,
586 pub name: Arc<str>,
587 pub name_loc: SourceRange,
588 pub modifiers: Box<[Arc<str>]>,
589 pub value: AttributeValueKind,
590 #[serde(skip_serializing, default)]
591 pub value_syntax: AttributeValueSyntax,
592}
593
594#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
595pub struct TransitionDirective {
596 pub start: usize,
597 pub end: usize,
598 pub name: Arc<str>,
599 pub name_loc: SourceRange,
600 pub expression: Expression,
601 pub modifiers: Box<[Arc<str>]>,
602 pub intro: bool,
603 pub outro: bool,
604 #[serde(skip_serializing, default)]
605 pub value_syntax: DirectiveValueSyntax,
606 #[serde(skip_serializing, default)]
607 pub value_start: usize,
608}
609
610#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
611pub struct AttachTag {
612 pub start: usize,
613 pub end: usize,
614 pub expression: Expression,
615}
616
617#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
618pub struct IfBlock {
619 pub elseif: bool,
620 pub start: usize,
621 pub end: usize,
622 pub test: Expression,
623 pub consequent: Fragment,
624 pub alternate: Option<Box<Alternate>>,
625}
626
627#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
628#[serde(untagged)]
629pub enum Alternate {
630 Fragment(Fragment),
631 IfBlock(IfBlock),
632}
633
634#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize)]
635pub struct ExpressionSyntax {
636 #[serde(skip_serializing, default)]
637 pub parens: u16,
638}
639
640#[derive(Debug, Clone, PartialEq, Eq)]
641pub enum JsNodeHandle {
642 Expression(Arc<JsExpression>),
643 SequenceItem {
644 root: Arc<JsExpression>,
645 index: usize,
646 },
647 Pattern(Arc<JsPattern>),
648 ParameterItem {
649 parameters: Arc<JsParameters>,
650 index: usize,
651 },
652 RestParameter(Arc<JsParameters>),
653 StatementInProgram {
654 program: Arc<JsProgram>,
655 index: usize,
656 },
657}
658
659#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
660pub struct Expression {
661 pub start: usize,
662 pub end: usize,
663 #[serde(skip_serializing, default)]
664 pub syntax: ExpressionSyntax,
665 #[serde(skip_serializing, skip_deserializing, default)]
666 pub node: Option<JsNodeHandle>,
667}
668
669impl Expression {
670 pub fn empty(start: usize, end: usize) -> Self {
671 Self {
672 start,
673 end,
674 syntax: Default::default(),
675 node: None,
676 }
677 }
678
679 pub fn is_empty(&self) -> bool {
681 self.node.is_none() && self.start == self.end
682 }
683
684 pub fn from_expression(parsed: Arc<JsExpression>, start: usize, end: usize) -> Self {
685 Self {
686 start,
687 end,
688 syntax: Default::default(),
689 node: Some(JsNodeHandle::Expression(parsed)),
690 }
691 }
692
693 pub fn from_sequence_item(
694 root: Arc<JsExpression>,
695 index: usize,
696 start: usize,
697 end: usize,
698 ) -> Self {
699 Self {
700 start,
701 end,
702 syntax: Default::default(),
703 node: Some(JsNodeHandle::SequenceItem { root, index }),
704 }
705 }
706
707 pub fn from_pattern(parsed: Arc<JsPattern>, start: usize, end: usize) -> Self {
708 Self {
709 start,
710 end,
711 syntax: Default::default(),
712 node: Some(JsNodeHandle::Pattern(parsed)),
713 }
714 }
715
716 pub fn from_parameter_item(
717 parameters: Arc<JsParameters>,
718 index: usize,
719 start: usize,
720 end: usize,
721 ) -> Self {
722 Self {
723 start,
724 end,
725 syntax: Default::default(),
726 node: Some(JsNodeHandle::ParameterItem { parameters, index }),
727 }
728 }
729
730 pub fn from_rest_parameter(parameters: Arc<JsParameters>, start: usize, end: usize) -> Self {
731 Self {
732 start,
733 end,
734 syntax: Default::default(),
735 node: Some(JsNodeHandle::RestParameter(parameters)),
736 }
737 }
738
739 pub fn from_statement(
740 program: Arc<JsProgram>,
741 index: usize,
742 start: usize,
743 end: usize,
744 ) -> Self {
745 Self {
746 start,
747 end,
748 syntax: Default::default(),
749 node: Some(JsNodeHandle::StatementInProgram { program, index }),
750 }
751 }
752
753 pub fn parens(&self) -> u16 {
754 self.syntax.parens.max(self.outer_parens())
755 }
756
757 pub fn is_parenthesized(&self) -> bool {
758 self.parens() != 0
759 }
760
761 fn outer_parens(&self) -> u16 {
762 let mut parens = 0u16;
763 let mut current = match &self.node {
764 Some(JsNodeHandle::Expression(parsed)) => parsed.expression(),
765 Some(JsNodeHandle::SequenceItem { root, .. }) => root.expression(),
766 Some(JsNodeHandle::Pattern(_))
767 | Some(JsNodeHandle::ParameterItem { .. })
768 | Some(JsNodeHandle::RestParameter(_))
769 | Some(JsNodeHandle::StatementInProgram { .. })
770 | None => return 0,
771 };
772
773 while let OxcExpression::ParenthesizedExpression(parenthesized) = current {
774 parens = parens.saturating_add(1);
775 current = &parenthesized.expression;
776 }
777
778 parens
779 }
780
781 pub fn parsed(&self) -> Option<&JsExpression> {
782 match &self.node {
783 Some(JsNodeHandle::Expression(parsed)) => Some(parsed),
784 Some(JsNodeHandle::SequenceItem { root, .. }) => Some(root),
785 Some(JsNodeHandle::Pattern(_))
786 | Some(JsNodeHandle::ParameterItem { .. })
787 | Some(JsNodeHandle::RestParameter(_))
788 | Some(JsNodeHandle::StatementInProgram { .. })
789 | None => None,
790 }
791 }
792
793 pub fn oxc_expression_raw(&self) -> Option<&OxcExpression<'_>> {
794 match &self.node {
795 Some(JsNodeHandle::Expression(parsed)) => Some(parsed.expression()),
796 Some(JsNodeHandle::SequenceItem { root, index }) => {
797 let OxcExpression::SequenceExpression(sequence) = root.expression() else {
798 return None;
799 };
800 sequence.expressions.get(*index)
801 }
802 Some(JsNodeHandle::Pattern(_))
803 | Some(JsNodeHandle::ParameterItem { .. })
804 | Some(JsNodeHandle::RestParameter(_))
805 | Some(JsNodeHandle::StatementInProgram { .. })
806 | None => None,
807 }
808 }
809
810 pub fn oxc_expression(&self) -> Option<&OxcExpression<'_>> {
811 let mut expression = self.oxc_expression_raw()?;
812
813 while let OxcExpression::ParenthesizedExpression(parenthesized) = expression {
814 expression = &parenthesized.expression;
815 }
816
817 Some(expression)
818 }
819
820 pub fn oxc_pattern(&self) -> Option<&BindingPattern<'_>> {
821 match &self.node {
822 Some(JsNodeHandle::Pattern(parsed)) => Some(parsed.pattern()),
823 Some(JsNodeHandle::ParameterItem { parameters, index }) => {
824 Some(¶meters.parameter(*index)?.pattern)
825 }
826 Some(JsNodeHandle::RestParameter(parameters)) => {
827 Some(¶meters.rest_parameter()?.rest.argument)
828 }
829 _ => None,
830 }
831 }
832
833 pub fn oxc_parameter(&self) -> Option<&FormalParameter<'_>> {
834 match &self.node {
835 Some(JsNodeHandle::ParameterItem { parameters, index }) => parameters.parameter(*index),
836 _ => None,
837 }
838 }
839
840 pub fn oxc_rest_parameter(&self) -> Option<&FormalParameterRest<'_>> {
841 match &self.node {
842 Some(JsNodeHandle::RestParameter(parameters)) => parameters.rest_parameter(),
843 _ => None,
844 }
845 }
846
847 pub fn oxc_statement(&self) -> Option<&OxcStatement<'_>> {
848 match &self.node {
849 Some(JsNodeHandle::StatementInProgram { program, index }) => program.statement(*index),
850 _ => None,
851 }
852 }
853
854 pub fn oxc_variable_declaration(&self) -> Option<&OxcVariableDeclaration<'_>> {
855 match &self.node {
856 Some(JsNodeHandle::StatementInProgram { program, index }) => {
857 program.variable_declaration(*index)
858 }
859 _ => None,
860 }
861 }
862
863 pub fn is_rest_parameter(&self) -> bool {
864 matches!(self.node, Some(JsNodeHandle::RestParameter(_)))
865 }
866
867 pub fn source_snippet(&self) -> Option<&str> {
868 match &self.node {
869 Some(JsNodeHandle::Expression(parsed)) => Some(parsed.source()),
870 Some(JsNodeHandle::SequenceItem { root, index }) => {
871 let OxcExpression::SequenceExpression(sequence) = root.expression() else {
872 return None;
873 };
874 let node = sequence.expressions.get(*index)?;
875 root.source().get(node.span().start as usize..node.span().end as usize)
876 }
877 Some(JsNodeHandle::Pattern(parsed)) => Some(parsed.source()),
878 Some(JsNodeHandle::ParameterItem { parameters, index }) => {
879 let parameter = parameters.parameter(*index)?;
880 parameters
881 .source()
882 .get(parameter.span.start as usize - 1..parameter.span.end as usize - 1)
883 }
884 Some(JsNodeHandle::RestParameter(parameters)) => {
885 let parameter = parameters.rest_parameter()?;
886 parameters
887 .source()
888 .get(parameter.span.start as usize - 1..parameter.span.end as usize - 1)
889 }
890 Some(JsNodeHandle::StatementInProgram { program, index }) => program.statement_source(*index),
891 None => None,
892 }
893 }
894
895 pub fn identifier_name(&self) -> Option<Arc<str>> {
896 if let Some(identifier) = self
897 .oxc_expression()
898 .and_then(OxcExpression::get_identifier_reference)
899 {
900 return Some(Arc::from(identifier.name.as_str()));
901 }
902
903 match self.oxc_pattern()? {
904 BindingPattern::BindingIdentifier(identifier) => {
905 Some(Arc::from(identifier.name.as_str()))
906 }
907 _ => None,
908 }
909 }
910
911 pub fn literal_string(&self) -> Option<Arc<str>> {
912 match self.oxc_expression()? {
913 OxcExpression::StringLiteral(value) => Some(Arc::from(value.value.as_str())),
914 _ => None,
915 }
916 }
917
918 pub fn literal_bool(&self) -> Option<bool> {
919 match self.oxc_expression()? {
920 OxcExpression::BooleanLiteral(value) => Some(value.value),
921 _ => None,
922 }
923 }
924
925 pub fn binding_identifier(&self) -> Option<&BindingIdentifier<'_>> {
926 if let Some(declaration) = self.oxc_variable_declaration() {
927 let [declarator] = declaration.declarations.as_slice() else {
928 return None;
929 };
930 return declarator.id.get_binding_identifier();
931 }
932
933 match self.oxc_pattern()? {
934 BindingPattern::BindingIdentifier(identifier) => Some(identifier),
935 _ => None,
936 }
937 }
938}
939
940impl Span for Expression {
941 fn start(&self) -> usize {
942 self.start
943 }
944
945 fn end(&self) -> usize {
946 self.end
947 }
948}
949
950impl Serialize for Expression {
951 fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
952 if let Some(raw_json) = self.to_estree_json() {
953 let raw = serde_json::value::RawValue::from_string(raw_json)
955 .map_err(serde::ser::Error::custom)?;
956 raw.serialize(serializer)
957 } else {
958 let mut map = serializer.serialize_map(Some(2))?;
960 map.serialize_entry("start", &self.start)?;
961 map.serialize_entry("end", &self.end)?;
962 map.end()
963 }
964 }
965}
966
967impl Expression {
968 pub fn to_estree_json(&self) -> Option<String> {
974 let json = self.serialize_oxc_node()?;
975 let offset = self.oxc_span_offset();
976 if offset == 0 {
977 Some(json)
978 } else {
979 Some(adjust_estree_span_offsets(&json, offset))
980 }
981 }
982
983 fn serialize_oxc_node(&self) -> Option<String> {
985 use oxc_estree::{CompactJSSerializer, ESTree};
986
987 match &self.node {
988 Some(JsNodeHandle::Expression(parsed)) => {
989 let mut ser = CompactJSSerializer::new(false);
990 serialize_oxc_expression_unwrapped(parsed.expression(), &mut ser);
991 Some(ser.into_string())
992 }
993 Some(JsNodeHandle::SequenceItem { root, index }) => {
994 let OxcExpression::SequenceExpression(seq) = root.expression() else {
995 return None;
996 };
997 let expr = seq.expressions.get(*index)?;
998 let mut ser = CompactJSSerializer::new(false);
999 expr.serialize(&mut ser);
1000 Some(ser.into_string())
1001 }
1002 Some(JsNodeHandle::Pattern(parsed)) => {
1003 let mut ser = CompactJSSerializer::new(false);
1004 parsed.pattern().serialize(&mut ser);
1005 Some(ser.into_string())
1006 }
1007 Some(JsNodeHandle::ParameterItem { parameters, index }) => {
1008 let param = parameters.parameter(*index)?;
1009 let mut ser = CompactJSSerializer::new(false);
1010 param.serialize(&mut ser);
1011 Some(ser.into_string())
1012 }
1013 Some(JsNodeHandle::RestParameter(parameters)) => {
1014 let rest = parameters.rest_parameter()?;
1015 let mut ser = CompactJSSerializer::new(false);
1016 rest.serialize(&mut ser);
1017 Some(ser.into_string())
1018 }
1019 Some(JsNodeHandle::StatementInProgram { program, index }) => {
1020 let stmt = program.statement(*index)?;
1021 let mut ser = CompactJSSerializer::new(false);
1022 stmt.serialize(&mut ser);
1023 Some(ser.into_string())
1024 }
1025 None => None,
1026 }
1027 }
1028
1029 fn oxc_span_offset(&self) -> i64 {
1031 match &self.node {
1032 Some(JsNodeHandle::Expression(parsed)) => {
1033 self.start as i64 - parsed.expression().span().start as i64
1034 }
1035 Some(JsNodeHandle::SequenceItem { root, index }) => {
1036 if let OxcExpression::SequenceExpression(seq) = root.expression() {
1037 if let Some(expr) = seq.expressions.get(*index) {
1038 return self.start as i64 - expr.span().start as i64;
1039 }
1040 }
1041 0
1042 }
1043 Some(JsNodeHandle::Pattern(parsed)) => {
1044 self.start as i64 - parsed.pattern().span().start as i64
1045 }
1046 Some(JsNodeHandle::ParameterItem { parameters, index }) => {
1047 if let Some(param) = parameters.parameter(*index) {
1048 return self.start as i64 - param.span.start as i64;
1049 }
1050 0
1051 }
1052 Some(JsNodeHandle::RestParameter(parameters)) => {
1053 if let Some(rest) = parameters.rest_parameter() {
1054 return self.start as i64 - rest.span.start as i64;
1055 }
1056 0
1057 }
1058 Some(JsNodeHandle::StatementInProgram { program, index }) => {
1059 if let Some(stmt) = program.statement(*index) {
1060 return self.start as i64 - stmt.span().start as i64;
1061 }
1062 0
1063 }
1064 None => 0,
1065 }
1066 }
1067}
1068
1069fn serialize_oxc_expression_unwrapped(
1072 expr: &OxcExpression<'_>,
1073 ser: &mut oxc_estree::CompactJSSerializer,
1074) {
1075 use oxc_estree::ESTree;
1076 let mut inner = expr;
1077 while let OxcExpression::ParenthesizedExpression(paren) = inner {
1078 inner = &paren.expression;
1079 }
1080 inner.serialize(ser);
1081}
1082
1083fn adjust_estree_span_offsets(json: &str, offset: i64) -> String {
1089 let bytes = json.as_bytes();
1090 let len = bytes.len();
1091 let mut result = String::with_capacity(len + 64);
1092 let mut i = 0;
1093
1094 while i < len {
1095 let remaining = &bytes[i..];
1096
1097 let key_len = if remaining.starts_with(b"\"start\":") {
1098 8 } else if remaining.starts_with(b"\"end\":") {
1100 6 } else {
1102 0
1103 };
1104
1105 if key_len > 0 {
1106 let before_ok = i == 0 || matches!(bytes[i - 1], b',' | b'{' | b'\n' | b' ');
1108 let num_start = i + key_len;
1109
1110 if before_ok && num_start < len && bytes[num_start].is_ascii_digit() {
1111 let mut num_end = num_start;
1112 while num_end < len && bytes[num_end].is_ascii_digit() {
1113 num_end += 1;
1114 }
1115
1116 if let Ok(val) = json[num_start..num_end].parse::<i64>() {
1117 let adjusted = (val + offset).max(0) as u64;
1118 result.push_str(&json[i..i + key_len]);
1119 result.push_str(&adjusted.to_string());
1120 i = num_end;
1121 continue;
1122 }
1123 }
1124 }
1125
1126 result.push(bytes[i] as char);
1128 i += 1;
1129 }
1130
1131 result
1132}
1133
1134#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
1135pub struct Identifier {
1136 pub start: usize,
1137 pub end: usize,
1138 #[serde(skip_serializing_if = "Option::is_none")]
1139 pub loc: Option<Loc>,
1140 pub name: Arc<str>,
1141}
1142
1143#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
1144pub struct Literal {
1145 pub start: usize,
1146 pub end: usize,
1147 #[serde(skip_serializing_if = "Option::is_none")]
1148 pub loc: Option<Loc>,
1149 pub value: LiteralValue,
1150 pub raw: Arc<str>,
1151}
1152
1153#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
1154pub struct BinaryExpression {
1155 pub start: usize,
1156 pub end: usize,
1157 #[serde(skip_serializing_if = "Option::is_none")]
1158 pub loc: Option<Loc>,
1159 pub left: Box<Expression>,
1160 pub operator: Arc<str>,
1161 pub right: Box<Expression>,
1162}
1163
1164#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
1165pub struct CallExpression {
1166 pub start: usize,
1167 pub end: usize,
1168 #[serde(skip_serializing_if = "Option::is_none")]
1169 pub loc: Option<Loc>,
1170 pub callee: Box<Expression>,
1171 pub arguments: Box<[Expression]>,
1172 pub optional: bool,
1173}
1174
1175#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
1176pub struct Text {
1177 pub start: usize,
1178 pub end: usize,
1179 pub raw: Arc<str>,
1180 pub data: Arc<str>,
1181}
1182
1183#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
1184pub struct Css {
1185 pub r#type: CssType,
1186 pub start: usize,
1187 pub end: usize,
1188 pub attributes: Box<[Attribute]>,
1189 pub children: Box<[CssNode]>,
1190 pub content: CssContent,
1191}
1192
1193#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
1194pub enum CssType {
1195 StyleSheet,
1196}
1197
1198#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
1199pub struct CssContent {
1200 pub start: usize,
1201 pub end: usize,
1202 pub styles: Arc<str>,
1203 pub comment: Option<Arc<str>>,
1204}
1205
1206#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
1207#[serde(tag = "type")]
1208pub enum CssNode {
1209 Rule(CssRule),
1210 Atrule(CssAtrule),
1211}
1212
1213#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
1214pub struct CssRule {
1215 pub prelude: CssSelectorList,
1216 pub block: CssBlock,
1217 pub start: usize,
1218 pub end: usize,
1219}
1220
1221#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
1222pub struct CssAtrule {
1223 pub start: usize,
1224 pub end: usize,
1225 pub name: Arc<str>,
1226 pub prelude: Arc<str>,
1227 pub block: Option<CssBlock>,
1228}
1229
1230#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
1231pub struct CssBlock {
1232 pub r#type: CssBlockType,
1233 pub start: usize,
1234 pub end: usize,
1235 pub children: Box<[CssBlockChild]>,
1236}
1237
1238#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
1239pub enum CssBlockType {
1240 Block,
1241}
1242
1243#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
1244#[serde(tag = "type")]
1245pub enum CssBlockChild {
1246 Declaration(CssDeclaration),
1247 Rule(CssRule),
1248 Atrule(CssAtrule),
1249}
1250
1251#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
1252pub struct CssDeclaration {
1253 pub start: usize,
1254 pub end: usize,
1255 pub property: Arc<str>,
1256 pub value: Arc<str>,
1257}
1258
1259#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
1260pub struct CssSelectorList {
1261 pub r#type: CssSelectorListType,
1262 pub start: usize,
1263 pub end: usize,
1264 pub children: Box<[CssComplexSelector]>,
1265}
1266
1267#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
1268pub enum CssSelectorListType {
1269 SelectorList,
1270}
1271
1272#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
1273pub struct CssComplexSelector {
1274 pub r#type: CssComplexSelectorType,
1275 pub start: usize,
1276 pub end: usize,
1277 pub children: Box<[CssRelativeSelector]>,
1278}
1279
1280#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
1281pub enum CssComplexSelectorType {
1282 ComplexSelector,
1283}
1284
1285#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
1286pub struct CssRelativeSelector {
1287 pub r#type: CssRelativeSelectorType,
1288 pub combinator: Option<CssCombinator>,
1289 pub selectors: Box<[CssSimpleSelector]>,
1290 pub start: usize,
1291 pub end: usize,
1292}
1293
1294#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
1295pub enum CssRelativeSelectorType {
1296 RelativeSelector,
1297}
1298
1299#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
1300pub struct CssCombinator {
1301 pub r#type: CssCombinatorType,
1302 pub name: Arc<str>,
1303 pub start: usize,
1304 pub end: usize,
1305}
1306
1307#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
1308pub enum CssCombinatorType {
1309 Combinator,
1310}
1311
1312#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
1313#[serde(tag = "type")]
1314pub enum CssSimpleSelector {
1315 TypeSelector(CssNameSelector),
1316 IdSelector(CssNameSelector),
1317 ClassSelector(CssNameSelector),
1318 PseudoElementSelector(CssNameSelector),
1319 PseudoClassSelector(CssPseudoClassSelector),
1320 AttributeSelector(CssAttributeSelector),
1321 Nth(CssValueSelector),
1322 Percentage(CssValueSelector),
1323 NestingSelector(CssNameSelector),
1324}
1325
1326#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
1327pub struct CssNameSelector {
1328 pub name: Arc<str>,
1329 pub start: usize,
1330 pub end: usize,
1331}
1332
1333#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
1334pub struct CssValueSelector {
1335 pub value: Arc<str>,
1336 pub start: usize,
1337 pub end: usize,
1338}
1339
1340#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
1341pub struct CssPseudoClassSelector {
1342 pub name: Arc<str>,
1343 pub args: Option<CssSelectorList>,
1344 pub start: usize,
1345 pub end: usize,
1346}
1347
1348#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
1349pub struct CssAttributeSelector {
1350 pub start: usize,
1351 pub end: usize,
1352 pub name: Arc<str>,
1353 pub matcher: Option<Arc<str>>,
1354 pub value: Option<Arc<str>>,
1355 pub flags: Option<Arc<str>>,
1356}
1357
1358#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
1359pub struct Options {
1360 pub start: usize,
1361 pub end: usize,
1362 pub attributes: Box<[Attribute]>,
1363 #[serde(skip_serializing, skip_deserializing, default)]
1364 pub fragment: Fragment,
1365 #[serde(skip_serializing_if = "Option::is_none")]
1366 #[serde(rename = "customElement")]
1367 pub custom_element: Option<CustomElement>,
1368 #[serde(skip_serializing_if = "Option::is_none")]
1369 pub runes: Option<bool>,
1370}
1371
1372#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
1373pub struct CustomElement {
1374 pub tag: Arc<str>,
1375}
1376
1377#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
1378#[serde(tag = "type")]
1379pub enum Node {
1380 Text(Text),
1381 IfBlock(IfBlock),
1382 EachBlock(EachBlock),
1383 KeyBlock(KeyBlock),
1384 AwaitBlock(AwaitBlock),
1385 SnippetBlock(SnippetBlock),
1386 RenderTag(RenderTag),
1387 HtmlTag(HtmlTag),
1388 ConstTag(ConstTag),
1389 DebugTag(DebugTag),
1390 ExpressionTag(ExpressionTag),
1391 Comment(Comment),
1392 RegularElement(RegularElement),
1393 Component(Component),
1394 SlotElement(SlotElement),
1395 SvelteHead(SvelteHead),
1396 SvelteBody(SvelteBody),
1397 SvelteWindow(SvelteWindow),
1398 SvelteDocument(SvelteDocument),
1399 SvelteComponent(SvelteComponent),
1400 SvelteElement(SvelteElement),
1401 SvelteSelf(SvelteSelf),
1402 SvelteFragment(SvelteFragment),
1403 SvelteBoundary(SvelteBoundary),
1404 TitleElement(TitleElement),
1405}
1406
1407pub trait HasFragment {
1408 fn fragment(&self) -> &Fragment;
1409}
1410
1411pub trait Element: Span + HasFragment {
1412 fn name(&self) -> &str;
1413 fn name_loc(&self) -> &SourceRange;
1414 fn attributes(&self) -> &[Attribute];
1415 fn expression(&self) -> Option<&Expression> {
1416 None
1417 }
1418 fn self_closing(&self) -> bool {
1419 false
1420 }
1421}
1422
1423macro_rules! impl_element {
1424 ($($ty:ty),* $(,)?) => {
1425 $(
1426 impl HasFragment for $ty {
1427 fn fragment(&self) -> &Fragment { &self.fragment }
1428 }
1429
1430 impl Element for $ty {
1431 fn name(&self) -> &str { &self.name }
1432 fn name_loc(&self) -> &SourceRange { &self.name_loc }
1433 fn attributes(&self) -> &[Attribute] { &self.attributes }
1434 }
1435 )*
1436 };
1437}
1438
1439impl_element!(
1440 Component,
1441 SlotElement,
1442 SvelteHead,
1443 SvelteBody,
1444 SvelteWindow,
1445 SvelteDocument,
1446 SvelteSelf,
1447 SvelteFragment,
1448 SvelteBoundary,
1449 TitleElement,
1450);
1451
1452impl Element for RegularElement {
1453 fn name(&self) -> &str {
1454 &self.name
1455 }
1456 fn name_loc(&self) -> &SourceRange {
1457 &self.name_loc
1458 }
1459 fn attributes(&self) -> &[Attribute] {
1460 &self.attributes
1461 }
1462 fn self_closing(&self) -> bool {
1463 self.self_closing
1464 }
1465}
1466
1467impl HasFragment for RegularElement {
1468 fn fragment(&self) -> &Fragment {
1469 &self.fragment
1470 }
1471}
1472
1473impl HasFragment for SvelteComponent {
1474 fn fragment(&self) -> &Fragment {
1475 &self.fragment
1476 }
1477}
1478
1479impl Element for SvelteComponent {
1480 fn name(&self) -> &str {
1481 &self.name
1482 }
1483 fn name_loc(&self) -> &SourceRange {
1484 &self.name_loc
1485 }
1486 fn attributes(&self) -> &[Attribute] {
1487 &self.attributes
1488 }
1489 fn expression(&self) -> Option<&Expression> {
1490 self.expression.as_ref()
1491 }
1492}
1493
1494impl HasFragment for SvelteElement {
1495 fn fragment(&self) -> &Fragment {
1496 &self.fragment
1497 }
1498}
1499
1500impl Element for SvelteElement {
1501 fn name(&self) -> &str {
1502 &self.name
1503 }
1504 fn name_loc(&self) -> &SourceRange {
1505 &self.name_loc
1506 }
1507 fn attributes(&self) -> &[Attribute] {
1508 &self.attributes
1509 }
1510 fn expression(&self) -> Option<&Expression> {
1511 self.expression.as_ref()
1512 }
1513}
1514
1515impl HasFragment for Root {
1516 fn fragment(&self) -> &Fragment {
1517 &self.fragment
1518 }
1519}
1520
1521impl HasFragment for KeyBlock {
1522 fn fragment(&self) -> &Fragment {
1523 &self.fragment
1524 }
1525}
1526
1527impl HasFragment for SnippetBlock {
1528 fn fragment(&self) -> &Fragment {
1529 &self.body
1530 }
1531}
1532
1533impl Alternate {
1534 pub fn try_for_each_fragment<B>(
1535 &self,
1536 mut visit: impl FnMut(&Fragment) -> ControlFlow<B>,
1537 ) -> ControlFlow<B> {
1538 match self {
1539 Self::Fragment(fragment) => visit(fragment),
1540 Self::IfBlock(block) => {
1541 visit(&block.consequent)?;
1542 if let Some(alternate) = block.alternate.as_deref() {
1543 alternate.try_for_each_fragment(visit)
1544 } else {
1545 ControlFlow::Continue(())
1546 }
1547 }
1548 }
1549 }
1550
1551 pub fn for_each_fragment(&self, mut visit: impl FnMut(&Fragment)) {
1552 let _ = self.try_for_each_fragment(|fragment| {
1553 visit(fragment);
1554 ControlFlow::<()>::Continue(())
1555 });
1556 }
1557}
1558
1559impl Node {
1560 pub fn as_element(&self) -> Option<&dyn Element> {
1561 match self {
1562 Node::RegularElement(el) => Some(el),
1563 Node::Component(el) => Some(el),
1564 Node::SlotElement(el) => Some(el),
1565 Node::SvelteHead(el) => Some(el),
1566 Node::SvelteBody(el) => Some(el),
1567 Node::SvelteWindow(el) => Some(el),
1568 Node::SvelteDocument(el) => Some(el),
1569 Node::SvelteComponent(el) => Some(el),
1570 Node::SvelteElement(el) => Some(el),
1571 Node::SvelteSelf(el) => Some(el),
1572 Node::SvelteFragment(el) => Some(el),
1573 Node::SvelteBoundary(el) => Some(el),
1574 Node::TitleElement(el) => Some(el),
1575 _ => None,
1576 }
1577 }
1578
1579 pub fn try_for_each_child_fragment<B>(
1580 &self,
1581 mut visit: impl FnMut(&Fragment) -> ControlFlow<B>,
1582 ) -> ControlFlow<B> {
1583 match self {
1584 Self::IfBlock(block) => {
1585 visit(&block.consequent)?;
1586 if let Some(alternate) = block.alternate.as_deref() {
1587 alternate.try_for_each_fragment(visit)
1588 } else {
1589 ControlFlow::Continue(())
1590 }
1591 }
1592 Self::EachBlock(block) => {
1593 visit(&block.body)?;
1594 if let Some(fallback) = block.fallback.as_ref() {
1595 visit(fallback)?;
1596 }
1597 ControlFlow::Continue(())
1598 }
1599 Self::KeyBlock(block) => visit(block.fragment()),
1600 Self::AwaitBlock(block) => {
1601 for fragment in [
1602 block.pending.as_ref(),
1603 block.then.as_ref(),
1604 block.catch.as_ref(),
1605 ]
1606 .into_iter()
1607 .flatten()
1608 {
1609 visit(fragment)?;
1610 }
1611 ControlFlow::Continue(())
1612 }
1613 Self::SnippetBlock(block) => visit(block.fragment()),
1614 _ => self
1615 .as_element()
1616 .map_or(ControlFlow::Continue(()), |element| {
1617 visit(element.fragment())
1618 }),
1619 }
1620 }
1621
1622 pub fn for_each_child_fragment(&self, mut visit: impl FnMut(&Fragment)) {
1623 let _ = self.try_for_each_child_fragment(|fragment| {
1624 visit(fragment);
1625 ControlFlow::<()>::Continue(())
1626 });
1627 }
1628}
1629
1630#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
1631pub struct RootComment {
1632 pub r#type: RootCommentType,
1633 pub start: usize,
1634 pub end: usize,
1635 pub value: Arc<str>,
1636 pub loc: SourceRange,
1637}
1638
1639#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
1640pub struct Root {
1641 pub css: Option<Css>,
1642 #[serde(skip_serializing, default)]
1643 pub styles: Box<[Css]>,
1644 pub js: Box<[Script]>,
1645 #[serde(skip_serializing, default)]
1646 pub scripts: Box<[Script]>,
1647 pub start: usize,
1648 pub end: usize,
1649 pub r#type: RootType,
1650 pub fragment: Fragment,
1651 pub options: Option<Options>,
1652 #[serde(skip_serializing_if = "Option::is_none")]
1653 pub module: Option<Script>,
1654 #[serde(skip_serializing_if = "Option::is_none")]
1655 pub instance: Option<Script>,
1656 #[serde(skip_serializing_if = "Option::is_none")]
1657 pub comments: Option<Box<[RootComment]>>,
1658 #[serde(skip_serializing, default)]
1659 pub errors: Box<[crate::ast::common::ParseError]>,
1660}
1661
1662macro_rules! impl_span_for_struct {
1663 ($($ty:ty),* $(,)?) => {
1664 $(
1665 impl Span for $ty {
1666 fn start(&self) -> usize {
1667 self.start
1668 }
1669
1670 fn end(&self) -> usize {
1671 self.end
1672 }
1673 }
1674 )*
1675 };
1676}
1677
1678impl_span_for_struct!(
1679 Script,
1680 EachBlock,
1681 KeyBlock,
1682 AwaitBlock,
1683 SnippetBlock,
1684 RenderTag,
1685 HtmlTag,
1686 ConstTag,
1687 DebugTag,
1688 ExpressionTag,
1689 Comment,
1690 RegularElement,
1691 Component,
1692 SlotElement,
1693 SvelteHead,
1694 SvelteBody,
1695 SvelteWindow,
1696 SvelteDocument,
1697 SvelteComponent,
1698 SvelteElement,
1699 SvelteSelf,
1700 SvelteFragment,
1701 SvelteBoundary,
1702 TitleElement,
1703 IfBlock,
1704 Text,
1705 Css,
1706 CssContent,
1707 CssRule,
1708 CssAtrule,
1709 CssBlock,
1710 CssDeclaration,
1711 CssSelectorList,
1712 CssComplexSelector,
1713 CssRelativeSelector,
1714 CssCombinator,
1715 CssNameSelector,
1716 CssValueSelector,
1717 CssPseudoClassSelector,
1718 CssAttributeSelector,
1719 Options,
1720 RootComment,
1721 Root
1722);
1723
1724impl Span for Node {
1725 fn start(&self) -> usize {
1726 match self {
1727 Node::Text(node) => node.start,
1728 Node::IfBlock(node) => node.start,
1729 Node::EachBlock(node) => node.start,
1730 Node::KeyBlock(node) => node.start,
1731 Node::AwaitBlock(node) => node.start,
1732 Node::SnippetBlock(node) => node.start,
1733 Node::RenderTag(node) => node.start,
1734 Node::HtmlTag(node) => node.start,
1735 Node::ConstTag(node) => node.start,
1736 Node::DebugTag(node) => node.start,
1737 Node::ExpressionTag(node) => node.start,
1738 Node::Comment(node) => node.start,
1739 Node::RegularElement(node) => node.start,
1740 Node::Component(node) => node.start,
1741 Node::SlotElement(node) => node.start,
1742 Node::SvelteHead(node) => node.start,
1743 Node::SvelteBody(node) => node.start,
1744 Node::SvelteWindow(node) => node.start,
1745 Node::SvelteDocument(node) => node.start,
1746 Node::SvelteComponent(node) => node.start,
1747 Node::SvelteElement(node) => node.start,
1748 Node::SvelteSelf(node) => node.start,
1749 Node::SvelteFragment(node) => node.start,
1750 Node::SvelteBoundary(node) => node.start,
1751 Node::TitleElement(node) => node.start,
1752 }
1753 }
1754
1755 fn end(&self) -> usize {
1756 match self {
1757 Node::Text(node) => node.end,
1758 Node::IfBlock(node) => node.end,
1759 Node::EachBlock(node) => node.end,
1760 Node::KeyBlock(node) => node.end,
1761 Node::AwaitBlock(node) => node.end,
1762 Node::SnippetBlock(node) => node.end,
1763 Node::RenderTag(node) => node.end,
1764 Node::HtmlTag(node) => node.end,
1765 Node::ConstTag(node) => node.end,
1766 Node::DebugTag(node) => node.end,
1767 Node::ExpressionTag(node) => node.end,
1768 Node::Comment(node) => node.end,
1769 Node::RegularElement(node) => node.end,
1770 Node::Component(node) => node.end,
1771 Node::SlotElement(node) => node.end,
1772 Node::SvelteHead(node) => node.end,
1773 Node::SvelteBody(node) => node.end,
1774 Node::SvelteWindow(node) => node.end,
1775 Node::SvelteDocument(node) => node.end,
1776 Node::SvelteComponent(node) => node.end,
1777 Node::SvelteElement(node) => node.end,
1778 Node::SvelteSelf(node) => node.end,
1779 Node::SvelteFragment(node) => node.end,
1780 Node::SvelteBoundary(node) => node.end,
1781 Node::TitleElement(node) => node.end,
1782 }
1783 }
1784}
1785
1786#[cfg(test)]
1787mod tests {
1788 use super::*;
1789
1790 #[test]
1791 fn adjust_estree_span_offsets_adds_offset() {
1792 let json = r#"{"type":"Identifier","name":"foo","start":0,"end":3}"#;
1793 let adjusted = adjust_estree_span_offsets(json, 10);
1794 assert_eq!(
1795 adjusted,
1796 r#"{"type":"Identifier","name":"foo","start":10,"end":13}"#
1797 );
1798 }
1799
1800 #[test]
1801 fn adjust_estree_span_offsets_handles_nested() {
1802 let json = r#"{"type":"BinaryExpression","left":{"type":"Identifier","name":"a","start":0,"end":1},"right":{"type":"NumericLiteral","value":1,"raw":"1","start":4,"end":5},"start":0,"end":5}"#;
1803 let adjusted = adjust_estree_span_offsets(json, 20);
1804 assert!(adjusted.contains(r#""start":20"#));
1805 assert!(adjusted.contains(r#""end":21"#));
1806 assert!(adjusted.contains(r#""start":24"#));
1807 assert!(adjusted.contains(r#""end":25"#));
1808 }
1809
1810 #[test]
1811 fn adjust_estree_span_offsets_preserves_string_values() {
1812 let json = r#"{"type":"Identifier","name":"start","start":0,"end":5}"#;
1814 let adjusted = adjust_estree_span_offsets(json, 10);
1815 assert_eq!(
1816 adjusted,
1817 r#"{"type":"Identifier","name":"start","start":10,"end":15}"#
1818 );
1819 }
1820
1821 #[test]
1822 fn expression_serializes_oxc_identifier_with_offset() {
1823 let parsed = crate::js::JsExpression::parse(
1824 "foo",
1825 oxc_span::SourceType::mjs(),
1826 )
1827 .expect("valid expression");
1828
1829 let expr = Expression::from_expression(Arc::new(parsed), 42, 45);
1830 let json = serde_json::to_string(&expr).expect("serialize");
1831 let value: serde_json::Value = serde_json::from_str(&json).expect("valid json");
1832
1833 assert_eq!(value["type"], "Identifier");
1834 assert_eq!(value["name"], "foo");
1835 assert_eq!(value["start"], 42);
1836 assert_eq!(value["end"], 45);
1837 }
1838
1839 #[test]
1840 fn expression_serializes_fallback_without_node() {
1841 let expr = Expression::empty(10, 20);
1842 let json = serde_json::to_string(&expr).expect("serialize");
1843 let value: serde_json::Value = serde_json::from_str(&json).expect("valid json");
1844
1845 assert_eq!(value["start"], 10);
1846 assert_eq!(value["end"], 20);
1847 assert!(value.get("type").is_none());
1848 }
1849}