csspool 4.0.0.pre → 4.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/CHANGELOG.rdoc +12 -0
- data/Gemfile.lock +6 -6
- data/Manifest.txt +10 -2
- data/Rakefile +1 -0
- data/lib/csspool/css/declaration.rb +1 -1
- data/lib/csspool/css/document.rb +5 -1
- data/lib/csspool/css/document_handler.rb +43 -11
- data/lib/csspool/css/fontface_rule.rb +13 -0
- data/lib/csspool/css/import_rule.rb +0 -5
- data/lib/csspool/css/media_feature.rb +14 -0
- data/lib/csspool/css/media_query.rb +19 -0
- data/lib/csspool/css/media_query_list.rb +41 -0
- data/lib/csspool/css/{media.rb → media_type.rb} +6 -4
- data/lib/csspool/css/parser.rb +1272 -671
- data/lib/csspool/css/parser.y +223 -53
- data/lib/csspool/css/rule_set.rb +4 -3
- data/lib/csspool/css/supports_rule.rb +14 -0
- data/lib/csspool/css/tokenizer.rb +92 -16
- data/lib/csspool/css/tokenizer.rex +42 -19
- data/lib/csspool/css.rb +6 -1
- data/lib/csspool/node.rb +22 -0
- data/lib/csspool/selector.rb +5 -4
- data/lib/csspool/selectors/pseudo.rb +2 -2
- data/lib/csspool/terms/function.rb +1 -1
- data/lib/csspool/terms/resolution.rb +13 -0
- data/lib/csspool/terms.rb +1 -0
- data/lib/csspool/visitors/children.rb +16 -2
- data/lib/csspool/visitors/comparable.rb +27 -8
- data/lib/csspool/visitors/iterator.rb +5 -3
- data/lib/csspool/visitors/to_css.rb +73 -20
- data/test/css/test_document_query.rb +37 -38
- data/test/css/test_font_face.rb +16 -0
- data/test/css/test_import_rule.rb +0 -3
- data/test/css/test_media_rule.rb +92 -0
- data/test/css/test_node_position.rb +81 -0
- data/test/css/test_parser.rb +12 -39
- data/test/css/test_supports_rule.rb +133 -0
- data/test/css/test_tokenizer.rb +4 -4
- data/test/css/test_variables.rb +33 -0
- data/test/helper.rb +3 -3
- data/test/sac/test_parser.rb +1 -0
- data/test/test_parser.rb +22 -9
- data/test/test_selector.rb +44 -4
- data/test/test_term.rb +29 -0
- data/test/visitors/test_comparable.rb +8 -0
- data/test/visitors/test_to_css.rb +89 -13
- metadata +54 -58
- data/test/_local_helper.rb +0 -2
data/lib/csspool/css/parser.y
CHANGED
@@ -1,17 +1,24 @@
|
|
1
1
|
class CSSPool::CSS::Parser
|
2
2
|
|
3
3
|
token CHARSET_SYM IMPORT_SYM STRING SEMI IDENT S COMMA LBRACE RBRACE STAR HASH
|
4
|
-
token LSQUARE RSQUARE EQUAL INCLUDES DASHMATCH RPAREN FUNCTION GREATER PLUS
|
5
|
-
token SLASH NUMBER MINUS LENGTH PERCENTAGE
|
6
|
-
token IMPORTANT_SYM MEDIA_SYM NTH_PSEUDO_CLASS
|
7
|
-
token
|
8
|
-
token
|
9
|
-
token
|
10
|
-
token
|
11
|
-
token
|
12
|
-
token
|
13
|
-
token NAMESPACE_SYM
|
14
|
-
token
|
4
|
+
token LSQUARE RSQUARE EQUAL INCLUDES DASHMATCH LPAREN RPAREN FUNCTION GREATER PLUS
|
5
|
+
token SLASH NUMBER MINUS LENGTH PERCENTAGE ANGLE TIME FREQ URI
|
6
|
+
token IMPORTANT_SYM MEDIA_SYM NOT ONLY AND NTH_PSEUDO_CLASS
|
7
|
+
token DOCUMENT_QUERY_SYM FUNCTION_NO_QUOTE
|
8
|
+
token TILDE
|
9
|
+
token PREFIXMATCH SUFFIXMATCH SUBSTRINGMATCH
|
10
|
+
token NOT_PSEUDO_CLASS
|
11
|
+
token KEYFRAMES_SYM
|
12
|
+
token MATCHES_PSEUDO_CLASS
|
13
|
+
token NAMESPACE_SYM
|
14
|
+
token MOZ_PSEUDO_ELEMENT
|
15
|
+
token RESOLUTION
|
16
|
+
token COLON
|
17
|
+
token SUPPORTS_SYM
|
18
|
+
token OR
|
19
|
+
token VARIABLE_NAME
|
20
|
+
token CALC_SYM
|
21
|
+
token FONTFACE_SYM
|
15
22
|
|
16
23
|
rule
|
17
24
|
document
|
@@ -33,7 +40,7 @@ rule
|
|
33
40
|
;
|
34
41
|
import
|
35
42
|
: IMPORT_SYM import_location medium SEMI {
|
36
|
-
@handler.import_style
|
43
|
+
@handler.import_style val[2], val[1]
|
37
44
|
}
|
38
45
|
| IMPORT_SYM import_location SEMI {
|
39
46
|
@handler.import_style [], val[1]
|
@@ -54,10 +61,46 @@ rule
|
|
54
61
|
;
|
55
62
|
medium
|
56
63
|
: medium COMMA IDENT {
|
57
|
-
result = [
|
64
|
+
result = val[0] << MediaType.new(val[2])
|
58
65
|
}
|
59
66
|
| IDENT {
|
60
|
-
result =
|
67
|
+
result = [MediaType.new(val[0])]
|
68
|
+
}
|
69
|
+
;
|
70
|
+
media_query_list
|
71
|
+
: media_query { result = MediaQueryList.new([ val[0] ]) }
|
72
|
+
| media_query_list COMMA media_query { result = val[0] << val[2] }
|
73
|
+
| { result = MediaQueryList.new }
|
74
|
+
;
|
75
|
+
media_query
|
76
|
+
: optional_only_or_not media_type optional_and_exprs { result = MediaQuery.new(val[0], val[1], val[2]) }
|
77
|
+
| media_expr optional_and_exprs { result = MediaQuery.new(nil, val[0], val[1]) }
|
78
|
+
;
|
79
|
+
optional_only_or_not
|
80
|
+
: ONLY { result = :only }
|
81
|
+
| NOT { result = :not }
|
82
|
+
| { result = nil }
|
83
|
+
;
|
84
|
+
media_type
|
85
|
+
: IDENT { result = MediaType.new(val[0]) }
|
86
|
+
;
|
87
|
+
media_expr
|
88
|
+
: LPAREN optional_space IDENT optional_space RPAREN { result = MediaType.new(val[2]) }
|
89
|
+
| LPAREN optional_space IDENT optional_space COLON optional_space expr RPAREN { result = MediaFeature.new(val[2], val[6][0]) }
|
90
|
+
;
|
91
|
+
optional_space
|
92
|
+
: S { result = val[0] }
|
93
|
+
| { result = nil }
|
94
|
+
;
|
95
|
+
optional_and_exprs
|
96
|
+
: optional_and_exprs AND media_expr { result = val[0] << val[2] }
|
97
|
+
| { result = [] }
|
98
|
+
;
|
99
|
+
resolution
|
100
|
+
: RESOLUTION {
|
101
|
+
unit = val.first.gsub(/[\s\d.]/, '')
|
102
|
+
number = numeric(val.first)
|
103
|
+
result = Terms::Resolution.new(number, unit)
|
61
104
|
}
|
62
105
|
;
|
63
106
|
body
|
@@ -67,28 +110,38 @@ rule
|
|
67
110
|
| ruleset
|
68
111
|
| conditional_rule
|
69
112
|
| keyframes_rule
|
113
|
+
| fontface_rule
|
70
114
|
;
|
71
115
|
conditional_rule
|
72
116
|
: media
|
73
117
|
| document_query
|
118
|
+
| supports
|
119
|
+
;
|
120
|
+
body_in_media
|
121
|
+
: body
|
122
|
+
| empty_ruleset
|
74
123
|
;
|
75
124
|
media
|
76
|
-
: start_media
|
125
|
+
: start_media body_in_media RBRACE { @handler.end_media val.first }
|
77
126
|
;
|
78
127
|
start_media
|
79
|
-
: MEDIA_SYM
|
80
|
-
result =
|
128
|
+
: MEDIA_SYM media_query_list LBRACE {
|
129
|
+
result = val[1]
|
81
130
|
@handler.start_media result
|
82
131
|
}
|
83
|
-
| MEDIA_SYM LBRACE { result = [] }
|
84
132
|
;
|
85
133
|
document_query
|
86
|
-
: start_document_query body RBRACE { @handler.end_document_query }
|
87
|
-
| start_document_query RBRACE { @handler.end_document_query }
|
134
|
+
: start_document_query body RBRACE { @handler.end_document_query(before_pos(val), after_pos(val)) }
|
135
|
+
| start_document_query RBRACE { @handler.end_document_query(before_pos(val), after_pos(val)) }
|
88
136
|
;
|
89
137
|
start_document_query
|
90
|
-
:
|
91
|
-
@handler.start_document_query
|
138
|
+
: start_document_query_pos url_match_fns LBRACE {
|
139
|
+
@handler.start_document_query(val[1], after_pos(val))
|
140
|
+
}
|
141
|
+
;
|
142
|
+
start_document_query_pos
|
143
|
+
: DOCUMENT_QUERY_SYM {
|
144
|
+
@handler.node_start_pos = before_pos(val)
|
92
145
|
}
|
93
146
|
;
|
94
147
|
url_match_fns
|
@@ -104,6 +157,48 @@ rule
|
|
104
157
|
| function
|
105
158
|
| uri
|
106
159
|
;
|
160
|
+
supports
|
161
|
+
: start_supports body RBRACE { @handler.end_supports }
|
162
|
+
| start_supports RBRACE { @handler.end_supports }
|
163
|
+
;
|
164
|
+
start_supports
|
165
|
+
: SUPPORTS_SYM supports_condition_root LBRACE {
|
166
|
+
@handler.start_supports val[1]
|
167
|
+
}
|
168
|
+
;
|
169
|
+
supports_condition_root
|
170
|
+
: supports_negation { result = val.join('') }
|
171
|
+
| supports_conjunction_or_disjunction { result = val.join('') }
|
172
|
+
| supports_condition_in_parens { result = val.join('') }
|
173
|
+
;
|
174
|
+
supports_condition
|
175
|
+
: supports_negation { result = val.join('') }
|
176
|
+
| supports_conjunction_or_disjunction { result = val.join('') }
|
177
|
+
| supports_condition_in_parens { result = val.join('') }
|
178
|
+
;
|
179
|
+
supports_condition_in_parens
|
180
|
+
: LPAREN supports_condition RPAREN { result = val.join('') }
|
181
|
+
| supports_declaration_condition { result = val.join('') }
|
182
|
+
;
|
183
|
+
supports_negation
|
184
|
+
: NOT supports_condition_in_parens { result = val.join('') }
|
185
|
+
;
|
186
|
+
supports_conjunction_or_disjunction
|
187
|
+
: supports_conjunction
|
188
|
+
| supports_disjunction
|
189
|
+
;
|
190
|
+
supports_conjunction
|
191
|
+
: supports_condition_in_parens AND supports_condition_in_parens { result = val.join('') }
|
192
|
+
| supports_conjunction_or_disjunction AND supports_condition_in_parens { result = val.join('') }
|
193
|
+
;
|
194
|
+
supports_disjunction
|
195
|
+
: supports_condition_in_parens OR supports_condition_in_parens { result = val.join('') }
|
196
|
+
| supports_conjunction_or_disjunction OR supports_condition_in_parens { result = val.join('') }
|
197
|
+
;
|
198
|
+
supports_declaration_condition
|
199
|
+
: LPAREN declaration_internal RPAREN { result = val.join('') }
|
200
|
+
| LPAREN S declaration_internal RPAREN { result = val.join('') }
|
201
|
+
;
|
107
202
|
keyframes_rule
|
108
203
|
: start_keyframes_rule keyframes_blocks RBRACE
|
109
204
|
| start_keyframes_rule RBRACE
|
@@ -136,6 +231,15 @@ rule
|
|
136
231
|
: IDENT
|
137
232
|
| PERCENTAGE { result = val[0].strip }
|
138
233
|
;
|
234
|
+
fontface_rule
|
235
|
+
: start_fontface_rule declarations RBRACE { @handler.end_fontface_rule }
|
236
|
+
| start_fontface_rule RBRACE { @handler.end_fontface_rule }
|
237
|
+
;
|
238
|
+
start_fontface_rule
|
239
|
+
: FONTFACE_SYM LBRACE {
|
240
|
+
@handler.start_fontface_rule
|
241
|
+
}
|
242
|
+
;
|
139
243
|
ruleset
|
140
244
|
: start_selector declarations RBRACE {
|
141
245
|
@handler.end_selector val.first
|
@@ -144,6 +248,12 @@ rule
|
|
144
248
|
@handler.end_selector val.first
|
145
249
|
}
|
146
250
|
;
|
251
|
+
empty_ruleset
|
252
|
+
: optional_space {
|
253
|
+
start = @handler.start_selector([])
|
254
|
+
@handler.end_selector(start)
|
255
|
+
}
|
256
|
+
;
|
147
257
|
start_selector
|
148
258
|
: S start_selector { result = val.last }
|
149
259
|
| selectors LBRACE {
|
@@ -153,9 +263,8 @@ rule
|
|
153
263
|
selectors
|
154
264
|
: selector COMMA selectors
|
155
265
|
{
|
156
|
-
# FIXME: should always garantee array
|
157
266
|
sel = Selector.new(val.first, {})
|
158
|
-
result = [sel
|
267
|
+
result = [sel].concat(val[2])
|
159
268
|
}
|
160
269
|
| selector
|
161
270
|
{
|
@@ -165,7 +274,7 @@ rule
|
|
165
274
|
selector
|
166
275
|
: simple_selector combinator selector
|
167
276
|
{
|
168
|
-
val
|
277
|
+
val.flatten!
|
169
278
|
val[2].combinator = val.delete_at 1
|
170
279
|
result = val
|
171
280
|
}
|
@@ -334,44 +443,62 @@ rule
|
|
334
443
|
}
|
335
444
|
;
|
336
445
|
pseudo
|
337
|
-
:
|
446
|
+
: COLON IDENT {
|
338
447
|
result = Selectors::pseudo interpret_identifier(val[1])
|
339
448
|
}
|
340
|
-
|
|
449
|
+
| COLON COLON IDENT {
|
341
450
|
result = Selectors::PseudoElement.new(
|
342
451
|
interpret_identifier(val[2])
|
343
452
|
)
|
344
453
|
}
|
345
|
-
|
|
454
|
+
| COLON FUNCTION RPAREN {
|
346
455
|
result = Selectors::PseudoClass.new(
|
347
456
|
interpret_identifier(val[1].sub(/\($/, '')),
|
348
457
|
''
|
349
458
|
)
|
350
459
|
}
|
351
|
-
|
|
460
|
+
| COLON FUNCTION IDENT RPAREN {
|
352
461
|
result = Selectors::PseudoClass.new(
|
353
462
|
interpret_identifier(val[1].sub(/\($/, '')),
|
354
463
|
interpret_identifier(val[2])
|
355
464
|
)
|
356
465
|
}
|
357
|
-
|
|
466
|
+
| COLON NOT_PSEUDO_CLASS simple_selector RPAREN {
|
358
467
|
result = Selectors::PseudoClass.new(
|
359
468
|
'not',
|
360
469
|
val[2].first.to_s
|
361
470
|
)
|
362
471
|
}
|
363
|
-
|
|
472
|
+
| COLON NTH_PSEUDO_CLASS {
|
364
473
|
result = Selectors::PseudoClass.new(
|
365
474
|
interpret_identifier(val[1].sub(/\(.*/, '')),
|
366
475
|
interpret_identifier(val[1].sub(/.*\(/, '').sub(/\).*/, ''))
|
367
476
|
)
|
368
477
|
}
|
369
|
-
|
|
478
|
+
| COLON MATCHES_PSEUDO_CLASS simple_selectors RPAREN {
|
370
479
|
result = Selectors::PseudoClass.new(
|
371
480
|
val[1].split('(').first.strip,
|
372
481
|
val[2].join(', ')
|
373
482
|
)
|
374
483
|
}
|
484
|
+
| COLON MOZ_PSEUDO_ELEMENT any_number_of_idents RPAREN {
|
485
|
+
result = Selectors::PseudoElement.new(
|
486
|
+
interpret_identifier(val[1].sub(/\($/, ''))
|
487
|
+
)
|
488
|
+
}
|
489
|
+
| COLON COLON MOZ_PSEUDO_ELEMENT any_number_of_idents RPAREN {
|
490
|
+
result = Selectors::PseudoElement.new(
|
491
|
+
interpret_identifier(val[2].sub(/\($/, ''))
|
492
|
+
)
|
493
|
+
}
|
494
|
+
;
|
495
|
+
any_number_of_idents
|
496
|
+
:
|
497
|
+
| multiple_idents
|
498
|
+
;
|
499
|
+
multiple_idents
|
500
|
+
: IDENT
|
501
|
+
| IDENT COMMA multiple_idents
|
375
502
|
;
|
376
503
|
# declarations can be separated by one *or more* semicolons. semi-colons at the start or end of a ruleset are also allowed
|
377
504
|
one_or_more_semis
|
@@ -386,14 +513,17 @@ rule
|
|
386
513
|
| one_or_more_semis
|
387
514
|
;
|
388
515
|
declaration
|
389
|
-
: property
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
|
396
|
-
|
516
|
+
: declaration_internal { @handler.property val.first }
|
517
|
+
;
|
518
|
+
declaration_internal
|
519
|
+
: property COLON expr prio
|
520
|
+
{ result = Declaration.new(val.first, val[2], val[3]) }
|
521
|
+
| property COLON S expr prio
|
522
|
+
{ result = Declaration.new(val.first, val[3], val[4]) }
|
523
|
+
| property S COLON expr prio
|
524
|
+
{ result = Declaration.new(val.first, val[3], val[4]) }
|
525
|
+
| property S COLON S expr prio
|
526
|
+
{ result = Declaration.new(val.first, val[4], val[5]) }
|
397
527
|
;
|
398
528
|
prio
|
399
529
|
: IMPORTANT_SYM { result = true }
|
@@ -402,6 +532,7 @@ rule
|
|
402
532
|
property
|
403
533
|
: IDENT { result = interpret_identifier val[0] }
|
404
534
|
| STAR IDENT { result = interpret_identifier val.join }
|
535
|
+
| VARIABLE_NAME { result = interpret_identifier val[0] }
|
405
536
|
;
|
406
537
|
operator
|
407
538
|
: COMMA
|
@@ -422,8 +553,10 @@ rule
|
|
422
553
|
| string
|
423
554
|
| uri
|
424
555
|
| hexcolor
|
425
|
-
|
|
556
|
+
| calc
|
426
557
|
| function
|
558
|
+
| resolution
|
559
|
+
| VARIABLE_NAME
|
427
560
|
;
|
428
561
|
function
|
429
562
|
: function S { result = val.first }
|
@@ -435,6 +568,10 @@ rule
|
|
435
568
|
result = Terms::Function.new name, val[1]
|
436
569
|
end
|
437
570
|
}
|
571
|
+
| FUNCTION RPAREN {
|
572
|
+
name = interpret_identifier val.first.sub(/\($/, '')
|
573
|
+
result = Terms::Function.new name
|
574
|
+
}
|
438
575
|
;
|
439
576
|
function_no_quote
|
440
577
|
: function_no_quote S { result = val.first }
|
@@ -444,14 +581,27 @@ rule
|
|
444
581
|
result = Terms::Function.new(name, [Terms::String.new(interpret_string_no_quote(parts.last))])
|
445
582
|
}
|
446
583
|
;
|
447
|
-
|
448
|
-
:
|
449
|
-
|
450
|
-
name = parts[0].strip
|
451
|
-
expression = parts[1][0..parts[1].rindex(')')-1].strip
|
452
|
-
result = Terms::Math.new(name, expression)
|
584
|
+
calc
|
585
|
+
: CALC_SYM calc_sum RPAREN optional_space {
|
586
|
+
result = Terms::Math.new(val.first.split('(').first, val[1])
|
453
587
|
}
|
454
588
|
;
|
589
|
+
# plus and minus are supposed to have whitespace around them, per http://dev.w3.org/csswg/css-values/#calc-syntax, but the numbers are eating trailing whitespace, so we inject it back in
|
590
|
+
calc_sum
|
591
|
+
: calc_product
|
592
|
+
| calc_product PLUS calc_sum { val.insert(1, ' '); result = val.join('') }
|
593
|
+
| calc_product MINUS calc_sum { val.insert(1, ' '); result = val.join('') }
|
594
|
+
;
|
595
|
+
calc_product
|
596
|
+
: calc_value
|
597
|
+
| calc_value STAR calc_value { result = val.join('') }
|
598
|
+
| calc_value SLASH calc_value { result = val.join('') }
|
599
|
+
;
|
600
|
+
calc_value
|
601
|
+
: numeric { result = val.join('') }
|
602
|
+
| function { result = val.join('') } # for var() variable references
|
603
|
+
| LPAREN calc_sum RPAREN { result = val.join('') }
|
604
|
+
;
|
455
605
|
hexcolor
|
456
606
|
: hexcolor S { result = val.first }
|
457
607
|
| HASH { result = Terms::Hash.new val.first.sub(/^#/, '') }
|
@@ -479,12 +629,6 @@ rule
|
|
479
629
|
unit = val.first.gsub(/[\s\d.]/, '')
|
480
630
|
result = Terms::Number.new numeric(val.first), nil, unit
|
481
631
|
}
|
482
|
-
| EMS {
|
483
|
-
result = Terms::Number.new numeric(val.first), nil, 'em'
|
484
|
-
}
|
485
|
-
| EXS {
|
486
|
-
result = Terms::Number.new numeric(val.first), nil, 'ex'
|
487
|
-
}
|
488
632
|
| ANGLE {
|
489
633
|
unit = val.first.gsub(/[\s\d.]/, '')
|
490
634
|
result = Terms::Number.new numeric(val.first), nil, unit
|
@@ -548,3 +692,29 @@ def interpret_escapes s
|
|
548
692
|
end
|
549
693
|
end.join ''
|
550
694
|
end
|
695
|
+
|
696
|
+
# override racc's on_error so we can have context in our error messages
|
697
|
+
def on_error(t, val, vstack)
|
698
|
+
errcontext = (@ss.pre_match[-10..-1] || @ss.pre_match) +
|
699
|
+
@ss.matched + @ss.post_match[0..9]
|
700
|
+
line_number = @ss.pre_match.lines.count
|
701
|
+
raise ParseError, sprintf("parse error on value %s (%s) " +
|
702
|
+
"on line %s around \"%s\"",
|
703
|
+
val.inspect, token_to_str(t) || '?',
|
704
|
+
line_number, errcontext)
|
705
|
+
end
|
706
|
+
|
707
|
+
def before_pos(val)
|
708
|
+
# don't include leading whitespace
|
709
|
+
return current_pos - val.last.length + val.last[/\A\s*/].size
|
710
|
+
end
|
711
|
+
|
712
|
+
def after_pos(val)
|
713
|
+
# don't include trailing whitespace
|
714
|
+
return current_pos - val.last[/\s*\z/].size
|
715
|
+
end
|
716
|
+
|
717
|
+
# charpos will work with multibyte strings but is not available until ruby 2
|
718
|
+
def current_pos
|
719
|
+
@ss.respond_to?('charpos') ? @ss.charpos : @ss.pos
|
720
|
+
end
|
data/lib/csspool/css/rule_set.rb
CHANGED
@@ -3,15 +3,16 @@ module CSSPool
|
|
3
3
|
class RuleSet < CSSPool::Node
|
4
4
|
attr_accessor :selectors
|
5
5
|
attr_accessor :declarations
|
6
|
-
attr_accessor :
|
6
|
+
attr_accessor :parent_rule
|
7
7
|
|
8
|
-
def initialize selectors, declarations = [],
|
8
|
+
def initialize selectors, declarations = [], parent_rule = nil
|
9
9
|
@selectors = selectors
|
10
10
|
@declarations = declarations
|
11
|
-
@
|
11
|
+
@parent_rule = parent_rule
|
12
12
|
|
13
13
|
selectors.each { |sel| sel.rule_set = self }
|
14
14
|
end
|
15
|
+
|
15
16
|
end
|
16
17
|
end
|
17
18
|
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# Represents an @supports conditional rule
|
2
|
+
module CSSPool
|
3
|
+
module CSS
|
4
|
+
class SupportsRule < CSSPool::Node
|
5
|
+
attr_accessor :conditions
|
6
|
+
attr_accessor :rule_sets
|
7
|
+
|
8
|
+
def initialize conditions
|
9
|
+
@conditions = conditions
|
10
|
+
@rule_sets = []
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -70,7 +70,7 @@ class Tokenizer < Parser
|
|
70
70
|
when (text = @ss.scan(/[\s]*\/\*(.|[\s]*)*?\*\/[\s]*/i))
|
71
71
|
action { next_token }
|
72
72
|
|
73
|
-
when (text = @ss.scan(/not\(\s*/i))
|
73
|
+
when (text = @ss.scan(/not\([\s]*/i))
|
74
74
|
action { [:NOT_PSEUDO_CLASS, st(text)] }
|
75
75
|
|
76
76
|
when (text = @ss.scan(/(nth\-child|nth\-last\-child|nth\-of\-type|nth\-last\-of\-type)\([\s]*([\+\-]?[0-9]*n([\s]*[\+\-][\s]*[0-9]+)?|[\+\-]?[0-9]+|odd|even)[\s]*\)/i))
|
@@ -85,10 +85,19 @@ class Tokenizer < Parser
|
|
85
85
|
when (text = @ss.scan(/(domain|url\-prefix)\([\s]*([!#\$%&*-~]|[^\0-\177]|\\[0-9A-Fa-f]{1,6}(\r\n|[\s])?|\\[^\n\r\f0-9A-Fa-f])*[\s]*\)/i))
|
86
86
|
action { [:FUNCTION_NO_QUOTE, st(text)] }
|
87
87
|
|
88
|
-
when (text = @ss.scan(/
|
89
|
-
action { [:
|
88
|
+
when (text = @ss.scan(/(\-moz\-non\-element|\-moz\-anonymous\-block|\-moz\-anonymous\-positioned\-block|\-moz\-mathml\-anonymous\-block|\-moz\-xul\-anonymous\-block|\-moz\-hframeset\-border|\-moz\-vframeset\-border|\-moz\-line\-frame|\-moz\-button\-content|\-moz\-buttonlabel|\-moz\-cell\-content|\-moz\-dropdown\-list|\-moz\-fieldset\-content|\-moz\-frameset\-blank|\-moz\-display\-comboboxcontrol\-frame|\-moz\-html\-canvas\-content|\-moz\-inline\-table|\-moz\-table|\-moz\-table\-cell|\-moz\-table\-column\-group|\-moz\-table\-column|\-moz\-table\-outer|\-moz\-table\-row\-group|\-moz\-table\-row|\-moz\-canvas|\-moz\-pagebreak|\-moz\-page|\-moz\-pagecontent|\-moz\-page\-sequence|\-moz\-scrolled\-content|\-moz\-scrolled\-canvas|\-moz\-scrolled\-page\-sequence|\-moz\-column\-content|\-moz\-viewport|\-moz\-viewport\-scroll|\-moz\-anonymous\-flex\-item|\-moz\-tree\-column|\-moz\-tree\-row|\-moz\-tree\-separator|\-moz\-tree\-cell|\-moz\-tree\-indentation|\-moz\-tree\-line|\-moz\-tree\-twisty|\-moz\-tree\-image|\-moz\-tree\-cell\-text|\-moz\-tree\-checkbox|\-moz\-tree\-progressmeter|\-moz\-tree\-drop\-feedback|\-moz\-svg\-outer\-svg\-anon\-child|\-moz\-svg\-foreign\-content|\-moz\-svg\-text)\(/i))
|
89
|
+
action { [:MOZ_PSEUDO_ELEMENT, st(text)] }
|
90
90
|
|
91
|
-
when (text = @ss.scan(/[
|
91
|
+
when (text = @ss.scan(/[\s]*@media[\s]*/i))
|
92
|
+
action { @state = :LOGICQUERY; [:MEDIA_SYM, st(text)] }
|
93
|
+
|
94
|
+
when (text = @ss.scan(/[\s]*@supports[\s]*/i))
|
95
|
+
action { @state = :LOGICQUERY; [:SUPPORTS_SYM, st(text)] }
|
96
|
+
|
97
|
+
when (text = @ss.scan(/calc\(\s*/i))
|
98
|
+
action { [:CALC_SYM, st(text)] }
|
99
|
+
|
100
|
+
when (text = @ss.scan(/\-?([_A-Za-z]|[^\0-\177]|\\[0-9A-Fa-f]{1,6}(\r\n|[\s])?|\\[^\n\r\f0-9A-Fa-f])([_A-Za-z0-9-]|[^\0-\177]|\\[0-9A-Fa-f]{1,6}(\r\n|[\s])?|\\[^\n\r\f0-9A-Fa-f])*\(\s*/i))
|
92
101
|
action { [:FUNCTION, st(text)] }
|
93
102
|
|
94
103
|
when (text = @ss.scan(/[\s]*@import[\s]*/i))
|
@@ -100,22 +109,25 @@ class Tokenizer < Parser
|
|
100
109
|
when (text = @ss.scan(/[\s]*@charset[\s]*/i))
|
101
110
|
action { [:CHARSET_SYM, st(text)] }
|
102
111
|
|
103
|
-
when (text = @ss.scan(/[\s]*@media[\s]*/i))
|
104
|
-
action { [:MEDIA_SYM, st(text)] }
|
105
|
-
|
106
112
|
when (text = @ss.scan(/[\s]*@(\-[A-Za-z]+\-)?document[\s]*/i))
|
107
113
|
action { [:DOCUMENT_QUERY_SYM, st(text)] }
|
108
114
|
|
109
115
|
when (text = @ss.scan(/[\s]*@namespace[\s]*/i))
|
110
116
|
action { [:NAMESPACE_SYM, st(text)] }
|
111
117
|
|
118
|
+
when (text = @ss.scan(/[\s]*@font\-face[\s]*/i))
|
119
|
+
action { [:FONTFACE_SYM, st(text)] }
|
120
|
+
|
112
121
|
when (text = @ss.scan(/[\s]*@(\-[A-Za-z]+\-)?keyframes[\s]*/i))
|
113
122
|
action { [:KEYFRAMES_SYM, st(text)] }
|
114
123
|
|
115
124
|
when (text = @ss.scan(/[\s]*!([\s]*|[\s]*\/\*(.|[\s]*)*?\*\/[\s]*)important[\s]*/i))
|
116
125
|
action { [:IMPORTANT_SYM, st(text)] }
|
117
126
|
|
118
|
-
when (text = @ss.scan(
|
127
|
+
when (text = @ss.scan(/\-\-([_A-Za-z0-9-]|[^\0-\177]|\\[0-9A-Fa-f]{1,6}(\r\n|[\s])?|\\[^\n\r\f0-9A-Fa-f])+/i))
|
128
|
+
action { [:VARIABLE_NAME, st(text)] }
|
129
|
+
|
130
|
+
when (text = @ss.scan(/\-?([_A-Za-z]|[^\0-\177]|\\[0-9A-Fa-f]{1,6}(\r\n|[\s])?|\\[^\n\r\f0-9A-Fa-f])([_A-Za-z0-9-]|[^\0-\177]|\\[0-9A-Fa-f]{1,6}(\r\n|[\s])?|\\[^\n\r\f0-9A-Fa-f])*/i))
|
119
131
|
action { [:IDENT, st(text)] }
|
120
132
|
|
121
133
|
when (text = @ss.scan(/\#([_A-Za-z0-9-]|[^\0-\177]|\\[0-9A-Fa-f]{1,6}(\r\n|[\s])?|\\[^\n\r\f0-9A-Fa-f])+/i))
|
@@ -145,6 +157,9 @@ class Tokenizer < Parser
|
|
145
157
|
when (text = @ss.scan(/[\s]*\)/i))
|
146
158
|
action { [:RPAREN, st(text)] }
|
147
159
|
|
160
|
+
when (text = @ss.scan(/[\s]*\(/i))
|
161
|
+
action { [:LPAREN, st(text)] }
|
162
|
+
|
148
163
|
when (text = @ss.scan(/\[[\s]*/i))
|
149
164
|
action { [:LSQUARE, st(text)] }
|
150
165
|
|
@@ -169,19 +184,16 @@ class Tokenizer < Parser
|
|
169
184
|
when (text = @ss.scan(/[\s]*;[\s]*/i))
|
170
185
|
action { [:SEMI, st(';')] }
|
171
186
|
|
187
|
+
when (text = @ss.scan(/\:/i))
|
188
|
+
action { [:COLON, st(text)] }
|
189
|
+
|
172
190
|
when (text = @ss.scan(/\*/i))
|
173
191
|
action { [:STAR, st(text)] }
|
174
192
|
|
175
193
|
when (text = @ss.scan(/[\s]*~[\s]*/i))
|
176
194
|
action { [:TILDE, st(text)] }
|
177
195
|
|
178
|
-
when (text = @ss.scan(/[\s]*([0-9]*\.[0-9]+|[0-9]+)em[\s]*/i))
|
179
|
-
action { [:EMS, st(text)] }
|
180
|
-
|
181
|
-
when (text = @ss.scan(/[\s]*([0-9]*\.[0-9]+|[0-9]+)ex[\s]*/i))
|
182
|
-
action { [:EXS, st(text)] }
|
183
|
-
|
184
|
-
when (text = @ss.scan(/[\s]*([0-9]*\.[0-9]+|[0-9]+)(px|cm|mm|in|pt|pc)[\s]*/i))
|
196
|
+
when (text = @ss.scan(/[\s]*([0-9]*\.[0-9]+|[0-9]+)(px|cm|mm|in|pt|pc|mozmm|em|ex|ch|rem|vh|vw|vmin|vmax)[\s]*/i))
|
185
197
|
action { [:LENGTH, st(text)] }
|
186
198
|
|
187
199
|
when (text = @ss.scan(/[\s]*([0-9]*\.[0-9]+|[0-9]+)(deg|rad|grad)[\s]*/i))
|
@@ -211,7 +223,7 @@ class Tokenizer < Parser
|
|
211
223
|
when (text = @ss.scan(/-->/i))
|
212
224
|
action { [:CDC, st(text)] }
|
213
225
|
|
214
|
-
when (text = @ss.scan(/[\s]*\-(
|
226
|
+
when (text = @ss.scan(/[\s]*\-(?!\-?([_A-Za-z]|[^\0-\177]|\\[0-9A-Fa-f]{1,6}(\r\n|[\s])?|\\[^\n\r\f0-9A-Fa-f])([_A-Za-z0-9-]|[^\0-\177]|\\[0-9A-Fa-f]{1,6}(\r\n|[\s])?|\\[^\n\r\f0-9A-Fa-f])*)[\s]*/i))
|
215
227
|
action { [:MINUS, st(text)] }
|
216
228
|
|
217
229
|
when (text = @ss.scan(/[\s]*\+[\s]*/i))
|
@@ -234,6 +246,70 @@ class Tokenizer < Parser
|
|
234
246
|
raise ScanError, "can not match: '" + text + "'"
|
235
247
|
end # if
|
236
248
|
|
249
|
+
when :LOGICQUERY
|
250
|
+
case
|
251
|
+
when (text = @ss.scan(/url\([\s]*("([^\n\r\f\\"]|\\(\n|\r\n|\r|\f)|[^\0-\177]|\\[0-9A-Fa-f]{1,6}(\r\n|[\s])?|\\[^\n\r\f0-9A-Fa-f])*"|'([^\n\r\f\\']|\\(\n|\r\n|\r|\f)|[^\0-\177]|\\[0-9A-Fa-f]{1,6}(\r\n|[\s])?|\\[^\n\r\f0-9A-Fa-f])*')[\s]*\)/i))
|
252
|
+
action { [:URI, st(text)] }
|
253
|
+
|
254
|
+
when (text = @ss.scan(/url\([\s]*([!#\$%&*-~]|[^\0-\177]|\\[0-9A-Fa-f]{1,6}(\r\n|[\s])?|\\[^\n\r\f0-9A-Fa-f])*[\s]*\)/i))
|
255
|
+
action { [:URI, st(text)] }
|
256
|
+
|
257
|
+
when (text = @ss.scan(/\-?([_A-Za-z]|[^\0-\177]|\\[0-9A-Fa-f]{1,6}(\r\n|[\s])?|\\[^\n\r\f0-9A-Fa-f])([_A-Za-z0-9-]|[^\0-\177]|\\[0-9A-Fa-f]{1,6}(\r\n|[\s])?|\\[^\n\r\f0-9A-Fa-f])*\(\s*/i))
|
258
|
+
action { [:FUNCTION, st(text)] }
|
259
|
+
|
260
|
+
when (text = @ss.scan(/[\s]*(and|only|not|or)[\s]+/i))
|
261
|
+
action { [text.upcase.strip.intern, st(text)] }
|
262
|
+
|
263
|
+
when (text = @ss.scan(/[\s]*([0-9]*\.[0-9]+|[0-9]+)(dpi|dpcm)/i))
|
264
|
+
action { [:RESOLUTION, st(text)]}
|
265
|
+
|
266
|
+
when (text = @ss.scan(/[\s]*([0-9]*\.[0-9]+|[0-9]+)(px|cm|mm|in|pt|pc|mozmm|em|ex|ch|rem|vh|vw|vmin|vmax)[\s]*/i))
|
267
|
+
action { [:LENGTH, st(text)] }
|
268
|
+
|
269
|
+
when (text = @ss.scan(/[\s]*([0-9]*\.[0-9]+|[0-9]+)(deg|rad|grad)[\s]*/i))
|
270
|
+
action { [:ANGLE, st(text)] }
|
271
|
+
|
272
|
+
when (text = @ss.scan(/[\s]*([0-9]*\.[0-9]+|[0-9]+)(ms|s)[\s]*/i))
|
273
|
+
action { [:TIME, st(text)] }
|
274
|
+
|
275
|
+
when (text = @ss.scan(/[\s]*([0-9]*\.[0-9]+|[0-9]+)[k]?hz[\s]*/i))
|
276
|
+
action { [:FREQ, st(text)] }
|
277
|
+
|
278
|
+
when (text = @ss.scan(/[\s]*([0-9]*\.[0-9]+|[0-9]+)%[\s]*/i))
|
279
|
+
action { [:PERCENTAGE, st(text)] }
|
280
|
+
|
281
|
+
when (text = @ss.scan(/[\s]*([0-9]*\.[0-9]+|[0-9]+)[\s]*/i))
|
282
|
+
action { [:NUMBER, st(text)] }
|
283
|
+
|
284
|
+
when (text = @ss.scan(/\-?([_A-Za-z]|[^\0-\177]|\\[0-9A-Fa-f]{1,6}(\r\n|[\s])?|\\[^\n\r\f0-9A-Fa-f])([_A-Za-z0-9-]|[^\0-\177]|\\[0-9A-Fa-f]{1,6}(\r\n|[\s])?|\\[^\n\r\f0-9A-Fa-f])*/i))
|
285
|
+
action { [:IDENT, st(text)] }
|
286
|
+
|
287
|
+
when (text = @ss.scan(/[\s]*,[\s]*/i))
|
288
|
+
action { [:COMMA, st(',')] }
|
289
|
+
|
290
|
+
when (text = @ss.scan(/[\s]*\)/i))
|
291
|
+
action { [:RPAREN, st(text)] }
|
292
|
+
|
293
|
+
when (text = @ss.scan(/[\s]*\(/i))
|
294
|
+
action { [:LPAREN, st(text)] }
|
295
|
+
|
296
|
+
when (text = @ss.scan(/\:/i))
|
297
|
+
action { [:COLON, st(text)] }
|
298
|
+
|
299
|
+
when (text = @ss.scan(/[\s]*!([\s]*|[\s]*\/\*(.|[\s]*)*?\*\/[\s]*)important[\s]*/i))
|
300
|
+
action { [:IMPORTANT_SYM, st(text)] }
|
301
|
+
|
302
|
+
when (text = @ss.scan(/[\s]*\{[\s]*/i))
|
303
|
+
action { @state = nil; [:LBRACE, st(text)] }
|
304
|
+
|
305
|
+
when (text = @ss.scan(/[\s]+/i))
|
306
|
+
action { [:S, st(text)] }
|
307
|
+
|
308
|
+
else
|
309
|
+
text = @ss.string[@ss.pos .. -1]
|
310
|
+
raise ScanError, "can not match: '" + text + "'"
|
311
|
+
end # if
|
312
|
+
|
237
313
|
else
|
238
314
|
raise ScanError, "undefined state: '" + state.to_s + "'"
|
239
315
|
end # case state
|