sass 3.2.0.alpha.93 → 3.2.0.alpha.94

Sign up to get free protection for your applications and to get access to all the features.
data/REVISION CHANGED
@@ -1 +1 @@
1
- f19a88c02e1ac7a174ad2ada5cab276a5084fb2e
1
+ 8f4869e608e70d7f468bb463ebfe7a939d834e27
data/VERSION CHANGED
@@ -1 +1 @@
1
- 3.2.0.alpha.93
1
+ 3.2.0.alpha.94
@@ -76,14 +76,15 @@ module Sass
76
76
  # These correspond to a {CommaSequence}'s {CommaSequence#members members array}.
77
77
  # @see CommaSequence#do_extend
78
78
  def do_extend(extends, seen = Set.new)
79
- paths = Sass::Util.paths(members.map do |sseq_or_op|
80
- next [[sseq_or_op]] unless sseq_or_op.is_a?(SimpleSequence)
81
- extended = sseq_or_op.do_extend(extends, seen)
82
- choices = extended.map {|seq| seq.members}
83
- choices.unshift([sseq_or_op]) unless extended.any? {|seq| seq.superselector?(sseq_or_op)}
84
- choices
85
- end)
86
- Sass::Util.flatten(paths.map {|path| weave(path)}, 1).map {|p| Sequence.new(p)}
79
+ extended_not_expanded = members.map do |sseq_or_op|
80
+ next [[sseq_or_op]] unless sseq_or_op.is_a?(SimpleSequence)
81
+ extended = sseq_or_op.do_extend(extends, seen)
82
+ choices = extended.map {|seq| seq.members}
83
+ choices.unshift([sseq_or_op]) unless extended.any? {|seq| seq.superselector?(sseq_or_op)}
84
+ choices
85
+ end
86
+ weaves = Sass::Util.paths(extended_not_expanded).map {|path| weave(path)}
87
+ Sass::Util.flatten(trim(weaves), 1).map {|p| Sequence.new(p)}
87
88
  end
88
89
 
89
90
  # Returns whether or not this selector matches all elements
@@ -171,13 +172,13 @@ module Sass
171
172
  lcs = Sass::Util.lcs(seq2, seq1) do |s1, s2|
172
173
  next s1 if s1 == s2
173
174
  next unless s1.first.is_a?(SimpleSequence) && s2.first.is_a?(SimpleSequence)
174
- next s2 if subweave_superselector?(s1, s2)
175
- next s1 if subweave_superselector?(s2, s1)
175
+ next s2 if parent_superselector?(s1, s2)
176
+ next s1 if parent_superselector?(s2, s1)
176
177
  end
177
178
 
178
179
  diff = [[init]]
179
180
  until lcs.empty?
180
- diff << chunks(seq1, seq2) {|s| subweave_superselector?(s.first, lcs.first)} << [lcs.shift]
181
+ diff << chunks(seq1, seq2) {|s| parent_superselector?(s.first, lcs.first)} << [lcs.shift]
181
182
  seq1.shift
182
183
  seq2.shift
183
184
  end
@@ -254,9 +255,9 @@ module Sass
254
255
  sel1 = seq1.pop
255
256
  sel2 = seq2.pop
256
257
  if op1 == '~' && op2 == '~'
257
- if subweave_superselector?([sel1], [sel2])
258
+ if sel1.superselector?(sel2)
258
259
  res.unshift sel2, '~'
259
- elsif subweave_superselector?([sel2], [sel1])
260
+ elsif sel2.superselector?(sel1)
260
261
  res.unshift sel1, '~'
261
262
  else
262
263
  merged = sel1.unify(sel2.members)
@@ -273,7 +274,7 @@ module Sass
273
274
  tilde_sel, plus_sel = sel2, sel1
274
275
  end
275
276
 
276
- if subweave_superselector?([tilde_sel], [plus_sel])
277
+ if tilde_sel.superselector?(plus_sel)
277
278
  res.unshift plus_sel, '+'
278
279
  else
279
280
  merged = plus_sel.unify(tilde_sel.members)
@@ -297,11 +298,11 @@ module Sass
297
298
  end
298
299
  return merge_final_ops(seq1, seq2, res)
299
300
  elsif op1
300
- seq2.pop if op1 == '>' && seq2.last && subweave_superselector?([seq2.last], [seq1.last])
301
+ seq2.pop if op1 == '>' && seq2.last && seq2.last.superselector?(seq1.last)
301
302
  res.unshift seq1.pop, op1
302
303
  return merge_final_ops(seq1, seq2, res)
303
304
  else # op2
