@@ -18,7 +18,7 @@ const REGEX_HTML_COMMENT_CLOSE = /-->/;
18
18
* @param {import('../index.js').Parser } parser
19
19
* @param {number } start
20
20
* @param {Array<import('#compiler').Attribute | import('#compiler').SpreadAttribute | import('#compiler').Directive> } attributes
21
- * @returns {import('#compiler').Style }
21
+ * @returns {import('#compiler').Css.StyleSheet }
22
22
*/
23
23
export default function read_style ( parser , start , attributes ) {
24
24
const content_start = parser . index ;
@@ -28,7 +28,7 @@ export default function read_style(parser, start, attributes) {
28
28
parser . read ( / ^ < \/ s t y l e \s * > / ) ;
29
29
30
30
return {
31
- type : 'Style ' ,
31
+ type : 'StyleSheet ' ,
32
32
start,
33
33
end : parser . index ,
34
34
attributes,
@@ -37,8 +37,7 @@ export default function read_style(parser, start, attributes) {
37
37
start : content_start ,
38
38
end : content_end ,
39
39
styles : parser . template . slice ( content_start , content_end )
40
- } ,
41
- parent : null
40
+ }
42
41
} ;
43
42
}
44
43
@@ -187,42 +186,66 @@ function read_selector_list(parser, inside_pseudo_class = false) {
187
186
function read_selector ( parser , inside_pseudo_class = false ) {
188
187
const list_start = parser . index ;
189
188
190
- /** @type {Array< import('#compiler').Css.SimpleSelector | import('#compiler').Css.Combinator> } */
189
+ /** @type {import('#compiler').Css.RelativeSelector[] } */
191
190
const children = [ ] ;
192
191
192
+ /**
193
+ * @param {import('#compiler').Css.Combinator | null } combinator
194
+ * @param {number } start
195
+ * @returns {import('#compiler').Css.RelativeSelector }
196
+ */
197
+ function create_selector ( combinator , start ) {
198
+ return {
199
+ type : 'RelativeSelector' ,
200
+ combinator,
201
+ selectors : [ ] ,
202
+ start,
203
+ end : - 1 ,
204
+ metadata : {
205
+ is_global : false ,
206
+ is_host : false ,
207
+ is_root : false ,
208
+ scoped : false
209
+ }
210
+ } ;
211
+ }
212
+
213
+ /** @type {import('#compiler').Css.RelativeSelector } */
214
+ let relative_selector = create_selector ( null , parser . index ) ;
215
+
193
216
while ( parser . index < parser . template . length ) {
194
- const start = parser . index ;
217
+ let start = parser . index ;
195
218
196
219
if ( parser . eat ( '*' ) ) {
197
220
let name = '*' ;
198
- if ( parser . match ( '|' ) ) {
221
+
222
+ if ( parser . eat ( '|' ) ) {
199
223
// * is the namespace (which we ignore)
200
- parser . index ++ ;
201
224
name = read_identifier ( parser ) ;
202
225
}
203
226
204
- children . push ( {
227
+ relative_selector . selectors . push ( {
205
228
type : 'TypeSelector' ,
206
229
name,
207
230
start,
208
231
end : parser . index
209
232
} ) ;
210
233
} else if ( parser . eat ( '#' ) ) {
211
- children . push ( {
234
+ relative_selector . selectors . push ( {
212
235
type : 'IdSelector' ,
213
236
name : read_identifier ( parser ) ,
214
237
start,
215
238
end : parser . index
216
239
} ) ;
217
240
} else if ( parser . eat ( '.' ) ) {
218
- children . push ( {
241
+ relative_selector . selectors . push ( {
219
242
type : 'ClassSelector' ,
220
243
name : read_identifier ( parser ) ,
221
244
start,
222
245
end : parser . index
223
246
} ) ;
224
247
} else if ( parser . eat ( '::' ) ) {
225
- children . push ( {
248
+ relative_selector . selectors . push ( {
226
249
type : 'PseudoElementSelector' ,
227
250
name : read_identifier ( parser ) ,
228
251
start,
@@ -247,7 +270,7 @@ function read_selector(parser, inside_pseudo_class = false) {
247
270
error ( parser . index , 'invalid-css-global-selector' ) ;
248
271
}
249
272
250
- children . push ( {
273
+ relative_selector . selectors . push ( {
251
274
type : 'PseudoClassSelector' ,
252
275
name,
253
276
args,
@@ -276,7 +299,7 @@ function read_selector(parser, inside_pseudo_class = false) {
276
299
parser . allow_whitespace ( ) ;
277
300
parser . eat ( ']' , true ) ;
278
301
279
- children . push ( {
302
+ relative_selector . selectors . push ( {
280
303
type : 'AttributeSelector' ,
281
304
start,
282
305
end : parser . index ,
@@ -288,37 +311,28 @@ function read_selector(parser, inside_pseudo_class = false) {
288
311
} else if ( inside_pseudo_class && parser . match_regex ( REGEX_NTH_OF ) ) {
289
312
// nth of matcher must come before combinator matcher to prevent collision else the '+' in '+2n-1' would be parsed as a combinator
290
313
291
- children . push ( {
314
+ relative_selector . selectors . push ( {
292
315
type : 'Nth' ,
293
316
value : /**@type {string } */ ( parser . read ( REGEX_NTH_OF ) ) ,
294
317
start,
295
318
end : parser . index
296
319
} ) ;
297
- } else if ( parser . match_regex ( REGEX_COMBINATOR_WHITESPACE ) ) {
298
- parser . allow_whitespace ( ) ;
299
- const start = parser . index ;
300
- children . push ( {
301
- type : 'Combinator' ,
302
- name : /** @type {string } */ ( parser . read ( REGEX_COMBINATOR ) ) ,
303
- start,
304
- end : parser . index
305
- } ) ;
306
- parser . allow_whitespace ( ) ;
307
320
} else if ( parser . match_regex ( REGEX_PERCENTAGE ) ) {
308
- children . push ( {
321
+ relative_selector . selectors . push ( {
309
322
type : 'Percentage' ,
310
323
value : /** @type {string } */ ( parser . read ( REGEX_PERCENTAGE ) ) ,
311
324
start,
312
325
end : parser . index
313
326
} ) ;
314
- } else {
327
+ } else if ( ! parser . match_regex ( REGEX_COMBINATOR ) ) {
315
328
let name = read_identifier ( parser ) ;
316
- if ( parser . match ( '|' ) ) {
329
+
330
+ if ( parser . eat ( '|' ) ) {
317
331
// we ignore the namespace when trying to find matching element classes
318
- parser . index ++ ;
319
332
name = read_identifier ( parser ) ;
320
333
}
321
- children . push ( {
334
+
335
+ relative_selector . selectors . push ( {
322
336
type : 'TypeSelector' ,
323
337
name,
324
338
start,
@@ -330,29 +344,85 @@ function read_selector(parser, inside_pseudo_class = false) {
330
344
parser . allow_whitespace ( ) ;
331
345
332
346
if ( parser . match ( ',' ) || ( inside_pseudo_class ? parser . match ( ')' ) : parser . match ( '{' ) ) ) {
347
+ // rewind, so we know whether to continue building the selector list
333
348
parser . index = index ;
334
349
350
+ relative_selector . end = index ;
351
+ children . push ( relative_selector ) ;
352
+
335
353
return {
336
- type : 'Selector ' ,
354
+ type : 'ComplexSelector ' ,
337
355
start : list_start ,
338
356
end : index ,
339
- children
357
+ children,
358
+ metadata : {
359
+ used : false
360
+ }
340
361
} ;
341
362
}
342
363
343
- if ( parser . index !== index && ! parser . match_regex ( REGEX_COMBINATOR ) ) {
344
- children . push ( {
345
- type : 'Combinator' ,
346
- name : ' ' ,
347
- start : index ,
348
- end : parser . index
349
- } ) ;
364
+ parser . index = index ;
365
+ const combinator = read_combinator ( parser ) ;
366
+
367
+ if ( combinator ) {
368
+ if ( relative_selector . selectors . length === 0 ) {
369
+ if ( ! inside_pseudo_class ) {
370
+ error ( start , 'invalid-css-selector' ) ;
371
+ }
372
+ } else {
373
+ relative_selector . end = index ;
374
+ children . push ( relative_selector ) ;
375
+ }
376
+
377
+ // ...and start a new one
378
+ relative_selector = create_selector ( combinator , combinator . start ) ;
379
+
380
+ parser . allow_whitespace ( ) ;
381
+
382
+ if ( parser . match ( ',' ) || ( inside_pseudo_class ? parser . match ( ')' ) : parser . match ( '{' ) ) ) {
383
+ error ( parser . index , 'invalid-css-selector' ) ;
384
+ }
350
385
}
351
386
}
352
387
353
388
error ( parser . template . length , 'unexpected-eof' ) ;
354
389
}
355
390
391
+ /**
392
+ * @param {import('../index.js').Parser } parser
393
+ * @returns {import('#compiler').Css.Combinator | null }
394
+ */
395
+ function read_combinator ( parser ) {
396
+ const start = parser . index ;
397
+ parser . allow_whitespace ( ) ;
398
+
399
+ const index = parser . index ;
400
+ const name = parser . read ( REGEX_COMBINATOR ) ;
401
+
402
+ if ( name ) {
403
+ const end = parser . index ;
404
+ parser . allow_whitespace ( ) ;
405
+
406
+ return {
407
+ type : 'Combinator' ,
408
+ name,
409
+ start : index ,
410
+ end
411
+ } ;
412
+ }
413
+
414
+ if ( parser . index !== start ) {
415
+ return {
416
+ type : 'Combinator' ,
417
+ name : ' ' ,
418
+ start,
419
+ end : parser . index
420
+ } ;
421
+ }
422
+
423
+ return null ;
424
+ }
425
+
356
426
/**
357
427
* @param {import('../index.js').Parser } parser
358
428
* @returns {import('#compiler').Css.Block }
0 commit comments