crass 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +8 -8
- data/HISTORY.md +14 -0
- data/README.md +50 -40
- data/lib/crass/parser.rb +42 -20
- data/lib/crass/version.rb +1 -1
- data/test/shared/parse_rules.rb +175 -0
- data/test/test_parse_properties.rb +88 -0
- data/test/test_parse_rules.rb +2 -2
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
---
|
2
2
|
!binary "U0hBMQ==":
|
3
3
|
metadata.gz: !binary |-
|
4
|
-
|
4
|
+
MDM3ZDU2Y2U1NDBkNGQxMDQwMzNhNGM1YTRjM2UyM2RjMTA5MGU5MA==
|
5
5
|
data.tar.gz: !binary |-
|
6
|
-
|
6
|
+
YTMyMDVkZTViMjEyNjVlMGJkNjE2N2M0MWRhYmQ3Mzc3NGU0YzE3Mg==
|
7
7
|
SHA512:
|
8
8
|
metadata.gz: !binary |-
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
ZDkwYmUyNGVkZjA5NGMwOWRlNzVlYmIwMmM5NjJlMDYxYWYxMzE0YzE2YWNl
|
10
|
+
MTYwZDU4MzZmMTkwZGVmMDk3ODI4MTMwZmE0NWQ3Y2M5ODE1MTllYjhlZWI2
|
11
|
+
NmQxMjExYmEzMmI1MTQzOWExOTk1Yjg0NjlkODNiYzM5ZDIwZjk=
|
12
12
|
data.tar.gz: !binary |-
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
OTQ4N2Y4MWNiYjQzNTdlN2MzMDVjMTRhY2U2NjE4YzczNDgwMzVhYzQ5ODcy
|
14
|
+
NjMwYTRhZmNiOTc5ZjViMjgyYzlhZThkOWU2Yjc5ODI4YTJlNDUzNmQ1ODAy
|
15
|
+
MTQ2YTA2ZDhmZWUzNDMwNDk2NjQ2MDk4OTBmNmI5NDdmOTNlNzE=
|
data/HISTORY.md
CHANGED
@@ -1,6 +1,20 @@
|
|
1
1
|
Crass Change History
|
2
2
|
====================
|
3
3
|
|
4
|
+
0.2.0 (2013-10-10)
|
5
|
+
------------------
|
6
|
+
|
7
|
+
* Added a `:children` field to `:property` nodes. It's an array containing all
|
8
|
+
the nodes that make up the property's value.
|
9
|
+
|
10
|
+
* Fixed: Incorrect value was given for `:property` nodes whose values contained
|
11
|
+
functions.
|
12
|
+
|
13
|
+
* Fixed: When parsing the value of an at-rule's block as a list of rules, a
|
14
|
+
selector containing a function (such as "#foo:not(.bar)") would cause that
|
15
|
+
property and the rest of the token stream to be discarded.
|
16
|
+
|
17
|
+
|
4
18
|
0.1.0 (2013-10-04)
|
5
19
|
------------------
|
6
20
|
|
data/README.md
CHANGED
@@ -83,47 +83,57 @@ This returns a big fat ugly parse tree, which looks like this:
|
|
83
83
|
```ruby
|
84
84
|
[{:node=>:comment, :pos=>0, :raw=>"/* Comment! */", :value=>" Comment! "},
|
85
85
|
{:node=>:whitespace, :pos=>14, :raw=>"\n"},
|
86
|
-
{:node=>:
|
87
|
-
:
|
88
|
-
|
89
|
-
:value=>"a:hover",
|
90
|
-
:tokens=>
|
91
|
-
[{:node=>:ident, :pos=>15, :raw=>"a", :value=>"a"},
|
92
|
-
{:node=>:colon, :pos=>16, :raw=>":"},
|
93
|
-
{:node=>:ident, :pos=>17, :raw=>"hover", :value=>"hover"},
|
94
|
-
{:node=>:whitespace, :pos=>22, :raw=>" "}]},
|
86
|
+
{:node=>:property,
|
87
|
+
:name=>"a",
|
88
|
+
:value=>"hover {\n color: #0d8bfa",
|
95
89
|
:children=>
|
96
|
-
[{:node=>:
|
97
|
-
{:node=>:
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
{:node=>:
|
112
|
-
{:node=>:
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
{:node=>:
|
90
|
+
[{:node=>:ident, :pos=>17, :raw=>"hover", :value=>"hover"},
|
91
|
+
{:node=>:whitespace, :pos=>22, :raw=>" "},
|
92
|
+
{:node=>:"{", :pos=>23, :raw=>"{"},
|
93
|
+
{:node=>:whitespace, :pos=>24, :raw=>"\n "},
|
94
|
+
{:node=>:ident, :pos=>27, :raw=>"color", :value=>"color"},
|
95
|
+
{:node=>:colon, :pos=>32, :raw=>":"},
|
96
|
+
{:node=>:whitespace, :pos=>33, :raw=>" "},
|
97
|
+
{:node=>:hash,
|
98
|
+
:pos=>34,
|
99
|
+
:raw=>"#0d8bfa",
|
100
|
+
:type=>:unrestricted,
|
101
|
+
:value=>"0d8bfa"}],
|
102
|
+
:important=>false,
|
103
|
+
:tokens=>
|
104
|
+
[{:node=>:ident, :pos=>15, :raw=>"a", :value=>"a"},
|
105
|
+
{:node=>:colon, :pos=>16, :raw=>":"},
|
106
|
+
{:node=>:ident, :pos=>17, :raw=>"hover", :value=>"hover"},
|
107
|
+
{:node=>:whitespace, :pos=>22, :raw=>" "},
|
108
|
+
{:node=>:"{", :pos=>23, :raw=>"{"},
|
109
|
+
{:node=>:whitespace, :pos=>24, :raw=>"\n "},
|
110
|
+
{:node=>:ident, :pos=>27, :raw=>"color", :value=>"color"},
|
111
|
+
{:node=>:colon, :pos=>32, :raw=>":"},
|
112
|
+
{:node=>:whitespace, :pos=>33, :raw=>" "},
|
113
|
+
{:node=>:hash,
|
114
|
+
:pos=>34,
|
115
|
+
:raw=>"#0d8bfa",
|
116
|
+
:type=>:unrestricted,
|
117
|
+
:value=>"0d8bfa"},
|
118
|
+
{:node=>:semicolon, :pos=>41, :raw=>";"}]},
|
119
|
+
{:node=>:whitespace, :pos=>42, :raw=>"\n "},
|
120
|
+
{:node=>:property,
|
121
|
+
:name=>"text-decoration",
|
122
|
+
:value=>"underline",
|
123
|
+
:children=>
|
124
|
+
[{:node=>:whitespace, :pos=>61, :raw=>" "},
|
125
|
+
{:node=>:ident, :pos=>62, :raw=>"underline", :value=>"underline"}],
|
126
|
+
:important=>false,
|
127
|
+
:tokens=>
|
128
|
+
[{:node=>:ident,
|
129
|
+
:pos=>45,
|
130
|
+
:raw=>"text-decoration",
|
131
|
+
:value=>"text-decoration"},
|
132
|
+
{:node=>:colon, :pos=>60, :raw=>":"},
|
133
|
+
{:node=>:whitespace, :pos=>61, :raw=>" "},
|
134
|
+
{:node=>:ident, :pos=>62, :raw=>"underline", :value=>"underline"},
|
135
|
+
{:node=>:semicolon, :pos=>71, :raw=>";"}]},
|
136
|
+
{:node=>:whitespace, :pos=>72, :raw=>"\n"}]
|
127
137
|
```
|
128
138
|
|
129
139
|
If you want, you can stringify the parse tree:
|
data/lib/crass/parser.rb
CHANGED
@@ -26,7 +26,7 @@ module Crass
|
|
26
26
|
Parser.new(input, options).parse_properties
|
27
27
|
end
|
28
28
|
|
29
|
-
# Parses
|
29
|
+
# Parses CSS rules (such as the content of a `@media` block) and returns a
|
30
30
|
# parse tree. The only difference from {#parse_stylesheet} is that CDO/CDC
|
31
31
|
# nodes (`<!--` and `-->`) aren't ignored.
|
32
32
|
#
|
@@ -143,10 +143,13 @@ module Crass
|
|
143
143
|
|
144
144
|
while token = input.consume
|
145
145
|
case token[:node]
|
146
|
-
when :comment
|
147
|
-
|
146
|
+
when :comment
|
147
|
+
next
|
148
148
|
|
149
|
-
when :
|
149
|
+
when :semicolon
|
150
|
+
break
|
151
|
+
|
152
|
+
when :'{'
|
150
153
|
rule[:block] = consume_simple_block(input)
|
151
154
|
break
|
152
155
|
|
@@ -171,14 +174,24 @@ module Crass
|
|
171
174
|
|
172
175
|
# Consumes a component value and returns it.
|
173
176
|
#
|
174
|
-
# http://www.w3.org/TR/2013/WD-css-syntax-3-20130919/#consume-a-component-
|
177
|
+
# http://www.w3.org/TR/2013/WD-css-syntax-3-20130919/#consume-a-component-value
|
175
178
|
def consume_component_value(input = @tokens)
|
176
179
|
return nil unless token = input.consume
|
177
180
|
|
178
181
|
case token[:node]
|
179
|
-
when :'{', :'[', :'('
|
180
|
-
|
181
|
-
|
182
|
+
when :'{', :'[', :'('
|
183
|
+
consume_simple_block(input)
|
184
|
+
|
185
|
+
when :function
|
186
|
+
if token.key?(:name)
|
187
|
+
# This is a parsed function, not a function token.
|
188
|
+
token
|
189
|
+
else
|
190
|
+
consume_function(input)
|
191
|
+
end
|
192
|
+
|
193
|
+
else
|
194
|
+
token
|
182
195
|
end
|
183
196
|
end
|
184
197
|
|
@@ -291,18 +304,21 @@ module Crass
|
|
291
304
|
:tokens => [input.current]
|
292
305
|
}
|
293
306
|
|
294
|
-
function[:tokens].concat(input.collect
|
307
|
+
function[:tokens].concat(input.collect {
|
295
308
|
while token = input.consume
|
296
309
|
case token[:node]
|
297
|
-
when :')'
|
298
|
-
|
310
|
+
when :')'
|
311
|
+
break
|
312
|
+
|
313
|
+
when :comment
|
314
|
+
next
|
299
315
|
|
300
316
|
else
|
301
317
|
input.reconsume
|
302
318
|
function[:value] << consume_component_value(input)
|
303
319
|
end
|
304
320
|
end
|
305
|
-
|
321
|
+
})
|
306
322
|
|
307
323
|
create_node(:function, function)
|
308
324
|
end
|
@@ -340,12 +356,10 @@ module Crass
|
|
340
356
|
def consume_rules(flags = {})
|
341
357
|
rules = []
|
342
358
|
|
343
|
-
while
|
344
|
-
return rules unless token = @tokens.consume
|
345
|
-
|
359
|
+
while token = @tokens.consume
|
346
360
|
case token[:node]
|
347
|
-
when :comment, :whitespace
|
348
|
-
|
361
|
+
when :comment, :whitespace
|
362
|
+
rules << token
|
349
363
|
|
350
364
|
when :cdc, :cdo
|
351
365
|
unless flags[:top_level]
|
@@ -365,6 +379,8 @@ module Crass
|
|
365
379
|
rules << rule if rule
|
366
380
|
end
|
367
381
|
end
|
382
|
+
|
383
|
+
rules
|
368
384
|
end
|
369
385
|
|
370
386
|
# Consumes and returns a simple block associated with the current input
|
@@ -384,7 +400,7 @@ module Crass
|
|
384
400
|
|
385
401
|
block[:tokens].concat(input.collect do
|
386
402
|
while token = input.consume
|
387
|
-
break if token[:node] == end_token
|
403
|
+
break if token[:node] == end_token
|
388
404
|
|
389
405
|
input.reconsume
|
390
406
|
block[:value] << consume_component_value(input)
|
@@ -435,9 +451,13 @@ module Crass
|
|
435
451
|
next
|
436
452
|
end
|
437
453
|
|
454
|
+
children = decl[:value].dup
|
455
|
+
children.pop if children.last[:node] == :semicolon
|
456
|
+
|
438
457
|
properties << create_node(:property,
|
439
458
|
:name => decl[:name],
|
440
459
|
:value => parse_value(decl[:value]),
|
460
|
+
:children => children,
|
441
461
|
:important => decl[:important] == true,
|
442
462
|
:tokens => decl[:tokens])
|
443
463
|
end
|
@@ -452,7 +472,8 @@ module Crass
|
|
452
472
|
|
453
473
|
nodes.each do |node|
|
454
474
|
case node[:node]
|
455
|
-
when :comment, :semicolon
|
475
|
+
when :comment, :semicolon
|
476
|
+
next
|
456
477
|
|
457
478
|
when :at_keyword, :ident
|
458
479
|
string << node[:value]
|
@@ -460,8 +481,9 @@ module Crass
|
|
460
481
|
when :function
|
461
482
|
if node[:value].is_a?(String)
|
462
483
|
string << node[:value]
|
484
|
+
string << '('
|
463
485
|
else
|
464
|
-
string << parse_value(node[:
|
486
|
+
string << parse_value(node[:tokens])
|
465
487
|
end
|
466
488
|
|
467
489
|
else
|
data/lib/crass/version.rb
CHANGED
data/test/shared/parse_rules.rb
CHANGED
@@ -188,6 +188,11 @@ shared_tests_for 'parsing a list of rules' do
|
|
188
188
|
assert_equal("#aaa", property[:value])
|
189
189
|
assert_equal(false, property[:important])
|
190
190
|
assert_tokens("color: #aaa;", property[:tokens], 16)
|
191
|
+
|
192
|
+
assert_equal([
|
193
|
+
{:node=>:whitespace, :pos=>22, :raw=>" "},
|
194
|
+
{:node=>:hash, :pos=>23, :raw=>"#aaa", :type=>:id, :value=>"aaa"},
|
195
|
+
], property[:children])
|
191
196
|
end
|
192
197
|
|
193
198
|
it 'with preceding comment, selector, block, comment, when :preserve_comments == true' do
|
@@ -217,6 +222,11 @@ shared_tests_for 'parsing a list of rules' do
|
|
217
222
|
assert_equal("#aaa", property[:value])
|
218
223
|
assert_equal(false, property[:important])
|
219
224
|
assert_tokens("color: #aaa;", property[:tokens], 16, options)
|
225
|
+
|
226
|
+
assert_equal([
|
227
|
+
{:node=>:whitespace, :pos=>22, :raw=>" "},
|
228
|
+
{:node=>:hash, :pos=>23, :raw=>"#aaa", :type=>:id, :value=>"aaa"}
|
229
|
+
], property[:children])
|
220
230
|
end
|
221
231
|
|
222
232
|
it 'unclosed, with preceding comment, no selector' do
|
@@ -243,6 +253,12 @@ shared_tests_for 'parsing a list of rules' do
|
|
243
253
|
assert_equal("#aaa", property[:value])
|
244
254
|
assert_equal(false, property[:important])
|
245
255
|
assert_tokens("color: #aaa ", property[:tokens], 8)
|
256
|
+
|
257
|
+
assert_equal([
|
258
|
+
{:node=>:whitespace, :pos=>14, :raw=>" "},
|
259
|
+
{:node=>:hash, :pos=>15, :raw=>"#aaa", :type=>:id, :value=>"aaa"},
|
260
|
+
{:node=>:whitespace, :pos=>19, :raw=>" "}
|
261
|
+
], property[:children])
|
246
262
|
end
|
247
263
|
|
248
264
|
it 'unclosed, with preceding comment, no selector, when :preserve_comments == true' do
|
@@ -270,6 +286,12 @@ shared_tests_for 'parsing a list of rules' do
|
|
270
286
|
assert_equal("#aaa", property[:value])
|
271
287
|
assert_equal(false, property[:important])
|
272
288
|
assert_tokens("color: #aaa ", property[:tokens], 8, options)
|
289
|
+
|
290
|
+
assert_equal([
|
291
|
+
{:node=>:whitespace, :pos=>14, :raw=>" "},
|
292
|
+
{:node=>:hash, :pos=>15, :raw=>"#aaa", :type=>:id, :value=>"aaa"},
|
293
|
+
{:node=>:whitespace, :pos=>19, :raw=>" "}
|
294
|
+
], property[:children])
|
273
295
|
end
|
274
296
|
end
|
275
297
|
|
@@ -298,6 +320,11 @@ shared_tests_for 'parsing a list of rules' do
|
|
298
320
|
assert_equal(false, prop[:important])
|
299
321
|
assert_tokens("color: #aaa;", prop[:tokens], 6)
|
300
322
|
|
323
|
+
assert_equal([
|
324
|
+
{:node=>:whitespace, :pos=>12, :raw=>" "},
|
325
|
+
{:node=>:hash, :pos=>13, :raw=>"#aaa", :type=>:id, :value=>"aaa"}
|
326
|
+
], prop[:children])
|
327
|
+
|
301
328
|
assert_tokens(" ", tree[1], 20)
|
302
329
|
|
303
330
|
rule = tree[2]
|
@@ -342,4 +369,152 @@ shared_tests_for 'parsing a list of rules' do
|
|
342
369
|
assert_equal([], rule[:prelude])
|
343
370
|
assert_tokens("@a", rule[:tokens], 2)
|
344
371
|
end
|
372
|
+
|
373
|
+
it 'should parse property values containing functions' do
|
374
|
+
tree = parse("p:before { content: a\\ttr(data-foo) \" \"; }")
|
375
|
+
|
376
|
+
assert_equal([
|
377
|
+
{:node=>:style_rule,
|
378
|
+
:selector=>
|
379
|
+
{:node=>:selector,
|
380
|
+
:value=>"p:before",
|
381
|
+
:tokens=>
|
382
|
+
[{:node=>:ident, :pos=>0, :raw=>"p", :value=>"p"},
|
383
|
+
{:node=>:colon, :pos=>1, :raw=>":"},
|
384
|
+
{:node=>:ident, :pos=>2, :raw=>"before", :value=>"before"},
|
385
|
+
{:node=>:whitespace, :pos=>8, :raw=>" "}]},
|
386
|
+
:children=>
|
387
|
+
[{:node=>:whitespace, :pos=>10, :raw=>" "},
|
388
|
+
{:node=>:property,
|
389
|
+
:name=>"content",
|
390
|
+
:value=>"attr(data-foo) \" \"",
|
391
|
+
:important=>false,
|
392
|
+
:children=>
|
393
|
+
[{:node=>:whitespace, :pos=>19, :raw=>" "},
|
394
|
+
{:node=>:function,
|
395
|
+
:name=>"attr",
|
396
|
+
:value=>
|
397
|
+
[{:node=>:ident, :pos=>26, :raw=>"data-foo", :value=>"data-foo"}],
|
398
|
+
:tokens=>
|
399
|
+
[{:node=>:function, :pos=>20, :raw=>"a\\ttr(", :value=>"attr"},
|
400
|
+
{:node=>:ident, :pos=>26, :raw=>"data-foo", :value=>"data-foo"},
|
401
|
+
{:node=>:")", :pos=>34, :raw=>")"}]},
|
402
|
+
{:node=>:whitespace, :pos=>35, :raw=>" "},
|
403
|
+
{:node=>:string, :pos=>36, :raw=>"\" \"", :value=>" "}],
|
404
|
+
:tokens=>
|
405
|
+
[{:node=>:ident, :pos=>11, :raw=>"content", :value=>"content"},
|
406
|
+
{:node=>:colon, :pos=>18, :raw=>":"},
|
407
|
+
{:node=>:whitespace, :pos=>19, :raw=>" "},
|
408
|
+
{:node=>:function,
|
409
|
+
:name=>"attr",
|
410
|
+
:value=>
|
411
|
+
[{:node=>:ident, :pos=>26, :raw=>"data-foo", :value=>"data-foo"}],
|
412
|
+
:tokens=>
|
413
|
+
[{:node=>:function, :pos=>20, :raw=>"a\\ttr(", :value=>"attr"},
|
414
|
+
{:node=>:ident, :pos=>26, :raw=>"data-foo", :value=>"data-foo"},
|
415
|
+
{:node=>:")", :pos=>34, :raw=>")"}]},
|
416
|
+
{:node=>:whitespace, :pos=>35, :raw=>" "},
|
417
|
+
{:node=>:string, :pos=>36, :raw=>"\" \"", :value=>" "},
|
418
|
+
{:node=>:semicolon, :pos=>39, :raw=>";"}]},
|
419
|
+
{:node=>:whitespace, :pos=>40, :raw=>" "}]}
|
420
|
+
], tree)
|
421
|
+
end
|
422
|
+
|
423
|
+
it 'should parse property values containing nested functions' do
|
424
|
+
tree = parse("div { width: e\\78 pression(alert(1)); }")
|
425
|
+
|
426
|
+
assert_equal([
|
427
|
+
{:node=>:style_rule,
|
428
|
+
:selector=>
|
429
|
+
{:node=>:selector,
|
430
|
+
:value=>"div",
|
431
|
+
:tokens=>
|
432
|
+
[{:node=>:ident, :pos=>0, :raw=>"div", :value=>"div"},
|
433
|
+
{:node=>:whitespace, :pos=>3, :raw=>" "}]},
|
434
|
+
:children=>
|
435
|
+
[{:node=>:whitespace, :pos=>5, :raw=>" "},
|
436
|
+
{:node=>:property,
|
437
|
+
:name=>"width",
|
438
|
+
:value=>"expression(alert(1))",
|
439
|
+
:important=>false,
|
440
|
+
:children=>
|
441
|
+
[{:node=>:whitespace, :pos=>12, :raw=>" "},
|
442
|
+
{:node=>:function,
|
443
|
+
:name=>"expression",
|
444
|
+
:value=>
|
445
|
+
[{:node=>:function,
|
446
|
+
:name=>"alert",
|
447
|
+
:value=>
|
448
|
+
[{:node=>:number,
|
449
|
+
:pos=>33,
|
450
|
+
:raw=>"1",
|
451
|
+
:repr=>"1",
|
452
|
+
:type=>:integer,
|
453
|
+
:value=>1}],
|
454
|
+
:tokens=>
|
455
|
+
[{:node=>:function, :pos=>27, :raw=>"alert(", :value=>"alert"},
|
456
|
+
{:node=>:number,
|
457
|
+
:pos=>33,
|
458
|
+
:raw=>"1",
|
459
|
+
:repr=>"1",
|
460
|
+
:type=>:integer,
|
461
|
+
:value=>1},
|
462
|
+
{:node=>:")", :pos=>34, :raw=>")"}]}],
|
463
|
+
:tokens=>
|
464
|
+
[{:node=>:function,
|
465
|
+
:pos=>13,
|
466
|
+
:raw=>"e\\78 pression(",
|
467
|
+
:value=>"expression"},
|
468
|
+
{:node=>:function, :pos=>27, :raw=>"alert(", :value=>"alert"},
|
469
|
+
{:node=>:number,
|
470
|
+
:pos=>33,
|
471
|
+
:raw=>"1",
|
472
|
+
:repr=>"1",
|
473
|
+
:type=>:integer,
|
474
|
+
:value=>1},
|
475
|
+
{:node=>:")", :pos=>34, :raw=>")"},
|
476
|
+
{:node=>:")", :pos=>35, :raw=>")"}]}],
|
477
|
+
:tokens=>
|
478
|
+
[{:node=>:ident, :pos=>6, :raw=>"width", :value=>"width"},
|
479
|
+
{:node=>:colon, :pos=>11, :raw=>":"},
|
480
|
+
{:node=>:whitespace, :pos=>12, :raw=>" "},
|
481
|
+
{:node=>:function,
|
482
|
+
:name=>"expression",
|
483
|
+
:value=>
|
484
|
+
[{:node=>:function,
|
485
|
+
:name=>"alert",
|
486
|
+
:value=>
|
487
|
+
[{:node=>:number,
|
488
|
+
:pos=>33,
|
489
|
+
:raw=>"1",
|
490
|
+
:repr=>"1",
|
491
|
+
:type=>:integer,
|
492
|
+
:value=>1}],
|
493
|
+
:tokens=>
|
494
|
+
[{:node=>:function, :pos=>27, :raw=>"alert(", :value=>"alert"},
|
495
|
+
{:node=>:number,
|
496
|
+
:pos=>33,
|
497
|
+
:raw=>"1",
|
498
|
+
:repr=>"1",
|
499
|
+
:type=>:integer,
|
500
|
+
:value=>1},
|
501
|
+
{:node=>:")", :pos=>34, :raw=>")"}]}],
|
502
|
+
:tokens=>
|
503
|
+
[{:node=>:function,
|
504
|
+
:pos=>13,
|
505
|
+
:raw=>"e\\78 pression(",
|
506
|
+
:value=>"expression"},
|
507
|
+
{:node=>:function, :pos=>27, :raw=>"alert(", :value=>"alert"},
|
508
|
+
{:node=>:number,
|
509
|
+
:pos=>33,
|
510
|
+
:raw=>"1",
|
511
|
+
:repr=>"1",
|
512
|
+
:type=>:integer,
|
513
|
+
:value=>1},
|
514
|
+
{:node=>:")", :pos=>34, :raw=>")"},
|
515
|
+
{:node=>:")", :pos=>35, :raw=>")"}]},
|
516
|
+
{:node=>:semicolon, :pos=>36, :raw=>";"}]},
|
517
|
+
{:node=>:whitespace, :pos=>37, :raw=>" "}]}
|
518
|
+
], tree)
|
519
|
+
end
|
345
520
|
end
|
@@ -40,6 +40,10 @@ describe 'Crass::Parser' do
|
|
40
40
|
assert_equal(false, prop[:important])
|
41
41
|
assert_tokens("a:b;", prop[:tokens])
|
42
42
|
|
43
|
+
assert_equal([
|
44
|
+
{:node=>:ident, :pos=>2, :raw=>"b", :value=>"b"}
|
45
|
+
], prop[:children])
|
46
|
+
|
43
47
|
assert_tokens(" ", tree[1], 4)
|
44
48
|
|
45
49
|
prop = tree[2]
|
@@ -49,6 +53,17 @@ describe 'Crass::Parser' do
|
|
49
53
|
assert_equal(true, prop[:important])
|
50
54
|
assert_tokens("c:d 42!important;", prop[:tokens], 5)
|
51
55
|
|
56
|
+
assert_equal([
|
57
|
+
{:node=>:ident, :pos=>7, :raw=>"d", :value=>"d"},
|
58
|
+
{:node=>:whitespace, :pos=>8, :raw=>" "},
|
59
|
+
{:node=>:number,
|
60
|
+
:pos=>9,
|
61
|
+
:raw=>"42",
|
62
|
+
:repr=>"42",
|
63
|
+
:type=>:integer,
|
64
|
+
:value=>42}
|
65
|
+
], prop[:children])
|
66
|
+
|
52
67
|
assert_tokens("\n", tree[3], 22)
|
53
68
|
end
|
54
69
|
|
@@ -71,6 +86,10 @@ describe 'Crass::Parser' do
|
|
71
86
|
assert_equal(false, prop[:important])
|
72
87
|
assert_tokens("a:b;", prop[:tokens], 19)
|
73
88
|
|
89
|
+
assert_equal([
|
90
|
+
{:node=>:ident, :pos=>21, :raw=>"b", :value=>"b"}
|
91
|
+
], prop[:children])
|
92
|
+
|
74
93
|
assert_tokens(" ", tree[3], 23)
|
75
94
|
|
76
95
|
rule = tree[4]
|
@@ -115,6 +134,9 @@ describe 'Crass::Parser' do
|
|
115
134
|
assert_equal("b", prop[:value])
|
116
135
|
assert_equal(false, prop[:important])
|
117
136
|
assert_tokens("a:b;", prop[:tokens], 24)
|
137
|
+
assert_equal([
|
138
|
+
{:node=>:ident, :pos=>26, :raw=>"b", :value=>"b"}
|
139
|
+
], prop[:children])
|
118
140
|
|
119
141
|
assert_tokens("; ", tree[3..4], 28)
|
120
142
|
|
@@ -171,5 +193,71 @@ describe 'Crass::Parser' do
|
|
171
193
|
assert_equal([], block[:value])
|
172
194
|
assert_tokens("{", block[:tokens], 47)
|
173
195
|
end
|
196
|
+
|
197
|
+
it 'should parse values containing functions' do
|
198
|
+
tree = parse("content: attr(data-foo) \" \";")
|
199
|
+
|
200
|
+
assert_equal([
|
201
|
+
{:node=>:property,
|
202
|
+
:name=>"content",
|
203
|
+
:value=>"attr(data-foo) \" \"",
|
204
|
+
:important=>false,
|
205
|
+
:children=>
|
206
|
+
[{:node=>:whitespace, :pos=>8, :raw=>" "},
|
207
|
+
{:node=>:function, :pos=>9, :raw=>"attr(", :value=>"attr"},
|
208
|
+
{:node=>:ident, :pos=>14, :raw=>"data-foo", :value=>"data-foo"},
|
209
|
+
{:node=>:")", :pos=>22, :raw=>")"},
|
210
|
+
{:node=>:whitespace, :pos=>23, :raw=>" "},
|
211
|
+
{:node=>:string, :pos=>24, :raw=>"\" \"", :value=>" "}],
|
212
|
+
:tokens=>
|
213
|
+
[{:node=>:ident, :pos=>0, :raw=>"content", :value=>"content"},
|
214
|
+
{:node=>:colon, :pos=>7, :raw=>":"},
|
215
|
+
{:node=>:whitespace, :pos=>8, :raw=>" "},
|
216
|
+
{:node=>:function, :pos=>9, :raw=>"attr(", :value=>"attr"},
|
217
|
+
{:node=>:ident, :pos=>14, :raw=>"data-foo", :value=>"data-foo"},
|
218
|
+
{:node=>:")", :pos=>22, :raw=>")"},
|
219
|
+
{:node=>:whitespace, :pos=>23, :raw=>" "},
|
220
|
+
{:node=>:string, :pos=>24, :raw=>"\" \"", :value=>" "},
|
221
|
+
{:node=>:semicolon, :pos=>27, :raw=>";"}]}
|
222
|
+
], tree)
|
223
|
+
end
|
224
|
+
|
225
|
+
it 'should parse values containing nested functions' do
|
226
|
+
tree = parse("width: expression(alert(1));")
|
227
|
+
|
228
|
+
assert_equal([
|
229
|
+
{:node=>:property,
|
230
|
+
:name=>"width",
|
231
|
+
:value=>"expression(alert(1))",
|
232
|
+
:important=>false,
|
233
|
+
:children=>
|
234
|
+
[{:node=>:whitespace, :pos=>6, :raw=>" "},
|
235
|
+
{:node=>:function, :pos=>7, :raw=>"expression(", :value=>"expression"},
|
236
|
+
{:node=>:function, :pos=>18, :raw=>"alert(", :value=>"alert"},
|
237
|
+
{:node=>:number,
|
238
|
+
:pos=>24,
|
239
|
+
:raw=>"1",
|
240
|
+
:repr=>"1",
|
241
|
+
:type=>:integer,
|
242
|
+
:value=>1},
|
243
|
+
{:node=>:")", :pos=>25, :raw=>")"},
|
244
|
+
{:node=>:")", :pos=>26, :raw=>")"}],
|
245
|
+
:tokens=>
|
246
|
+
[{:node=>:ident, :pos=>0, :raw=>"width", :value=>"width"},
|
247
|
+
{:node=>:colon, :pos=>5, :raw=>":"},
|
248
|
+
{:node=>:whitespace, :pos=>6, :raw=>" "},
|
249
|
+
{:node=>:function, :pos=>7, :raw=>"expression(", :value=>"expression"},
|
250
|
+
{:node=>:function, :pos=>18, :raw=>"alert(", :value=>"alert"},
|
251
|
+
{:node=>:number,
|
252
|
+
:pos=>24,
|
253
|
+
:raw=>"1",
|
254
|
+
:repr=>"1",
|
255
|
+
:type=>:integer,
|
256
|
+
:value=>1},
|
257
|
+
{:node=>:")", :pos=>25, :raw=>")"},
|
258
|
+
{:node=>:")", :pos=>26, :raw=>")"},
|
259
|
+
{:node=>:semicolon, :pos=>27, :raw=>";"}]}
|
260
|
+
], tree)
|
261
|
+
end
|
174
262
|
end
|
175
263
|
end
|
data/test/test_parse_rules.rb
CHANGED
@@ -52,12 +52,12 @@ describe 'Crass::Parser' do
|
|
52
52
|
end
|
53
53
|
|
54
54
|
it 'should parse the block of an at-rule' do
|
55
|
-
rule = CP.parse_stylesheet("@media (max-width: 400px) {.
|
55
|
+
rule = CP.parse_stylesheet("@media (max-width: 400px) {#foo:not(.bar){color:#fff;}}")[0]
|
56
56
|
assert_equal(:at_rule, rule[:node])
|
57
57
|
|
58
58
|
style_rule = parse(rule[:block][:value])[0]
|
59
59
|
assert_equal(:style_rule, style_rule[:node])
|
60
|
-
assert_equal(".
|
60
|
+
assert_equal("#foo:not(.bar)", style_rule[:selector][:value])
|
61
61
|
assert_equal(1, style_rule[:children].size)
|
62
62
|
|
63
63
|
prop = style_rule[:children][0]
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: crass
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ryan Grove
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2013-10-
|
11
|
+
date: 2013-10-10 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: minitest
|