304
- seq1.pop if op2 == '>' && seq1.last && subweave_superselector?([seq1.last], [seq2.last])
305
+ seq1.pop if op2 == '>' && seq1.last && seq1.last.superselector?(seq2.last)
305
306
  res.unshift seq2.pop, op2
306
307
  return merge_final_ops(seq1, seq2, res)
307
308
  end
@@ -360,36 +361,80 @@ module Sass
360
361
  return newseq
361
362
  end
362
363
 
363
- # Given two sequences of simple selectors, returns whether `sseq1` is a
364
- # superselector of `sseq2`; that is, whether `sseq1` matches every element
365
- # `sseq2` matches.
366
- #
367
- # Both `sseq1` and `sseq2` are of the form
368
- # `SimpleSelector (String SimpleSelector)* String*`, although selectors
369
- # with a trailing operator are considered to be neither superselectors nor
370
- # subselectors.
364
+ # Given two selector sequences, returns whether `seq1` is a
365
+ # superselector of `seq2`; that is, whether `seq1` matches every
366
+ # element `seq2` matches.
371
367
  #
372
- # @param sseq1 [Array<SimpleSequence or String>]
373
- # @param sseq2 [Array<SimpleSequence or String>]
368
+ # @param seq1 [Array<SimpleSequence or String>]
369
+ # @param seq2 [Array<SimpleSequence or String>]
374
370
  # @return [Boolean]
375
- def subweave_superselector?(sseq1, sseq2)
376
- sseq1 = sseq1.reject {|e| e == "\n"}
377
- sseq2 = sseq2.reject {|e| e == "\n"}
378
- # Selectors with trailing operators are neither superselectors nor
379
- # subselectors.
380
- return if sseq1.last.is_a?(String) || sseq2.last.is_a?(String)
381
- if sseq1.size > 1
382
- # More complex selectors are never superselectors of less complex ones
383
- return unless sseq2.size > 1
371
+ def _superselector?(seq1, seq2)
372
+ seq1 = seq1.reject {|e| e == "\n"}
373
+ seq2 = seq2.reject {|e| e == "\n"}
374
+ # Selectors with leading or trailing operators are neither
375
+ # superselectors nor subselectors.
376
+ return if seq1.last.is_a?(String) || seq2.last.is_a?(String) ||
377
+ seq1.first.is_a?(String) || seq2.first.is_a?(String)
378
+ # More complex selectors are never superselectors of less complex ones
379
+ return if seq1.size > seq2.size
380
+ return seq1.first.superselector?(seq2.last) if seq1.size == 1
381
+
382
+ _, si = Sass::Util.enum_with_index(seq2).find do |e, i|
383
+ return if i == seq2.size - 1
384
+ next if e.is_a?(String)
385
+ seq1.first.superselector?(e)
386
+ end
387
+ return unless si
388
+
389
+ if seq1[1].is_a?(String)
390
+ return unless seq2[si+1].is_a?(String)
384
391
  # .foo ~ .bar is a superselector of .foo + .bar
385
- return unless sseq1[1] == "~" ? sseq2[1] != ">" : sseq2[1] == sseq1[1]
386
- return unless sseq1.first.superselector?(sseq2.first)
387
- return subweave_superselector?(sseq1[2..-1], sseq2[2..-1])
388
- elsif sseq2.size > 1
389
- return true if sseq2[1] == ">" && sseq1.first.superselector?(sseq2.first)
390
- return subweave_superselector?(sseq1, sseq2[2..-1])
392
+ return unless seq1[1] == "~" ? seq2[si+1] != ">" : seq1[1] == seq2[si+1]
393
+ return _superselector?(seq1[2..-1], seq2[si+2..-1])
394
+ elsif seq2[si+1].is_a?(String)
395
+ return unless seq2[si+1] == ">"
396
+ return _superselector?(seq1[1..-1], seq2[si+2..-1])
391
397
  else
