sass 3.2.0.alpha.96 → 3.2.0.alpha.99
Sign up to get free protection for your applications and to get access to all the features.
- data/REVISION +1 -1
- data/VERSION +1 -1
- data/lib/sass/engine.rb +2 -0
- data/lib/sass/scss/parser.rb +29 -16
- data/lib/sass/selector.rb +47 -0
- data/lib/sass/selector/abstract_sequence.rb +16 -0
- data/lib/sass/selector/comma_sequence.rb +9 -1
- data/lib/sass/selector/sequence.rb +24 -2
- data/lib/sass/selector/simple_sequence.rb +36 -5
- data/lib/sass/supports.rb +229 -0
- data/lib/sass/tree/media_node.rb +3 -0
- data/lib/sass/tree/node.rb +7 -0
- data/lib/sass/tree/supports_node.rb +51 -0
- data/lib/sass/tree/visitors/convert.rb +4 -0
- data/lib/sass/tree/visitors/cssize.rb +22 -13
- data/lib/sass/tree/visitors/deep_copy.rb +5 -0
- data/lib/sass/tree/visitors/perform.rb +6 -0
- data/lib/sass/tree/visitors/set_options.rb +5 -0
- data/lib/sass/tree/visitors/to_css.rb +4 -0
- data/test/sass/conversion_test.rb +22 -0
- data/test/sass/extend_test.rb +114 -569
- data/test/sass/scss/css_test.rb +9 -0
- data/test/sass/scss/scss_test.rb +35 -0
- metadata +6 -4
data/lib/sass/tree/media_node.rb
CHANGED
data/lib/sass/tree/node.rb
CHANGED
@@ -188,6 +188,13 @@ module Sass
|
|
188
188
|
Sass::Tree::Visitors::DeepCopy.visit(self)
|
189
189
|
end
|
190
190
|
|
191
|
+
# Whether or not this node bubbles up through RuleNodes.
|
192
|
+
#
|
193
|
+
# @return [Boolean]
|
194
|
+
def bubbles?
|
195
|
+
false
|
196
|
+
end
|
197
|
+
|
191
198
|
protected
|
192
199
|
|
193
200
|
# @see Sass::Shared.balance
|
@@ -0,0 +1,51 @@
|
|
1
|
+
module Sass::Tree
|
2
|
+
# A static node representing a `@supports` rule.
|
3
|
+
# `@supports` rules behave differently from other directives
|
4
|
+
# in that when they're nested within rules,
|
5
|
+
# they bubble up to top-level.
|
6
|
+
#
|
7
|
+
# @see Sass::Tree
|
8
|
+
class SupportsNode < DirectiveNode
|
9
|
+
# The name, which may include a browser prefix.
|
10
|
+
#
|
11
|
+
# @return [String]
|
12
|
+
attr_accessor :name
|
13
|
+
|
14
|
+
# The supports condition.
|
15
|
+
#
|
16
|
+
# @return [Sass::Supports::Condition]
|
17
|
+
attr_accessor :condition
|
18
|
+
|
19
|
+
# @see RuleNode#tabs
|
20
|
+
attr_accessor :tabs
|
21
|
+
|
22
|
+
# @see RuleNode#group_end
|
23
|
+
attr_accessor :group_end
|
24
|
+
|
25
|
+
# @param condition [Sass::Supports::Condition] See \{#condition}
|
26
|
+
def initialize(name, condition)
|
27
|
+
@name = name
|
28
|
+
@condition = condition
|
29
|
+
@tabs = 0
|
30
|
+
super('')
|
31
|
+
end
|
32
|
+
|
33
|
+
# @see DirectiveNode#value
|
34
|
+
def value; raise NotImplementedError; end
|
35
|
+
|
36
|
+
# @see DirectiveNode#resolved_value
|
37
|
+
def resolved_value
|
38
|
+
@resolved_value ||= "@#{name} #{condition.to_css}"
|
39
|
+
end
|
40
|
+
|
41
|
+
# True when the directive has no visible children.
|
42
|
+
#
|
43
|
+
# @return [Boolean]
|
44
|
+
def invisible?
|
45
|
+
children.all? {|c| c.invisible?}
|
46
|
+
end
|
47
|
+
|
48
|
+
# @see Node#bubbles?
|
49
|
+
def bubbles?; true; end
|
50
|
+
end
|
51
|
+
end
|
@@ -150,6 +150,10 @@ class Sass::Tree::Visitors::Convert < Sass::Tree::Visitors::Base
|
|
150
150
|
"#{tab_str}@media #{node.query.to_src(@options)}#{yield}"
|
151
151
|
end
|
152
152
|
|
153
|
+
def visit_supports(node)
|
154
|
+
"#{tab_str}@#{node.name} #{node.condition.to_src(@options)}#{yield}"
|
155
|
+
end
|
156
|
+
|
153
157
|
def visit_cssimport(node)
|
154
158
|
if node.uri.is_a?(Sass::Script::Node)
|
155
159
|
str = "#{tab_str}@import #{node.uri.to_sass(@options)}"
|
@@ -121,23 +121,19 @@ class Sass::Tree::Visitors::Cssize < Sass::Tree::Visitors::Base
|
|
121
121
|
# Bubbles the `@media` directive up through RuleNodes
|
122
122
|
# and merges it with other `@media` directives.
|
123
123
|
def visit_media(node)
|
124
|
-
|
125
|
-
new_rule = parent.dup
|
126
|
-
new_rule.children = node.children
|
127
|
-
node.children = with_parent(node) {Array(visit(new_rule))}
|
128
|
-
# If the last child is actually the end of the group,
|
129
|
-
# the parent's cssize will set it properly
|
130
|
-
node.children.last.group_end = false unless node.children.empty?
|
131
|
-
else
|
132
|
-
yield
|
133
|
-
end
|
134
|
-
|
124
|
+
yield unless bubble(node)
|
135
125
|
media = node.children.select {|c| c.is_a?(Sass::Tree::MediaNode)}
|
136
126
|
node.children.reject! {|c| c.is_a?(Sass::Tree::MediaNode)}
|
137
127
|
media = media.select {|n| n.query = n.query.merge(node.query)}
|
138
128
|
(node.children.empty? ? [] : [node]) + media
|
139
129
|
end
|
140
130
|
|
131
|
+
# Bubbles the `@supports` directive up through RuleNodes.
|
132
|
+
def visit_supports(node)
|
133
|
+
yield unless bubble(node)
|
134
|
+
node
|
135
|
+
end
|
136
|
+
|
141
137
|
# Asserts that all the traced children are valid in their new location.
|
142
138
|
def visit_trace(node)
|
143
139
|
# Don't use #visit_children to avoid adding the trace node to the list of parents.
|
@@ -176,8 +172,8 @@ class Sass::Tree::Visitors::Cssize < Sass::Tree::Visitors::Base
|
|
176
172
|
|
177
173
|
yield
|
178
174
|
|
179
|
-
rules = node.children.select {|c| c.is_a?(Sass::Tree::RuleNode) || c.
|
180
|
-
props = node.children.reject {|c| c.is_a?(Sass::Tree::RuleNode) || c.
|
175
|
+
rules = node.children.select {|c| c.is_a?(Sass::Tree::RuleNode) || c.bubbles?}
|
176
|
+
props = node.children.reject {|c| c.is_a?(Sass::Tree::RuleNode) || c.bubbles? || c.invisible?}
|
181
177
|
|
182
178
|
unless props.empty?
|
183
179
|
node.children = props
|
@@ -189,4 +185,17 @@ class Sass::Tree::Visitors::Cssize < Sass::Tree::Visitors::Base
|
|
189
185
|
|
190
186
|
rules
|
191
187
|
end
|
188
|
+
|
189
|
+
private
|
190
|
+
|
191
|
+
def bubble(node)
|
192
|
+
return unless parent.is_a?(Sass::Tree::RuleNode)
|
193
|
+
new_rule = parent.dup
|
194
|
+
new_rule.children = node.children
|
195
|
+
node.children = with_parent(node) {Array(visit(new_rule))}
|
196
|
+
# If the last child is actually the end of the group,
|
197
|
+
# the parent's cssize will set it properly
|
198
|
+
node.children.last.group_end = false unless node.children.empty?
|
199
|
+
true
|
200
|
+
end
|
192
201
|
end
|
@@ -302,6 +302,12 @@ END
|
|
302
302
|
yield
|
303
303
|
end
|
304
304
|
|
305
|
+
def visit_supports(node)
|
306
|
+
node.condition = node.condition.deep_copy
|
307
|
+
node.condition.perform(@environment)
|
308
|
+
yield
|
309
|
+
end
|
310
|
+
|
305
311
|
def visit_cssimport(node)
|
306
312
|
node.resolved_uri = run_interp([node.uri])
|
307
313
|
if node.query
|
@@ -1184,6 +1184,28 @@ $val: 20;
|
|
1184
1184
|
SCSS
|
1185
1185
|
end
|
1186
1186
|
|
1187
|
+
def test_supports_with_expressions
|
1188
|
+
assert_renders <<SASS, <<SCSS
|
1189
|
+
$query: "(feature1: val)"
|
1190
|
+
$feature: feature2
|
1191
|
+
$val: val
|
1192
|
+
|
1193
|
+
@supports \#{$query} and ($feature: $val) or (not ($feature + 3: $val + 4))
|
1194
|
+
foo
|
1195
|
+
a: b
|
1196
|
+
SASS
|
1197
|
+
$query: "(feature1: val)";
|
1198
|
+
$feature: feature2;
|
1199
|
+
$val: val;
|
1200
|
+
|
1201
|
+
@supports \#{$query} and ($feature: $val) or (not ($feature + 3: $val + 4)) {
|
1202
|
+
foo {
|
1203
|
+
a: b;
|
1204
|
+
}
|
1205
|
+
}
|
1206
|
+
SCSS
|
1207
|
+
end
|
1208
|
+
|
1187
1209
|
# Hacks
|
1188
1210
|
|
1189
1211
|
def test_declaration_hacks
|
data/test/sass/extend_test.rb
CHANGED
@@ -181,591 +181,115 @@ SCSS
|
|
181
181
|
end
|
182
182
|
|
183
183
|
def test_class_unification
|
184
|
-
|
185
|
-
.foo.
|
186
|
-
a: b; }
|
187
|
-
CSS
|
188
|
-
.foo.bar {a: b}
|
189
|
-
.baz {@extend .foo}
|
190
|
-
SCSS
|
191
|
-
|
192
|
-
assert_equal <<CSS, render(<<SCSS)
|
193
|
-
.baz {
|
194
|
-
a: b; }
|
195
|
-
CSS
|
196
|
-
.foo.baz {a: b}
|
197
|
-
.baz {@extend .foo}
|
198
|
-
SCSS
|
184
|
+
assert_unification '.foo.bar', '.baz {@extend .foo}', '.foo.bar, .bar.baz'
|
185
|
+
assert_unification '.foo.baz', '.baz {@extend .foo}', '.baz'
|
199
186
|
end
|
200
187
|
|
201
188
|
def test_id_unification
|
202
|
-
|
203
|
-
.foo
|
204
|
-
|
205
|
-
CSS
|
206
|
-
.foo.bar {a: b}
|
207
|
-
#baz {@extend .foo}
|
208
|
-
SCSS
|
209
|
-
|
210
|
-
assert_equal <<CSS, render(<<SCSS)
|
211
|
-
#baz {
|
212
|
-
a: b; }
|
213
|
-
CSS
|
214
|
-
.foo#baz {a: b}
|
215
|
-
#baz {@extend .foo}
|
216
|
-
SCSS
|
217
|
-
|
218
|
-
assert_equal <<CSS, render(<<SCSS)
|
219
|
-
.foo#baz {
|
220
|
-
a: b; }
|
221
|
-
CSS
|
222
|
-
.foo#baz {a: b}
|
223
|
-
#bar {@extend .foo}
|
224
|
-
SCSS
|
189
|
+
assert_unification '.foo.bar', '#baz {@extend .foo}', '.foo.bar, .bar#baz'
|
190
|
+
assert_unification '.foo#baz', '#baz {@extend .foo}', '#baz'
|
191
|
+
assert_unification '.foo#baz', '#bar {@extend .foo}', '.foo#baz'
|
225
192
|
end
|
226
193
|
|
227
194
|
def test_universal_unification_with_simple_target
|
228
|
-
|
229
|
-
.foo,
|
230
|
-
|
231
|
-
|
232
|
-
.foo {
|
233
|
-
* {@extend .foo}
|
234
|
-
SCSS
|
235
|
-
|
236
|
-
assert_equal <<CSS, render(<<SCSS)
|
237
|
-
.foo, *|* {
|
238
|
-
a: b; }
|
239
|
-
CSS
|
240
|
-
.foo {a: b}
|
241
|
-
*|* {@extend .foo}
|
242
|
-
SCSS
|
243
|
-
|
244
|
-
assert_equal <<CSS, render(<<SCSS)
|
245
|
-
.bar {
|
246
|
-
a: b; }
|
247
|
-
CSS
|
248
|
-
.foo.bar {a: b}
|
249
|
-
* {@extend .foo}
|
250
|
-
SCSS
|
251
|
-
|
252
|
-
assert_equal <<CSS, render(<<SCSS)
|
253
|
-
.bar {
|
254
|
-
a: b; }
|
255
|
-
CSS
|
256
|
-
.foo.bar {a: b}
|
257
|
-
*|* {@extend .foo}
|
258
|
-
SCSS
|
259
|
-
|
260
|
-
assert_equal <<CSS, render(<<SCSS)
|
261
|
-
.foo.bar, ns|*.bar {
|
262
|
-
a: b; }
|
263
|
-
CSS
|
264
|
-
.foo.bar {a: b}
|
265
|
-
ns|* {@extend .foo}
|
266
|
-
SCSS
|
195
|
+
assert_unification '.foo', '* {@extend .foo}', '.foo, *'
|
196
|
+
assert_unification '.foo', '*|* {@extend .foo}', '.foo, *|*'
|
197
|
+
assert_unification '.foo.bar', '* {@extend .foo}', '.bar'
|
198
|
+
assert_unification '.foo.bar', '*|* {@extend .foo}', '.bar'
|
199
|
+
assert_unification '.foo.bar', 'ns|* {@extend .foo}', '.foo.bar, ns|*.bar'
|
267
200
|
end
|
268
201
|
|
269
202
|
def test_universal_unification_with_namespaceless_universal_target
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
*.foo {
|
275
|
-
|
276
|
-
SCSS
|
277
|
-
|
278
|
-
assert_equal <<CSS, render(<<SCSS)
|
279
|
-
* {
|
280
|
-
a: b; }
|
281
|
-
CSS
|
282
|
-
*.foo {a: b}
|
283
|
-
*|* {@extend .foo}
|
284
|
-
SCSS
|
285
|
-
|
286
|
-
assert_equal <<CSS, render(<<SCSS)
|
287
|
-
*|*.foo, * {
|
288
|
-
a: b; }
|
289
|
-
CSS
|
290
|
-
*|*.foo {a: b}
|
291
|
-
* {@extend .foo}
|
292
|
-
SCSS
|
293
|
-
|
294
|
-
assert_equal <<CSS, render(<<SCSS)
|
295
|
-
*|* {
|
296
|
-
a: b; }
|
297
|
-
CSS
|
298
|
-
*|*.foo {a: b}
|
299
|
-
*|* {@extend .foo}
|
300
|
-
SCSS
|
301
|
-
|
302
|
-
assert_equal <<CSS, render(<<SCSS)
|
303
|
-
*.foo, ns|* {
|
304
|
-
a: b; }
|
305
|
-
CSS
|
306
|
-
*.foo {a: b}
|
307
|
-
ns|* {@extend .foo}
|
308
|
-
SCSS
|
309
|
-
|
310
|
-
assert_equal <<CSS, render(<<SCSS)
|
311
|
-
*|*.foo, ns|* {
|
312
|
-
a: b; }
|
313
|
-
CSS
|
314
|
-
*|*.foo {a: b}
|
315
|
-
ns|* {@extend .foo}
|
316
|
-
SCSS
|
203
|
+
assert_unification '*.foo', '* {@extend .foo}', '*'
|
204
|
+
assert_unification '*.foo', '*|* {@extend .foo}', '*'
|
205
|
+
assert_unification '*|*.foo', '* {@extend .foo}', '*|*.foo, *'
|
206
|
+
assert_unification '*|*.foo', '*|* {@extend .foo}', '*|*'
|
207
|
+
assert_unification '*.foo', 'ns|* {@extend .foo}', '*.foo, ns|*'
|
208
|
+
assert_unification '*|*.foo', 'ns|* {@extend .foo}', '*|*.foo, ns|*'
|
317
209
|
end
|
318
210
|
|
319
211
|
def test_universal_unification_with_namespaced_universal_target
|
320
|
-
|
321
|
-
ns
|
322
|
-
|
323
|
-
|
324
|
-
ns|*.foo {a: b}
|
325
|
-
* {@extend .foo}
|
326
|
-
SCSS
|
327
|
-
|
328
|
-
assert_equal <<CSS, render(<<SCSS)
|
329
|
-
ns|* {
|
330
|
-
a: b; }
|
331
|
-
CSS
|
332
|
-
ns|*.foo {a: b}
|
333
|
-
*|* {@extend .foo}
|
334
|
-
SCSS
|
335
|
-
|
336
|
-
assert_equal <<CSS, render(<<SCSS)
|
337
|
-
ns1|*.foo {
|
338
|
-
a: b; }
|
339
|
-
CSS
|
340
|
-
ns1|*.foo {a: b}
|
341
|
-
ns2|* {@extend .foo}
|
342
|
-
SCSS
|
343
|
-
|
344
|
-
assert_equal <<CSS, render(<<SCSS)
|
345
|
-
ns|* {
|
346
|
-
a: b; }
|
347
|
-
CSS
|
348
|
-
ns|*.foo {a: b}
|
349
|
-
ns|* {@extend .foo}
|
350
|
-
SCSS
|
212
|
+
assert_unification 'ns|*.foo', '* {@extend .foo}', 'ns|*'
|
213
|
+
assert_unification 'ns|*.foo', '*|* {@extend .foo}', 'ns|*'
|
214
|
+
assert_unification 'ns1|*.foo', 'ns2|* {@extend .foo}', 'ns1|*.foo'
|
215
|
+
assert_unification 'ns|*.foo', 'ns|* {@extend .foo}', 'ns|*'
|
351
216
|
end
|
352
217
|
|
353
218
|
def test_universal_unification_with_namespaceless_element_target
|
354
|
-
|
355
|
-
a {
|
356
|
-
|
357
|
-
|
358
|
-
a.foo {a
|
359
|
-
|
360
|
-
SCSS
|
361
|
-
|
362
|
-
assert_equal <<CSS, render(<<SCSS)
|
363
|
-
a {
|
364
|
-
a: b; }
|
365
|
-
CSS
|
366
|
-
a.foo {a: b}
|
367
|
-
*|* {@extend .foo}
|
368
|
-
SCSS
|
369
|
-
|
370
|
-
assert_equal <<CSS, render(<<SCSS)
|
371
|
-
*|a.foo, a {
|
372
|
-
a: b; }
|
373
|
-
CSS
|
374
|
-
*|a.foo {a: b}
|
375
|
-
* {@extend .foo}
|
376
|
-
SCSS
|
377
|
-
|
378
|
-
assert_equal <<CSS, render(<<SCSS)
|
379
|
-
*|a {
|
380
|
-
a: b; }
|
381
|
-
CSS
|
382
|
-
*|a.foo {a: b}
|
383
|
-
*|* {@extend .foo}
|
384
|
-
SCSS
|
385
|
-
|
386
|
-
assert_equal <<CSS, render(<<SCSS)
|
387
|
-
a.foo, ns|a {
|
388
|
-
a: b; }
|
389
|
-
CSS
|
390
|
-
a.foo {a: b}
|
391
|
-
ns|* {@extend .foo}
|
392
|
-
SCSS
|
393
|
-
|
394
|
-
assert_equal <<CSS, render(<<SCSS)
|
395
|
-
*|a.foo, ns|a {
|
396
|
-
a: b; }
|
397
|
-
CSS
|
398
|
-
*|a.foo {a: b}
|
399
|
-
ns|* {@extend .foo}
|
400
|
-
SCSS
|
219
|
+
assert_unification 'a.foo', '* {@extend .foo}', 'a'
|
220
|
+
assert_unification 'a.foo', '*|* {@extend .foo}', 'a'
|
221
|
+
assert_unification '*|a.foo', '* {@extend .foo}', '*|a.foo, a'
|
222
|
+
assert_unification '*|a.foo', '*|* {@extend .foo}', '*|a'
|
223
|
+
assert_unification 'a.foo', 'ns|* {@extend .foo}', 'a.foo, ns|a'
|
224
|
+
assert_unification '*|a.foo', 'ns|* {@extend .foo}', '*|a.foo, ns|a'
|
401
225
|
end
|
402
226
|
|
403
227
|
def test_universal_unification_with_namespaced_element_target
|
404
|
-
|
405
|
-
ns|a {
|
406
|
-
|
407
|
-
|
408
|
-
ns|a.foo {a: b}
|
409
|
-
* {@extend .foo}
|
410
|
-
SCSS
|
411
|
-
|
412
|
-
assert_equal <<CSS, render(<<SCSS)
|
413
|
-
ns|a {
|
414
|
-
a: b; }
|
415
|
-
CSS
|
416
|
-
ns|a.foo {a: b}
|
417
|
-
*|* {@extend .foo}
|
418
|
-
SCSS
|
419
|
-
|
420
|
-
assert_equal <<CSS, render(<<SCSS)
|
421
|
-
ns1|a.foo {
|
422
|
-
a: b; }
|
423
|
-
CSS
|
424
|
-
ns1|a.foo {a: b}
|
425
|
-
ns2|* {@extend .foo}
|
426
|
-
SCSS
|
427
|
-
|
428
|
-
assert_equal <<CSS, render(<<SCSS)
|
429
|
-
ns|a {
|
430
|
-
a: b; }
|
431
|
-
CSS
|
432
|
-
ns|a.foo {a: b}
|
433
|
-
ns|* {@extend .foo}
|
434
|
-
SCSS
|
228
|
+
assert_unification 'ns|a.foo', '* {@extend .foo}', 'ns|a'
|
229
|
+
assert_unification 'ns|a.foo', '*|* {@extend .foo}', 'ns|a'
|
230
|
+
assert_unification 'ns1|a.foo', 'ns2|* {@extend .foo}', 'ns1|a.foo'
|
231
|
+
assert_unification 'ns|a.foo', 'ns|* {@extend .foo}', 'ns|a'
|
435
232
|
end
|
436
233
|
|
437
234
|
def test_element_unification_with_simple_target
|
438
|
-
|
439
|
-
.foo, a {
|
440
|
-
|
441
|
-
|
442
|
-
.foo {a: b}
|
443
|
-
a {@extend .foo}
|
444
|
-
SCSS
|
445
|
-
|
446
|
-
assert_equal <<CSS, render(<<SCSS)
|
447
|
-
.foo.bar, a.bar {
|
448
|
-
a: b; }
|
449
|
-
CSS
|
450
|
-
.foo.bar {a: b}
|
451
|
-
a {@extend .foo}
|
452
|
-
SCSS
|
453
|
-
|
454
|
-
assert_equal <<CSS, render(<<SCSS)
|
455
|
-
.foo.bar, *|a.bar {
|
456
|
-
a: b; }
|
457
|
-
CSS
|
458
|
-
.foo.bar {a: b}
|
459
|
-
*|a {@extend .foo}
|
460
|
-
SCSS
|
461
|
-
|
462
|
-
assert_equal <<CSS, render(<<SCSS)
|
463
|
-
.foo.bar, ns|a.bar {
|
464
|
-
a: b; }
|
465
|
-
CSS
|
466
|
-
.foo.bar {a: b}
|
467
|
-
ns|a {@extend .foo}
|
468
|
-
SCSS
|
235
|
+
assert_unification '.foo', 'a {@extend .foo}', '.foo, a'
|
236
|
+
assert_unification '.foo.bar', 'a {@extend .foo}', '.foo.bar, a.bar'
|
237
|
+
assert_unification '.foo.bar', '*|a {@extend .foo}', '.foo.bar, *|a.bar'
|
238
|
+
assert_unification '.foo.bar', 'ns|a {@extend .foo}', '.foo.bar, ns|a.bar'
|
469
239
|
end
|
470
240
|
|
471
241
|
def test_element_unification_with_namespaceless_universal_target
|
472
|
-
|
473
|
-
*.foo, a {
|
474
|
-
|
475
|
-
|
476
|
-
*.foo
|
477
|
-
a {@extend .foo}
|
478
|
-
SCSS
|
479
|
-
|
480
|
-
assert_equal <<CSS, render(<<SCSS)
|
481
|
-
*.foo, a {
|
482
|
-
a: b; }
|
483
|
-
CSS
|
484
|
-
*.foo {a: b}
|
485
|
-
*|a {@extend .foo}
|
486
|
-
SCSS
|
487
|
-
|
488
|
-
assert_equal <<CSS, render(<<SCSS)
|
489
|
-
*|*.foo, a {
|
490
|
-
a: b; }
|
491
|
-
CSS
|
492
|
-
*|*.foo {a: b}
|
493
|
-
a {@extend .foo}
|
494
|
-
SCSS
|
495
|
-
|
496
|
-
assert_equal <<CSS, render(<<SCSS)
|
497
|
-
*|*.foo, *|a {
|
498
|
-
a: b; }
|
499
|
-
CSS
|
500
|
-
*|*.foo {a: b}
|
501
|
-
*|a {@extend .foo}
|
502
|
-
SCSS
|
503
|
-
|
504
|
-
assert_equal <<CSS, render(<<SCSS)
|
505
|
-
*.foo, ns|a {
|
506
|
-
a: b; }
|
507
|
-
CSS
|
508
|
-
*.foo {a: b}
|
509
|
-
ns|a {@extend .foo}
|
510
|
-
SCSS
|
511
|
-
|
512
|
-
assert_equal <<CSS, render(<<SCSS)
|
513
|
-
*|*.foo, ns|a {
|
514
|
-
a: b; }
|
515
|
-
CSS
|
516
|
-
*|*.foo {a: b}
|
517
|
-
ns|a {@extend .foo}
|
518
|
-
SCSS
|
242
|
+
assert_unification '*.foo', 'a {@extend .foo}', '*.foo, a'
|
243
|
+
assert_unification '*.foo', '*|a {@extend .foo}', '*.foo, a'
|
244
|
+
assert_unification '*|*.foo', 'a {@extend .foo}', '*|*.foo, a'
|
245
|
+
assert_unification '*|*.foo', '*|a {@extend .foo}', '*|*.foo, *|a'
|
246
|
+
assert_unification '*.foo', 'ns|a {@extend .foo}', '*.foo, ns|a'
|
247
|
+
assert_unification '*|*.foo', 'ns|a {@extend .foo}', '*|*.foo, ns|a'
|
519
248
|
end
|
520
249
|
|
521
250
|
def test_element_unification_with_namespaced_universal_target
|
522
|
-
|
523
|
-
ns|*.foo, ns|a
|
524
|
-
|
525
|
-
|
526
|
-
ns|*.foo {a: b}
|
527
|
-
a {@extend .foo}
|
528
|
-
SCSS
|
529
|
-
|
530
|
-
assert_equal <<CSS, render(<<SCSS)
|
531
|
-
ns|*.foo, ns|a {
|
532
|
-
a: b; }
|
533
|
-
CSS
|
534
|
-
ns|*.foo {a: b}
|
535
|
-
*|a {@extend .foo}
|
536
|
-
SCSS
|
537
|
-
|
538
|
-
assert_equal <<CSS, render(<<SCSS)
|
539
|
-
ns1|*.foo {
|
540
|
-
a: b; }
|
541
|
-
CSS
|
542
|
-
ns1|*.foo {a: b}
|
543
|
-
ns2|a {@extend .foo}
|
544
|
-
SCSS
|
545
|
-
|
546
|
-
assert_equal <<CSS, render(<<SCSS)
|
547
|
-
ns|*.foo, ns|a {
|
548
|
-
a: b; }
|
549
|
-
CSS
|
550
|
-
ns|*.foo {a: b}
|
551
|
-
ns|a {@extend .foo}
|
552
|
-
SCSS
|
251
|
+
assert_unification 'ns|*.foo', 'a {@extend .foo}', 'ns|*.foo, ns|a'
|
252
|
+
assert_unification 'ns|*.foo', '*|a {@extend .foo}', 'ns|*.foo, ns|a'
|
253
|
+
assert_unification 'ns1|*.foo', 'ns2|a {@extend .foo}', 'ns1|*.foo'
|
254
|
+
assert_unification 'ns|*.foo', 'ns|a {@extend .foo}', 'ns|*.foo, ns|a'
|
553
255
|
end
|
554
256
|
|
555
257
|
def test_element_unification_with_namespaceless_element_target
|
556
|
-
|
557
|
-
a {
|
558
|
-
|
559
|
-
|
560
|
-
a.foo {a
|
561
|
-
a {@extend .foo}
|
562
|
-
|
563
|
-
|
564
|
-
assert_equal <<CSS, render(<<SCSS)
|
565
|
-
a {
|
566
|
-
a: b; }
|
567
|
-
CSS
|
568
|
-
a.foo {a: b}
|
569
|
-
*|a {@extend .foo}
|
570
|
-
SCSS
|
571
|
-
|
572
|
-
assert_equal <<CSS, render(<<SCSS)
|
573
|
-
*|a.foo, a {
|
574
|
-
a: b; }
|
575
|
-
CSS
|
576
|
-
*|a.foo {a: b}
|
577
|
-
a {@extend .foo}
|
578
|
-
SCSS
|
579
|
-
|
580
|
-
assert_equal <<CSS, render(<<SCSS)
|
581
|
-
*|a {
|
582
|
-
a: b; }
|
583
|
-
CSS
|
584
|
-
*|a.foo {a: b}
|
585
|
-
*|a {@extend .foo}
|
586
|
-
SCSS
|
587
|
-
|
588
|
-
assert_equal <<CSS, render(<<SCSS)
|
589
|
-
a.foo, ns|a {
|
590
|
-
a: b; }
|
591
|
-
CSS
|
592
|
-
a.foo {a: b}
|
593
|
-
ns|a {@extend .foo}
|
594
|
-
SCSS
|
595
|
-
|
596
|
-
assert_equal <<CSS, render(<<SCSS)
|
597
|
-
*|a.foo, ns|a {
|
598
|
-
a: b; }
|
599
|
-
CSS
|
600
|
-
*|a.foo {a: b}
|
601
|
-
ns|a {@extend .foo}
|
602
|
-
SCSS
|
603
|
-
|
604
|
-
assert_equal <<CSS, render(<<SCSS)
|
605
|
-
a.foo {
|
606
|
-
a: b; }
|
607
|
-
CSS
|
608
|
-
a.foo {a: b}
|
609
|
-
h1 {@extend .foo}
|
610
|
-
SCSS
|
258
|
+
assert_unification 'a.foo', 'a {@extend .foo}', 'a'
|
259
|
+
assert_unification 'a.foo', '*|a {@extend .foo}', 'a'
|
260
|
+
assert_unification '*|a.foo', 'a {@extend .foo}', '*|a.foo, a'
|
261
|
+
assert_unification '*|a.foo', '*|a {@extend .foo}', '*|a'
|
262
|
+
assert_unification 'a.foo', 'ns|a {@extend .foo}', 'a.foo, ns|a'
|
263
|
+
assert_unification '*|a.foo', 'ns|a {@extend .foo}', '*|a.foo, ns|a'
|
264
|
+
assert_unification 'a.foo', 'h1 {@extend .foo}', 'a.foo'
|
611
265
|
end
|
612
266
|
|
613
267
|
def test_element_unification_with_namespaced_element_target
|
614
|
-
|
615
|
-
ns|a {
|
616
|
-
|
617
|
-
|
618
|
-
ns|a.foo {a: b}
|
619
|
-
a {@extend .foo}
|
620
|
-
SCSS
|
621
|
-
|
622
|
-
assert_equal <<CSS, render(<<SCSS)
|
623
|
-
ns|a {
|
624
|
-
a: b; }
|
625
|
-
CSS
|
626
|
-
ns|a.foo {a: b}
|
627
|
-
*|a {@extend .foo}
|
628
|
-
SCSS
|
629
|
-
|
630
|
-
assert_equal <<CSS, render(<<SCSS)
|
631
|
-
ns1|a.foo {
|
632
|
-
a: b; }
|
633
|
-
CSS
|
634
|
-
ns1|a.foo {a: b}
|
635
|
-
ns2|a {@extend .foo}
|
636
|
-
SCSS
|
637
|
-
|
638
|
-
assert_equal <<CSS, render(<<SCSS)
|
639
|
-
ns|a {
|
640
|
-
a: b; }
|
641
|
-
CSS
|
642
|
-
ns|a.foo {a: b}
|
643
|
-
ns|a {@extend .foo}
|
644
|
-
SCSS
|
268
|
+
assert_unification 'ns|a.foo', 'a {@extend .foo}', 'ns|a'
|
269
|
+
assert_unification 'ns|a.foo', '*|a {@extend .foo}', 'ns|a'
|
270
|
+
assert_unification 'ns1|a.foo', 'ns2|a {@extend .foo}', 'ns1|a.foo'
|
271
|
+
assert_unification 'ns|a.foo', 'ns|a {@extend .foo}', 'ns|a'
|
645
272
|
end
|
646
273
|
|
647
274
|
def test_attribute_unification
|
648
|
-
|
649
|
-
[foo=bar].baz, [foo=bar][foo=
|
650
|
-
|
651
|
-
|
652
|
-
[foo=bar].
|
653
|
-
[foo=baz] {@extend .baz}
|
654
|
-
SCSS
|
655
|
-
|
656
|
-
assert_equal <<CSS, render(<<SCSS)
|
657
|
-
[foo=bar].baz, [foo=bar][foo^=bar] {
|
658
|
-
a: b; }
|
659
|
-
CSS
|
660
|
-
[foo=bar].baz {a: b}
|
661
|
-
[foo^=bar] {@extend .baz}
|
662
|
-
SCSS
|
663
|
-
|
664
|
-
assert_equal <<CSS, render(<<SCSS)
|
665
|
-
[foo=bar].baz, [foo=bar][foot=bar] {
|
666
|
-
a: b; }
|
667
|
-
CSS
|
668
|
-
[foo=bar].baz {a: b}
|
669
|
-
[foot=bar] {@extend .baz}
|
670
|
-
SCSS
|
671
|
-
|
672
|
-
assert_equal <<CSS, render(<<SCSS)
|
673
|
-
[foo=bar].baz, [foo=bar][ns|foo=bar] {
|
674
|
-
a: b; }
|
675
|
-
CSS
|
676
|
-
[foo=bar].baz {a: b}
|
677
|
-
[ns|foo=bar] {@extend .baz}
|
678
|
-
SCSS
|
679
|
-
|
680
|
-
assert_equal <<CSS, render(<<SCSS)
|
681
|
-
[foo=bar] {
|
682
|
-
a: b; }
|
683
|
-
CSS
|
684
|
-
[foo=bar].baz {a: b}
|
685
|
-
[foo=bar] {@extend .baz}
|
686
|
-
SCSS
|
275
|
+
assert_unification '[foo=bar].baz', '[foo=baz] {@extend .baz}', '[foo=bar].baz, [foo=bar][foo=baz]'
|
276
|
+
assert_unification '[foo=bar].baz', '[foo^=bar] {@extend .baz}', '[foo=bar].baz, [foo=bar][foo^=bar]'
|
277
|
+
assert_unification '[foo=bar].baz', '[foot=bar] {@extend .baz}', '[foo=bar].baz, [foo=bar][foot=bar]'
|
278
|
+
assert_unification '[foo=bar].baz', '[ns|foo=bar] {@extend .baz}', '[foo=bar].baz, [foo=bar][ns|foo=bar]'
|
279
|
+
assert_unification '%-a [foo=bar].bar', '[foo=bar] {@extend .bar}', '-a [foo=bar]'
|
687
280
|
end
|
688
281
|
|
689
282
|
def test_pseudo_unification
|
690
|
-
|
691
|
-
:foo.baz, :foo:foo
|
692
|
-
|
693
|
-
|
694
|
-
|
695
|
-
|
696
|
-
|
697
|
-
|
698
|
-
|
699
|
-
:foo.baz, :foo
|
700
|
-
a: b; }
|
701
|
-
CSS
|
702
|
-
:foo.baz {a: b}
|
703
|
-
::foo {@extend .baz}
|
704
|
-
SCSS
|
705
|
-
|
706
|
-
assert_equal <<CSS, render(<<SCSS)
|
707
|
-
::foo.baz {
|
708
|
-
a: b; }
|
709
|
-
CSS
|
710
|
-
::foo.baz {a: b}
|
711
|
-
::bar {@extend .baz}
|
712
|
-
SCSS
|
713
|
-
|
714
|
-
assert_equal <<CSS, render(<<SCSS)
|
715
|
-
::foo.baz {
|
716
|
-
a: b; }
|
717
|
-
CSS
|
718
|
-
::foo.baz {a: b}
|
719
|
-
::foo(2n+1) {@extend .baz}
|
720
|
-
SCSS
|
721
|
-
|
722
|
-
assert_equal <<CSS, render(<<SCSS)
|
723
|
-
::foo {
|
724
|
-
a: b; }
|
725
|
-
CSS
|
726
|
-
::foo.baz {a: b}
|
727
|
-
::foo {@extend .baz}
|
728
|
-
SCSS
|
729
|
-
|
730
|
-
assert_equal <<CSS, render(<<SCSS)
|
731
|
-
::foo(2n+1) {
|
732
|
-
a: b; }
|
733
|
-
CSS
|
734
|
-
::foo(2n+1).baz {a: b}
|
735
|
-
::foo(2n+1) {@extend .baz}
|
736
|
-
SCSS
|
737
|
-
|
738
|
-
assert_equal <<CSS, render(<<SCSS)
|
739
|
-
:foo.baz, :foo:bar {
|
740
|
-
a: b; }
|
741
|
-
CSS
|
742
|
-
:foo.baz {a: b}
|
743
|
-
:bar {@extend .baz}
|
744
|
-
SCSS
|
745
|
-
|
746
|
-
assert_equal <<CSS, render(<<SCSS)
|
747
|
-
.baz:foo, :foo:after {
|
748
|
-
a: b; }
|
749
|
-
CSS
|
750
|
-
.baz:foo {a: b}
|
751
|
-
:after {@extend .baz}
|
752
|
-
SCSS
|
753
|
-
|
754
|
-
assert_equal <<CSS, render(<<SCSS)
|
755
|
-
.baz:after, :foo:after {
|
756
|
-
a: b; }
|
757
|
-
CSS
|
758
|
-
.baz:after {a: b}
|
759
|
-
:foo {@extend .baz}
|
760
|
-
SCSS
|
761
|
-
|
762
|
-
assert_equal <<CSS, render(<<SCSS)
|
763
|
-
:foo {
|
764
|
-
a: b; }
|
765
|
-
CSS
|
766
|
-
:foo.baz {a: b}
|
767
|
-
:foo {@extend .baz}
|
768
|
-
SCSS
|
283
|
+
assert_unification ':foo.baz', ':foo(2n+1) {@extend .baz}', ':foo.baz, :foo:foo(2n+1)'
|
284
|
+
assert_unification ':foo.baz', '::foo {@extend .baz}', ':foo.baz, :foo::foo'
|
285
|
+
assert_unification '::foo.baz', '::bar {@extend .baz}', '::foo.baz'
|
286
|
+
assert_unification '::foo.baz', '::foo(2n+1) {@extend .baz}', '::foo.baz'
|
287
|
+
assert_unification '::foo.baz', '::foo {@extend .baz}', '::foo'
|
288
|
+
assert_unification '::foo(2n+1).baz', '::foo(2n+1) {@extend .baz}', '::foo(2n+1)'
|
289
|
+
assert_unification ':foo.baz', ':bar {@extend .baz}', ':foo.baz, :foo:bar'
|
290
|
+
assert_unification '.baz:foo', ':after {@extend .baz}', '.baz:foo, :foo:after'
|
291
|
+
assert_unification '.baz:after', ':foo {@extend .baz}', '.baz:after, :foo:after'
|
292
|
+
assert_unification ':foo.baz', ':foo {@extend .baz}', ':foo'
|
769
293
|
end
|
770
294
|
|
771
295
|
def test_pseudoelement_remains_at_end_of_selector
|
@@ -851,29 +375,9 @@ SCSS
|
|
851
375
|
end
|
852
376
|
|
853
377
|
def test_negation_unification
|
854
|
-
|
855
|
-
:not(.foo).baz, :not(.foo):not(.
|
856
|
-
|
857
|
-
CSS
|
858
|
-
:not(.foo).baz {a: b}
|
859
|
-
:not(.bar) {@extend .baz}
|
860
|
-
SCSS
|
861
|
-
|
862
|
-
assert_equal <<CSS, render(<<SCSS)
|
863
|
-
:not(.foo) {
|
864
|
-
a: b; }
|
865
|
-
CSS
|
866
|
-
:not(.foo).baz {a: b}
|
867
|
-
:not(.foo) {@extend .baz}
|
868
|
-
SCSS
|
869
|
-
|
870
|
-
assert_equal <<CSS, render(<<SCSS)
|
871
|
-
:not([a=b]) {
|
872
|
-
a: b; }
|
873
|
-
CSS
|
874
|
-
:not([a=b]).baz {a: b}
|
875
|
-
:not([a = b]) {@extend .baz}
|
876
|
-
SCSS
|
378
|
+
assert_unification ':not(.foo).baz', ':not(.bar) {@extend .baz}', ':not(.foo).baz, :not(.foo):not(.bar)'
|
379
|
+
assert_unification ':not(.foo).baz', ':not(.foo) {@extend .baz}', ':not(.foo)'
|
380
|
+
assert_unification ':not([a=b]).baz', ':not([a = b]) {@extend .baz}', ':not([a=b])'
|
877
381
|
end
|
878
382
|
|
879
383
|
def test_comma_extendee
|
@@ -2023,6 +1527,36 @@ d {@extend a}
|
|
2023
1527
|
SCSS
|
2024
1528
|
end
|
2025
1529
|
|
1530
|
+
def test_extend_redundancy_elimination_when_it_would_reduce_specificity
|
1531
|
+
assert_equal <<CSS, render(<<SCSS)
|
1532
|
+
a, a.foo {
|
1533
|
+
x: y; }
|
1534
|
+
CSS
|
1535
|
+
a {x: y}
|
1536
|
+
a.foo {@extend a}
|
1537
|
+
SCSS
|
1538
|
+
end
|
1539
|
+
|
1540
|
+
def test_extend_redundancy_elimination_when_it_would_preserve_specificity
|
1541
|
+
assert_equal <<CSS, render(<<SCSS)
|
1542
|
+
.bar a {
|
1543
|
+
x: y; }
|
1544
|
+
CSS
|
1545
|
+
.bar a {x: y}
|
1546
|
+
a.foo {@extend a}
|
1547
|
+
SCSS
|
1548
|
+
end
|
1549
|
+
|
1550
|
+
def test_extend_redundancy_elimination_never_eliminates_base_selector
|
1551
|
+
assert_equal <<CSS, render(<<SCSS)
|
1552
|
+
a.foo, .foo {
|
1553
|
+
x: y; }
|
1554
|
+
CSS
|
1555
|
+
a.foo {x: y}
|
1556
|
+
.foo {@extend a}
|
1557
|
+
SCSS
|
1558
|
+
end
|
1559
|
+
|
2026
1560
|
def test_extend_cross_branch_redundancy_elimination
|
2027
1561
|
assert_equal <<CSS, render(<<SCSS)
|
2028
1562
|
a c d, b c a d {
|
@@ -2046,6 +1580,17 @@ SCSS
|
|
2046
1580
|
|
2047
1581
|
private
|
2048
1582
|
|
1583
|
+
def assert_unification(selector, extension, unified)
|
1584
|
+
assert_equal <<CSS, render(<<SCSS)
|
1585
|
+
#{unified.split(', ').map {|s| "-a #{s}"}.join(', ')} {
|
1586
|
+
a: b; }
|
1587
|
+
CSS
|
1588
|
+
%-a #{selector} {a: b}
|
1589
|
+
#{extension}
|
1590
|
+
-a {@extend %-a}
|
1591
|
+
SCSS
|
1592
|
+
end
|
1593
|
+
|
2049
1594
|
def render(sass, options = {})
|
2050
1595
|
munge_filename options
|
2051
1596
|
Sass::Engine.new(sass, {:syntax => :scss}.merge(options)).render
|