@@ -75,6 +75,48 @@ module.exports = grammar(CSS, {
75
75
optional ( alias ( $ . pseudo_class_arguments , $ . arguments ) ) ,
76
76
) ,
77
77
78
+ pseudo_element_selector : $ => seq (
79
+ optional ( $ . _selector ) ,
80
+ '::' ,
81
+ alias ( choice ( $ . identifier , $ . _concatenated_identifier ) , $ . tag_name ) ,
82
+ optional ( alias ( $ . pseudo_element_arguments , $ . arguments ) ) ,
83
+ ) ,
84
+
85
+ id_selector : $ => seq (
86
+ optional ( $ . _selector ) ,
87
+ '#' ,
88
+ alias ( choice ( $ . identifier , $ . _concatenated_identifier ) , $ . id_name ) ,
89
+ ) ,
90
+
91
+ attribute_selector : $ => seq (
92
+ optional ( $ . _selector ) ,
93
+ '[' ,
94
+ alias ( choice ( $ . identifier , $ . _concatenated_identifier , $ . namespace_selector ) , $ . attribute_name ) ,
95
+ optional ( seq (
96
+ choice ( '=' , '~=' , '^=' , '|=' , '*=' , '$=' ) ,
97
+ $ . _value ,
98
+ ) ) ,
99
+ ']' ,
100
+ ) ,
101
+
102
+ child_selector : $ => prec . left ( seq (
103
+ optional ( $ . _selector ) ,
104
+ '>' ,
105
+ $ . _selector ,
106
+ ) ) ,
107
+
108
+ sibling_selector : $ => prec . left ( seq (
109
+ optional ( $ . _selector ) ,
110
+ '~' ,
111
+ $ . _selector ,
112
+ ) ) ,
113
+
114
+ adjacent_sibling_selector : $ => prec . left ( seq (
115
+ optional ( $ . _selector ) ,
116
+ '+' ,
117
+ $ . _selector ,
118
+ ) ) ,
119
+
78
120
// Declarations
79
121
80
122
declaration : $ => seq (
@@ -89,6 +131,8 @@ module.exports = grammar(CSS, {
89
131
';' ,
90
132
) ,
91
133
134
+ default : _ => '!default' ,
135
+
92
136
// Media queries
93
137
94
138
_query : ( $ , original ) => choice (
@@ -104,13 +148,71 @@ module.exports = grammar(CSS, {
104
148
$ . nesting_selector ,
105
149
$ . _concatenated_identifier ,
106
150
$ . list_value ,
151
+ $ . map_value ,
152
+ $ . unary_expression ,
153
+ $ . default ,
107
154
) ) ,
108
155
$ . variable ,
109
156
) ,
110
157
111
- use_statement : $ => seq ( '@use' , $ . _value , ';' ) ,
158
+ string_value : $ => choice (
159
+ seq (
160
+ '\'' ,
161
+ repeat ( choice (
162
+ alias ( / ( [ ^ # ' \n ] | \\ ( .| \n ) | \# [ ^ { ] ) + / , $ . string_content ) ,
163
+ $ . interpolation ,
164
+ ) ) ,
165
+ '\'' ,
166
+ ) ,
167
+ seq (
168
+ '"' ,
169
+ repeat ( choice (
170
+ alias ( / ( [ ^ # " \n ] | \\ ( .| \n ) | \# [ ^ { ] ) + / , $ . string_content ) ,
171
+ $ . interpolation ,
172
+ ) ) ,
173
+ '"' ,
174
+ ) ,
175
+ ) ,
176
+
177
+ use_statement : $ => seq (
178
+ '@use' ,
179
+ $ . _value ,
180
+ optional ( $ . as_clause ) ,
181
+ optional ( $ . with_clause ) ,
182
+ ';' ,
183
+ ) ,
184
+
185
+ as_clause : $ => seq ( 'as' , choice ( '*' , $ . identifier , $ . plain_value ) ) ,
186
+
187
+ with_clause : $ => seq ( 'with' , $ . with_parameters ) ,
188
+
189
+ with_parameters : $ => seq (
190
+ '(' ,
191
+ sep1 (
192
+ ',' ,
193
+ seq (
194
+ $ . variable ,
195
+ ':' ,
196
+ $ . _value ,
197
+ optional ( $ . default ) ,
198
+ ) ,
199
+ ) ,
200
+ optional ( ',' ) ,
201
+ ')' ,
202
+ ) ,
203
+
204
+ visibility_clause : $ => seq ( choice ( 'hide' , 'show' ) , $ . visibility_parameters ) ,
112
205
113
- forward_statement : $ => seq ( '@forward' , $ . _value , ';' ) ,
206
+ visibility_parameters : $ => sep1 ( ',' , $ . identifier ) ,
207
+
208
+ forward_statement : $ => seq (
209
+ '@forward' ,
210
+ $ . _value ,
211
+ optional ( $ . as_clause ) ,
212
+ optional ( $ . visibility_clause ) ,
213
+ optional ( $ . with_clause ) ,
214
+ ';' ,
215
+ ) ,
114
216
115
217
mixin_statement : $ => seq (
116
218
'@mixin' ,
@@ -146,12 +248,16 @@ module.exports = grammar(CSS, {
146
248
147
249
parameters : $ => seq ( '(' , sep1 ( ',' , $ . parameter ) , ')' ) ,
148
250
149
- parameter : $ => seq (
150
- $ . variable ,
151
- optional ( seq (
152
- ':' ,
153
- field ( 'default' , $ . _value ) ,
154
- ) ) ,
251
+ parameter : $ => choice (
252
+ seq (
253
+ $ . variable ,
254
+ optional ( '...' ) ,
255
+ optional ( seq (
256
+ ':' ,
257
+ field ( 'default' , $ . _value ) ,
258
+ ) ) ,
259
+ ) ,
260
+ '...' ,
155
261
) ,
156
262
157
263
return_statement : $ => seq ( '@return' , $ . _value , ';' ) ,
@@ -209,22 +315,46 @@ module.exports = grammar(CSS, {
209
315
$ . arguments ,
210
316
) ,
211
317
212
- binary_expression : $ => prec . left ( seq (
318
+ binary_expression : $ => prec . left ( 1 , seq (
213
319
$ . _value ,
214
- choice ( '+' , '-' , '*' , '/' , '==' , '<' , '>' , '!=' , '<=' , '>=' ) ,
320
+ choice ( '+' , '-' , '*' , '/' , '==' , '<' , '>' , '!=' , '<=' , '>=' , 'and' , 'or' ) ,
215
321
$ . _value ,
216
322
) ) ,
217
323
324
+ unary_expression : $ => seq (
325
+ choice ( '-' , '+' , '/' , 'not' ) ,
326
+ $ . _value ,
327
+ ) ,
328
+
218
329
list_value : $ => seq (
219
330
'(' ,
220
331
sep2 ( ',' , $ . _value ) ,
221
332
')' ,
222
333
) ,
223
334
335
+ map_value : $ => seq (
336
+ '(' ,
337
+ sep1 ( ',' , seq (
338
+ field ( 'key' , $ . _value ) ,
339
+ ':' ,
340
+ field ( 'value' , $ . _value ) ,
341
+ ) ) ,
342
+ ')' ,
343
+ ) ,
344
+
224
345
interpolation : $ => seq ( '#{' , $ . _value , '}' ) ,
225
346
226
347
placeholder : $ => seq ( '%' , $ . identifier ) ,
227
348
349
+ arguments : $ => seq (
350
+ token . immediate ( '(' ) ,
351
+ sep (
352
+ choice ( ',' , ';' ) ,
353
+ seq ( repeat1 ( $ . _value ) , optional ( '...' ) ) ,
354
+ ) ,
355
+ ')' ,
356
+ ) ,
357
+
228
358
_concatenated_identifier : $ => choice (
229
359
seq (
230
360
$ . identifier ,
@@ -243,9 +373,46 @@ module.exports = grammar(CSS, {
243
373
) ,
244
374
245
375
variable : _ => / ( [ a - z A - Z _ ] + \. ) ? \$ [ a - z A - Z - _ ] [ a - z A - Z 0 - 9 - _ ] * / ,
376
+
377
+ plain_value : _ => token ( seq (
378
+ repeat ( choice (
379
+ / [ - _ ] / ,
380
+ / \/ [ ^ \* \s , ; ! { } ( ) \[ \] ] / , // Slash not followed by a '*' (which would be a comment)
381
+ ) ) ,
382
+ / [ a - z A - Z ] / ,
383
+ choice (
384
+ / [ ^ / \s , : ; ! { } ( ) \[ \] ] / , // Not a slash, not a delimiter character (no colon)
385
+ / \/ [ ^ \* \s , : ; ! { } ( ) \[ \] ] / , // Slash not followed by a '*' (which would be a comment) (no colon)
386
+ seq (
387
+ repeat1 ( choice (
388
+ / [ ^ / \s , ; ! { } ( ) \[ \] ] / , // Not a slash, not a delimiter character
389
+ / \/ [ ^ \* \s , ; ! { } ( ) \[ \] ] / , // Slash not followed by a '*' (which would be a comment)
390
+ ) ) ,
391
+ choice (
392
+ / [ ^ / \s , : ; ! { } ( ) \[ \] ] / , // Not a slash, not a delimiter character (no colon)
393
+ / \/ [ ^ \* \s , : ; ! { } ( ) \[ \] ] / , // Slash not followed by a '*' (which would be a comment) (no colon)
394
+ ) ,
395
+ ) ,
396
+ ) ,
397
+ ) ) ,
398
+
246
399
} ,
247
400
} ) ;
248
401
402
+ /**
403
+ * Creates a rule to optionally match one or more of the rules separated by `separator`
404
+ *
405
+ * @param {RuleOrLiteral } separator
406
+ *
407
+ * @param {RuleOrLiteral } rule
408
+ *
409
+ * @return {ChoiceRule }
410
+ *
411
+ */
412
+ function sep ( separator , rule ) {
413
+ return optional ( sep1 ( separator , rule ) ) ;
414
+ }
415
+
249
416
/**
250
417
* Creates a rule to match one or more of the rules separated by `separator`
251
418
*
0 commit comments