sass 3.2.0.alpha.96 → 3.2.0.alpha.99
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.
- 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
|