392
- sseq1.first.superselector?(sseq2.first)
398
+ return _superselector?(seq1[1..-1], seq2[si+1..-1])
399
+ end
400
+ end
401
+
402
+ # Like \{#_superselector?}, but compares the selectors in the
403
+ # context of parent selectors, as though they shared an implicit
404
+ # base simple selector. For example, `B` is not normally a
405
+ # superselector of `B A`, since it doesn't match `A` elements.
406
+ # However, it is a parent superselector, since `B X` is a
407
+ # superselector of `B A X`.
408
+ #
409
+ # @param seq1 [Array<SimpleSequence or String>]
410
+ # @param seq2 [Array<SimpleSequence or String>]
411
+ # @return [Boolean]
412
+ def parent_superselector?(seq1, seq2)
413
+ base = Sass::Selector::SimpleSequence.new([Sass::Selector::Placeholder.new('<temp>')])
414
+ _superselector?(seq1 + [base], seq2 + [base])
415
+ end
416
+
417
+ # Removes redundant selectors from between multiple lists of
418
+ # selectors. This takes a list of lists of selector sequences;
419
+ # each individual list is assumed to have no redundancy within
420
+ # itself. A selector is only removed if it's redundant with a
421
+ # selector in another list.
422
+ #
423
+ # "Redundant" here means that one selector is a superselector of
424
+ # the other. The more specific selector is removed.
425
+ #
426
+ # @param seqses [Array<Array<Array<SimpleSequence or String>>>]
427
+ # @return [Array<Array<Array<SimpleSequence or String>>>]
428
+ def trim(seqses)
429
+ # This is n^2 on the sequences, but only comparing between
430
+ # separate sequences should limit the quadratic behavior.
431
+ seqses.map do |seqs1|
432
+ seqs1.reject do |seq1|
433
+ seqses.any? do |seqs2|
434
+ next if seqs1.object_id == seqs2.object_id
435
+ seqs2.any? {|seq2| _superselector?(seq2, seq1)}
436
+ end
437
+ end
393
438
  end
394
439
  end
395
440
 
@@ -400,6 +445,19 @@ module Sass
400
445
  def _eql?(other)
401
446
  other.members.reject {|m| m == "\n"}.eql?(self.members.reject {|m| m == "\n"})
402
447
  end
448
+
449
+ private
450
+
451
+ def extended_not_expanded_to_s(extended_not_expanded)
452
+ extended_not_expanded.map do |choices|
453
+ choices = choices.map do |sel|
454
+ next sel.first.to_s if sel.size == 1
455
+ "#{sel.join ' '}"
456
+ end
457
+ next choices.first if choices.size == 1 && !choices.include?(' ')
458
+ "(#{choices.join ', '})"
459
+ end.join ' '
460
+ end
403
461
  end
404
462
  end
405
463
  end
@@ -1753,7 +1753,7 @@ SCSS
1753
1753
  assert_equal <<CSS, render(<<SCSS)
1754
1754
  .bar, .bar .foo {
1755
1755
  a: b; }
1756
- .bar .foo, .bar .foo .foo {
1756
+ .bar .foo {
1757
1757
  c: d; }
1758
1758
  CSS
1759
1759
  .bar {
@@ -2010,6 +2010,40 @@ flip,
2010
2010
  SCSS
2011
2011
  end
2012
2012
 
2013
+ def test_extended_parent_and_child_redundancy_elimination
2014
+ assert_equal <<CSS, render(<<SCSS)
2015
+ a b, d b, a c, d c {
2016
+ a: b; }
2017
+ CSS
2018
+ a {
2019
+ b {a: b}
2020
+ c {@extend b}
2021
+ }
2022
+ d {@extend a}
2023
+ SCSS
2024
+ end
2025
+
2026
+ def test_extend_cross_branch_redundancy_elimination
2027
+ assert_equal <<CSS, render(<<SCSS)
2028
+ a c d, b c a d {
2029
+ a: b; }
2030
+ CSS
2031
+ %x c %y {a: b}
2032
+ a, b {@extend %x}
2033
+ a d {@extend %y}
2034
+ SCSS
2035
+
2036
+ assert_equal <<CSS, render(<<SCSS)
2037
+ e a c d, a c e d, e b c a d, b c a e d {
2038
+ a: b; }
2039
+ CSS
2040
+ e %z {a: b}
2041
+ %x c %y {@extend %z}
2042
+ a, b {@extend %x}
2043
+ a d {@extend %y}
2044
+ SCSS
2045
+ end
2046
+
2013
2047
  private
2014
2048
 
2015
2049
  def render(sass, options = {})
metadata CHANGED
@@ -1,15 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sass
3
3
  version: !ruby/object:Gem::Version
4
- hash: 592303015
4
+ hash: 592303009
5
5
  prerelease: 6
6
6
  segments:
7
7
  - 3
8
8
  - 2
9
9
  - 0
10
10
  - alpha
11
- - 93
12
- version: 3.2.0.alpha.93
11
+ - 94
12
+ version: 3.2.0.alpha.94
13
13
  platform: ruby
14
14
  authors:
15
15
  - Nathan Weizenbaum
@@ -19,7 +19,7 @@ autorequire:
19
19
  bindir: bin
20
20
  cert_chain: []
21
21
 
22
- date: 2012-03-09 00:00:00 -05:00
22
+ date: 2012-03-14 00:00:00 -04:00
23
23
  default_executable:
24
24
  dependencies:
25
25
  - !ruby/object:Gem::Dependency