csspool 4.0.0.pre → 4.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|