1
1
use hdx_atom:: Atom ;
2
2
use hdx_lexer:: Token ;
3
- use hdx_parser:: { diagnostics, Parse , Parser , Result as ParserResult , Span , Spanned , unexpected_ident, unexpected} ;
3
+ use hdx_parser:: {
4
+ diagnostics, expect, unexpected, unexpected_ident, Parse , Parser , Result as ParserResult , Span , Spanned ,
5
+ } ;
4
6
use hdx_writer:: { CssWriter , Result as WriterResult , WriteCss } ;
5
7
#[ cfg( feature = "serde" ) ]
6
8
use serde:: Serialize ;
@@ -37,37 +39,38 @@ impl<'a> Parse<'a> for Selector<'a> {
37
39
break ;
38
40
}
39
41
}
40
- _ => { }
41
- }
42
- let component = Component :: parse ( parser) ?;
43
- if let Some ( Spanned { node, span : component_span } ) = components. last ( ) {
44
- match ( node, & component. node ) {
45
- // A selector like `a /**/ b` would parse as // <Type>, <Descendant>,
46
- // <Descendant>, <Type>. The CSS selector grammar implicitly swallows adjacent
47
- // descendant combinators as whitespace, but due to simplifying AST nodes in our
48
- // parser, it means we must explicitly check for, and elide adjacent descendant
49
- // combinators. Adjacent Descendant Combinator Elision is the name of my metal
50
- // band, btw.
51
- ( Component :: Combinator ( _) , Component :: Combinator ( Combinator :: Descendant ) )
52
- | ( Component :: Combinator ( Combinator :: Descendant ) , Component :: Combinator ( _) ) => {
53
- continue ;
54
- }
55
- // Combinators cannot be next to eachother.
56
- ( Component :: Combinator ( _) , Component :: Combinator ( _) ) => {
57
- Err ( diagnostics:: AdjacentSelectorCombinators (
58
- * component_span,
59
- Span :: new ( span. start , component_span. start ) ,
60
- ) ) ?
42
+ _ => {
43
+ let component = Component :: parse ( parser) ?;
44
+ if let Some ( Spanned { node, span : component_span } ) = components. last ( ) {
45
+ match ( node, & component. node ) {
46
+ // A selector like `a /**/ b` would parse as // <Type>, <Descendant>,
47
+ // <Descendant>, <Type>. The CSS selector grammar implicitly swallows adjacent
48
+ // descendant combinators as whitespace, but due to simplifying AST nodes in our
49
+ // parser, it means we must explicitly check for, and elide adjacent descendant
50
+ // combinators. Adjacent Descendant Combinator Elision is the name of my metal
51
+ // band, btw.
52
+ ( Component :: Combinator ( _) , Component :: Combinator ( Combinator :: Descendant ) )
53
+ | ( Component :: Combinator ( Combinator :: Descendant ) , Component :: Combinator ( _) ) => {
54
+ continue ;
55
+ }
56
+ // Combinators cannot be next to eachother.
57
+ ( Component :: Combinator ( _) , Component :: Combinator ( _) ) => {
58
+ Err ( diagnostics:: AdjacentSelectorCombinators (
59
+ * component_span,
60
+ Span :: new ( span. start , component_span. start ) ,
61
+ ) ) ?
62
+ }
63
+ // Types cannot be next to eachother.
64
+ ( Component :: Type ( _) , Component :: Type ( _) ) => Err ( diagnostics:: AdjacentSelectorTypes (
65
+ * component_span,
66
+ Span :: new ( span. start , component_span. start ) ,
67
+ ) ) ?,
68
+ _ => { }
69
+ }
61
70
}
62
- // Types cannot be next to eachother.
63
- ( Component :: Type ( _) , Component :: Type ( _) ) => Err ( diagnostics:: AdjacentSelectorTypes (
64
- * component_span,
65
- Span :: new ( span. start , component_span. start ) ,
66
- ) ) ?,
67
- _ => { }
71
+ components. push ( component) ;
68
72
}
69
73
}
70
- components. push ( component) ;
71
74
}
72
75
Ok ( Self { components : parser. boxup ( components) } . spanned ( span. end ( parser. pos ( ) ) ) )
73
76
}
@@ -119,36 +122,36 @@ impl<'a> Parse<'a> for Component<'a> {
119
122
let span = parser. span ( ) ;
120
123
match parser. cur ( ) {
121
124
Token :: Whitespace => {
122
- parser. advance_including_whitespace_and_comments ( ) ;
125
+ parser. advance_including_whitespace ( ) ;
123
126
Ok ( Self :: Combinator ( Combinator :: Descendant ) . spanned ( span. end ( parser. pos ( ) ) ) )
124
127
}
125
128
Token :: Ident ( name) => {
126
- parser. advance_including_whitespace_and_comments ( ) ;
129
+ parser. advance_including_whitespace ( ) ;
127
130
Ok ( Self :: Type ( name. to_ascii_lowercase ( ) ) . spanned ( span) )
128
131
}
129
132
Token :: Colon => {
130
- parser. advance_including_whitespace_and_comments ( ) ;
131
- match parser. cur ( ) {
133
+ parser. advance_including_whitespace ( ) ;
134
+ match parser. cur ( ) {
132
135
Token :: Colon => {
133
- parser. advance_including_whitespace_and_comments ( ) ;
136
+ parser. advance_including_whitespace ( ) ;
134
137
match parser. cur ( ) {
135
138
Token :: Ident ( name) => {
136
139
if let Some ( selector) = PseudoElement :: from_atom ( name. clone ( ) ) {
137
- parser. advance_including_whitespace_and_comments ( ) ;
140
+ parser. advance_including_whitespace ( ) ;
138
141
Ok ( Self :: PseudoElement ( selector) . spanned ( span. end ( parser. pos ( ) ) ) )
139
142
} else {
140
143
unexpected_ident ! ( parser, name)
141
144
}
142
145
}
143
- token => unexpected ! ( parser, token)
146
+ token => unexpected ! ( parser, token) ,
144
147
}
145
148
}
146
149
Token :: Ident ( ident) => {
147
150
if let Some ( selector) = PseudoClass :: from_atom ( ident. clone ( ) ) {
148
- parser. advance_including_whitespace_and_comments ( ) ;
151
+ parser. advance_including_whitespace ( ) ;
149
152
Ok ( Self :: PseudoClass ( selector) . spanned ( span. end ( parser. pos ( ) ) ) )
150
153
} else if let Some ( e) = LegacyPseudoElement :: from_atom ( ident. clone ( ) ) {
151
- parser. advance_including_whitespace_and_comments ( ) ;
154
+ parser. advance_including_whitespace ( ) ;
152
155
Ok ( Self :: LegacyPseudoElement ( e) . spanned ( span. end ( parser. pos ( ) ) ) )
153
156
} else {
154
157
Err ( diagnostics:: UnexpectedIdent ( ident, parser. span ( ) ) ) ?
@@ -158,32 +161,30 @@ impl<'a> Parse<'a> for Component<'a> {
158
161
}
159
162
}
160
163
Token :: Hash ( name) => {
161
- parser. advance_including_whitespace_and_comments ( ) ;
164
+ parser. advance_including_whitespace ( ) ;
162
165
Ok ( Self :: Id ( name) . spanned ( span. end ( parser. pos ( ) ) ) )
163
166
}
164
167
Token :: Delim ( char) => match char {
165
168
'.' => {
166
- parser. advance_including_whitespace_and_comments ( ) ;
169
+ parser. advance_including_whitespace ( ) ;
167
170
match parser. cur ( ) {
168
171
Token :: Ident ( ident) => {
169
- parser. advance_including_whitespace_and_comments ( ) ;
172
+ parser. advance_including_whitespace ( ) ;
170
173
Ok ( Self :: Class ( ident) . spanned ( span. end ( parser. pos ( ) ) ) )
171
174
}
172
175
_ => Err ( diagnostics:: Unimplemented ( parser. span ( ) ) ) ?,
173
176
}
174
177
}
175
- '*' => {
176
- match parser. peek ( ) {
177
- Token :: Delim ( '|' ) => {
178
- let ( prefix, atom) = parse_wq_name ( parser) ?;
179
- Ok ( Self :: NSPrefixedType ( parser. boxup ( ( prefix, atom) ) ) . spanned ( span. end ( parser. pos ( ) ) ) )
180
- }
181
- _ => {
182
- parser. advance_including_whitespace_and_comments ( ) ;
183
- Ok ( Self :: Wildcard . spanned ( span. end ( parser. pos ( ) ) ) )
184
- }
178
+ '*' => match parser. peek ( ) {
179
+ Token :: Delim ( '|' ) => {
180
+ let ( prefix, atom) = parse_wq_name ( parser) ?;
181
+ Ok ( Self :: NSPrefixedType ( parser. boxup ( ( prefix, atom) ) ) . spanned ( span. end ( parser. pos ( ) ) ) )
185
182
}
186
- }
183
+ _ => {
184
+ parser. advance_including_whitespace ( ) ;
185
+ Ok ( Self :: Wildcard . spanned ( span. end ( parser. pos ( ) ) ) )
186
+ }
187
+ } ,
187
188
_ => Err ( diagnostics:: Unimplemented ( parser. span ( ) ) ) ?,
188
189
} ,
189
190
Token :: LeftSquare => {
@@ -344,41 +345,44 @@ pub struct ANBEvenOdd {
344
345
345
346
pub ( crate ) fn parse_wq_name ( parser : & mut Parser ) -> ParserResult < ( NSPrefix , Atom ) > {
346
347
let nsprefix = match parser. cur ( ) {
347
- Token :: Delim ( '|' ) => {
348
- parser. advance_including_whitespace_and_comments ( ) ;
348
+ Token :: Delim ( '|' ) if matches ! ( parser . peek ( ) , Token :: Ident ( _ ) ) => {
349
+ parser. advance_including_whitespace ( ) ;
349
350
NSPrefix :: None
350
- } ,
351
- Token :: Delim ( '*' ) => {
352
- parser. advance_including_whitespace_and_comments ( ) ;
353
- match parser. cur ( ) {
354
- Token :: Delim ( '|' ) => {
355
- parser. advance_including_whitespace_and_comments ( ) ;
356
- NSPrefix :: Wildcard
357
- } ,
358
- token => unexpected ! ( parser, token) ,
359
- }
351
+ }
352
+ Token :: Delim ( '*' ) if matches ! ( parser. peek( ) , Token :: Delim ( '|' ) ) => {
353
+ parser. advance_including_whitespace ( ) ;
354
+ expect ! ( parser, Token :: Delim ( '|' ) ) ;
355
+ parser. advance_including_whitespace ( ) ;
356
+ NSPrefix :: Wildcard
360
357
}
361
358
Token :: Ident ( name) => {
362
- parser. advance_including_whitespace_and_comments ( ) ;
359
+ parser. advance_including_whitespace ( ) ;
363
360
match parser. cur ( ) {
364
- Token :: Delim ( '|' ) => {
365
- parser. advance_including_whitespace_and_comments ( ) ;
361
+ Token :: Delim ( '|' ) if matches ! ( parser . peek ( ) , Token :: Ident ( _ ) ) => {
362
+ parser. advance_including_whitespace ( ) ;
366
363
NSPrefix :: Named ( name)
367
364
}
368
- _ => return Ok ( ( NSPrefix :: None , name) )
365
+ _ => return Ok ( ( NSPrefix :: None , name) ) ,
369
366
}
370
- } ,
367
+ }
371
368
token => unexpected ! ( parser, token) ,
372
369
} ;
373
370
match parser. cur ( ) {
374
- Token :: Ident ( name) => Ok ( ( nsprefix, name) ) ,
375
- token => unexpected ! ( parser, token)
371
+ Token :: Ident ( name) => {
372
+ parser. advance_including_whitespace ( ) ;
373
+ Ok ( ( nsprefix, name) )
374
+ }
375
+ token => unexpected ! ( parser, token) ,
376
376
}
377
377
}
378
378
379
379
#[ cfg( test) ]
380
380
mod test {
381
+ use oxc_allocator:: Allocator ;
382
+
381
383
use super :: * ;
384
+ use crate :: test_helpers:: test_write;
385
+
382
386
#[ test]
383
387
fn size_test ( ) {
384
388
assert_eq ! ( :: std:: mem:: size_of:: <Selector >( ) , 8 ) ;
@@ -394,4 +398,16 @@ mod test {
394
398
assert_eq ! ( :: std:: mem:: size_of:: <ANB >( ) , 8 ) ;
395
399
assert_eq ! ( :: std:: mem:: size_of:: <ANBEvenOdd >( ) , 8 ) ;
396
400
}
401
+
402
+ #[ test]
403
+ fn test_writes ( ) {
404
+ let allocator = Allocator :: default ( ) ;
405
+ test_write :: < Component > ( & allocator, ":root" , ":root" ) ;
406
+ test_write :: < Component > ( & allocator, "*" , "*" ) ;
407
+ test_write :: < Component > ( & allocator, "[attr|='foo']" , "[attr|=\" foo\" ]" ) ;
408
+ // test_write::<Component>(&allocator, "*|x", "*|x");
409
+ test_write :: < Selector > ( & allocator, ":root" , ":root" ) ;
410
+ test_write :: < Selector > ( & allocator, "body [attr|='foo']" , "body [attr|=\" foo\" ]" ) ;
411
+ // test_write::<Selector>(&allocator, "*|x :focus-within", "*|x :focus-within");
412
+ }
397
413
}
0 commit comments