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, Deserialize)]
246pub struct Script {
247 pub r#type: ScriptType,
248 pub start: usize,
249 pub end: usize,
250 #[serde(skip_deserializing, default)]
252 pub content_start: usize,
253 #[serde(skip_deserializing, default)]
254 pub content_end: usize,
255 pub context: ScriptContext,
256 #[serde(skip_deserializing, default = "empty_parsed_js_program")]
257 pub content: Arc<JsProgram>,
258 #[serde(skip_deserializing, default)]
260 pub content_json: Option<Arc<str>>,
261 pub attributes: Box<[Attribute]>,
262}
263
264impl Serialize for Script {
265 fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
266 use serde::ser::SerializeMap;
267 let mut map = serializer.serialize_map(None)?;
268 map.serialize_entry("type", &self.r#type)?;
269 map.serialize_entry("start", &self.start)?;
270 map.serialize_entry("end", &self.end)?;
271 map.serialize_entry("context", &self.context)?;
272 if let Some(ref json) = self.content_json {
273 let raw = serde_json::value::RawValue::from_string(json.to_string())
274 .map_err(serde::ser::Error::custom)?;
275 map.serialize_entry("content", &raw)?;
276 }
277 map.serialize_entry("attributes", &self.attributes)?;
278 map.end()
279 }
280}
281
282impl Script {
283 pub fn parsed_program(&self) -> &JsProgram {
284 &self.content
285 }
286
287 pub fn oxc_program(&self) -> &OxcProgram<'_> {
288 self.parsed_program().program()
289 }
290}
291
292#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
293pub struct EachBlock {
294 pub start: usize,
295 pub end: usize,
296 pub expression: Expression,
297 pub body: Fragment,
298 #[serde(skip_serializing, default)]
299 pub has_as_clause: bool,
300 #[serde(skip_serializing, default)]
301 pub invalid_key_without_as: bool,
302 pub context: Option<Expression>,
303 #[serde(skip_serializing, default)]
304 pub context_error: Option<ParseError>,
305 #[serde(skip_serializing_if = "Option::is_none")]
306 pub index: Option<Arc<str>>,
307 #[serde(skip_serializing_if = "Option::is_none")]
308 pub key: Option<Expression>,
309 #[serde(skip_serializing_if = "Option::is_none")]
310 pub fallback: Option<Fragment>,
311}
312
313#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
314pub struct KeyBlock {
315 pub start: usize,
316 pub end: usize,
317 pub expression: Expression,
318 pub fragment: Fragment,
319}
320
321#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
322pub struct AwaitBlock {
323 pub start: usize,
324 pub end: usize,
325 pub expression: Expression,
326 pub value: Option<Expression>,
327 pub error: Option<Expression>,
328 pub pending: Option<Fragment>,
329 pub then: Option<Fragment>,
330 pub catch: Option<Fragment>,
331}
332
333#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
334pub struct SnippetBlock {
335 pub start: usize,
336 pub end: usize,
337 pub expression: Expression,
338 #[serde(rename = "typeParams", skip_serializing_if = "Option::is_none")]
339 pub type_params: Option<Arc<str>>,
340 pub parameters: Box<[Expression]>,
341 pub body: Fragment,
342 #[serde(skip_serializing_if = "Option::is_none")]
343 pub header_error: Option<SnippetHeaderError>,
344}
345
346#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
347pub struct RenderTag {
348 pub start: usize,
349 pub end: usize,
350 pub expression: Expression,
351}
352
353#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
354pub struct HtmlTag {
355 pub start: usize,
356 pub end: usize,
357 pub expression: Expression,
358}
359
360#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
361pub struct ConstTag {
362 pub start: usize,
363 pub end: usize,
364 pub declaration: Expression,
365}
366
367#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
368pub struct DebugTag {
369 pub start: usize,
370 pub end: usize,
371 pub arguments: Box<[Expression]>,
372 pub identifiers: Box<[Identifier]>,
373}
374
375#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
376pub struct ExpressionTag {
377 pub r#type: ExpressionTagType,
378 pub start: usize,
379 pub end: usize,
380 pub expression: Expression,
381}
382
383#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
385pub enum ExpressionTagType {
386 ExpressionTag,
387}
388
389#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
390pub struct Comment {
391 pub start: usize,
392 pub end: usize,
393 pub data: Arc<str>,
394}
395
396#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
397pub struct RegularElement {
398 pub start: usize,
399 pub end: usize,
400 pub name: Arc<str>,
401 pub name_loc: SourceRange,
402 #[serde(skip_serializing, default)]
403 pub self_closing: bool,
404 #[serde(skip_serializing, default)]
405 pub has_end_tag: bool,
406 pub attributes: Box<[Attribute]>,
407 pub fragment: Fragment,
408}
409
410#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
411pub struct Component {
412 pub start: usize,
413 pub end: usize,
414 pub name: Arc<str>,
415 pub name_loc: SourceRange,
416 pub attributes: Box<[Attribute]>,
417 pub fragment: Fragment,
418}
419
420#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
421pub struct SlotElement {
422 pub start: usize,
423 pub end: usize,
424 pub name: Arc<str>,
425 pub name_loc: SourceRange,
426 pub attributes: Box<[Attribute]>,
427 pub fragment: Fragment,
428}
429
430#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
431pub struct SvelteHead {
432 pub start: usize,
433 pub end: usize,
434 pub name: Arc<str>,
435 pub name_loc: SourceRange,
436 pub attributes: Box<[Attribute]>,
437 pub fragment: Fragment,
438}
439
440#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
441pub struct SvelteBody {
442 pub start: usize,
443 pub end: usize,
444 pub name: Arc<str>,
445 pub name_loc: SourceRange,
446 pub attributes: Box<[Attribute]>,
447 pub fragment: Fragment,
448}
449
450#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
451pub struct SvelteWindow {
452 pub start: usize,
453 pub end: usize,
454 pub name: Arc<str>,
455 pub name_loc: SourceRange,
456 pub attributes: Box<[Attribute]>,
457 pub fragment: Fragment,
458}
459
460#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
461pub struct SvelteDocument {
462 pub start: usize,
463 pub end: usize,
464 pub name: Arc<str>,
465 pub name_loc: SourceRange,
466 pub attributes: Box<[Attribute]>,
467 pub fragment: Fragment,
468}
469
470#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
471pub struct SvelteComponent {
472 pub start: usize,
473 pub end: usize,
474 pub name: Arc<str>,
475 pub name_loc: SourceRange,
476 pub attributes: Box<[Attribute]>,
477 pub fragment: Fragment,
478 #[serde(skip_serializing_if = "Option::is_none")]
479 pub expression: Option<Expression>,
480}
481
482#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
483pub struct SvelteElement {
484 pub start: usize,
485 pub end: usize,
486 pub name: Arc<str>,
487 pub name_loc: SourceRange,
488 pub attributes: Box<[Attribute]>,
489 pub fragment: Fragment,
490 #[serde(skip_serializing_if = "Option::is_none")]
491 pub expression: Option<Expression>,
492}
493
494#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
495pub struct SvelteSelf {
496 pub start: usize,
497 pub end: usize,
498 pub name: Arc<str>,
499 pub name_loc: SourceRange,
500 pub attributes: Box<[Attribute]>,
501 pub fragment: Fragment,
502}
503
504#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
505pub struct SvelteFragment {
506 pub start: usize,
507 pub end: usize,
508 pub name: Arc<str>,
509 pub name_loc: SourceRange,
510 pub attributes: Box<[Attribute]>,
511 pub fragment: Fragment,
512}
513
514#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
515pub struct SvelteBoundary {
516 pub start: usize,
517 pub end: usize,
518 pub name: Arc<str>,
519 pub name_loc: SourceRange,
520 pub attributes: Box<[Attribute]>,
521 pub fragment: Fragment,
522}
523
524#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
525pub struct TitleElement {
526 pub start: usize,
527 pub end: usize,
528 pub name: Arc<str>,
529 pub name_loc: SourceRange,
530 pub attributes: Box<[Attribute]>,
531 pub fragment: Fragment,
532}
533
534#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
535#[serde(tag = "type")]
536pub enum Attribute {
537 Attribute(NamedAttribute),
538 SpreadAttribute(SpreadAttribute),
539 BindDirective(DirectiveAttribute),
540 OnDirective(DirectiveAttribute),
541 ClassDirective(DirectiveAttribute),
542 LetDirective(DirectiveAttribute),
543 StyleDirective(StyleDirective),
544 TransitionDirective(TransitionDirective),
545 AnimateDirective(DirectiveAttribute),
546 UseDirective(DirectiveAttribute),
547 AttachTag(AttachTag),
548}
549
550#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
551pub struct SpreadAttribute {
552 pub start: usize,
553 pub end: usize,
554 pub expression: Expression,
555}
556
557#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
558pub struct NamedAttribute {
559 pub start: usize,
560 pub end: usize,
561 pub name: Arc<str>,
562 pub name_loc: SourceRange,
563 pub value: AttributeValueKind,
564 #[serde(skip_serializing, default)]
565 pub value_syntax: AttributeValueSyntax,
566 #[serde(skip_serializing, default)]
567 pub error: Option<AttrError>,
568}
569
570#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
571#[serde(untagged)]
572pub enum AttributeValueKind {
573 Boolean(bool),
574 Values(Box<[AttributeValue]>),
575 ExpressionTag(ExpressionTag),
576}
577
578#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
579#[serde(tag = "type")]
580pub enum AttributeValue {
581 Text(Text),
582 ExpressionTag(ExpressionTag),
583}
584
585#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
586pub struct DirectiveAttribute {
587 pub start: usize,
588 pub end: usize,
589 pub name: Arc<str>,
590 pub name_loc: SourceRange,
591 pub expression: Expression,
592 pub modifiers: Box<[Arc<str>]>,
593 #[serde(skip_serializing, default)]
594 pub value_syntax: DirectiveValueSyntax,
595 #[serde(skip_serializing, default)]
596 pub value_start: usize,
597}
598
599#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
600pub struct StyleDirective {
601 pub start: usize,
602 pub end: usize,
603 pub name: Arc<str>,
604 pub name_loc: SourceRange,
605 pub modifiers: Box<[Arc<str>]>,
606 pub value: AttributeValueKind,
607 #[serde(skip_serializing, default)]
608 pub value_syntax: AttributeValueSyntax,
609}
610
611#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
612pub struct TransitionDirective {
613 pub start: usize,
614 pub end: usize,
615 pub name: Arc<str>,
616 pub name_loc: SourceRange,
617 pub expression: Expression,
618 pub modifiers: Box<[Arc<str>]>,
619 pub intro: bool,
620 pub outro: bool,
621 #[serde(skip_serializing, default)]
622 pub value_syntax: DirectiveValueSyntax,
623 #[serde(skip_serializing, default)]
624 pub value_start: usize,
625}
626
627#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
628pub struct AttachTag {
629 pub start: usize,
630 pub end: usize,
631 pub expression: Expression,
632}
633
634#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
635pub struct IfBlock {
636 pub elseif: bool,
637 pub start: usize,
638 pub end: usize,
639 pub test: Expression,
640 pub consequent: Fragment,
641 pub alternate: Option<Box<Alternate>>,
642}
643
644#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
645#[serde(untagged)]
646pub enum Alternate {
647 Fragment(Fragment),
648 IfBlock(IfBlock),
649}
650
651#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize)]
652pub struct ExpressionSyntax {
653 #[serde(skip_serializing, default)]
654 pub parens: u16,
655}
656
657#[derive(Debug, Clone, PartialEq, Eq)]
658pub enum JsNodeHandle {
659 Expression(Arc<JsExpression>),
660 SequenceItem {
661 root: Arc<JsExpression>,
662 index: usize,
663 },
664 Pattern(Arc<JsPattern>),
665 ParameterItem {
666 parameters: Arc<JsParameters>,
667 index: usize,
668 },
669 RestParameter(Arc<JsParameters>),
670 StatementInProgram {
671 program: Arc<JsProgram>,
672 index: usize,
673 },
674}
675
676#[derive(Debug, Clone, PartialEq, Eq)]
678pub struct JsComment {
679 pub kind: JsCommentKind,
680 pub value: Arc<str>,
681 pub start: Option<usize>,
683 pub end: Option<usize>,
685}
686
687#[derive(Debug, Clone, Copy, PartialEq, Eq)]
688pub enum JsCommentKind {
689 Line,
690 Block,
691}
692
693#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
694pub struct Expression {
695 pub start: usize,
696 pub end: usize,
697 #[serde(skip_serializing, default)]
698 pub syntax: ExpressionSyntax,
699 #[serde(skip_serializing, skip_deserializing, default)]
700 pub node: Option<JsNodeHandle>,
701 #[serde(skip_serializing, skip_deserializing, default)]
704 pub enriched_json: Option<Arc<str>>,
705 #[serde(skip_serializing, skip_deserializing, default)]
707 pub leading_comments: Vec<JsComment>,
708 #[serde(skip_serializing, skip_deserializing, default)]
710 pub trailing_comments: Vec<JsComment>,
711}
712
713impl Expression {
714 pub fn empty(start: usize, end: usize) -> Self {
715 Self {
716 start,
717 end,
718 syntax: Default::default(),
719 node: None,
720 enriched_json: None,
721 leading_comments: Vec::new(),
722 trailing_comments: Vec::new(),
723 }
724 }
725
726 pub fn is_empty(&self) -> bool {
728 self.node.is_none() && self.start == self.end
729 }
730
731 pub fn from_expression(parsed: Arc<JsExpression>, start: usize, end: usize) -> Self {
732 Self {
733 start,
734 end,
735 syntax: Default::default(),
736 node: Some(JsNodeHandle::Expression(parsed)),
737 enriched_json: None,
738 leading_comments: Vec::new(),
739 trailing_comments: Vec::new(),
740 }
741 }
742
743 pub fn from_sequence_item(
744 root: Arc<JsExpression>,
745 index: usize,
746 start: usize,
747 end: usize,
748 ) -> Self {
749 Self {
750 start,
751 end,
752 syntax: Default::default(),
753 node: Some(JsNodeHandle::SequenceItem { root, index }),
754 enriched_json: None,
755 leading_comments: Vec::new(),
756 trailing_comments: Vec::new(),
757 }
758 }
759
760 pub fn from_pattern(parsed: Arc<JsPattern>, start: usize, end: usize) -> Self {
761 Self {
762 start,
763 end,
764 syntax: Default::default(),
765 node: Some(JsNodeHandle::Pattern(parsed)),
766 enriched_json: None,
767 leading_comments: Vec::new(),
768 trailing_comments: Vec::new(),
769 }
770 }
771
772 pub fn from_parameter_item(
773 parameters: Arc<JsParameters>,
774 index: usize,
775 start: usize,
776 end: usize,
777 ) -> Self {
778 Self {
779 start,
780 end,
781 syntax: Default::default(),
782 node: Some(JsNodeHandle::ParameterItem { parameters, index }),
783 enriched_json: None,
784 leading_comments: Vec::new(),
785 trailing_comments: Vec::new(),
786 }
787 }
788
789 pub fn from_rest_parameter(parameters: Arc<JsParameters>, start: usize, end: usize) -> Self {
790 Self {
791 start,
792 end,
793 syntax: Default::default(),
794 node: Some(JsNodeHandle::RestParameter(parameters)),
795 enriched_json: None,
796 leading_comments: Vec::new(),
797 trailing_comments: Vec::new(),
798 }
799 }
800
801 pub fn from_statement(
802 program: Arc<JsProgram>,
803 index: usize,
804 start: usize,
805 end: usize,
806 ) -> Self {
807 Self {
808 start,
809 end,
810 syntax: Default::default(),
811 node: Some(JsNodeHandle::StatementInProgram { program, index }),
812 enriched_json: None,
813 leading_comments: Vec::new(),
814 trailing_comments: Vec::new(),
815 }
816 }
817
818 pub fn parens(&self) -> u16 {
819 self.syntax.parens.max(self.outer_parens())
820 }
821
822 pub fn is_parenthesized(&self) -> bool {
823 self.parens() != 0
824 }
825
826 fn outer_parens(&self) -> u16 {
827 let mut parens = 0u16;
828 let mut current = match &self.node {
829 Some(JsNodeHandle::Expression(parsed)) => parsed.expression(),
830 Some(JsNodeHandle::SequenceItem { root, .. }) => root.expression(),
831 Some(JsNodeHandle::Pattern(_))
832 | Some(JsNodeHandle::ParameterItem { .. })
833 | Some(JsNodeHandle::RestParameter(_))
834 | Some(JsNodeHandle::StatementInProgram { .. })
835 | None => return 0,
836 };
837
838 while let OxcExpression::ParenthesizedExpression(parenthesized) = current {
839 parens = parens.saturating_add(1);
840 current = &parenthesized.expression;
841 }
842
843 parens
844 }
845
846 pub fn parsed(&self) -> Option<&JsExpression> {
847 match &self.node {
848 Some(JsNodeHandle::Expression(parsed)) => Some(parsed),
849 Some(JsNodeHandle::SequenceItem { root, .. }) => Some(root),
850 Some(JsNodeHandle::Pattern(_))
851 | Some(JsNodeHandle::ParameterItem { .. })
852 | Some(JsNodeHandle::RestParameter(_))
853 | Some(JsNodeHandle::StatementInProgram { .. })
854 | None => None,
855 }
856 }
857
858 pub fn oxc_expression_raw(&self) -> Option<&OxcExpression<'_>> {
859 match &self.node {
860 Some(JsNodeHandle::Expression(parsed)) => Some(parsed.expression()),
861 Some(JsNodeHandle::SequenceItem { root, index }) => {
862 let OxcExpression::SequenceExpression(sequence) = root.expression() else {
863 return None;
864 };
865 sequence.expressions.get(*index)
866 }
867 Some(JsNodeHandle::Pattern(_))
868 | Some(JsNodeHandle::ParameterItem { .. })
869 | Some(JsNodeHandle::RestParameter(_))
870 | Some(JsNodeHandle::StatementInProgram { .. })
871 | None => None,
872 }
873 }
874
875 pub fn oxc_expression(&self) -> Option<&OxcExpression<'_>> {
876 let mut expression = self.oxc_expression_raw()?;
877
878 while let OxcExpression::ParenthesizedExpression(parenthesized) = expression {
879 expression = &parenthesized.expression;
880 }
881
882 Some(expression)
883 }
884
885 pub fn is_destructured_pattern(&self) -> bool {
888 self.oxc_pattern().is_some_and(|p| {
889 matches!(
890 p,
891 BindingPattern::ObjectPattern(_) | BindingPattern::ArrayPattern(_)
892 )
893 })
894 }
895
896 pub fn oxc_pattern(&self) -> Option<&BindingPattern<'_>> {
897 match &self.node {
898 Some(JsNodeHandle::Pattern(parsed)) => Some(parsed.pattern()),
899 Some(JsNodeHandle::ParameterItem { parameters, index }) => {
900 Some(¶meters.parameter(*index)?.pattern)
901 }
902 Some(JsNodeHandle::RestParameter(parameters)) => {
903 Some(¶meters.rest_parameter()?.rest.argument)
904 }
905 _ => None,
906 }
907 }
908
909 pub fn oxc_parameter(&self) -> Option<&FormalParameter<'_>> {
910 match &self.node {
911 Some(JsNodeHandle::ParameterItem { parameters, index }) => parameters.parameter(*index),
912 _ => None,
913 }
914 }
915
916 pub fn oxc_rest_parameter(&self) -> Option<&FormalParameterRest<'_>> {
917 match &self.node {
918 Some(JsNodeHandle::RestParameter(parameters)) => parameters.rest_parameter(),
919 _ => None,
920 }
921 }
922
923 pub fn oxc_statement(&self) -> Option<&OxcStatement<'_>> {
924 match &self.node {
925 Some(JsNodeHandle::StatementInProgram { program, index }) => program.statement(*index),
926 _ => None,
927 }
928 }
929
930 pub fn oxc_variable_declaration(&self) -> Option<&OxcVariableDeclaration<'_>> {
931 match &self.node {
932 Some(JsNodeHandle::StatementInProgram { program, index }) => {
933 program.variable_declaration(*index)
934 }
935 _ => None,
936 }
937 }
938
939 pub fn is_rest_parameter(&self) -> bool {
940 matches!(self.node, Some(JsNodeHandle::RestParameter(_)))
941 }
942
943 pub fn source_snippet(&self) -> Option<&str> {
944 match &self.node {
945 Some(JsNodeHandle::Expression(parsed)) => Some(parsed.source()),
946 Some(JsNodeHandle::SequenceItem { root, index }) => {
947 let OxcExpression::SequenceExpression(sequence) = root.expression() else {
948 return None;
949 };
950 let node = sequence.expressions.get(*index)?;
951 root.source().get(node.span().start as usize..node.span().end as usize)
952 }
953 Some(JsNodeHandle::Pattern(parsed)) => Some(parsed.source()),
954 Some(JsNodeHandle::ParameterItem { parameters, index }) => {
955 let parameter = parameters.parameter(*index)?;
956 parameters
957 .source()
958 .get(parameter.span.start as usize - 1..parameter.span.end as usize - 1)
959 }
960 Some(JsNodeHandle::RestParameter(parameters)) => {
961 let parameter = parameters.rest_parameter()?;
962 parameters
963 .source()
964 .get(parameter.span.start as usize - 1..parameter.span.end as usize - 1)
965 }
966 Some(JsNodeHandle::StatementInProgram { program, index }) => program.statement_source(*index),
967 None => None,
968 }
969 }
970
971 pub fn identifier_name(&self) -> Option<Arc<str>> {
972 if let Some(identifier) = self
973 .oxc_expression()
974 .and_then(OxcExpression::get_identifier_reference)
975 {
976 return Some(Arc::from(identifier.name.as_str()));
977 }
978
979 match self.oxc_pattern()? {
980 BindingPattern::BindingIdentifier(identifier) => {
981 Some(Arc::from(identifier.name.as_str()))
982 }
983 _ => None,
984 }
985 }
986
987 pub fn literal_string(&self) -> Option<Arc<str>> {
988 match self.oxc_expression()? {
989 OxcExpression::StringLiteral(value) => Some(Arc::from(value.value.as_str())),
990 _ => None,
991 }
992 }
993
994 pub fn literal_bool(&self) -> Option<bool> {
995 match self.oxc_expression()? {
996 OxcExpression::BooleanLiteral(value) => Some(value.value),
997 _ => None,
998 }
999 }
1000
1001 pub fn binding_identifier(&self) -> Option<&BindingIdentifier<'_>> {
1002 if let Some(declaration) = self.oxc_variable_declaration() {
1003 let [declarator] = declaration.declarations.as_slice() else {
1004 return None;
1005 };
1006 return declarator.id.get_binding_identifier();
1007 }
1008
1009 match self.oxc_pattern()? {
1010 BindingPattern::BindingIdentifier(identifier) => Some(identifier),
1011 _ => None,
1012 }
1013 }
1014}
1015
1016impl Span for Expression {
1017 fn start(&self) -> usize {
1018 self.start
1019 }
1020
1021 fn end(&self) -> usize {
1022 self.end
1023 }
1024}
1025
1026impl Serialize for Expression {
1027 fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
1028 if let Some(ref enriched) = self.enriched_json {
1030 let raw = serde_json::value::RawValue::from_string(enriched.to_string())
1031 .map_err(serde::ser::Error::custom)?;
1032 return raw.serialize(serializer);
1033 }
1034 if let Some(raw_json) = self.to_estree_json() {
1035 let raw = serde_json::value::RawValue::from_string(raw_json)
1037 .map_err(serde::ser::Error::custom)?;
1038 raw.serialize(serializer)
1039 } else {
1040 let mut map = serializer.serialize_map(Some(4))?;
1044 map.serialize_entry("type", "Identifier")?;
1045 map.serialize_entry("name", "")?;
1046 map.serialize_entry("start", &self.start)?;
1047 map.serialize_entry("end", &self.end)?;
1048 map.end()
1049 }
1050 }
1051}
1052
1053impl Expression {
1054 pub fn enrich_with_source(&mut self, full_source: &str) {
1059 self.enrich_inner(full_source, 0, false);
1060 }
1061
1062 pub fn enrich_with_source_and_column_offset(
1063 &mut self,
1064 full_source: &str,
1065 column_offset: usize,
1066 ) {
1067 self.enrich_inner(full_source, column_offset, false);
1068 }
1069
1070 pub fn enrich_with_character(&mut self, full_source: &str) {
1073 self.enrich_inner(full_source, 0, true);
1074 }
1075
1076 fn enrich_inner(
1077 &mut self,
1078 full_source: &str,
1079 column_offset: usize,
1080 with_character: bool,
1081 ) {
1082 let Some(raw_json) = self.serialize_oxc_node() else {
1083 if with_character {
1086 self.enrich_empty_with_character(full_source);
1087 }
1088 return;
1089 };
1090 let offset = self.oxc_span_offset();
1091 let Ok(mut value) = serde_json::from_str::<serde_json::Value>(&raw_json) else {
1092 return;
1093 };
1094 if self.uses_ts_serializer() {
1097 crate::js::fix_template_element_spans(&mut value);
1098 }
1099 if with_character {
1100 crate::js::adjust_expression_json_with_character(
1101 &mut value,
1102 full_source,
1103 offset,
1104 );
1105 } else {
1106 crate::js::adjust_expression_json_with_column_offset(
1107 &mut value,
1108 full_source,
1109 offset,
1110 column_offset,
1111 );
1112 }
1113 if !self.leading_comments.is_empty() {
1115 if let serde_json::Value::Object(ref mut map) = value {
1116 map.insert(
1117 "leadingComments".to_string(),
1118 serde_json::Value::Array(crate::estree::make_comment_json(&self.leading_comments)),
1119 );
1120 }
1121 }
1122 if !self.trailing_comments.is_empty() {
1124 if let serde_json::Value::Object(ref mut map) = value {
1125 map.insert(
1126 "trailingComments".to_string(),
1127 serde_json::Value::Array(crate::estree::make_comment_json(&self.trailing_comments)),
1128 );
1129 }
1130 }
1131 let internal_comments = self.extract_internal_comments();
1133 if !internal_comments.is_empty() {
1134 crate::js::attach_comments_to_json_tree(&mut value, &internal_comments, full_source);
1135 }
1136 if let Ok(enriched) = serde_json::to_string(&value) {
1137 self.enriched_json = Some(Arc::from(enriched));
1138 }
1139 }
1140
1141 fn uses_ts_serializer(&self) -> bool {
1143 matches!(
1144 &self.node,
1145 Some(JsNodeHandle::Expression(_))
1146 | Some(JsNodeHandle::SequenceItem { .. })
1147 | Some(JsNodeHandle::ParameterItem { .. })
1148 | Some(JsNodeHandle::RestParameter(_))
1149 | Some(JsNodeHandle::StatementInProgram { .. })
1150 )
1151 }
1152
1153 fn enrich_empty_with_character(&mut self, full_source: &str) {
1155 let start = self.start;
1156 let end = self.end;
1157 let (sl, sc) = crate::line_column_at_offset(full_source, start);
1158 let (el, ec) = crate::line_column_at_offset(full_source, end);
1159 let json = format!(
1160 r#"{{"type":"Identifier","name":"","start":{},"end":{},"loc":{{"start":{{"line":{},"column":{},"character":{}}},"end":{{"line":{},"column":{},"character":{}}}}}}}"#,
1161 start, end, sl, sc, start, el, ec, end
1162 );
1163 self.enriched_json = Some(Arc::from(json));
1164 }
1165
1166 pub fn to_estree_json(&self) -> Option<String> {
1172 let json = self.serialize_oxc_node()?;
1173 let offset = self.oxc_span_offset();
1174 if offset == 0 {
1175 Some(json)
1176 } else {
1177 Some(adjust_estree_span_offsets(&json, offset))
1178 }
1179 }
1180
1181 fn serialize_oxc_node(&self) -> Option<String> {
1183 use oxc_estree::ESTree;
1184
1185 match &self.node {
1186 Some(JsNodeHandle::Expression(parsed)) => {
1187 let mut ser = oxc_estree::CompactTSSerializer::new(false);
1188 serialize_oxc_expression_unwrapped_ts(parsed.expression(), &mut ser);
1189 Some(ser.into_string())
1190 }
1191 Some(JsNodeHandle::SequenceItem { root, index }) => {
1192 let OxcExpression::SequenceExpression(seq) = root.expression() else {
1193 return None;
1194 };
1195 let expr = seq.expressions.get(*index)?;
1196 let mut ser = oxc_estree::CompactTSSerializer::new(false);
1197 expr.serialize(&mut ser);
1198 Some(ser.into_string())
1199 }
1200 Some(JsNodeHandle::Pattern(parsed)) => {
1201 let mut ser = oxc_estree::CompactJSSerializer::new(false);
1202 parsed.pattern().serialize(&mut ser);
1203 Some(ser.into_string())
1204 }
1205 Some(JsNodeHandle::ParameterItem { parameters, index }) => {
1206 let param = parameters.parameter(*index)?;
1207 let mut ser = oxc_estree::CompactTSSerializer::new(false);
1209 param.serialize(&mut ser);
1210 Some(ser.into_string())
1211 }
1212 Some(JsNodeHandle::RestParameter(parameters)) => {
1213 let rest = parameters.rest_parameter()?;
1214 let mut ser = oxc_estree::CompactTSSerializer::new(false);
1216 rest.serialize(&mut ser);
1217 Some(ser.into_string())
1218 }
1219 Some(JsNodeHandle::StatementInProgram { program, index }) => {
1220 let stmt = program.statement(*index)?;
1221 let mut ser = oxc_estree::CompactTSSerializer::new(false);
1222 stmt.serialize(&mut ser);
1223 Some(ser.into_string())
1224 }
1225 None => None,
1226 }
1227 }
1228
1229 fn oxc_span_offset(&self) -> i64 {
1231 match &self.node {
1232 Some(JsNodeHandle::Expression(parsed)) => {
1233 self.start as i64 - parsed.expression().span().start as i64
1234 }
1235 Some(JsNodeHandle::SequenceItem { root, index }) => {
1236 if let OxcExpression::SequenceExpression(seq) = root.expression()
1237 && let Some(expr) = seq.expressions.get(*index)
1238 {
1239 return self.start as i64 - expr.span().start as i64;
1240 }
1241 0
1242 }
1243 Some(JsNodeHandle::Pattern(parsed)) => {
1244 self.start as i64 - parsed.pattern().span().start as i64
1245 }
1246 Some(JsNodeHandle::ParameterItem { parameters, index }) => {
1247 if let Some(param) = parameters.parameter(*index) {
1248 return self.start as i64 - param.span.start as i64;
1249 }
1250 0
1251 }
1252 Some(JsNodeHandle::RestParameter(parameters)) => {
1253 if let Some(rest) = parameters.rest_parameter() {
1254 return self.start as i64 - rest.span.start as i64;
1255 }
1256 0
1257 }
1258 Some(JsNodeHandle::StatementInProgram { program, index }) => {
1259 if let Some(stmt) = program.statement(*index) {
1260 return self.start as i64 - stmt.span().start as i64;
1261 }
1262 0
1263 }
1264 None => 0,
1265 }
1266 }
1267}
1268
1269impl Expression {
1270 pub fn extract_internal_comments(&self) -> Vec<(u32, u32, serde_json::Value)> {
1274 let source = match &self.node {
1275 Some(JsNodeHandle::Expression(parsed)) => parsed.source(),
1276 _ => return Vec::new(),
1277 };
1278 let offset = self.oxc_span_offset();
1279 let mut comments = Vec::new();
1280 let bytes = source.as_bytes();
1281 let mut i = 0;
1282
1283 while i < bytes.len() {
1284 match bytes[i] {
1285 b'/' if i + 1 < bytes.len() && bytes[i + 1] == b'/' => {
1286 let start = i;
1287 i += 2;
1288 let value_start = i;
1289 while i < bytes.len() && bytes[i] != b'\n' {
1290 i += 1;
1291 }
1292 let value = &source[value_start..i];
1293 let abs_start = (start as i64 + offset) as u32;
1294 let abs_end = (i as i64 + offset) as u32;
1295 comments.push((
1296 abs_start,
1297 abs_end,
1298 crate::estree::EstreeComment {
1299 kind: crate::estree::EstreeCommentKind::Line,
1300 value: value.to_string(),
1301 start: Some(abs_start as usize),
1302 end: Some(abs_end as usize),
1303 }
1304 .to_json_value(),
1305 ));
1306 if i < bytes.len() {
1307 i += 1;
1308 }
1309 }
1310 b'/' if i + 1 < bytes.len() && bytes[i + 1] == b'*' => {
1311 let start = i;
1312 i += 2;
1313 let value_start = i;
1314 while i + 1 < bytes.len() && !(bytes[i] == b'*' && bytes[i + 1] == b'/') {
1315 i += 1;
1316 }
1317 let value_end = i;
1318 if i + 1 < bytes.len() {
1319 i += 2;
1320 } else {
1321 i = bytes.len();
1322 }
1323 let value = &source[value_start..value_end];
1324 let abs_start = (start as i64 + offset) as u32;
1325 let abs_end = (i as i64 + offset) as u32;
1326 comments.push((
1327 abs_start,
1328 abs_end,
1329 crate::estree::EstreeComment {
1330 kind: crate::estree::EstreeCommentKind::Block,
1331 value: value.to_string(),
1332 start: Some(abs_start as usize),
1333 end: Some(abs_end as usize),
1334 }
1335 .to_json_value(),
1336 ));
1337 }
1338 b'"' => {
1339 i += 1;
1341 while i < bytes.len() && bytes[i] != b'"' {
1342 if bytes[i] == b'\\' {
1343 i += 1;
1344 }
1345 i += 1;
1346 }
1347 if i < bytes.len() {
1348 i += 1;
1349 }
1350 }
1351 b'\'' => {
1352 i += 1;
1353 while i < bytes.len() && bytes[i] != b'\'' {
1354 if bytes[i] == b'\\' {
1355 i += 1;
1356 }
1357 i += 1;
1358 }
1359 if i < bytes.len() {
1360 i += 1;
1361 }
1362 }
1363 b'`' => {
1364 i += 1;
1365 while i < bytes.len() && bytes[i] != b'`' {
1366 if bytes[i] == b'\\' {
1367 i += 1;
1368 }
1369 i += 1;
1370 }
1371 if i < bytes.len() {
1372 i += 1;
1373 }
1374 }
1375 _ => {
1376 i += 1;
1377 }
1378 }
1379 }
1380
1381 comments
1382 }
1383}
1384
1385fn serialize_oxc_expression_unwrapped_ts(
1389 expr: &OxcExpression<'_>,
1390 ser: &mut oxc_estree::CompactTSSerializer,
1391) {
1392 use oxc_estree::ESTree;
1393 let mut inner = expr;
1394 while let OxcExpression::ParenthesizedExpression(paren) = inner {
1395 inner = &paren.expression;
1396 }
1397 inner.serialize(ser);
1398}
1399
1400
1401fn adjust_estree_span_offsets(json: &str, offset: i64) -> String {
1407 let bytes = json.as_bytes();
1408 let len = bytes.len();
1409 let mut result = String::with_capacity(len + 64);
1410 let mut i = 0;
1411
1412 while i < len {
1413 let remaining = &bytes[i..];
1414
1415 let key_len = if remaining.starts_with(b"\"start\":") {
1416 8 } else if remaining.starts_with(b"\"end\":") {
1418 6 } else {
1420 0
1421 };
1422
1423 if key_len > 0 {
1424 let before_ok = i == 0 || matches!(bytes[i - 1], b',' | b'{' | b'\n' | b' ');
1426 let num_start = i + key_len;
1427
1428 if before_ok && num_start < len && bytes[num_start].is_ascii_digit() {
1429 let mut num_end = num_start;
1430 while num_end < len && bytes[num_end].is_ascii_digit() {
1431 num_end += 1;
1432 }
1433
1434 if let Ok(val) = json[num_start..num_end].parse::<i64>() {
1435 let adjusted = (val + offset).max(0) as u64;
1436 result.push_str(&json[i..i + key_len]);
1437 result.push_str(&adjusted.to_string());
1438 i = num_end;
1439 continue;
1440 }
1441 }
1442 }
1443
1444 result.push(bytes[i] as char);
1446 i += 1;
1447 }
1448
1449 result
1450}
1451
1452#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
1453pub struct Identifier {
1454 pub start: usize,
1455 pub end: usize,
1456 #[serde(skip_serializing_if = "Option::is_none")]
1457 pub loc: Option<Loc>,
1458 pub name: Arc<str>,
1459}
1460
1461#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
1462pub struct Literal {
1463 pub start: usize,
1464 pub end: usize,
1465 #[serde(skip_serializing_if = "Option::is_none")]
1466 pub loc: Option<Loc>,
1467 pub value: LiteralValue,
1468 pub raw: Arc<str>,
1469}
1470
1471#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
1472pub struct BinaryExpression {
1473 pub start: usize,
1474 pub end: usize,
1475 #[serde(skip_serializing_if = "Option::is_none")]
1476 pub loc: Option<Loc>,
1477 pub left: Box<Expression>,
1478 pub operator: Arc<str>,
1479 pub right: Box<Expression>,
1480}
1481
1482#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
1483pub struct CallExpression {
1484 pub start: usize,
1485 pub end: usize,
1486 #[serde(skip_serializing_if = "Option::is_none")]
1487 pub loc: Option<Loc>,
1488 pub callee: Box<Expression>,
1489 pub arguments: Box<[Expression]>,
1490 pub optional: bool,
1491}
1492
1493#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
1494pub struct Text {
1495 pub start: usize,
1496 pub end: usize,
1497 pub raw: Arc<str>,
1498 pub data: Arc<str>,
1499}
1500
1501#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
1502pub struct Css {
1503 pub r#type: CssType,
1504 pub start: usize,
1505 pub end: usize,
1506 pub attributes: Box<[Attribute]>,
1507 pub children: Box<[CssNode]>,
1508 pub content: CssContent,
1509}
1510
1511#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
1512pub enum CssType {
1513 StyleSheet,
1514}
1515
1516#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
1517pub struct CssContent {
1518 pub start: usize,
1519 pub end: usize,
1520 pub styles: Arc<str>,
1521 pub comment: Option<Arc<str>>,
1522}
1523
1524#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
1525#[serde(tag = "type")]
1526pub enum CssNode {
1527 Rule(CssRule),
1528 Atrule(CssAtrule),
1529}
1530
1531#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
1532pub struct CssRule {
1533 pub prelude: CssSelectorList,
1534 pub block: CssBlock,
1535 pub start: usize,
1536 pub end: usize,
1537}
1538
1539#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
1540pub struct CssAtrule {
1541 pub start: usize,
1542 pub end: usize,
1543 pub name: Arc<str>,
1544 pub prelude: Arc<str>,
1545 pub block: Option<CssBlock>,
1546}
1547
1548#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
1549pub struct CssBlock {
1550 pub r#type: CssBlockType,
1551 pub start: usize,
1552 pub end: usize,
1553 pub children: Box<[CssBlockChild]>,
1554}
1555
1556#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
1557pub enum CssBlockType {
1558 Block,
1559}
1560
1561#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
1562#[serde(tag = "type")]
1563pub enum CssBlockChild {
1564 Declaration(CssDeclaration),
1565 Rule(CssRule),
1566 Atrule(CssAtrule),
1567}
1568
1569#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
1570pub struct CssDeclaration {
1571 pub start: usize,
1572 pub end: usize,
1573 pub property: Arc<str>,
1574 pub value: Arc<str>,
1575}
1576
1577#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
1578pub struct CssSelectorList {
1579 pub r#type: CssSelectorListType,
1580 pub start: usize,
1581 pub end: usize,
1582 pub children: Box<[CssComplexSelector]>,
1583}
1584
1585#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
1586pub enum CssSelectorListType {
1587 SelectorList,
1588}
1589
1590#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
1591pub struct CssComplexSelector {
1592 pub r#type: CssComplexSelectorType,
1593 pub start: usize,
1594 pub end: usize,
1595 pub children: Box<[CssRelativeSelector]>,
1596}
1597
1598#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
1599pub enum CssComplexSelectorType {
1600 ComplexSelector,
1601}
1602
1603#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
1604pub struct CssRelativeSelector {
1605 pub r#type: CssRelativeSelectorType,
1606 pub combinator: Option<CssCombinator>,
1607 pub selectors: Box<[CssSimpleSelector]>,
1608 pub start: usize,
1609 pub end: usize,
1610}
1611
1612#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
1613pub enum CssRelativeSelectorType {
1614 RelativeSelector,
1615}
1616
1617#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
1618pub struct CssCombinator {
1619 pub r#type: CssCombinatorType,
1620 pub name: Arc<str>,
1621 pub start: usize,
1622 pub end: usize,
1623}
1624
1625#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
1626pub enum CssCombinatorType {
1627 Combinator,
1628}
1629
1630#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
1631#[serde(tag = "type")]
1632pub enum CssSimpleSelector {
1633 TypeSelector(CssNameSelector),
1634 IdSelector(CssNameSelector),
1635 ClassSelector(CssNameSelector),
1636 PseudoElementSelector(CssNameSelector),
1637 PseudoClassSelector(CssPseudoClassSelector),
1638 AttributeSelector(CssAttributeSelector),
1639 Nth(CssValueSelector),
1640 Percentage(CssValueSelector),
1641 NestingSelector(CssNameSelector),
1642}
1643
1644#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
1645pub struct CssNameSelector {
1646 pub name: Arc<str>,
1647 pub start: usize,
1648 pub end: usize,
1649}
1650
1651#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
1652pub struct CssValueSelector {
1653 pub value: Arc<str>,
1654 pub start: usize,
1655 pub end: usize,
1656}
1657
1658#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
1659pub struct CssPseudoClassSelector {
1660 pub name: Arc<str>,
1661 pub args: Option<CssSelectorList>,
1662 pub start: usize,
1663 pub end: usize,
1664}
1665
1666#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
1667pub struct CssAttributeSelector {
1668 pub start: usize,
1669 pub end: usize,
1670 pub name: Arc<str>,
1671 pub matcher: Option<Arc<str>>,
1672 pub value: Option<Arc<str>>,
1673 pub flags: Option<Arc<str>>,
1674}
1675
1676#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
1677pub struct Options {
1678 pub start: usize,
1679 pub end: usize,
1680 pub attributes: Box<[Attribute]>,
1681 #[serde(skip_serializing, skip_deserializing, default)]
1682 pub fragment: Fragment,
1683 #[serde(skip_serializing_if = "Option::is_none")]
1684 #[serde(rename = "customElement")]
1685 pub custom_element: Option<CustomElement>,
1686 #[serde(skip_serializing_if = "Option::is_none")]
1687 pub runes: Option<bool>,
1688}
1689
1690#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
1691pub struct CustomElement {
1692 pub tag: Arc<str>,
1693}
1694
1695#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
1696#[serde(tag = "type")]
1697pub enum Node {
1698 Text(Text),
1699 IfBlock(IfBlock),
1700 EachBlock(EachBlock),
1701 KeyBlock(KeyBlock),
1702 AwaitBlock(AwaitBlock),
1703 SnippetBlock(SnippetBlock),
1704 RenderTag(RenderTag),
1705 HtmlTag(HtmlTag),
1706 ConstTag(ConstTag),
1707 DebugTag(DebugTag),
1708 ExpressionTag(ExpressionTag),
1709 Comment(Comment),
1710 RegularElement(RegularElement),
1711 Component(Component),
1712 SlotElement(SlotElement),
1713 SvelteHead(SvelteHead),
1714 SvelteBody(SvelteBody),
1715 SvelteWindow(SvelteWindow),
1716 SvelteDocument(SvelteDocument),
1717 SvelteComponent(SvelteComponent),
1718 SvelteElement(SvelteElement),
1719 SvelteSelf(SvelteSelf),
1720 SvelteFragment(SvelteFragment),
1721 SvelteBoundary(SvelteBoundary),
1722 TitleElement(TitleElement),
1723}
1724
1725pub trait HasFragment {
1726 fn fragment(&self) -> &Fragment;
1727}
1728
1729pub trait Element: Span + HasFragment {
1730 fn name(&self) -> &str;
1731 fn name_loc(&self) -> &SourceRange;
1732 fn attributes(&self) -> &[Attribute];
1733 fn expression(&self) -> Option<&Expression> {
1734 None
1735 }
1736 fn self_closing(&self) -> bool {
1737 false
1738 }
1739}
1740
1741macro_rules! impl_element {
1742 ($($ty:ty),* $(,)?) => {
1743 $(
1744 impl HasFragment for $ty {
1745 fn fragment(&self) -> &Fragment { &self.fragment }
1746 }
1747
1748 impl Element for $ty {
1749 fn name(&self) -> &str { &self.name }
1750 fn name_loc(&self) -> &SourceRange { &self.name_loc }
1751 fn attributes(&self) -> &[Attribute] { &self.attributes }
1752 }
1753 )*
1754 };
1755}
1756
1757impl_element!(
1758 Component,
1759 SlotElement,
1760 SvelteHead,
1761 SvelteBody,
1762 SvelteWindow,
1763 SvelteDocument,
1764 SvelteSelf,
1765 SvelteFragment,
1766 SvelteBoundary,
1767 TitleElement,
1768);
1769
1770impl Element for RegularElement {
1771 fn name(&self) -> &str {
1772 &self.name
1773 }
1774 fn name_loc(&self) -> &SourceRange {
1775 &self.name_loc
1776 }
1777 fn attributes(&self) -> &[Attribute] {
1778 &self.attributes
1779 }
1780 fn self_closing(&self) -> bool {
1781 self.self_closing
1782 }
1783}
1784
1785impl HasFragment for RegularElement {
1786 fn fragment(&self) -> &Fragment {
1787 &self.fragment
1788 }
1789}
1790
1791impl HasFragment for SvelteComponent {
1792 fn fragment(&self) -> &Fragment {
1793 &self.fragment
1794 }
1795}
1796
1797impl Element for SvelteComponent {
1798 fn name(&self) -> &str {
1799 &self.name
1800 }
1801 fn name_loc(&self) -> &SourceRange {
1802 &self.name_loc
1803 }
1804 fn attributes(&self) -> &[Attribute] {
1805 &self.attributes
1806 }
1807 fn expression(&self) -> Option<&Expression> {
1808 self.expression.as_ref()
1809 }
1810}
1811
1812impl HasFragment for SvelteElement {
1813 fn fragment(&self) -> &Fragment {
1814 &self.fragment
1815 }
1816}
1817
1818impl Element for SvelteElement {
1819 fn name(&self) -> &str {
1820 &self.name
1821 }
1822 fn name_loc(&self) -> &SourceRange {
1823 &self.name_loc
1824 }
1825 fn attributes(&self) -> &[Attribute] {
1826 &self.attributes
1827 }
1828 fn expression(&self) -> Option<&Expression> {
1829 self.expression.as_ref()
1830 }
1831}
1832
1833impl HasFragment for Root {
1834 fn fragment(&self) -> &Fragment {
1835 &self.fragment
1836 }
1837}
1838
1839impl HasFragment for KeyBlock {
1840 fn fragment(&self) -> &Fragment {
1841 &self.fragment
1842 }
1843}
1844
1845impl HasFragment for SnippetBlock {
1846 fn fragment(&self) -> &Fragment {
1847 &self.body
1848 }
1849}
1850
1851impl Alternate {
1852 pub fn try_for_each_fragment<B>(
1853 &self,
1854 mut visit: impl FnMut(&Fragment) -> ControlFlow<B>,
1855 ) -> ControlFlow<B> {
1856 match self {
1857 Self::Fragment(fragment) => visit(fragment),
1858 Self::IfBlock(block) => {
1859 visit(&block.consequent)?;
1860 if let Some(alternate) = block.alternate.as_deref() {
1861 alternate.try_for_each_fragment(visit)
1862 } else {
1863 ControlFlow::Continue(())
1864 }
1865 }
1866 }
1867 }
1868
1869 pub fn for_each_fragment(&self, mut visit: impl FnMut(&Fragment)) {
1870 let _ = self.try_for_each_fragment(|fragment| {
1871 visit(fragment);
1872 ControlFlow::<()>::Continue(())
1873 });
1874 }
1875}
1876
1877impl Node {
1878 pub fn as_element(&self) -> Option<&dyn Element> {
1879 match self {
1880 Node::RegularElement(el) => Some(el),
1881 Node::Component(el) => Some(el),
1882 Node::SlotElement(el) => Some(el),
1883 Node::SvelteHead(el) => Some(el),
1884 Node::SvelteBody(el) => Some(el),
1885 Node::SvelteWindow(el) => Some(el),
1886 Node::SvelteDocument(el) => Some(el),
1887 Node::SvelteComponent(el) => Some(el),
1888 Node::SvelteElement(el) => Some(el),
1889 Node::SvelteSelf(el) => Some(el),
1890 Node::SvelteFragment(el) => Some(el),
1891 Node::SvelteBoundary(el) => Some(el),
1892 Node::TitleElement(el) => Some(el),
1893 _ => None,
1894 }
1895 }
1896
1897 pub fn try_for_each_child_fragment<B>(
1898 &self,
1899 mut visit: impl FnMut(&Fragment) -> ControlFlow<B>,
1900 ) -> ControlFlow<B> {
1901 match self {
1902 Self::IfBlock(block) => {
1903 visit(&block.consequent)?;
1904 if let Some(alternate) = block.alternate.as_deref() {
1905 alternate.try_for_each_fragment(visit)
1906 } else {
1907 ControlFlow::Continue(())
1908 }
1909 }
1910 Self::EachBlock(block) => {
1911 visit(&block.body)?;
1912 if let Some(fallback) = block.fallback.as_ref() {
1913 visit(fallback)?;
1914 }
1915 ControlFlow::Continue(())
1916 }
1917 Self::KeyBlock(block) => visit(block.fragment()),
1918 Self::AwaitBlock(block) => {
1919 for fragment in [
1920 block.pending.as_ref(),
1921 block.then.as_ref(),
1922 block.catch.as_ref(),
1923 ]
1924 .into_iter()
1925 .flatten()
1926 {
1927 visit(fragment)?;
1928 }
1929 ControlFlow::Continue(())
1930 }
1931 Self::SnippetBlock(block) => visit(block.fragment()),
1932 _ => self
1933 .as_element()
1934 .map_or(ControlFlow::Continue(()), |element| {
1935 visit(element.fragment())
1936 }),
1937 }
1938 }
1939
1940 pub fn for_each_child_fragment(&self, mut visit: impl FnMut(&Fragment)) {
1941 let _ = self.try_for_each_child_fragment(|fragment| {
1942 visit(fragment);
1943 ControlFlow::<()>::Continue(())
1944 });
1945 }
1946}
1947
1948pub trait NodeVisitorMut {
1954 fn visit_expression(&mut self, expr: &mut Expression);
1956
1957 fn visit_node(&mut self, node: &mut Node) {
1959 self.walk_node_children(node);
1960 }
1961
1962 fn visit_fragment(&mut self, fragment: &mut Fragment) {
1964 for node in fragment.nodes.iter_mut() {
1965 self.visit_node(node);
1966 }
1967 }
1968
1969 fn visit_attribute(&mut self, attr: &mut Attribute) {
1971 self.walk_attribute_expressions(attr);
1972 }
1973
1974 fn walk_node_children(&mut self, node: &mut Node) {
1979 match node {
1980 Node::ExpressionTag(tag) => {
1981 self.visit_expression(&mut tag.expression);
1982 }
1983 Node::IfBlock(block) => {
1984 self.visit_expression(&mut block.test);
1985 self.visit_fragment(&mut block.consequent);
1986 if let Some(ref mut alt) = block.alternate {
1987 self.walk_alternate(alt);
1988 }
1989 }
1990 Node::EachBlock(block) => {
1991 self.visit_expression(&mut block.expression);
1992 if let Some(ref mut ctx) = block.context {
1993 self.visit_expression(ctx);
1994 }
1995 if let Some(ref mut key) = block.key {
1996 self.visit_expression(key);
1997 }
1998 self.visit_fragment(&mut block.body);
1999 if let Some(ref mut fallback) = block.fallback {
2000 self.visit_fragment(fallback);
2001 }
2002 }
2003 Node::KeyBlock(block) => {
2004 self.visit_expression(&mut block.expression);
2005 self.visit_fragment(&mut block.fragment);
2006 }
2007 Node::AwaitBlock(block) => {
2008 self.visit_expression(&mut block.expression);
2009 if let Some(ref mut v) = block.value {
2010 self.visit_expression(v);
2011 }
2012 if let Some(ref mut e) = block.error {
2013 self.visit_expression(e);
2014 }
2015 if let Some(ref mut f) = block.pending {
2016 self.visit_fragment(f);
2017 }
2018 if let Some(ref mut f) = block.then {
2019 self.visit_fragment(f);
2020 }
2021 if let Some(ref mut f) = block.catch {
2022 self.visit_fragment(f);
2023 }
2024 }
2025 Node::SnippetBlock(block) => {
2026 self.visit_expression(&mut block.expression);
2027 for param in block.parameters.iter_mut() {
2028 self.visit_expression(param);
2029 }
2030 self.visit_fragment(&mut block.body);
2031 }
2032 Node::RenderTag(tag) => {
2033 self.visit_expression(&mut tag.expression);
2034 }
2035 Node::HtmlTag(tag) => {
2036 self.visit_expression(&mut tag.expression);
2037 }
2038 Node::ConstTag(tag) => {
2039 self.visit_expression(&mut tag.declaration);
2040 }
2041 Node::DebugTag(tag) => {
2042 for expr in tag.arguments.iter_mut() {
2043 self.visit_expression(expr);
2044 }
2045 }
2046 Node::RegularElement(el) => {
2048 for attr in el.attributes.iter_mut() { self.visit_attribute(attr); }
2049 self.visit_fragment(&mut el.fragment);
2050 }
2051 Node::Component(el) => {
2052 for attr in el.attributes.iter_mut() { self.visit_attribute(attr); }
2053 self.visit_fragment(&mut el.fragment);
2054 }
2055 Node::SlotElement(el) => {
2056 for attr in el.attributes.iter_mut() { self.visit_attribute(attr); }
2057 self.visit_fragment(&mut el.fragment);
2058 }
2059 Node::SvelteHead(el) => {
2060 self.visit_fragment(&mut el.fragment);
2062 }
2063 Node::SvelteBody(el) => {
2064 for attr in el.attributes.iter_mut() { self.visit_attribute(attr); }
2065 self.visit_fragment(&mut el.fragment);
2066 }
2067 Node::SvelteWindow(el) => {
2068 for attr in el.attributes.iter_mut() { self.visit_attribute(attr); }
2069 self.visit_fragment(&mut el.fragment);
2070 }
2071 Node::SvelteDocument(el) => {
2072 for attr in el.attributes.iter_mut() { self.visit_attribute(attr); }
2073 self.visit_fragment(&mut el.fragment);
2074 }
2075 Node::SvelteComponent(el) => {
2076 if let Some(ref mut expr) = el.expression {
2077 self.visit_expression(expr);
2078 }
2079 for attr in el.attributes.iter_mut() { self.visit_attribute(attr); }
2080 self.visit_fragment(&mut el.fragment);
2081 }
2082 Node::SvelteElement(el) => {
2083 if let Some(ref mut expr) = el.expression {
2084 self.visit_expression(expr);
2085 }
2086 for attr in el.attributes.iter_mut() { self.visit_attribute(attr); }
2087 self.visit_fragment(&mut el.fragment);
2088 }
2089 Node::SvelteSelf(el) => {
2090 for attr in el.attributes.iter_mut() { self.visit_attribute(attr); }
2091 self.visit_fragment(&mut el.fragment);
2092 }
2093 Node::SvelteFragment(el) => {
2094 for attr in el.attributes.iter_mut() { self.visit_attribute(attr); }
2095 self.visit_fragment(&mut el.fragment);
2096 }
2097 Node::SvelteBoundary(el) => {
2098 for attr in el.attributes.iter_mut() { self.visit_attribute(attr); }
2099 self.visit_fragment(&mut el.fragment);
2100 }
2101 Node::TitleElement(el) => {
2102 for attr in el.attributes.iter_mut() { self.visit_attribute(attr); }
2103 self.visit_fragment(&mut el.fragment);
2104 }
2105 Node::Text(_) | Node::Comment(_) => {}
2106 }
2107 }
2108
2109 fn walk_alternate(&mut self, alt: &mut Alternate) {
2111 match alt {
2112 Alternate::Fragment(f) => self.visit_fragment(f),
2113 Alternate::IfBlock(block) => {
2114 self.visit_expression(&mut block.test);
2115 self.visit_fragment(&mut block.consequent);
2116 if let Some(ref mut inner) = block.alternate {
2117 self.walk_alternate(inner);
2118 }
2119 }
2120 }
2121 }
2122
2123 fn walk_attribute_expressions(&mut self, attr: &mut Attribute) {
2127 match attr {
2128 Attribute::Attribute(a) => {
2129 match &mut a.value {
2130 AttributeValueKind::ExpressionTag(tag) => {
2131 self.visit_expression(&mut tag.expression);
2132 }
2133 AttributeValueKind::Values(values) => {
2134 for val in values.iter_mut() {
2135 if let AttributeValue::ExpressionTag(tag) = val {
2136 self.visit_expression(&mut tag.expression);
2137 }
2138 }
2139 }
2140 AttributeValueKind::Boolean(_) => {}
2141 }
2142 }
2143 Attribute::SpreadAttribute(a) => {
2144 self.visit_expression(&mut a.expression);
2145 }
2146 Attribute::OnDirective(d)
2147 | Attribute::BindDirective(d)
2148 | Attribute::ClassDirective(d)
2149 | Attribute::LetDirective(d)
2150 | Attribute::AnimateDirective(d)
2151 | Attribute::UseDirective(d) => {
2152 self.visit_expression(&mut d.expression);
2153 }
2154 Attribute::StyleDirective(d) => {
2155 match &mut d.value {
2156 AttributeValueKind::ExpressionTag(tag) => {
2157 self.visit_expression(&mut tag.expression);
2158 }
2159 AttributeValueKind::Values(values) => {
2160 for val in values.iter_mut() {
2161 if let AttributeValue::ExpressionTag(tag) = val {
2162 self.visit_expression(&mut tag.expression);
2163 }
2164 }
2165 }
2166 AttributeValueKind::Boolean(_) => {}
2167 }
2168 }
2169 Attribute::TransitionDirective(d) => {
2170 self.visit_expression(&mut d.expression);
2171 }
2172 Attribute::AttachTag(a) => {
2173 self.visit_expression(&mut a.expression);
2174 }
2175 }
2176 }
2177}
2178
2179#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
2180pub struct RootComment {
2181 pub r#type: RootCommentType,
2182 pub start: usize,
2183 pub end: usize,
2184 pub value: Arc<str>,
2185 pub loc: SourceRange,
2186}
2187
2188#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
2189pub struct Root {
2190 pub css: Option<Css>,
2191 #[serde(skip_serializing, default)]
2192 pub styles: Box<[Css]>,
2193 pub js: Box<[Script]>,
2194 #[serde(skip_serializing, default)]
2195 pub scripts: Box<[Script]>,
2196 pub start: usize,
2197 pub end: usize,
2198 pub r#type: RootType,
2199 pub fragment: Fragment,
2200 pub options: Option<Options>,
2201 #[serde(skip_serializing_if = "Option::is_none")]
2202 pub module: Option<Script>,
2203 #[serde(skip_serializing_if = "Option::is_none")]
2204 pub instance: Option<Script>,
2205 #[serde(skip_serializing_if = "Option::is_none")]
2206 pub comments: Option<Box<[RootComment]>>,
2207 #[serde(skip_serializing, default)]
2208 pub errors: Box<[crate::ast::common::ParseError]>,
2209}
2210
2211impl Root {
2212 pub fn enrich_expressions(&mut self, source: &str, loose: bool) {
2215 enrich_fragment_expressions(&mut self.fragment, source, loose);
2216 if let Some(ref mut options) = self.options {
2217 enrich_options_expressions(options, source, loose);
2218 }
2219 self.inject_html_comments_into_scripts();
2221 }
2222
2223 fn inject_html_comments_into_scripts(&mut self) {
2226 let mut html_comments_before_instance: Vec<JsComment> = Vec::new();
2228 let mut html_comments_before_module: Vec<JsComment> = Vec::new();
2229
2230 let instance_start = self.instance.as_ref().map(|s| s.start);
2231 let module_start = self.module.as_ref().map(|s| s.start);
2232
2233 for node in self.fragment.nodes.iter() {
2234 if let Node::Comment(comment) = node {
2235 if let Some(inst_start) = instance_start {
2237 if comment.end <= inst_start {
2238 html_comments_before_instance.push(JsComment {
2239 kind: JsCommentKind::Line,
2240 value: comment.data.clone(),
2241 start: None,
2242 end: None,
2243 });
2244 }
2245 }
2246 if let Some(mod_start) = module_start {
2248 if comment.end <= mod_start {
2249 html_comments_before_module.push(JsComment {
2250 kind: JsCommentKind::Line,
2251 value: comment.data.clone(),
2252 start: None,
2253 end: None,
2254 });
2255 }
2256 }
2257 }
2258 }
2259
2260 if !html_comments_before_instance.is_empty() {
2262 if let Some(ref mut script) = self.instance {
2263 inject_leading_comments_into_content_json(
2264 &mut script.content_json,
2265 &html_comments_before_instance,
2266 );
2267 }
2268 }
2269 if !html_comments_before_module.is_empty() {
2270 if let Some(ref mut script) = self.module {
2271 inject_leading_comments_into_content_json(
2272 &mut script.content_json,
2273 &html_comments_before_module,
2274 );
2275 }
2276 }
2277 }
2278}
2279
2280fn inject_leading_comments_into_content_json(
2281 content_json: &mut Option<Arc<str>>,
2282 comments: &[JsComment],
2283) {
2284 let Some(json_str) = content_json.as_ref() else {
2285 return;
2286 };
2287 let Ok(mut value) = serde_json::from_str::<serde_json::Value>(json_str.as_ref()) else {
2288 return;
2289 };
2290 if let serde_json::Value::Object(ref mut map) = value {
2291 map.insert(
2292 "leadingComments".to_string(),
2293 serde_json::Value::Array(crate::estree::make_comment_json(comments)),
2294 );
2295 }
2296 if let Ok(enriched) = serde_json::to_string(&value) {
2297 *content_json = Some(Arc::from(enriched));
2298 }
2299}
2300
2301fn enrich_expression(expr: &mut Expression, source: &str) {
2302 if expr.node.is_some() && expr.enriched_json.is_none() {
2303 expr.enrich_with_source(source);
2304 }
2305}
2306
2307fn enrich_expression_with_character(expr: &mut Expression, source: &str) {
2308 if expr.enriched_json.is_none() {
2309 expr.enrich_with_character(source);
2310 }
2311}
2312
2313struct EnrichVisitor<'a> {
2315 source: &'a str,
2316 loose: bool,
2317}
2318
2319impl NodeVisitorMut for EnrichVisitor<'_> {
2320 fn visit_expression(&mut self, expr: &mut Expression) {
2321 enrich_expression(expr, self.source);
2322 }
2323
2324 fn visit_node(&mut self, node: &mut Node) {
2325 match node {
2328 Node::EachBlock(block) => {
2329 self.visit_expression(&mut block.expression);
2330 if let Some(ref mut ctx) = block.context {
2331 if ctx.is_destructured_pattern() {
2332 ctx.enrich_with_source_and_column_offset(self.source, 1);
2334 } else if self.loose {
2335 enrich_expression_with_character(ctx, self.source);
2336 } else {
2337 enrich_expression(ctx, self.source);
2338 }
2339 }
2340 if let Some(ref mut key) = block.key {
2341 self.visit_expression(key);
2342 }
2343 self.visit_fragment(&mut block.body);
2344 if let Some(ref mut fallback) = block.fallback {
2345 self.visit_fragment(fallback);
2346 }
2347 }
2348 Node::AwaitBlock(block) => {
2349 self.visit_expression(&mut block.expression);
2350 for opt_expr in [&mut block.value, &mut block.error] {
2352 if let Some(expr) = opt_expr {
2353 if self.loose {
2354 enrich_expression_with_character(expr, self.source);
2355 } else {
2356 enrich_expression(expr, self.source);
2357 }
2358 }
2359 }
2360 if let Some(ref mut f) = block.pending {
2361 self.visit_fragment(f);
2362 }
2363 if let Some(ref mut f) = block.then {
2364 self.visit_fragment(f);
2365 }
2366 if let Some(ref mut f) = block.catch {
2367 self.visit_fragment(f);
2368 }
2369 }
2370 Node::SnippetBlock(block) => {
2371 block.expression.enrich_with_character(self.source);
2373 for param in block.parameters.iter_mut() {
2374 self.visit_expression(param);
2375 }
2376 self.visit_fragment(&mut block.body);
2377 }
2378 _ => self.walk_node_children(node),
2380 }
2381 }
2382
2383 fn visit_attribute(&mut self, attr: &mut Attribute) {
2384 if self.loose {
2386 if let Attribute::Attribute(a) = attr {
2387 if let AttributeValueKind::ExpressionTag(tag) = &mut a.value {
2388 if tag.expression.node.is_none() && a.name.is_empty() {
2389 enrich_expression_with_character(&mut tag.expression, self.source);
2390 return;
2391 }
2392 }
2393 }
2394 }
2395 self.walk_attribute_expressions(attr);
2396 }
2397}
2398
2399fn enrich_fragment_expressions(fragment: &mut Fragment, source: &str, loose: bool) {
2400 let mut visitor = EnrichVisitor { source, loose };
2401 visitor.visit_fragment(fragment);
2402}
2403
2404fn enrich_options_expressions(options: &mut Options, source: &str, loose: bool) {
2405 let mut visitor = EnrichVisitor { source, loose };
2406 for attr in options.attributes.iter_mut() {
2407 visitor.visit_attribute(attr);
2408 }
2409}
2410
2411macro_rules! impl_span_for_struct {
2412 ($($ty:ty),* $(,)?) => {
2413 $(
2414 impl Span for $ty {
2415 fn start(&self) -> usize {
2416 self.start
2417 }
2418
2419 fn end(&self) -> usize {
2420 self.end
2421 }
2422 }
2423 )*
2424 };
2425}
2426
2427impl_span_for_struct!(
2428 Script,
2429 EachBlock,
2430 KeyBlock,
2431 AwaitBlock,
2432 SnippetBlock,
2433 RenderTag,
2434 HtmlTag,
2435 ConstTag,
2436 DebugTag,
2437 ExpressionTag,
2438 Comment,
2439 RegularElement,
2440 Component,
2441 SlotElement,
2442 SvelteHead,
2443 SvelteBody,
2444 SvelteWindow,
2445 SvelteDocument,
2446 SvelteComponent,
2447 SvelteElement,
2448 SvelteSelf,
2449 SvelteFragment,
2450 SvelteBoundary,
2451 TitleElement,
2452 IfBlock,
2453 Text,
2454 Css,
2455 CssContent,
2456 CssRule,
2457 CssAtrule,
2458 CssBlock,
2459 CssDeclaration,
2460 CssSelectorList,
2461 CssComplexSelector,
2462 CssRelativeSelector,
2463 CssCombinator,
2464 CssNameSelector,
2465 CssValueSelector,
2466 CssPseudoClassSelector,
2467 CssAttributeSelector,
2468 Options,
2469 RootComment,
2470 Root
2471);
2472
2473impl Span for Node {
2474 fn start(&self) -> usize {
2475 match self {
2476 Node::Text(node) => node.start,
2477 Node::IfBlock(node) => node.start,
2478 Node::EachBlock(node) => node.start,
2479 Node::KeyBlock(node) => node.start,
2480 Node::AwaitBlock(node) => node.start,
2481 Node::SnippetBlock(node) => node.start,
2482 Node::RenderTag(node) => node.start,
2483 Node::HtmlTag(node) => node.start,
2484 Node::ConstTag(node) => node.start,
2485 Node::DebugTag(node) => node.start,
2486 Node::ExpressionTag(node) => node.start,
2487 Node::Comment(node) => node.start,
2488 Node::RegularElement(node) => node.start,
2489 Node::Component(node) => node.start,
2490 Node::SlotElement(node) => node.start,
2491 Node::SvelteHead(node) => node.start,
2492 Node::SvelteBody(node) => node.start,
2493 Node::SvelteWindow(node) => node.start,
2494 Node::SvelteDocument(node) => node.start,
2495 Node::SvelteComponent(node) => node.start,
2496 Node::SvelteElement(node) => node.start,
2497 Node::SvelteSelf(node) => node.start,
2498 Node::SvelteFragment(node) => node.start,
2499 Node::SvelteBoundary(node) => node.start,
2500 Node::TitleElement(node) => node.start,
2501 }
2502 }
2503
2504 fn end(&self) -> usize {
2505 match self {
2506 Node::Text(node) => node.end,
2507 Node::IfBlock(node) => node.end,
2508 Node::EachBlock(node) => node.end,
2509 Node::KeyBlock(node) => node.end,
2510 Node::AwaitBlock(node) => node.end,
2511 Node::SnippetBlock(node) => node.end,
2512 Node::RenderTag(node) => node.end,
2513 Node::HtmlTag(node) => node.end,
2514 Node::ConstTag(node) => node.end,
2515 Node::DebugTag(node) => node.end,
2516 Node::ExpressionTag(node) => node.end,
2517 Node::Comment(node) => node.end,
2518 Node::RegularElement(node) => node.end,
2519 Node::Component(node) => node.end,
2520 Node::SlotElement(node) => node.end,
2521 Node::SvelteHead(node) => node.end,
2522 Node::SvelteBody(node) => node.end,
2523 Node::SvelteWindow(node) => node.end,
2524 Node::SvelteDocument(node) => node.end,
2525 Node::SvelteComponent(node) => node.end,
2526 Node::SvelteElement(node) => node.end,
2527 Node::SvelteSelf(node) => node.end,
2528 Node::SvelteFragment(node) => node.end,
2529 Node::SvelteBoundary(node) => node.end,
2530 Node::TitleElement(node) => node.end,
2531 }
2532 }
2533}
2534
2535#[cfg(test)]
2536mod tests {
2537 use super::*;
2538
2539 #[test]
2540 fn adjust_estree_span_offsets_adds_offset() {
2541 let json = r#"{"type":"Identifier","name":"foo","start":0,"end":3}"#;
2542 let adjusted = adjust_estree_span_offsets(json, 10);
2543 assert_eq!(
2544 adjusted,
2545 r#"{"type":"Identifier","name":"foo","start":10,"end":13}"#
2546 );
2547 }
2548
2549 #[test]
2550 fn adjust_estree_span_offsets_handles_nested() {
2551 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}"#;
2552 let adjusted = adjust_estree_span_offsets(json, 20);
2553 assert!(adjusted.contains(r#""start":20"#));
2554 assert!(adjusted.contains(r#""end":21"#));
2555 assert!(adjusted.contains(r#""start":24"#));
2556 assert!(adjusted.contains(r#""end":25"#));
2557 }
2558
2559 #[test]
2560 fn adjust_estree_span_offsets_preserves_string_values() {
2561 let json = r#"{"type":"Identifier","name":"start","start":0,"end":5}"#;
2563 let adjusted = adjust_estree_span_offsets(json, 10);
2564 assert_eq!(
2565 adjusted,
2566 r#"{"type":"Identifier","name":"start","start":10,"end":15}"#
2567 );
2568 }
2569
2570 #[test]
2571 fn expression_serializes_oxc_identifier_with_offset() {
2572 let parsed = crate::js::JsExpression::parse(
2573 "foo",
2574 oxc_span::SourceType::mjs(),
2575 )
2576 .expect("valid expression");
2577
2578 let expr = Expression::from_expression(Arc::new(parsed), 42, 45);
2579 let json = serde_json::to_string(&expr).expect("serialize");
2580 let value: serde_json::Value = serde_json::from_str(&json).expect("valid json");
2581
2582 assert_eq!(value["type"], "Identifier");
2583 assert_eq!(value["name"], "foo");
2584 assert_eq!(value["start"], 42);
2585 assert_eq!(value["end"], 45);
2586 }
2587
2588 #[test]
2589 fn expression_serializes_fallback_without_node() {
2590 let expr = Expression::empty(10, 20);
2591 let json = serde_json::to_string(&expr).expect("serialize");
2592 let value: serde_json::Value = serde_json::from_str(&json).expect("valid json");
2593
2594 assert_eq!(value["type"], "Identifier");
2595 assert_eq!(value["name"], "");
2596 assert_eq!(value["start"], 10);
2597 assert_eq!(value["end"], 20);
2598 }
2599
2600 #[test]
2601 fn ts_serializer_emits_type_annotation_on_arrow_params() {
2602 let parsed = crate::js::JsExpression::parse(
2603 "(e: MouseEvent) => e",
2604 oxc_span::SourceType::ts().with_module(true),
2605 )
2606 .expect("valid expression");
2607
2608 let expr = Expression::from_expression(Arc::new(parsed), 0, 20);
2609 let raw = expr.serialize_oxc_node().expect("should serialize");
2610 let value: serde_json::Value = serde_json::from_str(&raw).expect("valid json");
2611 assert_eq!(value["type"], "ArrowFunctionExpression");
2612 let param = &value["params"][0];
2613 assert!(param.get("typeAnnotation").is_some(), "param should have typeAnnotation");
2614 }
2615}