crass 0.2.1 → 1.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 +4 -4
- data/.travis.yml +4 -0
- data/HISTORY.md +22 -1
- data/LICENSE +1 -1
- data/README.md +64 -72
- data/Rakefile +4 -0
- data/crass.gemspec +2 -2
- data/lib/crass.rb +1 -1
- data/lib/crass/parser.rb +231 -96
- data/lib/crass/scanner.rb +21 -21
- data/lib/crass/token-scanner.rb +8 -1
- data/lib/crass/tokenizer.rb +133 -131
- data/lib/crass/version.rb +1 -1
- data/test/css-parsing-tests/An+B.json +156 -0
- data/test/css-parsing-tests/LICENSE +8 -0
- data/test/css-parsing-tests/README.rst +301 -0
- data/test/css-parsing-tests/color3.json +142 -0
- data/test/css-parsing-tests/color3_hsl.json +3890 -0
- data/test/css-parsing-tests/color3_keywords.json +803 -0
- data/test/css-parsing-tests/component_value_list.json +432 -0
- data/test/css-parsing-tests/declaration_list.json +44 -0
- data/test/css-parsing-tests/make_color3_hsl.py +17 -0
- data/test/css-parsing-tests/make_color3_keywords.py +191 -0
- data/test/css-parsing-tests/one_component_value.json +27 -0
- data/test/css-parsing-tests/one_declaration.json +46 -0
- data/test/css-parsing-tests/one_rule.json +36 -0
- data/test/css-parsing-tests/rule_list.json +48 -0
- data/test/css-parsing-tests/stylesheet.json +44 -0
- data/test/css-parsing-tests/stylesheet_bytes.json +146 -0
- data/test/shared/parse_rules.rb +377 -434
- data/test/support/common.rb +124 -0
- data/test/support/serialization/animate.css +3158 -0
- data/test/support/serialization/html5-boilerplate.css +268 -0
- data/test/support/serialization/misc.css +9 -0
- data/test/test_css_parsing_tests.rb +150 -0
- data/test/test_parse_properties.rb +136 -211
- data/test/test_parse_rules.rb +0 -52
- data/test/test_parse_stylesheet.rb +0 -39
- data/test/test_serialization.rb +13 -4
- metadata +44 -7
- data/test/test_tokenizer.rb +0 -1562
@@ -0,0 +1,268 @@
|
|
1
|
+
/*! HTML5 Boilerplate v4.3.0 | MIT License | http://h5bp.com/ */
|
2
|
+
|
3
|
+
/*
|
4
|
+
* What follows is the result of much research on cross-browser styling.
|
5
|
+
* Credit left inline and big thanks to Nicolas Gallagher, Jonathan Neal,
|
6
|
+
* Kroc Camen, and the H5BP dev community and team.
|
7
|
+
*/
|
8
|
+
|
9
|
+
/* ==========================================================================
|
10
|
+
Base styles: opinionated defaults
|
11
|
+
========================================================================== */
|
12
|
+
|
13
|
+
html {
|
14
|
+
color: #222;
|
15
|
+
font-size: 1em;
|
16
|
+
line-height: 1.4;
|
17
|
+
}
|
18
|
+
|
19
|
+
/*
|
20
|
+
* Remove text-shadow in selection highlight: h5bp.com/i
|
21
|
+
* These selection rule sets have to be separate.
|
22
|
+
* Customize the background color to match your design.
|
23
|
+
*/
|
24
|
+
|
25
|
+
::-moz-selection {
|
26
|
+
background: #b3d4fc;
|
27
|
+
text-shadow: none;
|
28
|
+
}
|
29
|
+
|
30
|
+
::selection {
|
31
|
+
background: #b3d4fc;
|
32
|
+
text-shadow: none;
|
33
|
+
}
|
34
|
+
|
35
|
+
/*
|
36
|
+
* A better looking default horizontal rule
|
37
|
+
*/
|
38
|
+
|
39
|
+
hr {
|
40
|
+
display: block;
|
41
|
+
height: 1px;
|
42
|
+
border: 0;
|
43
|
+
border-top: 1px solid #ccc;
|
44
|
+
margin: 1em 0;
|
45
|
+
padding: 0;
|
46
|
+
}
|
47
|
+
|
48
|
+
/*
|
49
|
+
* Remove the gap between images, videos, audio and canvas and the bottom of
|
50
|
+
* their containers: h5bp.com/i/440
|
51
|
+
*/
|
52
|
+
|
53
|
+
audio,
|
54
|
+
canvas,
|
55
|
+
img,
|
56
|
+
svg,
|
57
|
+
video {
|
58
|
+
vertical-align: middle;
|
59
|
+
}
|
60
|
+
|
61
|
+
/*
|
62
|
+
* Remove default fieldset styles.
|
63
|
+
*/
|
64
|
+
|
65
|
+
fieldset {
|
66
|
+
border: 0;
|
67
|
+
margin: 0;
|
68
|
+
padding: 0;
|
69
|
+
}
|
70
|
+
|
71
|
+
/*
|
72
|
+
* Allow only vertical resizing of textareas.
|
73
|
+
*/
|
74
|
+
|
75
|
+
textarea {
|
76
|
+
resize: vertical;
|
77
|
+
}
|
78
|
+
|
79
|
+
/* ==========================================================================
|
80
|
+
Browser Upgrade Prompt
|
81
|
+
========================================================================== */
|
82
|
+
|
83
|
+
.browserupgrade {
|
84
|
+
margin: 0.2em 0;
|
85
|
+
background: #ccc;
|
86
|
+
color: #000;
|
87
|
+
padding: 0.2em 0;
|
88
|
+
}
|
89
|
+
|
90
|
+
/* ==========================================================================
|
91
|
+
Author's custom styles
|
92
|
+
========================================================================== */
|
93
|
+
|
94
|
+
|
95
|
+
|
96
|
+
|
97
|
+
|
98
|
+
|
99
|
+
|
100
|
+
|
101
|
+
|
102
|
+
|
103
|
+
|
104
|
+
|
105
|
+
|
106
|
+
|
107
|
+
|
108
|
+
|
109
|
+
|
110
|
+
/* ==========================================================================
|
111
|
+
Helper classes
|
112
|
+
========================================================================== */
|
113
|
+
|
114
|
+
/*
|
115
|
+
* Hide visually and from screen readers: h5bp.com/u
|
116
|
+
*/
|
117
|
+
|
118
|
+
.hidden {
|
119
|
+
display: none !important;
|
120
|
+
visibility: hidden;
|
121
|
+
}
|
122
|
+
|
123
|
+
/*
|
124
|
+
* Hide only visually, but have it available for screen readers: h5bp.com/v
|
125
|
+
*/
|
126
|
+
|
127
|
+
.visuallyhidden {
|
128
|
+
border: 0;
|
129
|
+
clip: rect(0 0 0 0);
|
130
|
+
height: 1px;
|
131
|
+
margin: -1px;
|
132
|
+
overflow: hidden;
|
133
|
+
padding: 0;
|
134
|
+
position: absolute;
|
135
|
+
width: 1px;
|
136
|
+
}
|
137
|
+
|
138
|
+
/*
|
139
|
+
* Extends the .visuallyhidden class to allow the element to be focusable
|
140
|
+
* when navigated to via the keyboard: h5bp.com/p
|
141
|
+
*/
|
142
|
+
|
143
|
+
.visuallyhidden.focusable:active,
|
144
|
+
.visuallyhidden.focusable:focus {
|
145
|
+
clip: auto;
|
146
|
+
height: auto;
|
147
|
+
margin: 0;
|
148
|
+
overflow: visible;
|
149
|
+
position: static;
|
150
|
+
width: auto;
|
151
|
+
}
|
152
|
+
|
153
|
+
/*
|
154
|
+
* Hide visually and from screen readers, but maintain layout
|
155
|
+
*/
|
156
|
+
|
157
|
+
.invisible {
|
158
|
+
visibility: hidden;
|
159
|
+
}
|
160
|
+
|
161
|
+
/*
|
162
|
+
* Clearfix: contain floats
|
163
|
+
*
|
164
|
+
* For modern browsers
|
165
|
+
* 1. The space content is one way to avoid an Opera bug when the
|
166
|
+
* `contenteditable` attribute is included anywhere else in the document.
|
167
|
+
* Otherwise it causes space to appear at the top and bottom of elements
|
168
|
+
* that receive the `clearfix` class.
|
169
|
+
* 2. The use of `table` rather than `block` is only necessary if using
|
170
|
+
* `:before` to contain the top-margins of child elements.
|
171
|
+
*/
|
172
|
+
|
173
|
+
.clearfix:before,
|
174
|
+
.clearfix:after {
|
175
|
+
content: " "; /* 1 */
|
176
|
+
display: table; /* 2 */
|
177
|
+
}
|
178
|
+
|
179
|
+
.clearfix:after {
|
180
|
+
clear: both;
|
181
|
+
}
|
182
|
+
|
183
|
+
/* ==========================================================================
|
184
|
+
EXAMPLE Media Queries for Responsive Design.
|
185
|
+
These examples override the primary ('mobile first') styles.
|
186
|
+
Modify as content requires.
|
187
|
+
========================================================================== */
|
188
|
+
|
189
|
+
@media only screen and (min-width: 35em) {
|
190
|
+
/* Style adjustments for viewports that meet the condition */
|
191
|
+
}
|
192
|
+
|
193
|
+
@media print,
|
194
|
+
(-o-min-device-pixel-ratio: 5/4),
|
195
|
+
(-webkit-min-device-pixel-ratio: 1.25),
|
196
|
+
(min-resolution: 120dpi) {
|
197
|
+
/* Style adjustments for high resolution devices */
|
198
|
+
}
|
199
|
+
|
200
|
+
/* ==========================================================================
|
201
|
+
Print styles.
|
202
|
+
Inlined to avoid the additional HTTP request: h5bp.com/r
|
203
|
+
========================================================================== */
|
204
|
+
|
205
|
+
@media print {
|
206
|
+
*,
|
207
|
+
*:before,
|
208
|
+
*:after {
|
209
|
+
background: transparent !important;
|
210
|
+
color: #000 !important; /* Black prints faster: h5bp.com/s */
|
211
|
+
box-shadow: none !important;
|
212
|
+
text-shadow: none !important;
|
213
|
+
}
|
214
|
+
|
215
|
+
a,
|
216
|
+
a:visited {
|
217
|
+
text-decoration: underline;
|
218
|
+
}
|
219
|
+
|
220
|
+
a[href]:after {
|
221
|
+
content: " (" attr(href) ")";
|
222
|
+
}
|
223
|
+
|
224
|
+
abbr[title]:after {
|
225
|
+
content: " (" attr(title) ")";
|
226
|
+
}
|
227
|
+
|
228
|
+
/*
|
229
|
+
* Don't show links that are fragment identifiers,
|
230
|
+
* or use the `javascript:` pseudo protocol
|
231
|
+
*/
|
232
|
+
|
233
|
+
a[href^="#"]:after,
|
234
|
+
a[href^="javascript:"]:after {
|
235
|
+
content: "";
|
236
|
+
}
|
237
|
+
|
238
|
+
pre,
|
239
|
+
blockquote {
|
240
|
+
border: 1px solid #999;
|
241
|
+
page-break-inside: avoid;
|
242
|
+
}
|
243
|
+
|
244
|
+
thead {
|
245
|
+
display: table-header-group; /* h5bp.com/t */
|
246
|
+
}
|
247
|
+
|
248
|
+
tr,
|
249
|
+
img {
|
250
|
+
page-break-inside: avoid;
|
251
|
+
}
|
252
|
+
|
253
|
+
img {
|
254
|
+
max-width: 100% !important;
|
255
|
+
}
|
256
|
+
|
257
|
+
p,
|
258
|
+
h2,
|
259
|
+
h3 {
|
260
|
+
orphans: 3;
|
261
|
+
widows: 3;
|
262
|
+
}
|
263
|
+
|
264
|
+
h2,
|
265
|
+
h3 {
|
266
|
+
page-break-after: avoid;
|
267
|
+
}
|
268
|
+
}
|
@@ -0,0 +1,150 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
# This file loads and runs Simon Sapin's CSS parsing tests, which live under the
|
4
|
+
# test/css-parsing-tests directory. The original test repo can be found at:
|
5
|
+
#
|
6
|
+
# https://github.com/SimonSapin/css-parsing-tests/
|
7
|
+
|
8
|
+
require 'json'
|
9
|
+
require_relative 'support/common'
|
10
|
+
|
11
|
+
def load_css_tests(filename)
|
12
|
+
JSON.parse(File.read(File.join(File.dirname(__FILE__), "/css-parsing-tests/#{filename}")))
|
13
|
+
end
|
14
|
+
|
15
|
+
describe 'CSS Parsing Tests' do
|
16
|
+
describe 'component_value_list' do
|
17
|
+
make_my_diffs_pretty!
|
18
|
+
parallelize_me!
|
19
|
+
|
20
|
+
tests = load_css_tests('component_value_list.json')
|
21
|
+
|
22
|
+
tests.each_slice(2) do |test|
|
23
|
+
css = test[0]
|
24
|
+
expected = test[1]
|
25
|
+
|
26
|
+
it "should parse: #{css.gsub("\n", "\\n")}" do
|
27
|
+
parser = Crass::Parser.new(css)
|
28
|
+
assert_equal(expected, translate_tokens(parser.parse_component_values))
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
describe 'declaration_list' do
|
34
|
+
make_my_diffs_pretty!
|
35
|
+
parallelize_me!
|
36
|
+
|
37
|
+
tests = load_css_tests('declaration_list.json')
|
38
|
+
|
39
|
+
tests.each_slice(2) do |test|
|
40
|
+
css = test[0]
|
41
|
+
expected = test[1]
|
42
|
+
|
43
|
+
it "should parse: #{css.gsub("\n", "\\n")}" do
|
44
|
+
parser = Crass::Parser.new(css)
|
45
|
+
assert_equal(expected, translate_tokens(parser.parse_declarations(parser.tokens, {:strict => true})))
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
describe 'one_component_value' do
|
51
|
+
make_my_diffs_pretty!
|
52
|
+
parallelize_me!
|
53
|
+
|
54
|
+
tests = load_css_tests('one_component_value.json')
|
55
|
+
|
56
|
+
tests.each_slice(2) do |test|
|
57
|
+
css = test[0]
|
58
|
+
expected = test[1]
|
59
|
+
|
60
|
+
it "should parse: #{css.gsub("\n", "\\n")}" do
|
61
|
+
parser = Crass::Parser.new(css)
|
62
|
+
assert_equal(expected, translate_tokens(parser.parse_component_value)[0])
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
describe 'one_declaration' do
|
68
|
+
make_my_diffs_pretty!
|
69
|
+
parallelize_me!
|
70
|
+
|
71
|
+
tests = load_css_tests('one_declaration.json')
|
72
|
+
|
73
|
+
tests.each_slice(2) do |test|
|
74
|
+
css = test[0]
|
75
|
+
expected = test[1]
|
76
|
+
|
77
|
+
it "should parse: #{css.gsub("\n", "\\n")}" do
|
78
|
+
parser = Crass::Parser.new(css)
|
79
|
+
assert_equal(expected, translate_tokens(parser.parse_declaration)[0])
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
describe 'one_rule' do
|
85
|
+
make_my_diffs_pretty!
|
86
|
+
parallelize_me!
|
87
|
+
|
88
|
+
tests = load_css_tests('one_rule.json')
|
89
|
+
|
90
|
+
tests.each_slice(2) do |test|
|
91
|
+
css = test[0]
|
92
|
+
expected = test[1]
|
93
|
+
|
94
|
+
it "should parse: #{css.gsub("\n", "\\n")}" do
|
95
|
+
parser = Crass::Parser.new(css)
|
96
|
+
assert_equal(expected, translate_tokens(parser.parse_rule)[0])
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
describe 'rule_list' do
|
102
|
+
make_my_diffs_pretty!
|
103
|
+
parallelize_me!
|
104
|
+
|
105
|
+
tests = load_css_tests('rule_list.json')
|
106
|
+
|
107
|
+
tests.each_slice(2) do |test|
|
108
|
+
css = test[0]
|
109
|
+
expected = test[1]
|
110
|
+
|
111
|
+
it "should parse: #{css.gsub("\n", "\\n")}" do
|
112
|
+
parser = Crass::Parser.new(css)
|
113
|
+
rules = parser.consume_rules
|
114
|
+
|
115
|
+
# Remove non-standard whitespace tokens.
|
116
|
+
rules.reject! do |token|
|
117
|
+
node = token[:node]
|
118
|
+
node == :whitespace
|
119
|
+
end
|
120
|
+
|
121
|
+
assert_equal(expected, translate_tokens(rules))
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
describe 'stylesheet' do
|
127
|
+
make_my_diffs_pretty!
|
128
|
+
parallelize_me!
|
129
|
+
|
130
|
+
tests = load_css_tests('stylesheet.json')
|
131
|
+
|
132
|
+
tests.each_slice(2) do |test|
|
133
|
+
css = test[0]
|
134
|
+
expected = test[1]
|
135
|
+
|
136
|
+
it "should parse: #{css.gsub("\n", "\\n")}" do
|
137
|
+
parser = Crass::Parser.new(css)
|
138
|
+
rules = parser.consume_rules(:top_level => true)
|
139
|
+
|
140
|
+
# Remove non-standard whitespace tokens.
|
141
|
+
rules.reject! do |token|
|
142
|
+
node = token[:node]
|
143
|
+
node == :whitespace
|
144
|
+
end
|
145
|
+
|
146
|
+
assert_equal(expected, translate_tokens(rules))
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|
@@ -29,169 +29,42 @@ describe 'Crass::Parser' do
|
|
29
29
|
assert_tokens(";; /**/ ; ;", tree, 0, :preserve_comments => true)
|
30
30
|
end
|
31
31
|
|
32
|
-
it 'should parse a list of declarations' do
|
33
|
-
tree = parse("a:b; c:d 42!important;\n")
|
34
|
-
assert_equal(4, tree.size)
|
35
|
-
|
36
|
-
prop = tree[0]
|
37
|
-
assert_equal(:property, prop[:node])
|
38
|
-
assert_equal("a", prop[:name])
|
39
|
-
assert_equal("b", prop[:value])
|
40
|
-
assert_equal(false, prop[:important])
|
41
|
-
assert_tokens("a:b;", prop[:tokens])
|
42
|
-
|
43
|
-
assert_equal([
|
44
|
-
{:node=>:ident, :pos=>2, :raw=>"b", :value=>"b"}
|
45
|
-
], prop[:children])
|
46
|
-
|
47
|
-
assert_tokens(" ", tree[1], 4)
|
48
|
-
|
49
|
-
prop = tree[2]
|
50
|
-
assert_equal(:property, prop[:node])
|
51
|
-
assert_equal("c", prop[:name])
|
52
|
-
assert_equal("d 42", prop[:value])
|
53
|
-
assert_equal(true, prop[:important])
|
54
|
-
assert_tokens("c:d 42!important;", prop[:tokens], 5)
|
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
|
-
|
67
|
-
assert_tokens("\n", tree[3], 22)
|
68
|
-
end
|
69
|
-
|
70
32
|
it 'should parse at-rules even though they may be invalid in the given context' do
|
71
33
|
tree = parse("@import 'foo.css'; a:b; @import 'bar.css'")
|
72
|
-
assert_equal(5, tree.size)
|
73
|
-
|
74
|
-
rule = tree[0]
|
75
|
-
assert_equal(:at_rule, rule[:node])
|
76
|
-
assert_equal("import", rule[:name])
|
77
|
-
assert_tokens(" 'foo.css'", rule[:prelude], 7)
|
78
|
-
assert_tokens("@import 'foo.css';", rule[:tokens])
|
79
|
-
|
80
|
-
assert_tokens(" ", tree[1], 18)
|
81
|
-
|
82
|
-
prop = tree[2]
|
83
|
-
assert_equal(:property, prop[:node])
|
84
|
-
assert_equal("a", prop[:name])
|
85
|
-
assert_equal("b", prop[:value])
|
86
|
-
assert_equal(false, prop[:important])
|
87
|
-
assert_tokens("a:b;", prop[:tokens], 19)
|
88
34
|
|
89
35
|
assert_equal([
|
90
|
-
{:node=>:
|
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
|
-
block = value[2]
|
123
|
-
assert_equal(:simple_block, block[:node])
|
124
|
-
assert_equal("{", block[:start])
|
125
|
-
assert_equal("}", block[:end])
|
126
|
-
assert_tokens(";", block[:value], 20)
|
127
|
-
assert_tokens("{;}", block[:tokens], 19)
|
128
|
-
|
129
|
-
assert_tokens(" ", tree[1], 23)
|
130
|
-
|
131
|
-
prop = tree[2]
|
132
|
-
assert_equal(:property, prop[:node])
|
133
|
-
assert_equal("a", prop[:name])
|
134
|
-
assert_equal("b", prop[:value])
|
135
|
-
assert_equal(false, prop[:important])
|
136
|
-
assert_tokens("a:b;", prop[:tokens], 24)
|
137
|
-
assert_equal([
|
138
|
-
{:node=>:ident, :pos=>26, :raw=>"b", :value=>"b"}
|
139
|
-
], prop[:children])
|
140
|
-
|
141
|
-
assert_tokens("; ", tree[3..4], 28)
|
142
|
-
|
143
|
-
rule = tree[5]
|
144
|
-
assert_equal(:at_rule, rule[:node])
|
145
|
-
assert_equal("media", rule[:name])
|
146
|
-
assert_tokens(" print", rule[:prelude], 36)
|
147
|
-
assert_tokens("@media print{div{", rule[:tokens], 30)
|
148
|
-
|
149
|
-
block = rule[:block]
|
150
|
-
assert_equal(:simple_block, block[:node])
|
151
|
-
assert_equal("{", block[:start])
|
152
|
-
assert_equal("}", block[:end])
|
153
|
-
assert_tokens("{div{", block[:tokens], 42)
|
154
|
-
|
155
|
-
value = block[:value]
|
156
|
-
assert_equal(2, value.size)
|
157
|
-
assert_tokens("div", value[0], 43)
|
158
|
-
|
159
|
-
block = value[1]
|
160
|
-
assert_equal(:simple_block, block[:node])
|
161
|
-
assert_equal("{", block[:start])
|
162
|
-
assert_equal("}", block[:end])
|
163
|
-
assert_equal([], block[:value])
|
164
|
-
assert_tokens("{", block[:tokens], 46)
|
165
|
-
end
|
166
|
-
|
167
|
-
it 'should discard invalid nodes' do
|
168
|
-
tree = parse("@ media screen { div{;}} a:b;; @media print{div{")
|
169
|
-
assert_equal(3, tree.size)
|
170
|
-
|
171
|
-
assert_tokens("; ", tree[0..1], 29)
|
172
|
-
|
173
|
-
rule = tree[2]
|
174
|
-
assert_equal(:at_rule, rule[:node])
|
175
|
-
assert_equal("media", rule[:name])
|
176
|
-
assert_tokens(" print", rule[:prelude], 37)
|
177
|
-
assert_tokens("@media print{div{", rule[:tokens], 31)
|
178
|
-
|
179
|
-
block = rule[:block]
|
180
|
-
assert_equal(:simple_block, block[:node])
|
181
|
-
assert_equal("{", block[:start])
|
182
|
-
assert_equal("}", block[:end])
|
183
|
-
assert_tokens("{div{", block[:tokens], 43)
|
184
|
-
|
185
|
-
value = block[:value]
|
186
|
-
assert_equal(2, value.size)
|
187
|
-
assert_tokens("div", value[0], 44)
|
188
|
-
|
189
|
-
block = value[1]
|
190
|
-
assert_equal(:simple_block, block[:node])
|
191
|
-
assert_equal("{", block[:start])
|
192
|
-
assert_equal("}", block[:end])
|
193
|
-
assert_equal([], block[:value])
|
194
|
-
assert_tokens("{", block[:tokens], 47)
|
36
|
+
{:node=>:at_rule,
|
37
|
+
:name=>"import",
|
38
|
+
:prelude=>
|
39
|
+
[{:node=>:whitespace, :pos=>7, :raw=>" "},
|
40
|
+
{:node=>:string, :pos=>8, :raw=>"'foo.css'", :value=>"foo.css"}],
|
41
|
+
:tokens=>
|
42
|
+
[{:node=>:at_keyword, :pos=>0, :raw=>"@import", :value=>"import"},
|
43
|
+
{:node=>:whitespace, :pos=>7, :raw=>" "},
|
44
|
+
{:node=>:string, :pos=>8, :raw=>"'foo.css'", :value=>"foo.css"},
|
45
|
+
{:node=>:semicolon, :pos=>17, :raw=>";"}]},
|
46
|
+
{:node=>:whitespace, :pos=>18, :raw=>" "},
|
47
|
+
{:node=>:property,
|
48
|
+
:name=>"a",
|
49
|
+
:value=>"b",
|
50
|
+
:children=>[{:node=>:ident, :pos=>21, :raw=>"b", :value=>"b"}],
|
51
|
+
:important=>false,
|
52
|
+
:tokens=>
|
53
|
+
[{:node=>:ident, :pos=>19, :raw=>"a", :value=>"a"},
|
54
|
+
{:node=>:colon, :pos=>20, :raw=>":"},
|
55
|
+
{:node=>:ident, :pos=>21, :raw=>"b", :value=>"b"}]},
|
56
|
+
{:node=>:semicolon, :pos=>22, :raw=>";"},
|
57
|
+
{:node=>:whitespace, :pos=>23, :raw=>" "},
|
58
|
+
{:node=>:at_rule,
|
59
|
+
:name=>"import",
|
60
|
+
:prelude=>
|
61
|
+
[{:node=>:whitespace, :pos=>31, :raw=>" "},
|
62
|
+
{:node=>:string, :pos=>32, :raw=>"'bar.css'", :value=>"bar.css"}],
|
63
|
+
:tokens=>
|
64
|
+
[{:node=>:at_keyword, :pos=>24, :raw=>"@import", :value=>"import"},
|
65
|
+
{:node=>:whitespace, :pos=>31, :raw=>" "},
|
66
|
+
{:node=>:string, :pos=>32, :raw=>"'bar.css'", :value=>"bar.css"}]}
|
67
|
+
], tree)
|
195
68
|
end
|
196
69
|
|
197
70
|
it 'should parse values containing functions' do
|
@@ -199,27 +72,35 @@ describe 'Crass::Parser' do
|
|
199
72
|
|
200
73
|
assert_equal([
|
201
74
|
{:node=>:property,
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
{:node=>:ident, :pos=>
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
75
|
+
:name=>"content",
|
76
|
+
:value=>"attr(data-foo) \" \"",
|
77
|
+
:children=>
|
78
|
+
[{:node=>:whitespace, :pos=>8, :raw=>" "},
|
79
|
+
{:node=>:function,
|
80
|
+
:name=>"attr",
|
81
|
+
:value=>[{:node=>:ident, :pos=>14, :raw=>"data-foo", :value=>"data-foo"}],
|
82
|
+
:tokens=>
|
83
|
+
[{:node=>:function, :pos=>9, :raw=>"attr(", :value=>"attr"},
|
84
|
+
{:node=>:ident, :pos=>14, :raw=>"data-foo", :value=>"data-foo"},
|
85
|
+
{:node=>:")", :pos=>22, :raw=>")"}]},
|
86
|
+
{:node=>:whitespace, :pos=>23, :raw=>" "},
|
87
|
+
{:node=>:string, :pos=>24, :raw=>"\" \"", :value=>" "}],
|
88
|
+
:important=>false,
|
89
|
+
:tokens=>
|
90
|
+
[{:node=>:ident, :pos=>0, :raw=>"content", :value=>"content"},
|
91
|
+
{:node=>:colon, :pos=>7, :raw=>":"},
|
92
|
+
{:node=>:whitespace, :pos=>8, :raw=>" "},
|
93
|
+
{:node=>:function,
|
94
|
+
:name=>"attr",
|
95
|
+
:value=>[{:node=>:ident, :pos=>14, :raw=>"data-foo", :value=>"data-foo"}],
|
96
|
+
:tokens=>
|
97
|
+
[{:node=>:function, :pos=>9, :raw=>"attr(", :value=>"attr"},
|
98
|
+
{:node=>:ident, :pos=>14, :raw=>"data-foo", :value=>"data-foo"},
|
99
|
+
{:node=>:")", :pos=>22, :raw=>")"}]},
|
100
|
+
{:node=>:whitespace, :pos=>23, :raw=>" "},
|
101
|
+
{:node=>:string, :pos=>24, :raw=>"\" \"", :value=>" "}]},
|
102
|
+
{:node=>:semicolon, :pos=>27, :raw=>";"}
|
103
|
+
], tree)
|
223
104
|
end
|
224
105
|
|
225
106
|
it 'should parse values containing nested functions' do
|
@@ -227,37 +108,81 @@ describe 'Crass::Parser' do
|
|
227
108
|
|
228
109
|
assert_equal([
|
229
110
|
{:node=>:property,
|
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
|
-
|
111
|
+
:name=>"width",
|
112
|
+
:value=>"expression(alert(1))",
|
113
|
+
:children=>
|
114
|
+
[{:node=>:whitespace, :pos=>6, :raw=>" "},
|
115
|
+
{:node=>:function,
|
116
|
+
:name=>"expression",
|
117
|
+
:value=>
|
118
|
+
[{:node=>:function,
|
119
|
+
:name=>"alert",
|
120
|
+
:value=>
|
121
|
+
[{:node=>:number,
|
122
|
+
:pos=>24,
|
123
|
+
:raw=>"1",
|
124
|
+
:repr=>"1",
|
125
|
+
:type=>:integer,
|
126
|
+
:value=>1}],
|
127
|
+
:tokens=>
|
128
|
+
[{:node=>:function, :pos=>18, :raw=>"alert(", :value=>"alert"},
|
129
|
+
{:node=>:number,
|
130
|
+
:pos=>24,
|
131
|
+
:raw=>"1",
|
132
|
+
:repr=>"1",
|
133
|
+
:type=>:integer,
|
134
|
+
:value=>1},
|
135
|
+
{:node=>:")", :pos=>25, :raw=>")"}]}],
|
136
|
+
:tokens=>
|
137
|
+
[{:node=>:function, :pos=>7, :raw=>"expression(", :value=>"expression"},
|
138
|
+
{:node=>:function, :pos=>18, :raw=>"alert(", :value=>"alert"},
|
139
|
+
{:node=>:number,
|
140
|
+
:pos=>24,
|
141
|
+
:raw=>"1",
|
142
|
+
:repr=>"1",
|
143
|
+
:type=>:integer,
|
144
|
+
:value=>1},
|
145
|
+
{:node=>:")", :pos=>25, :raw=>")"},
|
146
|
+
{:node=>:")", :pos=>26, :raw=>")"}]}],
|
147
|
+
:important=>false,
|
148
|
+
:tokens=>
|
149
|
+
[{:node=>:ident, :pos=>0, :raw=>"width", :value=>"width"},
|
150
|
+
{:node=>:colon, :pos=>5, :raw=>":"},
|
151
|
+
{:node=>:whitespace, :pos=>6, :raw=>" "},
|
152
|
+
{:node=>:function,
|
153
|
+
:name=>"expression",
|
154
|
+
:value=>
|
155
|
+
[{:node=>:function,
|
156
|
+
:name=>"alert",
|
157
|
+
:value=>
|
158
|
+
[{:node=>:number,
|
159
|
+
:pos=>24,
|
160
|
+
:raw=>"1",
|
161
|
+
:repr=>"1",
|
162
|
+
:type=>:integer,
|
163
|
+
:value=>1}],
|
164
|
+
:tokens=>
|
165
|
+
[{:node=>:function, :pos=>18, :raw=>"alert(", :value=>"alert"},
|
166
|
+
{:node=>:number,
|
167
|
+
:pos=>24,
|
168
|
+
:raw=>"1",
|
169
|
+
:repr=>"1",
|
170
|
+
:type=>:integer,
|
171
|
+
:value=>1},
|
172
|
+
{:node=>:")", :pos=>25, :raw=>")"}]}],
|
173
|
+
:tokens=>
|
174
|
+
[{:node=>:function, :pos=>7, :raw=>"expression(", :value=>"expression"},
|
175
|
+
{:node=>:function, :pos=>18, :raw=>"alert(", :value=>"alert"},
|
176
|
+
{:node=>:number,
|
177
|
+
:pos=>24,
|
178
|
+
:raw=>"1",
|
179
|
+
:repr=>"1",
|
180
|
+
:type=>:integer,
|
181
|
+
:value=>1},
|
182
|
+
{:node=>:")", :pos=>25, :raw=>")"},
|
183
|
+
{:node=>:")", :pos=>26, :raw=>")"}]}]},
|
184
|
+
{:node=>:semicolon, :pos=>27, :raw=>";"}
|
185
|
+
], tree)
|
261
186
|
end
|
262
187
|
|
263
188
|
it 'should not choke on a missing property value' do
|