-
Notifications
You must be signed in to change notification settings - Fork 20
Expand file tree
/
Copy pathcss-spec.mjs
More file actions
3693 lines (3436 loc) · 470 KB
/
css-spec.mjs
File metadata and controls
3693 lines (3436 loc) · 470 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
import { describe, it } from 'node:test';
import assert from 'node:assert';
import testGrammar from '../testing-util/test.mjs';
describe('CSS grammar', function () {
it('parses the grammar', function () {
assert.ok(testGrammar.grammar);
assert.equal(testGrammar.grammar._grammar.scopeName, 'source.css');
});
describe('selectors', function () {
it('tokenizes type selectors', function () {
var tokens;
tokens = testGrammar.tokenizeLine('p {}').tokens;
assert.deepStrictEqual(tokens[0], { scopes: ['source.css', 'meta.selector.css', 'entity.name.tag.css'], value: 'p' });
});
it('tokenizes the universal selector', function () {
var tokens;
tokens = testGrammar.tokenizeLine('*').tokens;
assert.deepStrictEqual(tokens[0], { scopes: ['source.css', 'meta.selector.css', 'entity.name.tag.wildcard.css'], value: '*' });
});
it('tokenises combinators', function () {
var tokens;
tokens = testGrammar.tokenizeLine('a > b + * ~ :not(.nah)').tokens;
assert.deepStrictEqual(tokens[2], { scopes: ['source.css', 'meta.selector.css', 'keyword.operator.combinator.css'], value: '>' });
assert.deepStrictEqual(tokens[6], { scopes: ['source.css', 'meta.selector.css', 'keyword.operator.combinator.css'], value: '+' });
assert.deepStrictEqual(tokens[10], { scopes: ['source.css', 'meta.selector.css', 'keyword.operator.combinator.css'], value: '~' });
});
it('highlights deprecated combinators', function () {
var tokens;
tokens = testGrammar.tokenizeLine('.sooo /deep/ >>>_.>>>').tokens;
assert.deepStrictEqual(tokens[3], { scopes: ['source.css', 'invalid.deprecated.combinator.css'], value: '/deep/' });
assert.deepStrictEqual(tokens[5], { scopes: ['source.css', 'invalid.deprecated.combinator.css'], value: '>>>' });
});
it('tokenizes complex selectors', function () {
var lines, tokens;
tokens = testGrammar.tokenizeLine('[disabled], [disabled] + p').tokens;
assert.deepStrictEqual(tokens[0], { scopes: ["source.css", "meta.selector.css", "meta.attribute-selector.css", "punctuation.definition.entity.begin.bracket.square.css"], value: '[' });
assert.deepStrictEqual(tokens[1], { scopes: ["source.css", "meta.selector.css", "meta.attribute-selector.css", "entity.other.attribute-name.css"], value: 'disabled' });
assert.deepStrictEqual(tokens[2], { scopes: ["source.css", "meta.selector.css", "meta.attribute-selector.css", "punctuation.definition.entity.end.bracket.square.css"], value: ']' });
assert.deepStrictEqual(tokens[3], { scopes: ["source.css", "meta.selector.css", "punctuation.separator.list.comma.css"], value: ',' });
assert.deepStrictEqual(tokens[5], { scopes: ["source.css", "meta.selector.css", "meta.attribute-selector.css", "punctuation.definition.entity.begin.bracket.square.css"], value: '[' });
assert.deepStrictEqual(tokens[6], { scopes: ["source.css", "meta.selector.css", "meta.attribute-selector.css", "entity.other.attribute-name.css"], value: 'disabled' });
assert.deepStrictEqual(tokens[7], { scopes: ["source.css", "meta.selector.css", "meta.attribute-selector.css", "punctuation.definition.entity.end.bracket.square.css"], value: ']' });
assert.deepStrictEqual(tokens[9], { scopes: ["source.css", "meta.selector.css", "keyword.operator.combinator.css"], value: '+' });
assert.deepStrictEqual(tokens[11], { scopes: ["source.css", "meta.selector.css", "entity.name.tag.css"], value: 'p' });
lines = testGrammar.tokenizeLines("[disabled]:not(:first-child)::before:hover\n ~ div.object\n + #id.thing:hover > strong ~ p::before,\na::last-of-type,/*Comment*/::selection > html[lang^=en-AU],\n*>em.i.ly[data-name|=\"Life\"] { }");
assert.deepStrictEqual(lines[0][0], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'punctuation.definition.entity.begin.bracket.square.css'], value: '[' });
assert.deepStrictEqual(lines[0][1], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'entity.other.attribute-name.css'], value: 'disabled' });
assert.deepStrictEqual(lines[0][2], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'punctuation.definition.entity.end.bracket.square.css'], value: ']' });
assert.deepStrictEqual(lines[0][3], { scopes: ['source.css', 'meta.selector.css', 'entity.other.attribute-name.pseudo-class.css', 'punctuation.definition.entity.css'], value: ':' });
assert.deepStrictEqual(lines[0][4], { scopes: ['source.css', 'meta.selector.css', 'entity.other.attribute-name.pseudo-class.css'], value: 'not' });
assert.deepStrictEqual(lines[0][5], { scopes: ['source.css', 'meta.selector.css', 'punctuation.section.function.begin.bracket.round.css'], value: '(' });
assert.deepStrictEqual(lines[0][6], { scopes: ['source.css', 'meta.selector.css', 'entity.other.attribute-name.pseudo-class.css', 'punctuation.definition.entity.css'], value: ':' });
assert.deepStrictEqual(lines[0][7], { scopes: ['source.css', 'meta.selector.css', 'entity.other.attribute-name.pseudo-class.css'], value: 'first-child' });
assert.deepStrictEqual(lines[0][8], { scopes: ['source.css', 'meta.selector.css', 'punctuation.section.function.end.bracket.round.css'], value: ')' });
assert.deepStrictEqual(lines[0][9], { scopes: ['source.css', 'meta.selector.css', 'entity.other.attribute-name.pseudo-element.css', 'punctuation.definition.entity.css'], value: '::' });
assert.deepStrictEqual(lines[0][10], { scopes: ['source.css', 'meta.selector.css', 'entity.other.attribute-name.pseudo-element.css'], value: 'before' });
assert.deepStrictEqual(lines[0][11], { scopes: ['source.css', 'meta.selector.css', 'entity.other.attribute-name.pseudo-class.css', 'punctuation.definition.entity.css'], value: ':' });
assert.deepStrictEqual(lines[0][12], { scopes: ['source.css', 'meta.selector.css', 'entity.other.attribute-name.pseudo-class.css'], value: 'hover' });
assert.deepStrictEqual(lines[1][1], { scopes: ['source.css', 'meta.selector.css', 'keyword.operator.combinator.css'], value: '~' });
assert.deepStrictEqual(lines[1][3], { scopes: ['source.css', 'meta.selector.css', 'entity.name.tag.css'], value: 'div' });
assert.deepStrictEqual(lines[1][4], { scopes: ['source.css', 'meta.selector.css', 'entity.other.attribute-name.class.css', 'punctuation.definition.entity.css'], value: '.' });
assert.deepStrictEqual(lines[1][5], { scopes: ['source.css', 'meta.selector.css', 'entity.other.attribute-name.class.css'], value: 'object' });
assert.deepStrictEqual(lines[2][1], { scopes: ['source.css', 'meta.selector.css', 'keyword.operator.combinator.css'], value: '+' });
assert.deepStrictEqual(lines[2][3], { scopes: ['source.css', 'meta.selector.css', 'entity.other.attribute-name.id.css', 'punctuation.definition.entity.css'], value: '#' });
assert.deepStrictEqual(lines[2][4], { scopes: ['source.css', 'meta.selector.css', 'entity.other.attribute-name.id.css'], value: 'id' });
assert.deepStrictEqual(lines[2][5], { scopes: ['source.css', 'meta.selector.css', 'entity.other.attribute-name.class.css', 'punctuation.definition.entity.css'], value: '.' });
assert.deepStrictEqual(lines[2][6], { scopes: ['source.css', 'meta.selector.css', 'entity.other.attribute-name.class.css'], value: 'thing' });
assert.deepStrictEqual(lines[2][7], { scopes: ['source.css', 'meta.selector.css', 'entity.other.attribute-name.pseudo-class.css', 'punctuation.definition.entity.css'], value: ':' });
assert.deepStrictEqual(lines[2][8], { scopes: ['source.css', 'meta.selector.css', 'entity.other.attribute-name.pseudo-class.css'], value: 'hover' });
assert.deepStrictEqual(lines[2][10], { scopes: ['source.css', 'meta.selector.css', 'keyword.operator.combinator.css'], value: '>' });
assert.deepStrictEqual(lines[2][12], { scopes: ['source.css', 'meta.selector.css', 'entity.name.tag.css'], value: 'strong' });
assert.deepStrictEqual(lines[2][14], { scopes: ['source.css', 'meta.selector.css', 'keyword.operator.combinator.css'], value: '~' });
assert.deepStrictEqual(lines[2][16], { scopes: ['source.css', 'meta.selector.css', 'entity.name.tag.css'], value: 'p' });
assert.deepStrictEqual(lines[2][17], { scopes: ['source.css', 'meta.selector.css', 'entity.other.attribute-name.pseudo-element.css', 'punctuation.definition.entity.css'], value: '::' });
assert.deepStrictEqual(lines[2][18], { scopes: ['source.css', 'meta.selector.css', 'entity.other.attribute-name.pseudo-element.css'], value: 'before' });
assert.deepStrictEqual(lines[2][19], { scopes: ['source.css', 'meta.selector.css', 'punctuation.separator.list.comma.css'], value: ',' });
assert.deepStrictEqual(lines[3][0], { scopes: ['source.css', 'meta.selector.css', 'entity.name.tag.css'], value: 'a' });
assert.deepStrictEqual(lines[3][1], { scopes: ['source.css', 'meta.selector.css', 'entity.other.attribute-name.pseudo-class.css', 'punctuation.definition.entity.css'], value: ':' });
assert.deepStrictEqual(lines[3][2], { scopes: ['source.css', 'meta.selector.css', 'entity.other.attribute-name.pseudo-class.css', 'invalid.illegal.colon.css'], value: ':' });
assert.deepStrictEqual(lines[3][3], { scopes: ['source.css', 'meta.selector.css', 'entity.other.attribute-name.pseudo-class.css'], value: 'last-of-type' });
assert.deepStrictEqual(lines[3][4], { scopes: ['source.css', 'meta.selector.css', 'punctuation.separator.list.comma.css'], value: ',' });
assert.deepStrictEqual(lines[3][5], { scopes: ['source.css', 'comment.block.css', 'punctuation.definition.comment.begin.css'], value: '/*' });
assert.deepStrictEqual(lines[3][6], { scopes: ['source.css', 'comment.block.css'], value: 'Comment' });
assert.deepStrictEqual(lines[3][7], { scopes: ['source.css', 'comment.block.css', 'punctuation.definition.comment.end.css'], value: '*/' });
assert.deepStrictEqual(lines[3][8], { scopes: ['source.css', 'meta.selector.css', 'entity.other.attribute-name.pseudo-element.css', 'punctuation.definition.entity.css'], value: '::' });
assert.deepStrictEqual(lines[3][9], { scopes: ['source.css', 'meta.selector.css', 'entity.other.attribute-name.pseudo-element.css'], value: 'selection' });
assert.deepStrictEqual(lines[3][11], { scopes: ['source.css', 'meta.selector.css', 'keyword.operator.combinator.css'], value: '>' });
assert.deepStrictEqual(lines[3][13], { scopes: ['source.css', 'meta.selector.css', 'entity.name.tag.css'], value: 'html' });
assert.deepStrictEqual(lines[3][14], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'punctuation.definition.entity.begin.bracket.square.css'], value: '[' });
assert.deepStrictEqual(lines[3][15], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'entity.other.attribute-name.css'], value: 'lang' });
assert.deepStrictEqual(lines[3][16], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'keyword.operator.pattern.css'], value: '^=' });
assert.deepStrictEqual(lines[3][17], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'string.unquoted.attribute-value.css'], value: 'en-AU' });
assert.deepStrictEqual(lines[3][18], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'punctuation.definition.entity.end.bracket.square.css'], value: ']' });
assert.deepStrictEqual(lines[3][19], { scopes: ['source.css', 'meta.selector.css', 'punctuation.separator.list.comma.css'], value: ',' });
assert.deepStrictEqual(lines[4][0], { scopes: ['source.css', 'meta.selector.css', 'entity.name.tag.wildcard.css'], value: '*' });
assert.deepStrictEqual(lines[4][1], { scopes: ['source.css', 'meta.selector.css', 'keyword.operator.combinator.css'], value: '>' });
assert.deepStrictEqual(lines[4][2], { scopes: ['source.css', 'meta.selector.css', 'entity.name.tag.css'], value: 'em' });
assert.deepStrictEqual(lines[4][3], { scopes: ['source.css', 'meta.selector.css', 'entity.other.attribute-name.class.css', 'punctuation.definition.entity.css'], value: '.' });
assert.deepStrictEqual(lines[4][4], { scopes: ['source.css', 'meta.selector.css', 'entity.other.attribute-name.class.css'], value: 'i' });
assert.deepStrictEqual(lines[4][5], { scopes: ['source.css', 'meta.selector.css', 'entity.other.attribute-name.class.css', 'punctuation.definition.entity.css'], value: '.' });
assert.deepStrictEqual(lines[4][6], { scopes: ['source.css', 'meta.selector.css', 'entity.other.attribute-name.class.css'], value: 'ly' });
assert.deepStrictEqual(lines[4][7], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'punctuation.definition.entity.begin.bracket.square.css'], value: '[' });
assert.deepStrictEqual(lines[4][8], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'entity.other.attribute-name.css'], value: 'data-name' });
assert.deepStrictEqual(lines[4][9], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'keyword.operator.pattern.css'], value: '|=' });
assert.deepStrictEqual(lines[4][10], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'string.quoted.double.css', 'punctuation.definition.string.begin.css'], value: '"' });
assert.deepStrictEqual(lines[4][11], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'string.quoted.double.css'], value: 'Life' });
assert.deepStrictEqual(lines[4][12], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'string.quoted.double.css', 'punctuation.definition.string.end.css'], value: '"' });
assert.deepStrictEqual(lines[4][13], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'punctuation.definition.entity.end.bracket.square.css'], value: ']' });
assert.deepStrictEqual(lines[4][15], { scopes: ['source.css', 'meta.property-list.css', 'punctuation.section.property-list.begin.bracket.curly.css'], value: '{' });
assert.deepStrictEqual(lines[4][17], { scopes: ['source.css', 'meta.property-list.css', 'punctuation.section.property-list.end.bracket.curly.css'], value: '}' });
});
describe('custom elements (as type selectors)', function () {
it('only tokenizes identifiers beginning with [a-z]', function () {
var tokens;
tokens = testGrammar.tokenizeLine('pearl-1941 1941-pearl -pearl-1941').tokens;
assert.deepStrictEqual(tokens[0], { scopes: ['source.css', 'meta.selector.css', 'entity.name.tag.custom.css'], value: 'pearl-1941' });
assert.deepStrictEqual(tokens[1], { scopes: ['source.css', 'meta.selector.css'], value: ' 1941-pearl -pearl-1941' });
});
it('tokenizes custom elements containing non-ASCII letters', function () {
var tokens;
tokens = testGrammar.tokenizeLine('pokémon-ピカチュウ').tokens;
assert.deepStrictEqual(tokens[0], { scopes: ['source.css', 'meta.selector.css', 'entity.name.tag.custom.css'], value: 'pokémon-ピカチュウ' });
});
it('does not tokenize identifiers containing [A-Z]', function () {
var tokens;
tokens = testGrammar.tokenizeLine('Basecamp-schedule basecamp-Schedule').tokens;
assert.deepStrictEqual(tokens[0], { scopes: ['source.css', 'meta.selector.css'], value: 'Basecamp-schedule basecamp-Schedule' });
});
it('does not tokenize identifiers containing no hyphens', function () {
var tokens;
tokens = testGrammar.tokenizeLine('halo_night').tokens;
assert.deepStrictEqual(tokens[0], { scopes: ['source.css', 'meta.selector.css'], value: 'halo_night' });
});
it('does not tokenise identifiers following an @ symbol', function () {
var tokens;
tokens = testGrammar.tokenizeLine('@some-weird-new-feature').tokens;
assert.deepStrictEqual(tokens[0], { scopes: ['source.css', 'meta.at-rule.header.css', 'keyword.control.at-rule.css', 'punctuation.definition.keyword.css'], value: '@' });
assert.deepStrictEqual(tokens[1], { scopes: ['source.css', 'meta.at-rule.header.css', 'keyword.control.at-rule.css'], value: 'some-weird-new-feature' });
});
it('does not tokenise identifiers in unfamiliar functions', function () {
var tokens;
tokens = testGrammar.tokenizeLine('some-edgy-new-function()').tokens;
assert.deepStrictEqual(tokens[0], { scopes: ['source.css', 'meta.selector.css'], value: 'some-edgy-new-function(' });
assert.deepStrictEqual(tokens[1], { scopes: ['source.css'], value: ')' });
});
});
describe('attribute selectors', function () {
it('tokenizes attribute selectors without values', function () {
var tokens;
tokens = testGrammar.tokenizeLine('[title]').tokens;
assert.deepStrictEqual(tokens[0], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'punctuation.definition.entity.begin.bracket.square.css'], value: '[' });
assert.deepStrictEqual(tokens[1], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'entity.other.attribute-name.css'], value: 'title' });
assert.deepStrictEqual(tokens[2], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'punctuation.definition.entity.end.bracket.square.css'], value: ']' });
});
it('tokenizes attribute selectors with identifier values', function () {
var tokens;
tokens = testGrammar.tokenizeLine('[hreflang|=fr]').tokens;
assert.deepStrictEqual(tokens[0], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'punctuation.definition.entity.begin.bracket.square.css'], value: '[' });
assert.deepStrictEqual(tokens[1], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'entity.other.attribute-name.css'], value: 'hreflang' });
assert.deepStrictEqual(tokens[2], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'keyword.operator.pattern.css'], value: '|=' });
assert.deepStrictEqual(tokens[3], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'string.unquoted.attribute-value.css'], value: 'fr' });
assert.deepStrictEqual(tokens[4], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'punctuation.definition.entity.end.bracket.square.css'], value: ']' });
});
it('tokenizes attribute selectors with string values', function () {
var tokens;
tokens = testGrammar.tokenizeLine('[href^="http://www.w3.org/"]').tokens;
assert.deepStrictEqual(tokens[0], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'punctuation.definition.entity.begin.bracket.square.css'], value: '[' });
assert.deepStrictEqual(tokens[1], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'entity.other.attribute-name.css'], value: 'href' });
assert.deepStrictEqual(tokens[2], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'keyword.operator.pattern.css'], value: '^=' });
assert.deepStrictEqual(tokens[3], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'string.quoted.double.css', 'punctuation.definition.string.begin.css'], value: '"' });
assert.deepStrictEqual(tokens[4], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'string.quoted.double.css'], value: 'http://www.w3.org/' });
assert.deepStrictEqual(tokens[5], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'string.quoted.double.css', 'punctuation.definition.string.end.css'], value: '"' });
assert.deepStrictEqual(tokens[6], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'punctuation.definition.entity.end.bracket.square.css'], value: ']' });
});
it('tokenizes CSS qualified attribute names with wildcard prefix', function () {
var tokens;
tokens = testGrammar.tokenizeLine('[*|title]').tokens;
assert.deepStrictEqual(tokens[0], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'punctuation.definition.entity.begin.bracket.square.css'], value: '[' });
assert.deepStrictEqual(tokens[1], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'entity.other.namespace-prefix.css'], value: '*' });
assert.deepStrictEqual(tokens[2], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'punctuation.separator.css'], value: '|' });
assert.deepStrictEqual(tokens[3], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'entity.other.attribute-name.css'], value: 'title' });
assert.deepStrictEqual(tokens[4], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'punctuation.definition.entity.end.bracket.square.css'], value: ']' });
});
it('tokenizes CSS qualified attribute names with namespace prefix', function () {
var tokens;
tokens = testGrammar.tokenizeLine('[marvel|origin=radiation]').tokens;
assert.deepStrictEqual(tokens[0], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'punctuation.definition.entity.begin.bracket.square.css'], value: '[' });
assert.deepStrictEqual(tokens[1], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'entity.other.namespace-prefix.css'], value: 'marvel' });
assert.deepStrictEqual(tokens[2], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'punctuation.separator.css'], value: '|' });
assert.deepStrictEqual(tokens[3], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'entity.other.attribute-name.css'], value: 'origin' });
assert.deepStrictEqual(tokens[4], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'keyword.operator.pattern.css'], value: '=' });
assert.deepStrictEqual(tokens[5], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'string.unquoted.attribute-value.css'], value: 'radiation' });
assert.deepStrictEqual(tokens[6], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'punctuation.definition.entity.end.bracket.square.css'], value: ']' });
});
it('tokenizes CSS qualified attribute names without namespace prefix', function () {
var tokens;
tokens = testGrammar.tokenizeLine('[|data-hp="75"]').tokens;
assert.deepStrictEqual(tokens[0], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'punctuation.definition.entity.begin.bracket.square.css'], value: '[' });
assert.deepStrictEqual(tokens[1], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'punctuation.separator.css'], value: '|' });
assert.deepStrictEqual(tokens[2], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'entity.other.attribute-name.css'], value: 'data-hp' });
assert.deepStrictEqual(tokens[3], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'keyword.operator.pattern.css'], value: '=' });
assert.deepStrictEqual(tokens[4], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'string.quoted.double.css', 'punctuation.definition.string.begin.css'], value: '"' });
assert.deepStrictEqual(tokens[5], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'string.quoted.double.css'], value: '75' });
assert.deepStrictEqual(tokens[6], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'string.quoted.double.css', 'punctuation.definition.string.end.css'], value: '"' });
assert.deepStrictEqual(tokens[7], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'punctuation.definition.entity.end.bracket.square.css'], value: ']' });
});
it('tokenises compound ID/attribute selectors', function () {
var tokens;
tokens = testGrammar.tokenizeLine('#div[id="0"]{ }').tokens;
assert.deepStrictEqual(tokens[0], { scopes: ['source.css', 'meta.selector.css', 'entity.other.attribute-name.id.css', 'punctuation.definition.entity.css'], value: '#' });
assert.deepStrictEqual(tokens[1], { scopes: ['source.css', 'meta.selector.css', 'entity.other.attribute-name.id.css'], value: 'div' });
assert.deepStrictEqual(tokens[2], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'punctuation.definition.entity.begin.bracket.square.css'], value: '[' });
assert.deepStrictEqual(tokens[3], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'entity.other.attribute-name.css'], value: 'id' });
assert.deepStrictEqual(tokens[8], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'punctuation.definition.entity.end.bracket.square.css'], value: ']' });
tokens = testGrammar.tokenizeLine('.bar#div[id="0"]').tokens;
assert.deepStrictEqual(tokens[0], { scopes: ['source.css', 'meta.selector.css', 'entity.other.attribute-name.class.css', 'punctuation.definition.entity.css'], value: '.' });
assert.deepStrictEqual(tokens[1], { scopes: ['source.css', 'meta.selector.css', 'entity.other.attribute-name.class.css'], value: 'bar' });
assert.deepStrictEqual(tokens[2], { scopes: ['source.css', 'meta.selector.css', 'entity.other.attribute-name.id.css', 'punctuation.definition.entity.css'], value: '#' });
assert.deepStrictEqual(tokens[3], { scopes: ['source.css', 'meta.selector.css', 'entity.other.attribute-name.id.css'], value: 'div' });
assert.deepStrictEqual(tokens[4], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'punctuation.definition.entity.begin.bracket.square.css'], value: '[' });
assert.deepStrictEqual(tokens[5], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'entity.other.attribute-name.css'], value: 'id' });
});
it('tokenises compound class/attribute selectors', function () {
var tokens;
tokens = testGrammar.tokenizeLine('.div[id="0"]{ }').tokens;
assert.deepStrictEqual(tokens[0], { scopes: ['source.css', 'meta.selector.css', 'entity.other.attribute-name.class.css', 'punctuation.definition.entity.css'], value: '.' });
assert.deepStrictEqual(tokens[1], { scopes: ['source.css', 'meta.selector.css', 'entity.other.attribute-name.class.css'], value: 'div' });
assert.deepStrictEqual(tokens[2], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'punctuation.definition.entity.begin.bracket.square.css'], value: '[' });
assert.deepStrictEqual(tokens[3], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'entity.other.attribute-name.css'], value: 'id' });
assert.deepStrictEqual(tokens[8], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'punctuation.definition.entity.end.bracket.square.css'], value: ']' });
tokens = testGrammar.tokenizeLine('#bar.div[id]').tokens;
assert.deepStrictEqual(tokens[0], { scopes: ['source.css', 'meta.selector.css', 'entity.other.attribute-name.id.css', 'punctuation.definition.entity.css'], value: '#' });
assert.deepStrictEqual(tokens[1], { scopes: ['source.css', 'meta.selector.css', 'entity.other.attribute-name.id.css'], value: 'bar' });
assert.deepStrictEqual(tokens[2], { scopes: ['source.css', 'meta.selector.css', 'entity.other.attribute-name.class.css', 'punctuation.definition.entity.css'], value: '.' });
assert.deepStrictEqual(tokens[3], { scopes: ['source.css', 'meta.selector.css', 'entity.other.attribute-name.class.css'], value: 'div' });
assert.deepStrictEqual(tokens[4], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'punctuation.definition.entity.begin.bracket.square.css'], value: '[' });
assert.deepStrictEqual(tokens[5], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'entity.other.attribute-name.css'], value: 'id' });
assert.deepStrictEqual(tokens[6], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'punctuation.definition.entity.end.bracket.square.css'], value: ']' });
});
it('allows whitespace to be inserted between tokens', function () {
var tokens;
tokens = testGrammar.tokenizeLine('span[ er|lang |= "%%" ]').tokens;
assert.deepStrictEqual(tokens[1], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'punctuation.definition.entity.begin.bracket.square.css'], value: '[' });
assert.deepStrictEqual(tokens[2], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css'], value: ' ' });
assert.deepStrictEqual(tokens[3], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'entity.other.namespace-prefix.css'], value: 'er' });
assert.deepStrictEqual(tokens[4], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'punctuation.separator.css'], value: '|' });
assert.deepStrictEqual(tokens[5], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'entity.other.attribute-name.css'], value: 'lang' });
assert.deepStrictEqual(tokens[6], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css'], value: ' ' });
assert.deepStrictEqual(tokens[7], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'keyword.operator.pattern.css'], value: '|=' });
assert.deepStrictEqual(tokens[8], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css'], value: ' ' });
assert.deepStrictEqual(tokens[9], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'string.quoted.double.css', 'punctuation.definition.string.begin.css'], value: '"' });
assert.deepStrictEqual(tokens[10], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'string.quoted.double.css'], value: '%%' });
assert.deepStrictEqual(tokens[11], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'string.quoted.double.css', 'punctuation.definition.string.end.css'], value: '"' });
assert.deepStrictEqual(tokens[12], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css'], value: ' ' });
assert.deepStrictEqual(tokens[13], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'punctuation.definition.entity.end.bracket.square.css'], value: ']' });
});
it('tokenises escape sequences inside attribute selectors', function () {
var tokens;
tokens = testGrammar.tokenizeLine('a[name\\[0\\]="value"]').tokens;
assert.deepStrictEqual(tokens[2], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'entity.other.attribute-name.css'], value: 'name' });
assert.deepStrictEqual(tokens[3], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'entity.other.attribute-name.css', 'constant.character.escape.css'], value: '\\[' });
assert.deepStrictEqual(tokens[4], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'entity.other.attribute-name.css'], value: '0' });
assert.deepStrictEqual(tokens[5], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'entity.other.attribute-name.css', 'constant.character.escape.css'], value: '\\]' });
assert.deepStrictEqual(tokens[6], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'keyword.operator.pattern.css'], value: '=' });
assert.deepStrictEqual(tokens[10], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'punctuation.definition.entity.end.bracket.square.css'], value: ']' });
});
it('tokenises escape sequences inside namespace prefixes', function () {
var tokens;
tokens = testGrammar.tokenizeLine('a[name\\ space|Get\\ It\\?="kek"]').tokens;
assert.deepStrictEqual(tokens[2], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'entity.other.namespace-prefix.css'], value: 'name' });
assert.deepStrictEqual(tokens[3], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'entity.other.namespace-prefix.css', 'constant.character.escape.css'], value: '\\ ' });
assert.deepStrictEqual(tokens[4], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'entity.other.namespace-prefix.css'], value: 'space' });
assert.deepStrictEqual(tokens[5], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'punctuation.separator.css'], value: '|' });
assert.deepStrictEqual(tokens[6], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'entity.other.attribute-name.css'], value: 'Get' });
assert.deepStrictEqual(tokens[7], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'entity.other.attribute-name.css', 'constant.character.escape.css'], value: '\\ ' });
assert.deepStrictEqual(tokens[8], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'entity.other.attribute-name.css'], value: 'It' });
assert.deepStrictEqual(tokens[9], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'entity.other.attribute-name.css', 'constant.character.escape.css'], value: '\\?' });
assert.deepStrictEqual(tokens[10], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'keyword.operator.pattern.css'], value: '=' });
assert.deepStrictEqual(tokens[14], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'punctuation.definition.entity.end.bracket.square.css'], value: ']' });
});
it('tokenises comments inside attribute selectors', function () {
var tokens;
tokens = testGrammar.tokenizeLine('span[/*]*/lang]').tokens;
assert.deepStrictEqual(tokens[0], { scopes: ['source.css', 'meta.selector.css', 'entity.name.tag.css'], value: 'span' });
assert.deepStrictEqual(tokens[1], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'punctuation.definition.entity.begin.bracket.square.css'], value: '[' });
assert.deepStrictEqual(tokens[2], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'comment.block.css', 'punctuation.definition.comment.begin.css'], value: '/*' });
assert.deepStrictEqual(tokens[3], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'comment.block.css'], value: ']' });
assert.deepStrictEqual(tokens[4], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'comment.block.css', 'punctuation.definition.comment.end.css'], value: '*/' });
assert.deepStrictEqual(tokens[5], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'entity.other.attribute-name.css'], value: 'lang' });
assert.deepStrictEqual(tokens[6], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'punctuation.definition.entity.end.bracket.square.css'], value: ']' });
});
it('tokenises quoted strings in attribute selectors', function () {
var tokens;
tokens = testGrammar.tokenizeLine('a[href^="#"] a[href^= "#"] a[href^="#" ]').tokens;
assert.deepStrictEqual(tokens[4], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'string.quoted.double.css', 'punctuation.definition.string.begin.css'], value: '"' });
assert.deepStrictEqual(tokens[5], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'string.quoted.double.css'], value: '#' });
assert.deepStrictEqual(tokens[6], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'string.quoted.double.css', 'punctuation.definition.string.end.css'], value: '"' });
assert.deepStrictEqual(tokens[12], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'keyword.operator.pattern.css'], value: '^=' });
assert.deepStrictEqual(tokens[13], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css'], value: ' ' });
assert.deepStrictEqual(tokens[14], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'string.quoted.double.css', 'punctuation.definition.string.begin.css'], value: '"' });
assert.deepStrictEqual(tokens[15], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'string.quoted.double.css'], value: '#' });
assert.deepStrictEqual(tokens[16], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'string.quoted.double.css', 'punctuation.definition.string.end.css'], value: '"' });
assert.deepStrictEqual(tokens[23], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'string.quoted.double.css', 'punctuation.definition.string.begin.css'], value: '"' });
assert.deepStrictEqual(tokens[24], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'string.quoted.double.css'], value: '#' });
assert.deepStrictEqual(tokens[25], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'string.quoted.double.css', 'punctuation.definition.string.end.css'], value: '"' });
assert.deepStrictEqual(tokens[26], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css'], value: ' ' });
assert.deepStrictEqual(tokens[27], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'punctuation.definition.entity.end.bracket.square.css'], value: ']' });
tokens = testGrammar.tokenizeLine("a[href^='#'] a[href^= '#'] a[href^='#' ]").tokens;
assert.deepStrictEqual(tokens[4], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'string.quoted.single.css', 'punctuation.definition.string.begin.css'], value: "'" });
assert.deepStrictEqual(tokens[5], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'string.quoted.single.css'], value: '#' });
assert.deepStrictEqual(tokens[6], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'string.quoted.single.css', 'punctuation.definition.string.end.css'], value: "'" });
assert.deepStrictEqual(tokens[12], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'keyword.operator.pattern.css'], value: '^=' });
assert.deepStrictEqual(tokens[13], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css'], value: ' ' });
assert.deepStrictEqual(tokens[14], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'string.quoted.single.css', 'punctuation.definition.string.begin.css'], value: "'" });
assert.deepStrictEqual(tokens[15], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'string.quoted.single.css'], value: '#' });
assert.deepStrictEqual(tokens[16], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'string.quoted.single.css', 'punctuation.definition.string.end.css'], value: "'" });
assert.deepStrictEqual(tokens[23], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'string.quoted.single.css', 'punctuation.definition.string.begin.css'], value: "'" });
assert.deepStrictEqual(tokens[24], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'string.quoted.single.css'], value: '#' });
assert.deepStrictEqual(tokens[25], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'string.quoted.single.css', 'punctuation.definition.string.end.css'], value: "'" });
assert.deepStrictEqual(tokens[26], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css'], value: ' ' });
assert.deepStrictEqual(tokens[27], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'punctuation.definition.entity.end.bracket.square.css'], value: ']' });
});
it('tokenises unquoted strings in attribute selectors', function () {
var tokens;
tokens = testGrammar.tokenizeLine('span[class~=Java]').tokens;
assert.deepStrictEqual(tokens[3], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'keyword.operator.pattern.css'], value: '~=' });
assert.deepStrictEqual(tokens[4], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'string.unquoted.attribute-value.css'], value: 'Java' });
assert.deepStrictEqual(tokens[5], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'punctuation.definition.entity.end.bracket.square.css'], value: ']' });
tokens = testGrammar.tokenizeLine('span[class^= 0xDEADCAFE=|~BEEFBABE ]').tokens;
assert.deepStrictEqual(tokens[3], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'keyword.operator.pattern.css'], value: '^=' });
assert.deepStrictEqual(tokens[4], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css'], value: ' ' });
assert.deepStrictEqual(tokens[5], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'string.unquoted.attribute-value.css'], value: '0xDEADCAFE=|~BEEFBABE' });
assert.deepStrictEqual(tokens[6], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css'], value: ' ' });
assert.deepStrictEqual(tokens[7], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'punctuation.definition.entity.end.bracket.square.css'], value: ']' });
});
it('tokenises escape sequences in unquoted strings', function () {
var tokens;
tokens = testGrammar.tokenizeLine('a[name\\[0\\]=a\\BAD\\AF\\]a\\ i] {}').tokens;
assert.deepStrictEqual(tokens[6], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'keyword.operator.pattern.css'], value: '=' });
assert.deepStrictEqual(tokens[7], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'string.unquoted.attribute-value.css'], value: 'a' });
assert.deepStrictEqual(tokens[8], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'string.unquoted.attribute-value.css', 'constant.character.escape.codepoint.css'], value: '\\BAD' });
assert.deepStrictEqual(tokens[9], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'string.unquoted.attribute-value.css', 'constant.character.escape.codepoint.css'], value: '\\AF' });
assert.deepStrictEqual(tokens[10], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'string.unquoted.attribute-value.css', 'constant.character.escape.css'], value: '\\]' });
assert.deepStrictEqual(tokens[11], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'string.unquoted.attribute-value.css'], value: 'a' });
assert.deepStrictEqual(tokens[12], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'string.unquoted.attribute-value.css', 'constant.character.escape.css'], value: '\\ ' });
assert.deepStrictEqual(tokens[13], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'string.unquoted.attribute-value.css'], value: 'i' });
assert.deepStrictEqual(tokens[14], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'punctuation.definition.entity.end.bracket.square.css'], value: ']' });
assert.deepStrictEqual(tokens[16], { scopes: ['source.css', 'meta.property-list.css', 'punctuation.section.property-list.begin.bracket.curly.css'], value: '{' });
});
it('tokenises the ignore-case modifier at the end of a selector', function () {
var tokens;
tokens = testGrammar.tokenizeLine('a[attr=val i] a[attr="val" i] a[attr=\'val\'I] a[val^= \'"\'i] a[attr= i] a[attr= i i]').tokens;
assert.deepStrictEqual(tokens[6], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'storage.modifier.ignore-case.css'], value: 'i' });
assert.deepStrictEqual(tokens[7], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'punctuation.definition.entity.end.bracket.square.css'], value: ']' });
assert.deepStrictEqual(tokens[16], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css'], value: ' ' });
assert.deepStrictEqual(tokens[17], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'storage.modifier.ignore-case.css'], value: 'i' });
assert.deepStrictEqual(tokens[26], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'string.quoted.single.css', 'punctuation.definition.string.end.css'], value: "'" });
assert.deepStrictEqual(tokens[27], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'storage.modifier.ignore-case.css'], value: 'I' });
assert.deepStrictEqual(tokens[28], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'punctuation.definition.entity.end.bracket.square.css'], value: ']' });
assert.deepStrictEqual(tokens[34], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css'], value: ' ' });
assert.deepStrictEqual(tokens[35], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'string.quoted.single.css', 'punctuation.definition.string.begin.css'], value: "'" });
assert.deepStrictEqual(tokens[36], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'string.quoted.single.css'], value: '"' });
assert.deepStrictEqual(tokens[37], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'string.quoted.single.css', 'punctuation.definition.string.end.css'], value: "'" });
assert.deepStrictEqual(tokens[38], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'storage.modifier.ignore-case.css'], value: 'i' });
assert.deepStrictEqual(tokens[39], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'punctuation.definition.entity.end.bracket.square.css'], value: ']' });
assert.deepStrictEqual(tokens[44], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'keyword.operator.pattern.css'], value: '=' });
assert.deepStrictEqual(tokens[45], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css'], value: ' ' });
assert.deepStrictEqual(tokens[46], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'string.unquoted.attribute-value.css'], value: 'i' });
assert.deepStrictEqual(tokens[47], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'punctuation.definition.entity.end.bracket.square.css'], value: ']' });
assert.deepStrictEqual(tokens[52], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'keyword.operator.pattern.css'], value: '=' });
assert.deepStrictEqual(tokens[53], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css'], value: ' ' });
assert.deepStrictEqual(tokens[54], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'string.unquoted.attribute-value.css'], value: 'i' });
assert.deepStrictEqual(tokens[55], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css'], value: ' ' });
assert.deepStrictEqual(tokens[56], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'storage.modifier.ignore-case.css'], value: 'i' });
assert.deepStrictEqual(tokens[57], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'punctuation.definition.entity.end.bracket.square.css'], value: ']' });
});
it('tokenises attribute selectors spanning multiple lines', function () {
var lines;
lines = testGrammar.tokenizeLines("span[\n \\x20{2}\n ns|lang/**/\n |=\n\"pt\"]");
assert.deepStrictEqual(lines[0][0], { scopes: ['source.css', 'meta.selector.css', 'entity.name.tag.css'], value: 'span' });
assert.deepStrictEqual(lines[0][1], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'punctuation.definition.entity.begin.bracket.square.css'], value: '[' });
assert.deepStrictEqual(lines[1][0], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css'], value: ' ' });
assert.deepStrictEqual(lines[2][1], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'entity.other.namespace-prefix.css'], value: 'ns' });
assert.deepStrictEqual(lines[2][2], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'punctuation.separator.css'], value: '|' });
assert.deepStrictEqual(lines[2][3], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'entity.other.attribute-name.css'], value: 'lang' });
assert.deepStrictEqual(lines[2][4], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'comment.block.css', 'punctuation.definition.comment.begin.css'], value: '/*' });
assert.deepStrictEqual(lines[2][5], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'comment.block.css', 'punctuation.definition.comment.end.css'], value: '*/' });
assert.deepStrictEqual(lines[3][1], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'keyword.operator.pattern.css'], value: '|=' });
assert.deepStrictEqual(lines[4][0], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'string.quoted.double.css', 'punctuation.definition.string.begin.css'], value: '"' });
assert.deepStrictEqual(lines[4][1], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'string.quoted.double.css'], value: 'pt' });
assert.deepStrictEqual(lines[4][2], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'string.quoted.double.css', 'punctuation.definition.string.end.css'], value: '"' });
assert.deepStrictEqual(lines[4][3], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'punctuation.definition.entity.end.bracket.square.css'], value: ']' });
lines = testGrammar.tokenizeLines("span[/*===\n==|span[/*}\n====*/*|lang/*]=*/~=/*\"|\"*/\"en-AU\"/*\n |\n*/\ni]");
assert.deepStrictEqual(lines[0][2], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'comment.block.css', 'punctuation.definition.comment.begin.css'], value: '/*' });
assert.deepStrictEqual(lines[0][3], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'comment.block.css'], value: '===' });
assert.deepStrictEqual(lines[1][0], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'comment.block.css'], value: '==|span[/*}' });
assert.deepStrictEqual(lines[2][0], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'comment.block.css'], value: '====' });
assert.deepStrictEqual(lines[2][1], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'comment.block.css', 'punctuation.definition.comment.end.css'], value: '*/' });
assert.deepStrictEqual(lines[2][2], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'entity.other.namespace-prefix.css'], value: '*' });
assert.deepStrictEqual(lines[2][3], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'punctuation.separator.css'], value: '|' });
assert.deepStrictEqual(lines[2][4], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'entity.other.attribute-name.css'], value: 'lang' });
assert.deepStrictEqual(lines[2][5], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'comment.block.css', 'punctuation.definition.comment.begin.css'], value: '/*' });
assert.deepStrictEqual(lines[2][6], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'comment.block.css'], value: ']=' });
assert.deepStrictEqual(lines[2][7], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'comment.block.css', 'punctuation.definition.comment.end.css'], value: '*/' });
assert.deepStrictEqual(lines[2][8], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'keyword.operator.pattern.css'], value: '~=' });
assert.deepStrictEqual(lines[2][9], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'comment.block.css', 'punctuation.definition.comment.begin.css'], value: '/*' });
assert.deepStrictEqual(lines[2][10], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'comment.block.css'], value: '"|"' });
assert.deepStrictEqual(lines[2][11], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'comment.block.css', 'punctuation.definition.comment.end.css'], value: '*/' });
assert.deepStrictEqual(lines[2][12], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'string.quoted.double.css', 'punctuation.definition.string.begin.css'], value: '"' });
assert.deepStrictEqual(lines[2][13], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'string.quoted.double.css'], value: 'en-AU' });
assert.deepStrictEqual(lines[2][14], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'string.quoted.double.css', 'punctuation.definition.string.end.css'], value: '"' });
assert.deepStrictEqual(lines[2][15], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'comment.block.css', 'punctuation.definition.comment.begin.css'], value: '/*' });
assert.deepStrictEqual(lines[3][0], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'comment.block.css'], value: ' |' });
assert.deepStrictEqual(lines[4][0], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'comment.block.css', 'punctuation.definition.comment.end.css'], value: '*/' });
assert.deepStrictEqual(lines[5][0], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'storage.modifier.ignore-case.css'], value: 'i' });
assert.deepStrictEqual(lines[5][1], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'punctuation.definition.entity.end.bracket.square.css'], value: ']' });
});
});
describe('class selectors', function () {
it('tokenizes class selectors containing non-ASCII letters', function () {
var tokens;
tokens = testGrammar.tokenizeLine('.étendard').tokens;
assert.deepStrictEqual(tokens[0], { scopes: ['source.css', 'meta.selector.css', 'entity.other.attribute-name.class.css', 'punctuation.definition.entity.css'], value: '.' });
assert.deepStrictEqual(tokens[1], { scopes: ['source.css', 'meta.selector.css', 'entity.other.attribute-name.class.css'], value: 'étendard' });
tokens = testGrammar.tokenizeLine('.スポンサー').tokens;
assert.deepStrictEqual(tokens[0], { scopes: ['source.css', 'meta.selector.css', 'entity.other.attribute-name.class.css', 'punctuation.definition.entity.css'], value: '.' });
assert.deepStrictEqual(tokens[1], { scopes: ['source.css', 'meta.selector.css', 'entity.other.attribute-name.class.css'], value: 'スポンサー' });
});
it('tokenizes a class selector consisting of two hypens', function () {
var tokens;
tokens = testGrammar.tokenizeLine('.--').tokens;
assert.deepStrictEqual(tokens[0], { scopes: ['source.css', 'meta.selector.css', 'entity.other.attribute-name.class.css', 'punctuation.definition.entity.css'], value: '.' });
assert.deepStrictEqual(tokens[1], { scopes: ['source.css', 'meta.selector.css', 'entity.other.attribute-name.class.css'], value: '--' });
});
it('tokenizes class selectors consisting of one (valid) character', function () {
var tokens;
tokens = testGrammar.tokenizeLine('._').tokens;
assert.deepStrictEqual(tokens[0], { scopes: ['source.css', 'meta.selector.css', 'entity.other.attribute-name.class.css', 'punctuation.definition.entity.css'], value: '.' });
assert.deepStrictEqual(tokens[1], { scopes: ['source.css', 'meta.selector.css', 'entity.other.attribute-name.class.css'], value: '_' });
});
it('tokenises class selectors starting with an escape sequence', function () {
var tokens;
tokens = testGrammar.tokenizeLine('.\\33\\44-model {').tokens;
assert.deepStrictEqual(tokens[0], { scopes: ['source.css', 'meta.selector.css', 'entity.other.attribute-name.class.css', 'punctuation.definition.entity.css'], value: '.' });
assert.deepStrictEqual(tokens[1], { scopes: ['source.css', 'meta.selector.css', 'entity.other.attribute-name.class.css', 'constant.character.escape.codepoint.css'], value: '\\33' });
assert.deepStrictEqual(tokens[2], { scopes: ['source.css', 'meta.selector.css', 'entity.other.attribute-name.class.css', 'constant.character.escape.codepoint.css'], value: '\\44' });
assert.deepStrictEqual(tokens[3], { scopes: ['source.css', 'meta.selector.css', 'entity.other.attribute-name.class.css'], value: '-model' });
assert.deepStrictEqual(tokens[5], { scopes: ['source.css', 'meta.property-list.css', 'punctuation.section.property-list.begin.bracket.curly.css'], value: '{' });
});
it('tokenises class selectors ending with an escape sequence', function () {
var tokens;
tokens = testGrammar.tokenizeLine('.la\\{tex\\} {').tokens;
assert.deepStrictEqual(tokens[0], { scopes: ['source.css', 'meta.selector.css', 'entity.other.attribute-name.class.css', 'punctuation.definition.entity.css'], value: '.' });
assert.deepStrictEqual(tokens[1], { scopes: ['source.css', 'meta.selector.css', 'entity.other.attribute-name.class.css'], value: 'la' });
assert.deepStrictEqual(tokens[2], { scopes: ['source.css', 'meta.selector.css', 'entity.other.attribute-name.class.css', 'constant.character.escape.css'], value: '\\{' });
assert.deepStrictEqual(tokens[3], { scopes: ['source.css', 'meta.selector.css', 'entity.other.attribute-name.class.css'], value: 'tex' });
assert.deepStrictEqual(tokens[4], { scopes: ['source.css', 'meta.selector.css', 'entity.other.attribute-name.class.css', 'constant.character.escape.css'], value: '\\}' });
assert.deepStrictEqual(tokens[6], { scopes: ['source.css', 'meta.property-list.css', 'punctuation.section.property-list.begin.bracket.curly.css'], value: '{' });
});
it('marks a class invalid if it contains unescaped ASCII punctuation or symbols other than "-" and "_"', function () {
var tokens;
tokens = testGrammar.tokenizeLine('.B!W{').tokens;
assert.deepStrictEqual(tokens[0], { scopes: ['source.css', 'meta.selector.css', 'invalid.illegal.bad-identifier.css', 'punctuation.definition.entity.css'], value: '.' });
assert.deepStrictEqual(tokens[1], { scopes: ['source.css', 'meta.selector.css', 'invalid.illegal.bad-identifier.css'], value: 'B!W' });
assert.deepStrictEqual(tokens[2], { scopes: ['source.css', 'meta.property-list.css', 'punctuation.section.property-list.begin.bracket.curly.css'], value: '{' });
});
it('marks a class invalid if it starts with ASCII digits ([0-9])', function () {
var tokens;
tokens = testGrammar.tokenizeLine('.666{').tokens;
assert.deepStrictEqual(tokens[0], { scopes: ['source.css', 'meta.selector.css', 'invalid.illegal.bad-identifier.css', 'punctuation.definition.entity.css'], value: '.' });
assert.deepStrictEqual(tokens[1], { scopes: ['source.css', 'meta.selector.css', 'invalid.illegal.bad-identifier.css'], value: '666' });
assert.deepStrictEqual(tokens[2], { scopes: ['source.css', 'meta.property-list.css', 'punctuation.section.property-list.begin.bracket.curly.css'], value: '{' });
});
it('marks a class invalid if it starts with "-" followed by ASCII digits', function () {
var tokens;
tokens = testGrammar.tokenizeLine('.-911-{').tokens;
assert.deepStrictEqual(tokens[0], { scopes: ['source.css', 'meta.selector.css', 'invalid.illegal.bad-identifier.css', 'punctuation.definition.entity.css'], value: '.' });
assert.deepStrictEqual(tokens[1], { scopes: ['source.css', 'meta.selector.css', 'invalid.illegal.bad-identifier.css'], value: '-911-' });
assert.deepStrictEqual(tokens[2], { scopes: ['source.css', 'meta.property-list.css', 'punctuation.section.property-list.begin.bracket.curly.css'], value: '{' });
});
it('marks a class invalid if it consists of only one hyphen', function () {
var tokens;
tokens = testGrammar.tokenizeLine('.-{').tokens;
assert.deepStrictEqual(tokens[0], { scopes: ['source.css', 'meta.selector.css', 'invalid.illegal.bad-identifier.css', 'punctuation.definition.entity.css'], value: '.' });
assert.deepStrictEqual(tokens[1], { scopes: ['source.css', 'meta.selector.css', 'invalid.illegal.bad-identifier.css'], value: '-' });
assert.deepStrictEqual(tokens[2], { scopes: ['source.css', 'meta.property-list.css', 'punctuation.section.property-list.begin.bracket.curly.css'], value: '{' });
});
});
describe('id selectors', function () {
it('tokenizes id selectors consisting of ASCII letters', function () {
var tokens;
tokens = testGrammar.tokenizeLine('#unicorn').tokens;
assert.deepStrictEqual(tokens[0], { scopes: ['source.css', 'meta.selector.css', 'entity.other.attribute-name.id.css', 'punctuation.definition.entity.css'], value: '#' });
assert.deepStrictEqual(tokens[1], { scopes: ['source.css', 'meta.selector.css', 'entity.other.attribute-name.id.css'], value: 'unicorn' });
});
it('tokenizes id selectors containing non-ASCII letters', function () {
var tokens;
tokens = testGrammar.tokenizeLine('#洪荒之力').tokens;
assert.deepStrictEqual(tokens[0], { scopes: ['source.css', 'meta.selector.css', 'entity.other.attribute-name.id.css', 'punctuation.definition.entity.css'], value: '#' });
assert.deepStrictEqual(tokens[1], { scopes: ['source.css', 'meta.selector.css', 'entity.other.attribute-name.id.css'], value: '洪荒之力' });
});
it('tokenizes id selectors containing [0-9], "-", or "_"', function () {
var tokens;
tokens = testGrammar.tokenizeLine('#_zer0-day').tokens;
assert.deepStrictEqual(tokens[0], { scopes: ['source.css', 'meta.selector.css', 'entity.other.attribute-name.id.css', 'punctuation.definition.entity.css'], value: '#' });
assert.deepStrictEqual(tokens[1], { scopes: ['source.css', 'meta.selector.css', 'entity.other.attribute-name.id.css'], value: '_zer0-day' });
});
it('tokenizes id selectors beginning with two hyphens', function () {
var tokens;
tokens = testGrammar.tokenizeLine('#--d3bug--').tokens;
assert.deepStrictEqual(tokens[0], { scopes: ['source.css', 'meta.selector.css', 'entity.other.attribute-name.id.css', 'punctuation.definition.entity.css'], value: '#' });
assert.deepStrictEqual(tokens[1], { scopes: ['source.css', 'meta.selector.css', 'entity.other.attribute-name.id.css'], value: '--d3bug--' });
});
it('marks an id invalid if it contains ASCII punctuation or symbols other than "-" and "_"', function () {
var tokens;
tokens = testGrammar.tokenizeLine('#sort!{').tokens;
assert.deepStrictEqual(tokens[0], { scopes: ['source.css', 'meta.selector.css', 'invalid.illegal.bad-identifier.css', 'punctuation.definition.entity.css'], value: '#' });
assert.deepStrictEqual(tokens[1], { scopes: ['source.css', 'meta.selector.css', 'invalid.illegal.bad-identifier.css'], value: 'sort!' });
assert.deepStrictEqual(tokens[2], { scopes: ['source.css', 'meta.property-list.css', 'punctuation.section.property-list.begin.bracket.curly.css'], value: '{' });
});
it('marks an id invalid if it starts with ASCII digits ([0-9])', function () {
var tokens;
tokens = testGrammar.tokenizeLine('#666{').tokens;
assert.deepStrictEqual(tokens[0], { scopes: ['source.css', 'meta.selector.css', 'invalid.illegal.bad-identifier.css', 'punctuation.definition.entity.css'], value: '#' });
assert.deepStrictEqual(tokens[1], { scopes: ['source.css', 'meta.selector.css', 'invalid.illegal.bad-identifier.css'], value: '666' });
assert.deepStrictEqual(tokens[2], { scopes: ['source.css', 'meta.property-list.css', 'punctuation.section.property-list.begin.bracket.curly.css'], value: '{' });
});
it('marks an id invalid if it starts with "-" followed by ASCII digits', function () {
var tokens;
tokens = testGrammar.tokenizeLine('#-911-{').tokens;
assert.deepStrictEqual(tokens[0], { scopes: ['source.css', 'meta.selector.css', 'invalid.illegal.bad-identifier.css', 'punctuation.definition.entity.css'], value: '#' });
assert.deepStrictEqual(tokens[1], { scopes: ['source.css', 'meta.selector.css', 'invalid.illegal.bad-identifier.css'], value: '-911-' });
assert.deepStrictEqual(tokens[2], { scopes: ['source.css', 'meta.property-list.css', 'punctuation.section.property-list.begin.bracket.curly.css'], value: '{' });
});
it('marks an id invalid if it consists of one hyphen only', function () {
var tokens;
tokens = testGrammar.tokenizeLine('#-{').tokens;
assert.deepStrictEqual(tokens[0], { scopes: ['source.css', 'meta.selector.css', 'invalid.illegal.bad-identifier.css', 'punctuation.definition.entity.css'], value: '#' });
assert.deepStrictEqual(tokens[1], { scopes: ['source.css', 'meta.selector.css', 'invalid.illegal.bad-identifier.css'], value: '-' });
assert.deepStrictEqual(tokens[2], { scopes: ['source.css', 'meta.property-list.css', 'punctuation.section.property-list.begin.bracket.curly.css'], value: '{' });
});
it('tokenises ID selectors starting with an escape sequence', function () {
var tokens;
tokens = testGrammar.tokenizeLine('#\\33\\44-model {').tokens;
assert.deepStrictEqual(tokens[0], { scopes: ['source.css', 'meta.selector.css', 'entity.other.attribute-name.id.css', 'punctuation.definition.entity.css'], value: '#' });
assert.deepStrictEqual(tokens[1], { scopes: ['source.css', 'meta.selector.css', 'entity.other.attribute-name.id.css', 'constant.character.escape.codepoint.css'], value: '\\33' });
assert.deepStrictEqual(tokens[2], { scopes: ['source.css', 'meta.selector.css', 'entity.other.attribute-name.id.css', 'constant.character.escape.codepoint.css'], value: '\\44' });
assert.deepStrictEqual(tokens[3], { scopes: ['source.css', 'meta.selector.css', 'entity.other.attribute-name.id.css'], value: '-model' });
assert.deepStrictEqual(tokens[5], { scopes: ['source.css', 'meta.property-list.css', 'punctuation.section.property-list.begin.bracket.curly.css'], value: '{' });
});
it('tokenises ID selectors ending with an escape sequence', function () {
var tokens;
tokens = testGrammar.tokenizeLine('#la\\{tex\\} {').tokens;
assert.deepStrictEqual(tokens[0], { scopes: ['source.css', 'meta.selector.css', 'entity.other.attribute-name.id.css', 'punctuation.definition.entity.css'], value: '#' });
assert.deepStrictEqual(tokens[1], { scopes: ['source.css', 'meta.selector.css', 'entity.other.attribute-name.id.css'], value: 'la' });
assert.deepStrictEqual(tokens[2], { scopes: ['source.css', 'meta.selector.css', 'entity.other.attribute-name.id.css', 'constant.character.escape.css'], value: '\\{' });
assert.deepStrictEqual(tokens[3], { scopes: ['source.css', 'meta.selector.css', 'entity.other.attribute-name.id.css'], value: 'tex' });
assert.deepStrictEqual(tokens[4], { scopes: ['source.css', 'meta.selector.css', 'entity.other.attribute-name.id.css', 'constant.character.escape.css'], value: '\\}' });
assert.deepStrictEqual(tokens[6], { scopes: ['source.css', 'meta.property-list.css', 'punctuation.section.property-list.begin.bracket.curly.css'], value: '{' });
});
});
describe('namespace prefixes', function () {
it('tokenises arbitrary namespace prefixes', function () {
var tokens;
tokens = testGrammar.tokenizeLine('foo|h1 { }').tokens;
assert.deepStrictEqual(tokens[0], { scopes: ['source.css', 'meta.selector.css', 'entity.other.namespace-prefix.css'], value: 'foo' });
assert.deepStrictEqual(tokens[1], { scopes: ['source.css', 'meta.selector.css', 'punctuation.separator.css'], value: '|' });
assert.deepStrictEqual(tokens[2], { scopes: ['source.css', 'meta.selector.css', 'entity.name.tag.css'], value: 'h1' });
assert.deepStrictEqual(tokens[3], { scopes: ['source.css'], value: ' ' });
assert.deepStrictEqual(tokens[4], { scopes: ['source.css', 'meta.property-list.css', 'punctuation.section.property-list.begin.bracket.curly.css'], value: '{' });
assert.deepStrictEqual(tokens[6], { scopes: ['source.css', 'meta.property-list.css', 'punctuation.section.property-list.end.bracket.curly.css'], value: '}' });
});
it('tokenises anonymous namespace prefixes', function () {
var tokens;
tokens = testGrammar.tokenizeLine('*|abbr {}').tokens;
assert.deepStrictEqual(tokens[0], { scopes: ['source.css', 'meta.selector.css', 'entity.other.namespace-prefix.css'], value: '*' });
assert.deepStrictEqual(tokens[1], { scopes: ['source.css', 'meta.selector.css', 'punctuation.separator.css'], value: '|' });
assert.deepStrictEqual(tokens[2], { scopes: ['source.css', 'meta.selector.css', 'entity.name.tag.css'], value: 'abbr' });
assert.deepStrictEqual(tokens[3], { scopes: ['source.css'], value: ' ' });
assert.deepStrictEqual(tokens[4], { scopes: ['source.css', 'meta.property-list.css', 'punctuation.section.property-list.begin.bracket.curly.css'], value: '{' });
assert.deepStrictEqual(tokens[5], { scopes: ['source.css', 'meta.property-list.css', 'punctuation.section.property-list.end.bracket.curly.css'], value: '}' });
tokens = testGrammar.tokenizeLine('*|* {}').tokens;
assert.deepStrictEqual(tokens[0], { scopes: ['source.css', 'meta.selector.css', 'entity.other.namespace-prefix.css'], value: '*' });
assert.deepStrictEqual(tokens[1], { scopes: ['source.css', 'meta.selector.css', 'punctuation.separator.css'], value: '|' });
assert.deepStrictEqual(tokens[2], { scopes: ['source.css', 'meta.selector.css', 'entity.name.tag.wildcard.css'], value: '*' });
assert.deepStrictEqual(tokens[3], { scopes: ['source.css'], value: ' ' });
assert.deepStrictEqual(tokens[4], { scopes: ['source.css', 'meta.property-list.css', 'punctuation.section.property-list.begin.bracket.curly.css'], value: '{' });
assert.deepStrictEqual(tokens[5], { scopes: ['source.css', 'meta.property-list.css', 'punctuation.section.property-list.end.bracket.curly.css'], value: '}' });
tokens = testGrammar.tokenizeLine('foo|* { }').tokens;
assert.deepStrictEqual(tokens[0], { scopes: ['source.css', 'meta.selector.css', 'entity.other.namespace-prefix.css'], value: 'foo' });
assert.deepStrictEqual(tokens[1], { scopes: ['source.css', 'meta.selector.css', 'punctuation.separator.css'], value: '|' });
assert.deepStrictEqual(tokens[2], { scopes: ['source.css', 'meta.selector.css', 'entity.name.tag.wildcard.css'], value: '*' });
assert.deepStrictEqual(tokens[4], { scopes: ['source.css', 'meta.property-list.css', 'punctuation.section.property-list.begin.bracket.curly.css'], value: '{' });
assert.deepStrictEqual(tokens[6], { scopes: ['source.css', 'meta.property-list.css', 'punctuation.section.property-list.end.bracket.curly.css'], value: '}' });
tokens = testGrammar.tokenizeLine('|[svg|attr=name]{}').tokens;
assert.deepStrictEqual(tokens[0], { scopes: ['source.css', 'meta.selector.css', 'punctuation.separator.css'], value: '|' });
assert.deepStrictEqual(tokens[1], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'punctuation.definition.entity.begin.bracket.square.css'], value: '[' });
assert.deepStrictEqual(tokens[2], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'entity.other.namespace-prefix.css'], value: 'svg' });
assert.deepStrictEqual(tokens[3], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'punctuation.separator.css'], value: '|' });
assert.deepStrictEqual(tokens[4], { scopes: ['source.css', 'meta.selector.css', 'meta.attribute-selector.css', 'entity.other.attribute-name.css'], value: 'attr' });
});
it('tokenises the "no-namespace" prefix', function () {
var tokens;
tokens = testGrammar.tokenizeLine('|h1 { }').tokens;
assert.deepStrictEqual(tokens[0], { scopes: ['source.css', 'meta.selector.css', 'punctuation.separator.css'], value: '|' });
assert.deepStrictEqual(tokens[1], { scopes: ['source.css', 'meta.selector.css', 'entity.name.tag.css'], value: 'h1' });
assert.deepStrictEqual(tokens[3], { scopes: ['source.css', 'meta.property-list.css', 'punctuation.section.property-list.begin.bracket.curly.css'], value: '{' });
assert.deepStrictEqual(tokens[5], { scopes: ['source.css', 'meta.property-list.css', 'punctuation.section.property-list.end.bracket.curly.css'], value: '}' });
});
it("doesn't tokenise prefixes without a selector", function () {
var tokens;
tokens = testGrammar.tokenizeLine('*| { }').tokens;
assert.deepStrictEqual(tokens[0], { scopes: ['source.css', 'meta.selector.css', 'entity.name.tag.wildcard.css'], value: '*' });
assert.deepStrictEqual(tokens[1], { scopes: ['source.css', 'meta.selector.css'], value: '|' });
assert.deepStrictEqual(tokens[2], { scopes: ['source.css'], value: ' ' });
assert.deepStrictEqual(tokens[3], { scopes: ['source.css', 'meta.property-list.css', 'punctuation.section.property-list.begin.bracket.curly.css'], value: '{' });
assert.deepStrictEqual(tokens[5], { scopes: ['source.css', 'meta.property-list.css', 'punctuation.section.property-list.end.bracket.curly.css'], value: '}' });
tokens = testGrammar.tokenizeLine('*|{ }').tokens;
assert.deepStrictEqual(tokens[0], { scopes: ['source.css', 'meta.selector.css', 'entity.name.tag.wildcard.css'], value: '*' });
assert.deepStrictEqual(tokens[1], { scopes: ['source.css', 'meta.selector.css'], value: '|' });
assert.deepStrictEqual(tokens[2], { scopes: ['source.css', 'meta.property-list.css', 'punctuation.section.property-list.begin.bracket.curly.css'], value: '{' });
assert.deepStrictEqual(tokens[4], { scopes: ['source.css', 'meta.property-list.css', 'punctuation.section.property-list.end.bracket.curly.css'], value: '}' });
});
});
describe('at-rules', function () {
describe('@charset', function () {
it('tokenises @charset rules at the start of a file', function () {
var lines;
lines = testGrammar.tokenizeLines('@charset "US-ASCII";');
assert.deepStrictEqual(lines[0][0], { scopes: ['source.css', 'meta.at-rule.charset.css', 'keyword.control.at-rule.charset.css', 'punctuation.definition.keyword.css'], value: '@' });
assert.deepStrictEqual(lines[0][1], { scopes: ['source.css', 'meta.at-rule.charset.css', 'keyword.control.at-rule.charset.css'], value: 'charset' });
assert.deepStrictEqual(lines[0][2], { scopes: ['source.css', 'meta.at-rule.charset.css'], value: ' ' });
assert.deepStrictEqual(lines[0][3], { scopes: ['source.css', 'meta.at-rule.charset.css', 'string.quoted.double.css', 'punctuation.definition.string.begin.css'], value: '"' });
assert.deepStrictEqual(lines[0][4], { scopes: ['source.css', 'meta.at-rule.charset.css', 'string.quoted.double.css'], value: 'US-ASCII' });
assert.deepStrictEqual(lines[0][5], { scopes: ['source.css', 'meta.at-rule.charset.css', 'string.quoted.double.css', 'punctuation.definition.string.end.css'], value: '"' });
assert.deepStrictEqual(lines[0][6], { scopes: ['source.css', 'meta.at-rule.charset.css', 'punctuation.terminator.rule.css'], value: ';' });
lines = testGrammar.tokenizeLines('/* Not the first line */\n@charset "UTF-8";');
assert.deepStrictEqual(lines[0][0], { scopes: ['source.css', 'comment.block.css', 'punctuation.definition.comment.begin.css'], value: '/*' });
assert.deepStrictEqual(lines[0][1], { scopes: ['source.css', 'comment.block.css'], value: ' Not the first line ' });
assert.deepStrictEqual(lines[0][2], { scopes: ['source.css', 'comment.block.css', 'punctuation.definition.comment.end.css'], value: '*/' });
assert.deepStrictEqual(lines[1][0], { scopes: ['source.css', 'meta.at-rule.header.css', 'keyword.control.at-rule.css', 'punctuation.definition.keyword.css'], value: '@' });
assert.deepStrictEqual(lines[1][1], { scopes: ['source.css', 'meta.at-rule.header.css', 'keyword.control.at-rule.css'], value: 'charset' });
});
it('highlights invalid @charset statements', function () {
var lines;
lines = testGrammar.tokenizeLines(" @charset 'US-ASCII';");
assert.deepStrictEqual(lines[0][0], { scopes: ['source.css', 'meta.at-rule.charset.css', 'invalid.illegal.leading-whitespace.charset.css'], value: ' ' });
assert.deepStrictEqual(lines[0][1], { scopes: ['source.css', 'meta.at-rule.charset.css', 'keyword.control.at-rule.charset.css', 'punctuation.definition.keyword.css'], value: '@' });
assert.deepStrictEqual(lines[0][2], { scopes: ['source.css', 'meta.at-rule.charset.css', 'keyword.control.at-rule.charset.css'], value: 'charset' });
assert.deepStrictEqual(lines[0][4], { scopes: ['source.css', 'meta.at-rule.charset.css', 'invalid.illegal.not-double-quoted.charset.css'], value: "'US-ASCII'" });
assert.deepStrictEqual(lines[0][5], { scopes: ['source.css', 'meta.at-rule.charset.css', 'punctuation.terminator.rule.css'], value: ';' });
lines = testGrammar.tokenizeLines('@charset "iso-8859-15";');
assert.deepStrictEqual(lines[0][0], { scopes: ['source.css', 'meta.at-rule.charset.css', 'keyword.control.at-rule.charset.css', 'punctuation.definition.keyword.css'], value: '@' });
assert.deepStrictEqual(lines[0][1], { scopes: ['source.css', 'meta.at-rule.charset.css', 'keyword.control.at-rule.charset.css'], value: 'charset' });
assert.deepStrictEqual(lines[0][2], { scopes: ['source.css', 'meta.at-rule.charset.css', 'invalid.illegal.whitespace.charset.css'], value: ' ' });
assert.deepStrictEqual(lines[0][3], { scopes: ['source.css', 'meta.at-rule.charset.css', 'string.quoted.double.css', 'punctuation.definition.string.begin.css'], value: '"' });
assert.deepStrictEqual(lines[0][4], { scopes: ['source.css', 'meta.at-rule.charset.css', 'string.quoted.double.css'], value: 'iso-8859-15' });
assert.deepStrictEqual(lines[0][5], { scopes: ['source.css', 'meta.at-rule.charset.css', 'string.quoted.double.css', 'punctuation.definition.string.end.css'], value: '"' });
assert.deepStrictEqual(lines[0][6], { scopes: ['source.css', 'meta.at-rule.charset.css', 'punctuation.terminator.rule.css'], value: ';' });
lines = testGrammar.tokenizeLines('@charset"US-ASCII";');
assert.deepStrictEqual(lines[0][0], { scopes: ['source.css', 'meta.at-rule.charset.css', 'invalid.illegal.no-whitespace.charset.css'], value: '@charset"US-ASCII"' });
assert.deepStrictEqual(lines[0][1], { scopes: ['source.css', 'meta.at-rule.charset.css', 'punctuation.terminator.rule.css'], value: ';' });
lines = testGrammar.tokenizeLines('@charset "UTF-8" ;');
assert.deepStrictEqual(lines[0][0], { scopes: ['source.css', 'meta.at-rule.charset.css', 'keyword.control.at-rule.charset.css', 'punctuation.definition.keyword.css'], value: '@' });
assert.deepStrictEqual(lines[0][1], { scopes: ['source.css', 'meta.at-rule.charset.css', 'keyword.control.at-rule.charset.css'], value: 'charset' });
assert.deepStrictEqual(lines[0][2], { scopes: ['source.css', 'meta.at-rule.charset.css'], value: ' ' });
assert.deepStrictEqual(lines[0][3], { scopes: ['source.css', 'meta.at-rule.charset.css', 'string.quoted.double.css', 'punctuation.definition.string.begin.css'], value: '"' });
assert.deepStrictEqual(lines[0][4], { scopes: ['source.css', 'meta.at-rule.charset.css', 'string.quoted.double.css'], value: 'UTF-8' });
assert.deepStrictEqual(lines[0][5], { scopes: ['source.css', 'meta.at-rule.charset.css', 'string.quoted.double.css', 'punctuation.definition.string.end.css'], value: '"' });
assert.deepStrictEqual(lines[0][6], { scopes: ['source.css', 'meta.at-rule.charset.css', 'invalid.illegal.unexpected-characters.charset.css'], value: ' ' });
assert.deepStrictEqual(lines[0][7], { scopes: ['source.css', 'meta.at-rule.charset.css', 'punctuation.terminator.rule.css'], value: ';' });
lines = testGrammar.tokenizeLines('@charset "WTF-8" /* Nope */ ;');
assert.deepStrictEqual(lines[0][0], { scopes: ['source.css', 'meta.at-rule.charset.css', 'keyword.control.at-rule.charset.css', 'punctuation.definition.keyword.css'], value: '@' });
assert.deepStrictEqual(lines[0][1], { scopes: ['source.css', 'meta.at-rule.charset.css', 'keyword.control.at-rule.charset.css'], value: 'charset' });
assert.deepStrictEqual(lines[0][2], { scopes: ['source.css', 'meta.at-rule.charset.css'], value: ' ' });
assert.deepStrictEqual(lines[0][3], { scopes: ['source.css', 'meta.at-rule.charset.css', 'string.quoted.double.css', 'punctuation.definition.string.begin.css'], value: '"' });
assert.deepStrictEqual(lines[0][4], { scopes: ['source.css', 'meta.at-rule.charset.css', 'string.quoted.double.css'], value: 'WTF-8' });
assert.deepStrictEqual(lines[0][5], { scopes: ['source.css', 'meta.at-rule.charset.css', 'string.quoted.double.css', 'punctuation.definition.string.end.css'], value: '"' });
assert.deepStrictEqual(lines[0][6], { scopes: ['source.css', 'meta.at-rule.charset.css', 'invalid.illegal.unexpected-characters.charset.css'], value: ' /* Nope */ ' });
assert.deepStrictEqual(lines[0][7], { scopes: ['source.css', 'meta.at-rule.charset.css', 'punctuation.terminator.rule.css'], value: ';' });
lines = testGrammar.tokenizeLines('@charset "UTF-8');
assert.deepStrictEqual(lines[0][0], { scopes: ['source.css', 'meta.at-rule.charset.css', 'keyword.control.at-rule.charset.css', 'punctuation.definition.keyword.css'], value: '@' });
assert.deepStrictEqual(lines[0][1], { scopes: ['source.css', 'meta.at-rule.charset.css', 'keyword.control.at-rule.charset.css'], value: 'charset' });
assert.deepStrictEqual(lines[0][2], { scopes: ['source.css', 'meta.at-rule.charset.css'], value: ' ' });
assert.deepStrictEqual(lines[0][3], { scopes: ['source.css', 'meta.at-rule.charset.css', 'invalid.illegal.unclosed-string.charset.css'], value: '"UTF-8' });
lines = testGrammar.tokenizeLines("@CHARSET 'US-ASCII';");
assert.deepStrictEqual(lines[0][0], { scopes: ['source.css', 'meta.at-rule.charset.css', 'invalid.illegal.not-lowercase.charset.css'], value: '@CHARSET' });
assert.deepStrictEqual(lines[0][1], { scopes: ['source.css', 'meta.at-rule.charset.css'], value: " 'US-ASCII'" });
assert.deepStrictEqual(lines[0][2], { scopes: ['source.css', 'meta.at-rule.charset.css', 'punctuation.terminator.rule.css'], value: ';' });
});
});
describe('@import', function () {
it('tokenises @import statements', function () {
var tokens;
tokens = testGrammar.tokenizeLine('@import url("file.css");').tokens;
assert.deepStrictEqual(tokens[0], { scopes: ['source.css', 'meta.at-rule.import.css', 'keyword.control.at-rule.import.css', 'punctuation.definition.keyword.css'], value: '@' });
assert.deepStrictEqual(tokens[1], { scopes: ['source.css', 'meta.at-rule.import.css', 'keyword.control.at-rule.import.css'], value: 'import' });
assert.deepStrictEqual(tokens[3], { scopes: ['source.css', 'meta.at-rule.import.css', 'meta.function.url.css', 'support.function.url.css'], value: 'url' });
assert.deepStrictEqual(tokens[4], { scopes: ['source.css', 'meta.at-rule.import.css', 'meta.function.url.css', 'punctuation.section.function.begin.bracket.round.css'], value: '(' });
assert.deepStrictEqual(tokens[5], { scopes: ['source.css', 'meta.at-rule.import.css', 'meta.function.url.css', 'string.quoted.double.css', 'punctuation.definition.string.begin.css'], value: '"' });
assert.deepStrictEqual(tokens[6], { scopes: ['source.css', 'meta.at-rule.import.css', 'meta.function.url.css', 'string.quoted.double.css'], value: 'file.css' });
assert.deepStrictEqual(tokens[7], { scopes: ['source.css', 'meta.at-rule.import.css', 'meta.function.url.css', 'string.quoted.double.css', 'punctuation.definition.string.end.css'], value: '"' });
assert.deepStrictEqual(tokens[8], { scopes: ['source.css', 'meta.at-rule.import.css', 'meta.function.url.css', 'punctuation.section.function.end.bracket.round.css'], value: ')' });
assert.deepStrictEqual(tokens[9], { scopes: ['source.css', 'meta.at-rule.import.css', 'punctuation.terminator.rule.css'], value: ';' });
tokens = testGrammar.tokenizeLine('@import "file.css";').tokens;
assert.deepStrictEqual(tokens[0], { scopes: ['source.css', 'meta.at-rule.import.css', 'keyword.control.at-rule.import.css', 'punctuation.definition.keyword.css'], value: '@' });
assert.deepStrictEqual(tokens[1], { scopes: ['source.css', 'meta.at-rule.import.css', 'keyword.control.at-rule.import.css'], value: 'import' });
assert.deepStrictEqual(tokens[3], { scopes: ['source.css', 'meta.at-rule.import.css', 'string.quoted.double.css', 'punctuation.definition.string.begin.css'], value: '"' });
assert.deepStrictEqual(tokens[4], { scopes: ['source.css', 'meta.at-rule.import.css', 'string.quoted.double.css'], value: 'file.css' });
assert.deepStrictEqual(tokens[5], { scopes: ['source.css', 'meta.at-rule.import.css', 'string.quoted.double.css', 'punctuation.definition.string.end.css'], value: '"' });
assert.deepStrictEqual(tokens[6], { scopes: ['source.css', 'meta.at-rule.import.css', 'punctuation.terminator.rule.css'], value: ';' });
tokens = testGrammar.tokenizeLine("@import 'file.css';").tokens;
assert.deepStrictEqual(tokens[3], { scopes: ['source.css', 'meta.at-rule.import.css', 'string.quoted.single.css', 'punctuation.definition.string.begin.css'], value: "'" });
assert.deepStrictEqual(tokens[4], { scopes: ['source.css', 'meta.at-rule.import.css', 'string.quoted.single.css'], value: 'file.css' });
assert.deepStrictEqual(tokens[5], { scopes: ['source.css', 'meta.at-rule.import.css', 'string.quoted.single.css', 'punctuation.definition.string.end.css'], value: "'" });
});
it("doesn't let injected comments impact parameter matching", function () {
var tokens;
tokens = testGrammar.tokenizeLine('@import /* url("name"); */ "1.css";').tokens;
assert.deepStrictEqual(tokens[0], { scopes: ['source.css', 'meta.at-rule.import.css', 'keyword.control.at-rule.import.css', 'punctuation.definition.keyword.css'], value: '@' });
assert.deepStrictEqual(tokens[1], { scopes: ['source.css', 'meta.at-rule.import.css', 'keyword.control.at-rule.import.css'], value: 'import' });
assert.deepStrictEqual(tokens[3], { scopes: ['source.css', 'meta.at-rule.import.css', 'comment.block.css', 'punctuation.definition.comment.begin.css'], value: '/*' });
assert.deepStrictEqual(tokens[4], { scopes: ['source.css', 'meta.at-rule.import.css', 'comment.block.css'], value: ' url("name"); ' });
assert.deepStrictEqual(tokens[5], { scopes: ['source.css', 'meta.at-rule.import.css', 'comment.block.css', 'punctuation.definition.comment.end.css'], value: '*/' });
assert.deepStrictEqual(tokens[7], { scopes: ['source.css', 'meta.at-rule.import.css', 'string.quoted.double.css', 'punctuation.definition.string.begin.css'], value: '"' });
assert.deepStrictEqual(tokens[8], { scopes: ['source.css', 'meta.at-rule.import.css', 'string.quoted.double.css'], value: '1.css' });
assert.deepStrictEqual(tokens[9], { scopes: ['source.css', 'meta.at-rule.import.css', 'string.quoted.double.css', 'punctuation.definition.string.end.css'], value: '"' });
assert.deepStrictEqual(tokens[10], { scopes: ['source.css', 'meta.at-rule.import.css', 'punctuation.terminator.rule.css'], value: ';' });
tokens = testGrammar.tokenizeLine('@import/* Comment */"2.css";').tokens;
assert.deepStrictEqual(tokens[0], { scopes: ['source.css', 'meta.at-rule.import.css', 'keyword.control.at-rule.import.css', 'punctuation.definition.keyword.css'], value: '@' });
assert.deepStrictEqual(tokens[1], { scopes: ['source.css', 'meta.at-rule.import.css', 'keyword.control.at-rule.import.css'], value: 'import' });
assert.deepStrictEqual(tokens[2], { scopes: ['source.css', 'meta.at-rule.import.css', 'comment.block.css', 'punctuation.definition.comment.begin.css'], value: '/*' });
assert.deepStrictEqual(tokens[3], { scopes: ['source.css', 'meta.at-rule.import.css', 'comment.block.css'], value: ' Comment ' });
assert.deepStrictEqual(tokens[4], { scopes: ['source.css', 'meta.at-rule.import.css', 'comment.block.css', 'punctuation.definition.comment.end.css'], value: '*/' });
assert.deepStrictEqual(tokens[5], { scopes: ['source.css', 'meta.at-rule.import.css', 'string.quoted.double.css', 'punctuation.definition.string.begin.css'], value: '"' });
assert.deepStrictEqual(tokens[6], { scopes: ['source.css', 'meta.at-rule.import.css', 'string.quoted.double.css'], value: '2.css' });
assert.deepStrictEqual(tokens[7], { scopes: ['source.css', 'meta.at-rule.import.css', 'string.quoted.double.css', 'punctuation.definition.string.end.css'], value: '"' });
assert.deepStrictEqual(tokens[8], { scopes: ['source.css', 'meta.at-rule.import.css', 'punctuation.terminator.rule.css'], value: ';' });
});
it('correctly handles word boundaries', function () {
var tokens;
tokens = testGrammar.tokenizeLine('@import"file.css";').tokens;
assert.deepStrictEqual(tokens[0], { scopes: ['source.css', 'meta.at-rule.import.css', 'keyword.control.at-rule.import.css', 'punctuation.definition.keyword.css'], value: '@' });
assert.deepStrictEqual(tokens[1], { scopes: ['source.css', 'meta.at-rule.import.css', 'keyword.control.at-rule.import.css'], value: 'import' });
assert.deepStrictEqual(tokens[2], { scopes: ['source.css', 'meta.at-rule.import.css', 'string.quoted.double.css', 'punctuation.definition.string.begin.css'], value: '"' });
assert.deepStrictEqual(tokens[3], { scopes: ['source.css', 'meta.at-rule.import.css', 'string.quoted.double.css'], value: 'file.css' });
assert.deepStrictEqual(tokens[4], { scopes: ['source.css', 'meta.at-rule.import.css', 'string.quoted.double.css', 'punctuation.definition.string.end.css'], value: '"' });
assert.deepStrictEqual(tokens[5], { scopes: ['source.css', 'meta.at-rule.import.css', 'punctuation.terminator.rule.css'], value: ';' });
tokens = testGrammar.tokenizeLine('@import-file.css;').tokens;
assert.deepStrictEqual(tokens[0], { scopes: ['source.css', 'meta.at-rule.header.css', 'keyword.control.at-rule.css', 'punctuation.definition.keyword.css'], value: '@' });
assert.deepStrictEqual(tokens[1], { scopes: ['source.css', 'meta.at-rule.header.css', 'keyword.control.at-rule.css'], value: 'import-file' });
assert.deepStrictEqual(tokens[2], { scopes: ['source.css', 'meta.at-rule.header.css'], value: '.css' });
assert.deepStrictEqual(tokens[3], { scopes: ['source.css', 'meta.at-rule.header.css', 'punctuation.terminator.rule.css'], value: ';' });
});
it('matches a URL that starts on the next line', function () {
var lines;
lines = testGrammar.tokenizeLines('@import\nurl("file.css");');
assert.deepStrictEqual(lines[0][0], { scopes: ['source.css', 'meta.at-rule.import.css', 'keyword.control.at-rule.import.css', 'punctuation.definition.keyword.css'], value: '@' });
assert.deepStrictEqual(lines[0][1], { scopes: ['source.css', 'meta.at-rule.import.css', 'keyword.control.at-rule.import.css'], value: 'import' });
assert.deepStrictEqual(lines[1][0], { scopes: ['source.css', 'meta.at-rule.import.css', 'meta.function.url.css', 'support.function.url.css'], value: 'url' });
assert.deepStrictEqual(lines[1][1], { scopes: ['source.css', 'meta.at-rule.import.css', 'meta.function.url.css', 'punctuation.section.function.begin.bracket.round.css'], value: '(' });
assert.deepStrictEqual(lines[1][2], { scopes: ['source.css', 'meta.at-rule.import.css', 'meta.function.url.css', 'string.quoted.double.css', 'punctuation.definition.string.begin.css'], value: '"' });
assert.deepStrictEqual(lines[1][3], { scopes: ['source.css', 'meta.at-rule.import.css', 'meta.function.url.css', 'string.quoted.double.css'], value: 'file.css' });
assert.deepStrictEqual(lines[1][4], { scopes: ['source.css', 'meta.at-rule.import.css', 'meta.function.url.css', 'string.quoted.double.css', 'punctuation.definition.string.end.css'], value: '"' });
assert.deepStrictEqual(lines[1][5], { scopes: ['source.css', 'meta.at-rule.import.css', 'meta.function.url.css', 'punctuation.section.function.end.bracket.round.css'], value: ')' });
assert.deepStrictEqual(lines[1][6], { scopes: ['source.css', 'meta.at-rule.import.css', 'punctuation.terminator.rule.css'], value: ';' });
});
// Skipped because `vscode-textmate` does not produce this token
it.skip('matches a URL that starts on the next line and produces a token for whitespace', function () {
var lines;
lines = testGrammar.tokenizeLines('@import\nurl("file.css");');
assert.deepStrictEqual(lines[0][2], { scopes: ['source.css', 'meta.at-rule.import.css'], value: '' });
});
it('matches comments inside query lists', function () {
var tokens;
tokens = testGrammar.tokenizeLine('@import url("1.css") print /* url(";"); */ all;').tokens;
assert.deepStrictEqual(tokens[0], { scopes: ['source.css', 'meta.at-rule.import.css', 'keyword.control.at-rule.import.css', 'punctuation.definition.keyword.css'], value: '@' });
assert.deepStrictEqual(tokens[1], { scopes: ['source.css', 'meta.at-rule.import.css', 'keyword.control.at-rule.import.css'], value: 'import' });
assert.deepStrictEqual(tokens[3], { scopes: ['source.css', 'meta.at-rule.import.css', 'meta.function.url.css', 'support.function.url.css'], value: 'url' });
assert.deepStrictEqual(tokens[4], { scopes: ['source.css', 'meta.at-rule.import.css', 'meta.function.url.css', 'punctuation.section.function.begin.bracket.round.css'], value: '(' });
assert.deepStrictEqual(tokens[5], { scopes: ['source.css', 'meta.at-rule.import.css', 'meta.function.url.css', 'string.quoted.double.css', 'punctuation.definition.string.begin.css'], value: '"' });
assert.deepStrictEqual(tokens[6], { scopes: ['source.css', 'meta.at-rule.import.css', 'meta.function.url.css', 'string.quoted.double.css'], value: '1.css' });
assert.deepStrictEqual(tokens[7], { scopes: ['source.css', 'meta.at-rule.import.css', 'meta.function.url.css', 'string.quoted.double.css', 'punctuation.definition.string.end.css'], value: '"' });
assert.deepStrictEqual(tokens[8], { scopes: ['source.css', 'meta.at-rule.import.css', 'meta.function.url.css', 'punctuation.section.function.end.bracket.round.css'], value: ')' });
assert.deepStrictEqual(tokens[10], { scopes: ['source.css', 'meta.at-rule.import.css', 'support.constant.media.css'], value: 'print' });
assert.deepStrictEqual(tokens[12], { scopes: ['source.css', 'meta.at-rule.import.css', 'comment.block.css', 'punctuation.definition.comment.begin.css'], value: '/*' });
assert.deepStrictEqual(tokens[13], { scopes: ['source.css', 'meta.at-rule.import.css', 'comment.block.css'], value: ' url(";"); ' });
assert.deepStrictEqual(tokens[14], { scopes: ['source.css', 'meta.at-rule.import.css', 'comment.block.css', 'punctuation.definition.comment.end.css'], value: '*/' });
assert.deepStrictEqual(tokens[16], { scopes: ['source.css', 'meta.at-rule.import.css', 'support.constant.media.css'], value: 'all' });
assert.deepStrictEqual(tokens[17], { scopes: ['source.css', 'meta.at-rule.import.css', 'punctuation.terminator.rule.css'], value: ';' });
});
it('highlights deprecated media types', function () {
var tokens;
tokens = testGrammar.tokenizeLine('@import "astral.css" projection;').tokens;
assert.deepStrictEqual(tokens[0], { scopes: ['source.css', 'meta.at-rule.import.css', 'keyword.control.at-rule.import.css', 'punctuation.definition.keyword.css'], value: '@' });
assert.deepStrictEqual(tokens[1], { scopes: ['source.css', 'meta.at-rule.import.css', 'keyword.control.at-rule.import.css'], value: 'import' });
assert.deepStrictEqual(tokens[3], { scopes: ['source.css', 'meta.at-rule.import.css', 'string.quoted.double.css', 'punctuation.definition.string.begin.css'], value: '"' });
assert.deepStrictEqual(tokens[4], { scopes: ['source.css', 'meta.at-rule.import.css', 'string.quoted.double.css'], value: 'astral.css' });
assert.deepStrictEqual(tokens[5], { scopes: ['source.css', 'meta.at-rule.import.css', 'string.quoted.double.css', 'punctuation.definition.string.end.css'], value: '"' });
assert.deepStrictEqual(tokens[7], { scopes: ['source.css', 'meta.at-rule.import.css', 'invalid.deprecated.constant.media.css'], value: 'projection' });
assert.deepStrictEqual(tokens[8], { scopes: ['source.css', 'meta.at-rule.import.css', 'punctuation.terminator.rule.css'], value: ';' });
});
it('highlights media features in query lists', function () {
var tokens;
tokens = testGrammar.tokenizeLine('@import url(\'landscape.css\') screen and (orientation:landscape);').tokens;
assert.deepStrictEqual(tokens[0], { scopes: ['source.css', 'meta.at-rule.import.css', 'keyword.control.at-rule.import.css', 'punctuation.definition.keyword.css'], value: '@' });
assert.deepStrictEqual(tokens[1], { scopes: ['source.css', 'meta.at-rule.import.css', 'keyword.control.at-rule.import.css'], value: 'import' });
assert.deepStrictEqual(tokens[3], { scopes: ['source.css', 'meta.at-rule.import.css', 'meta.function.url.css', 'support.function.url.css'], value: 'url' });
assert.deepStrictEqual(tokens[4], { scopes: ['source.css', 'meta.at-rule.import.css', 'meta.function.url.css', 'punctuation.section.function.begin.bracket.round.css'], value: '(' });
assert.deepStrictEqual(tokens[5], { scopes: ['source.css', 'meta.at-rule.import.css', 'meta.function.url.css', 'string.quoted.single.css', 'punctuation.definition.string.begin.css'], value: '\'' });
assert.deepStrictEqual(tokens[6], { scopes: ['source.css', 'meta.at-rule.import.css', 'meta.function.url.css', 'string.quoted.single.css'], value: 'landscape.css' });
assert.deepStrictEqual(tokens[7], { scopes: ['source.css', 'meta.at-rule.import.css', 'meta.function.url.css', 'string.quoted.single.css', 'punctuation.definition.string.end.css'], value: '\'' });
assert.deepStrictEqual(tokens[8], { scopes: ['source.css', 'meta.at-rule.import.css', 'meta.function.url.css', 'punctuation.section.function.end.bracket.round.css'], value: ')' });
assert.deepStrictEqual(tokens[10], { scopes: ['source.css', 'meta.at-rule.import.css', 'support.constant.media.css'], value: 'screen' });
assert.deepStrictEqual(tokens[12], { scopes: ['source.css', 'meta.at-rule.import.css', 'keyword.operator.logical.and.media.css'], value: 'and' });
assert.deepStrictEqual(tokens[14], { scopes: ['source.css', 'meta.at-rule.import.css', 'punctuation.definition.parameters.begin.bracket.round.css'], value: '(' });
assert.deepStrictEqual(tokens[15], { scopes: ['source.css', 'meta.at-rule.import.css', 'support.type.property-name.media.css'], value: 'orientation' });
assert.deepStrictEqual(tokens[16], { scopes: ['source.css', 'meta.at-rule.import.css', 'punctuation.separator.key-value.css'], value: ':' });
assert.deepStrictEqual(tokens[17], { scopes: ['source.css', 'meta.at-rule.import.css', 'support.constant.property-value.css'], value: 'landscape' });
assert.deepStrictEqual(tokens[18], { scopes: ['source.css', 'meta.at-rule.import.css', 'punctuation.definition.parameters.end.bracket.round.css'], value: ')' });
assert.deepStrictEqual(tokens[19], { scopes: ['source.css', 'meta.at-rule.import.css', 'punctuation.terminator.rule.css'], value: ';' });
});
});
describe('@media', function () {
it('tokenises @media keywords correctly', function () {
var tokens;
tokens = testGrammar.tokenizeLine('@media(max-width: 37.5em) { }').tokens;
assert.deepStrictEqual(tokens[0], { scopes: ['source.css', 'meta.at-rule.media.header.css', 'keyword.control.at-rule.media.css', 'punctuation.definition.keyword.css'], value: '@' });
assert.deepStrictEqual(tokens[1], { scopes: ['source.css', 'meta.at-rule.media.header.css', 'keyword.control.at-rule.media.css'], value: 'media' });
assert.deepStrictEqual(tokens[2], { scopes: ['source.css', 'meta.at-rule.media.header.css', 'punctuation.definition.parameters.begin.bracket.round.css'], value: '(' });
assert.deepStrictEqual(tokens[3], { scopes: ['source.css', 'meta.at-rule.media.header.css', 'support.type.property-name.media.css'], value: 'max-width' });
assert.deepStrictEqual(tokens[4], { scopes: ['source.css', 'meta.at-rule.media.header.css', 'punctuation.separator.key-value.css'], value: ':' });
assert.deepStrictEqual(tokens[6], { scopes: ['source.css', 'meta.at-rule.media.header.css', 'constant.numeric.css'], value: '37.5' });
assert.deepStrictEqual(tokens[7], { scopes: ['source.css', 'meta.at-rule.media.header.css', 'constant.numeric.css', 'keyword.other.unit.em.css'], value: 'em' });
assert.deepStrictEqual(tokens[8], { scopes: ['source.css', 'meta.at-rule.media.header.css', 'punctuation.definition.parameters.end.bracket.round.css'], value: ')' });
assert.deepStrictEqual(tokens[9], { scopes: ['source.css'], value: ' ' });
assert.deepStrictEqual(tokens[10], { scopes: ['source.css', 'meta.at-rule.media.body.css', 'punctuation.section.media.begin.bracket.curly.css'], value: '{' });
assert.deepStrictEqual(tokens[12], { scopes: ['source.css', 'meta.at-rule.media.body.css', 'punctuation.section.media.end.bracket.curly.css'], value: '}' });
tokens = testGrammar.tokenizeLine('@media not print and (max-width: 37.5em){ }').tokens;
assert.deepStrictEqual(tokens[0], { scopes: ['source.css', 'meta.at-rule.media.header.css', 'keyword.control.at-rule.media.css', 'punctuation.definition.keyword.css'], value: '@' });
assert.deepStrictEqual(tokens[1], { scopes: ['source.css', 'meta.at-rule.media.header.css', 'keyword.control.at-rule.media.css'], value: 'media' });
assert.deepStrictEqual(tokens[3], { scopes: ['source.css', 'meta.at-rule.media.header.css', 'keyword.operator.logical.not.media.css'], value: 'not' });
assert.deepStrictEqual(tokens[5], { scopes: ['source.css', 'meta.at-rule.media.header.css', 'support.constant.media.css'], value: 'print' });
assert.deepStrictEqual(tokens[7], { scopes: ['source.css', 'meta.at-rule.media.header.css', 'keyword.operator.logical.and.media.css'], value: 'and' });
assert.deepStrictEqual(tokens[9], { scopes: ['source.css', 'meta.at-rule.media.header.css', 'punctuation.definition.parameters.begin.bracket.round.css'], value: '(' });
assert.deepStrictEqual(tokens[10], { scopes: ['source.css', 'meta.at-rule.media.header.css', 'support.type.property-name.media.css'], value: 'max-width' });
assert.deepStrictEqual(tokens[11], { scopes: ['source.css', 'meta.at-rule.media.header.css', 'punctuation.separator.key-value.css'], value: ':' });
assert.deepStrictEqual(tokens[13], { scopes: ['source.css', 'meta.at-rule.media.header.css', 'constant.numeric.css'], value: '37.5' });
assert.deepStrictEqual(tokens[14], { scopes: ['source.css', 'meta.at-rule.media.header.css', 'constant.numeric.css', 'keyword.other.unit.em.css'], value: 'em' });
assert.deepStrictEqual(tokens[15], { scopes: ['source.css', 'meta.at-rule.media.header.css', 'punctuation.definition.parameters.end.bracket.round.css'], value: ')' });
assert.deepStrictEqual(tokens[16], { scopes: ['source.css', 'meta.at-rule.media.body.css', 'punctuation.section.media.begin.bracket.curly.css'], value: '{' });
assert.deepStrictEqual(tokens[18], { scopes: ['source.css', 'meta.at-rule.media.body.css', 'punctuation.section.media.end.bracket.curly.css'], value: '}' });
});
it('highlights deprecated media types', function () {
var tokens;
tokens = testGrammar.tokenizeLine('@media (max-device-width: 2px){ }').tokens;
assert.deepStrictEqual(tokens[0], { scopes: ['source.css', 'meta.at-rule.media.header.css', 'keyword.control.at-rule.media.css', 'punctuation.definition.keyword.css'], value: '@' });
assert.deepStrictEqual(tokens[1], { scopes: ['source.css', 'meta.at-rule.media.header.css', 'keyword.control.at-rule.media.css'], value: 'media' });
assert.deepStrictEqual(tokens[3], { scopes: ['source.css', 'meta.at-rule.media.header.css', 'punctuation.definition.parameters.begin.bracket.round.css'], value: '(' });
assert.deepStrictEqual(tokens[4], { scopes: ['source.css', 'meta.at-rule.media.header.css', 'support.type.property-name.media.css'], value: 'max-device-width' });
assert.deepStrictEqual(tokens[5], { scopes: ['source.css', 'meta.at-rule.media.header.css', 'punctuation.separator.key-value.css'], value: ':' });
assert.deepStrictEqual(tokens[7], { scopes: ['source.css', 'meta.at-rule.media.header.css', 'constant.numeric.css'], value: '2' });
assert.deepStrictEqual(tokens[8], { scopes: ['source.css', 'meta.at-rule.media.header.css', 'constant.numeric.css', 'keyword.other.unit.px.css'], value: 'px' });
assert.deepStrictEqual(tokens[9], { scopes: ['source.css', 'meta.at-rule.media.header.css', 'punctuation.definition.parameters.end.bracket.round.css'], value: ')' });
assert.deepStrictEqual(tokens[10], { scopes: ['source.css', 'meta.at-rule.media.body.css', 'punctuation.section.media.begin.bracket.curly.css'], value: '{' });
assert.deepStrictEqual(tokens[12], { scopes: ['source.css', 'meta.at-rule.media.body.css', 'punctuation.section.media.end.bracket.curly.css'], value: '}' });
});
it('highlights vendored media features', function () {
var tokens;
tokens = testGrammar.tokenizeLine('@media (-webkit-foo: bar){ b{ } }').tokens;
assert.deepStrictEqual(tokens[3], { scopes: ['source.css', 'meta.at-rule.media.header.css', 'punctuation.definition.parameters.begin.bracket.round.css'], value: '(' });
assert.deepStrictEqual(tokens[4], { scopes: ['source.css', 'meta.at-rule.media.header.css', 'support.type.vendored.property-name.media.css'], value: '-webkit-foo' });
assert.deepStrictEqual(tokens[5], { scopes: ['source.css', 'meta.at-rule.media.header.css', 'punctuation.separator.key-value.css'], value: ':' });
assert.deepStrictEqual(tokens[6], { scopes: ['source.css', 'meta.at-rule.media.header.css'], value: ' bar' });
assert.deepStrictEqual(tokens[7], { scopes: ['source.css', 'meta.at-rule.media.header.css', 'punctuation.definition.parameters.end.bracket.round.css'], value: ')' });
assert.deepStrictEqual(tokens[8], { scopes: ['source.css', 'meta.at-rule.media.body.css', 'punctuation.section.media.begin.bracket.curly.css'], value: '{' });
tokens = testGrammar.tokenizeLine('@media screen and (-ms-high-contrast:black-on-white){ }').tokens;
assert.deepStrictEqual(tokens[0], { scopes: ['source.css', 'meta.at-rule.media.header.css', 'keyword.control.at-rule.media.css', 'punctuation.definition.keyword.css'], value: '@' });
assert.deepStrictEqual(tokens[1], { scopes: ['source.css', 'meta.at-rule.media.header.css', 'keyword.control.at-rule.media.css'], value: 'media' });
assert.deepStrictEqual(tokens[3], { scopes: ['source.css', 'meta.at-rule.media.header.css', 'support.constant.media.css'], value: 'screen' });
assert.deepStrictEqual(tokens[5], { scopes: ['source.css', 'meta.at-rule.media.header.css', 'keyword.operator.logical.and.media.css'], value: 'and' });
assert.deepStrictEqual(tokens[7], { scopes: ['source.css', 'meta.at-rule.media.header.css', 'punctuation.definition.parameters.begin.bracket.round.css'], value: '(' });
assert.deepStrictEqual(tokens[8], { scopes: ['source.css', 'meta.at-rule.media.header.css', 'support.type.vendored.property-name.media.css'], value: '-ms-high-contrast' });
assert.deepStrictEqual(tokens[9], { scopes: ['source.css', 'meta.at-rule.media.header.css', 'punctuation.separator.key-value.css'], value: ':' });
assert.deepStrictEqual(tokens[10], { scopes: ['source.css', 'meta.at-rule.media.header.css'], value: 'black-on-white' });
assert.deepStrictEqual(tokens[11], { scopes: ['source.css', 'meta.at-rule.media.header.css', 'punctuation.definition.parameters.end.bracket.round.css'], value: ')' });
assert.deepStrictEqual(tokens[12], { scopes: ['source.css', 'meta.at-rule.media.body.css', 'punctuation.section.media.begin.bracket.curly.css'], value: '{' });
assert.deepStrictEqual(tokens[14], { scopes: ['source.css', 'meta.at-rule.media.body.css', 'punctuation.section.media.end.bracket.curly.css'], value: '}' });
tokens = testGrammar.tokenizeLine('@media (_moz-a:b){}').tokens;
assert.deepStrictEqual(tokens[0], { scopes: ['source.css', 'meta.at-rule.media.header.css', 'keyword.control.at-rule.media.css', 'punctuation.definition.keyword.css'], value: '@' });
assert.deepStrictEqual(tokens[1], { scopes: ['source.css', 'meta.at-rule.media.header.css', 'keyword.control.at-rule.media.css'], value: 'media' });
assert.deepStrictEqual(tokens[3], { scopes: ['source.css', 'meta.at-rule.media.header.css', 'punctuation.definition.parameters.begin.bracket.round.css'], value: '(' });
assert.deepStrictEqual(tokens[4], { scopes: ['source.css', 'meta.at-rule.media.header.css', 'support.type.vendored.property-name.media.css'], value: '_moz-a' });
assert.deepStrictEqual(tokens[5], { scopes: ['source.css', 'meta.at-rule.media.header.css', 'punctuation.separator.key-value.css'], value: ':' });
assert.deepStrictEqual(tokens[6], { scopes: ['source.css', 'meta.at-rule.media.header.css'], value: 'b' });
assert.deepStrictEqual(tokens[7], { scopes: ['source.css', 'meta.at-rule.media.header.css', 'punctuation.definition.parameters.end.bracket.round.css'], value: ')' });
tokens = testGrammar.tokenizeLine('@media (-hp-foo:bar){}').tokens;
assert.deepStrictEqual(tokens[0], { scopes: ['source.css', 'meta.at-rule.media.header.css', 'keyword.control.at-rule.media.css', 'punctuation.definition.keyword.css'], value: '@' });
assert.deepStrictEqual(tokens[1], { scopes: ['source.css', 'meta.at-rule.media.header.css', 'keyword.control.at-rule.media.css'], value: 'media' });
assert.deepStrictEqual(tokens[3], { scopes: ['source.css', 'meta.at-rule.media.header.css', 'punctuation.definition.parameters.begin.bracket.round.css'], value: '(' });
assert.deepStrictEqual(tokens[4], { scopes: ['source.css', 'meta.at-rule.media.header.css', 'support.type.vendored.property-name.media.css'], value: '-hp-foo' });
assert.deepStrictEqual(tokens[5], { scopes: ['source.css', 'meta.at-rule.media.header.css', 'punctuation.separator.key-value.css'], value: ':' });
assert.deepStrictEqual(tokens[6], { scopes: ['source.css', 'meta.at-rule.media.header.css'], value: 'bar' });
assert.deepStrictEqual(tokens[7], { scopes: ['source.css', 'meta.at-rule.media.header.css', 'punctuation.definition.parameters.end.bracket.round.css'], value: ')' });
tokens = testGrammar.tokenizeLine('@media (mso-page-size:wide){}').tokens;
assert.deepStrictEqual(tokens[0], { scopes: ['source.css', 'meta.at-rule.media.header.css', 'keyword.control.at-rule.media.css', 'punctuation.definition.keyword.css'], value: '@' });
assert.deepStrictEqual(tokens[1], { scopes: ['source.css', 'meta.at-rule.media.header.css', 'keyword.control.at-rule.media.css'], value: 'media' });
assert.deepStrictEqual(tokens[3], { scopes: ['source.css', 'meta.at-rule.media.header.css', 'punctuation.definition.parameters.begin.bracket.round.css'], value: '(' });
assert.deepStrictEqual(tokens[4], { scopes: ['source.css', 'meta.at-rule.media.header.css', 'support.type.vendored.property-name.media.css'], value: 'mso-page-size' });
assert.deepStrictEqual(tokens[5], { scopes: ['source.css', 'meta.at-rule.media.header.css', 'punctuation.separator.key-value.css'], value: ':' });
assert.deepStrictEqual(tokens[6], { scopes: ['source.css', 'meta.at-rule.media.header.css'], value: 'wide' });
assert.deepStrictEqual(tokens[7], { scopes: ['source.css', 'meta.at-rule.media.header.css', 'punctuation.definition.parameters.end.bracket.round.css'], value: ')' });
});