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