@@ -8,6 +8,34 @@ use oxc_span::{Atom, Span};
88
99use super :: expression:: AngularExpression ;
1010
11+ // ============================================================================
12+ // Token Types (ported from Angular's ml_parser/tokens.ts)
13+ // ============================================================================
14+
15+ /// Token types for text and attribute value tokens.
16+ /// These are used to preserve the original token structure for transforms.
17+ #[ derive( Debug , Clone , Copy , PartialEq , Eq ) ]
18+ pub enum InterpolatedTokenType {
19+ /// Plain text: parts = [text]
20+ Text ,
21+ /// Interpolation: parts = [startMarker, expression, endMarker]
22+ Interpolation ,
23+ /// Encoded entity: parts = [decoded, encoded]
24+ EncodedEntity ,
25+ }
26+
27+ /// A token within interpolated text or attribute values.
28+ /// Preserves the original lexer tokens for transforms like whitespace removal.
29+ #[ derive( Debug ) ]
30+ pub struct InterpolatedToken < ' a > {
31+ /// The token type.
32+ pub token_type : InterpolatedTokenType ,
33+ /// The token parts (structure depends on token type).
34+ pub parts : Vec < ' a , Atom < ' a > > ,
35+ /// The source span.
36+ pub span : Span ,
37+ }
38+
1139/// An HTML AST node.
1240#[ derive( Debug ) ]
1341pub enum HtmlNode < ' a > {
@@ -34,10 +62,16 @@ pub enum HtmlNode<'a> {
3462/// A text node in the HTML AST.
3563#[ derive( Debug ) ]
3664pub struct HtmlText < ' a > {
37- /// The text value.
65+ /// The decoded text value (entities resolved, interpolations joined) .
3866 pub value : Atom < ' a > ,
39- /// The source span.
67+ /// The source span (after stripping leading trivia) .
4068 pub span : Span ,
69+ /// The full start offset before stripping leading trivia (for source maps).
70+ /// If None, there was no leading trivia stripped.
71+ pub full_start : Option < u32 > ,
72+ /// The original tokens (text, interpolation, encoded entity).
73+ /// Used by transforms like whitespace removal.
74+ pub tokens : Vec < ' a , InterpolatedToken < ' a > > ,
4175}
4276
4377/// An element node in the HTML AST.
@@ -83,14 +117,17 @@ pub struct HtmlDirective<'a> {
83117pub struct HtmlAttribute < ' a > {
84118 /// The attribute name.
85119 pub name : Atom < ' a > ,
86- /// The attribute value (may be empty ).
120+ /// The decoded attribute value (entities resolved, interpolations joined ).
87121 pub value : Atom < ' a > ,
88122 /// The source span.
89123 pub span : Span ,
90124 /// The name span.
91125 pub name_span : Span ,
92126 /// The value span (if value exists).
93127 pub value_span : Option < Span > ,
128+ /// The original value tokens (text, interpolation, encoded entity).
129+ /// Used by transforms. None for valueless attributes.
130+ pub value_tokens : Option < Vec < ' a , InterpolatedToken < ' a > > > ,
94131}
95132
96133/// A comment node in the HTML AST.
@@ -438,7 +475,12 @@ mod tests {
438475 fn test_traverse_all ( ) {
439476 let allocator = Allocator :: default ( ) ;
440477
441- let text = HtmlText { value : Atom :: from ( "Hello" ) , span : Span :: default ( ) } ;
478+ let text = HtmlText {
479+ value : Atom :: from ( "Hello" ) ,
480+ span : Span :: default ( ) ,
481+ full_start : None ,
482+ tokens : Vec :: new_in ( & allocator) ,
483+ } ;
442484
443485 let mut nodes = Vec :: new_in ( & allocator) ;
444486 nodes. push ( HtmlNode :: Text ( Box :: new_in ( text, & allocator) ) ) ;
0 commit comments