sass 3.4.20 → 3.4.21

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.
Files changed (48) hide show
  1. checksums.yaml +5 -13
  2. data/Rakefile +3 -1
  3. data/VERSION +1 -1
  4. data/VERSION_DATE +1 -1
  5. data/lib/sass/cache_stores/filesystem.rb +1 -1
  6. data/lib/sass/cache_stores/memory.rb +4 -5
  7. data/lib/sass/engine.rb +4 -10
  8. data/lib/sass/error.rb +4 -4
  9. data/lib/sass/exec/sass_convert.rb +6 -4
  10. data/lib/sass/exec/sass_scss.rb +5 -2
  11. data/lib/sass/plugin.rb +2 -1
  12. data/lib/sass/plugin/compiler.rb +14 -11
  13. data/lib/sass/plugin/configuration.rb +1 -1
  14. data/lib/sass/plugin/merb.rb +1 -1
  15. data/lib/sass/script/css_parser.rb +2 -3
  16. data/lib/sass/script/functions.rb +20 -33
  17. data/lib/sass/script/lexer.rb +7 -8
  18. data/lib/sass/script/parser.rb +1 -1
  19. data/lib/sass/script/tree/node.rb +1 -1
  20. data/lib/sass/script/tree/operation.rb +1 -1
  21. data/lib/sass/script/tree/variable.rb +1 -1
  22. data/lib/sass/script/value/base.rb +6 -6
  23. data/lib/sass/script/value/color.rb +2 -2
  24. data/lib/sass/script/value/helpers.rb +7 -7
  25. data/lib/sass/script/value/number.rb +9 -2
  26. data/lib/sass/scss/parser.rb +34 -33
  27. data/lib/sass/scss/rx.rb +2 -3
  28. data/lib/sass/selector.rb +7 -10
  29. data/lib/sass/selector/abstract_sequence.rb +3 -1
  30. data/lib/sass/selector/comma_sequence.rb +4 -2
  31. data/lib/sass/selector/pseudo.rb +2 -2
  32. data/lib/sass/selector/sequence.rb +2 -2
  33. data/lib/sass/selector/simple.rb +3 -1
  34. data/lib/sass/selector/simple_sequence.rb +4 -4
  35. data/lib/sass/tree/function_node.rb +2 -3
  36. data/lib/sass/tree/prop_node.rb +4 -5
  37. data/lib/sass/tree/rule_node.rb +1 -1
  38. data/lib/sass/tree/visitors/check_nesting.rb +16 -22
  39. data/lib/sass/tree/visitors/convert.rb +2 -2
  40. data/lib/sass/tree/visitors/extend.rb +15 -13
  41. data/lib/sass/tree/visitors/perform.rb +1 -1
  42. data/lib/sass/tree/visitors/set_options.rb +1 -1
  43. data/lib/sass/tree/visitors/to_css.rb +18 -15
  44. data/lib/sass/util.rb +7 -8
  45. data/lib/sass/util/multibyte_string_scanner.rb +0 -2
  46. data/test/sass/engine_test.rb +45 -4
  47. data/test/sass/script_test.rb +31 -0
  48. metadata +99 -98
@@ -23,8 +23,10 @@ module Sass
23
23
 
24
24
  # Returns the selector string.
25
25
  #
26
+ # @param opts [Hash] rendering options.
27
+ # @option opts [Symbol] :style The css rendering style.
26
28
  # @return [String]
27
- def to_s
29
+ def to_s(opts = {})
28
30
  Sass::Util.abstract(self)
29
31
  end
30
32
 
@@ -158,7 +158,7 @@ module Sass
158
158
  seen_with_pseudo_selectors = seen.dup
159
159
 
160
160
  modified_original = false
161
- members = Sass::Util.enum_with_index(self.members).map do |sel, i|
161
+ members = self.members.map do |sel|
162
162
  next sel unless sel.is_a?(Pseudo) && sel.selector
163
163
  next sel if seen.include?([sel])
164
164
  extended = sel.selector.do_extend(extends, parent_directives, replace, seen, !:original)
@@ -279,14 +279,14 @@ module Sass
279
279
  end
280
280
  end
281
281
 
282
- our_spcs.all? do |name, pseudos|
282
+ our_spcs.all? do |_name, pseudos|
283
283
  pseudos.all? {|pseudo| pseudo.superselector?(their_sseq, parents)}
284
284
  end
285
285
  end
286
286
 
287
287
  # @see Simple#to_s
288
- def to_s
289
- res = @members.join
288
+ def to_s(opts = {})
289
+ res = @members.map {|m| m.to_s(opts)}.join
290
290
  res << '!' if subject?
291
291
  res
292
292
  end
@@ -36,9 +36,8 @@ module Sass
36
36
  @splat = splat
37
37
  super()
38
38
 
39
- if %w[and or not].include?(name)
40
- raise Sass::SyntaxError.new("Invalid function name \"#{name}\".")
41
- end
39
+ return unless %w[and or not].include?(name)
40
+ raise Sass::SyntaxError.new("Invalid function name \"#{name}\".")
42
41
  end
43
42
  end
44
43
  end
@@ -119,11 +119,10 @@ module Sass::Tree
119
119
  private
120
120
 
121
121
  def check!
122
- if @options[:property_syntax] && @options[:property_syntax] != @prop_syntax
123
- raise Sass::SyntaxError.new(
124
- "Illegal property syntax: can't use #{@prop_syntax} syntax when " +
125
- ":property_syntax => #{@options[:property_syntax].inspect} is set.")
126
- end
122
+ return unless @options[:property_syntax] && @options[:property_syntax] != @prop_syntax
123
+ raise Sass::SyntaxError.new(
124
+ "Illegal property syntax: can't use #{@prop_syntax} syntax when " +
125
+ ":property_syntax => #{@options[:property_syntax].inspect} is set.")
127
126
  end
128
127
 
129
128
  class << self
@@ -133,7 +133,7 @@ module Sass::Tree
133
133
 
134
134
  def try_to_parse_non_interpolated_rules
135
135
  @parsed_rules = nil
136
- return unless @rule.all? {|t| t.kind_of?(String)}
136
+ return unless @rule.all? {|t| t.is_a?(String)}
137
137
 
138
138
  # We don't use real filename/line info because we don't have it yet.
139
139
  # When we get it, we'll set it on the parsed rules if possible.
@@ -90,9 +90,8 @@ class Sass::Tree::Visitors::CheckNesting < Sass::Tree::Visitors::Base
90
90
 
91
91
  VALID_EXTEND_PARENTS = [Sass::Tree::RuleNode, Sass::Tree::MixinDefNode, Sass::Tree::MixinNode]
92
92
  def invalid_extend_parent?(parent, child)
93
- unless is_any_of?(parent, VALID_EXTEND_PARENTS)
94
- return "Extend directives may only be used within rules."
95
- end
93
+ return if is_any_of?(parent, VALID_EXTEND_PARENTS)
94
+ "Extend directives may only be used within rules."
96
95
  end
97
96
 
98
97
  INVALID_IMPORT_PARENTS = CONTROL_NODES +
@@ -110,15 +109,13 @@ class Sass::Tree::Visitors::CheckNesting < Sass::Tree::Visitors::Base
110
109
  end
111
110
 
112
111
  def invalid_mixindef_parent?(parent, child)
113
- unless (@parents.map {|p| p.class} & INVALID_IMPORT_PARENTS).empty?
114
- return "Mixins may not be defined within control directives or other mixins."
115
- end
112
+ return if (@parents.map {|p| p.class} & INVALID_IMPORT_PARENTS).empty?
113
+ "Mixins may not be defined within control directives or other mixins."
116
114
  end
117
115
 
118
116
  def invalid_function_parent?(parent, child)
119
- unless (@parents.map {|p| p.class} & INVALID_IMPORT_PARENTS).empty?
120
- return "Functions may not be defined within control directives or other mixins."
121
- end
117
+ return if (@parents.map {|p| p.class} & INVALID_IMPORT_PARENTS).empty?
118
+ "Functions may not be defined within control directives or other mixins."
122
119
  end
123
120
 
124
121
  VALID_FUNCTION_CHILDREN = [
@@ -126,27 +123,24 @@ class Sass::Tree::Visitors::CheckNesting < Sass::Tree::Visitors::Base
126
123
  Sass::Tree::VariableNode, Sass::Tree::WarnNode, Sass::Tree::ErrorNode
127
124
  ] + CONTROL_NODES
128
125
  def invalid_function_child?(parent, child)
129
- unless is_any_of?(child, VALID_FUNCTION_CHILDREN)
130
- "Functions can only contain variable declarations and control directives."
131
- end
126
+ return if is_any_of?(child, VALID_FUNCTION_CHILDREN)
127
+ "Functions can only contain variable declarations and control directives."
132
128
  end
133
129
 
134
- VALID_PROP_CHILDREN = CONTROL_NODES + [Sass::Tree::CommentNode,
135
- Sass::Tree::PropNode,
136
- Sass::Tree::MixinNode]
130
+ VALID_PROP_CHILDREN = CONTROL_NODES + [Sass::Tree::CommentNode,
131
+ Sass::Tree::PropNode,
132
+ Sass::Tree::MixinNode]
137
133
  def invalid_prop_child?(parent, child)
138
- unless is_any_of?(child, VALID_PROP_CHILDREN)
139
- "Illegal nesting: Only properties may be nested beneath properties."
140
- end
134
+ return if is_any_of?(child, VALID_PROP_CHILDREN)
135
+ "Illegal nesting: Only properties may be nested beneath properties."
141
136
  end
142
137
 
143
138
  VALID_PROP_PARENTS = [Sass::Tree::RuleNode, Sass::Tree::KeyframeRuleNode, Sass::Tree::PropNode,
144
139
  Sass::Tree::MixinDefNode, Sass::Tree::DirectiveNode, Sass::Tree::MixinNode]
145
140
  def invalid_prop_parent?(parent, child)
146
- unless is_any_of?(parent, VALID_PROP_PARENTS)
147
- "Properties are only allowed within rules, directives, mixin includes, or other properties." +
148
- child.pseudo_class_selector_message
149
- end
141
+ return if is_any_of?(parent, VALID_PROP_PARENTS)
142
+ "Properties are only allowed within rules, directives, mixin includes, or other properties." +
143
+ child.pseudo_class_selector_message
150
144
  end
151
145
 
152
146
  def invalid_return_parent?(parent, child)
@@ -27,7 +27,7 @@ class Sass::Tree::Visitors::Convert < Sass::Tree::Visitors::Base
27
27
  res = visit_rule_level(parent.children)
28
28
 
29
29
  if @format == :sass
30
- "\n" + res.rstrip + "\n"
30
+ "\n" + res.rstrip + "\n"
31
31
  else
32
32
  " {\n" + res.rstrip + "\n#{ @tab_chars * (@tabs - 1)}}\n"
33
33
  end
@@ -340,7 +340,7 @@ class Sass::Tree::Visitors::Convert < Sass::Tree::Visitors::Base
340
340
 
341
341
  def dasherize(s)
342
342
  if @options[:dasherize]
343
- s.gsub('_', '-')
343
+ s.tr('_', '-')
344
344
  else
345
345
  s
346
346
  end
@@ -44,25 +44,27 @@ class Sass::Tree::Visitors::Extend < Sass::Tree::Visitors::Base
44
44
  node.resolved_rules = node.resolved_rules.do_extend(@extends, @parent_directives)
45
45
  end
46
46
 
47
- private
47
+ class << self
48
+ private
48
49
 
49
- def self.check_extends_fired!(extends)
50
- extends.each_value do |ex|
51
- next if ex.result == :succeeded || ex.node.optional?
52
- message = "\"#{ex.extender}\" failed to @extend \"#{ex.target.join}\"."
53
- reason =
54
- if ex.result == :not_found
55
- "The selector \"#{ex.target.join}\" was not found."
56
- else
57
- "No selectors matching \"#{ex.target.join}\" could be unified with \"#{ex.extender}\"."
58
- end
50
+ def check_extends_fired!(extends)
51
+ extends.each_value do |ex|
52
+ next if ex.result == :succeeded || ex.node.optional?
53
+ message = "\"#{ex.extender}\" failed to @extend \"#{ex.target.join}\"."
54
+ reason =
55
+ if ex.result == :not_found
56
+ "The selector \"#{ex.target.join}\" was not found."
57
+ else
58
+ "No selectors matching \"#{ex.target.join}\" could be unified with \"#{ex.extender}\"."
59
+ end
59
60
 
60
- # TODO(nweiz): this should use the Sass stack trace of the extend node.
61
- raise Sass::SyntaxError.new(<<MESSAGE, :filename => ex.node.filename, :line => ex.node.line)
61
+ # TODO(nweiz): this should use the Sass stack trace of the extend node.
62
+ raise Sass::SyntaxError.new(<<MESSAGE, :filename => ex.node.filename, :line => ex.node.line)
62
63
  #{message}
63
64
  #{reason}
64
65
  Use "@extend #{ex.target.join} !optional" if the extend should be able to fail.
65
66
  MESSAGE
67
+ end
66
68
  end
67
69
  end
68
70
  end
@@ -349,7 +349,7 @@ WARNING
349
349
  raise Sass::SyntaxError.new("Undefined mixin '#{node.name}'.") unless mixin
350
350
 
351
351
  if node.children.any? && !mixin.has_content
352
- raise Sass::SyntaxError.new(%Q{Mixin "#{node.name}" does not accept a content block.})
352
+ raise Sass::SyntaxError.new(%{Mixin "#{node.name}" does not accept a content block.})
353
353
  end
354
354
 
355
355
  args = node.args.map {|a| a.perform(@environment)}
@@ -80,7 +80,7 @@ class Sass::Tree::Visitors::SetOptions < Sass::Tree::Visitors::Base
80
80
 
81
81
  def visit_mixin(node)
82
82
  node.args.each {|a| a.options = @options}
83
- node.keywords.each {|k, v| v.options = @options}
83
+ node.keywords.each {|_k, v| v.options = @options}
84
84
  node.splat.options = @options if node.splat
85
85
  node.kwarg_splat.options = @options if node.kwarg_splat
86
86
  yield
@@ -51,8 +51,8 @@ class Sass::Tree::Visitors::ToCss < Sass::Tree::Visitors::Base
51
51
  @source_mapping.add(source_range, target_range)
52
52
  end
53
53
 
54
- def ends_with?(str)
55
- @result.end_with?(str)
54
+ def trailing_semicolon?
55
+ @result.end_with?(";") && !@result.end_with?('\;')
56
56
  end
57
57
 
58
58
  # Move the output cursor back `chars` characters.
@@ -128,7 +128,7 @@ class Sass::Tree::Visitors::ToCss < Sass::Tree::Visitors::Base
128
128
  end
129
129
  end
130
130
  rstrip!
131
- if node.style == :compressed && ends_with?(";")
131
+ if node.style == :compressed && trailing_semicolon?
132
132
  erase! 1
133
133
  end
134
134
  return "" if @result.empty?
@@ -163,7 +163,7 @@ class Sass::Tree::Visitors::ToCss < Sass::Tree::Visitors::Base
163
163
 
164
164
  content = node.resolved_value.split("\n").join("\n" + spaces)
165
165
  if node.type == :silent
166
- content.gsub!(%r{^(\s*)//(.*)$}) {|md| "#{$1}/*#{$2} */"}
166
+ content.gsub!(%r{^(\s*)//(.*)$}) {"#{$1}/*#{$2} */"}
167
167
  end
168
168
  if (node.style == :compact || node.style == :compressed) && node.type != :loud
169
169
  content.gsub!(/\n +(\* *(?!\/))?/, ' ')
@@ -222,7 +222,7 @@ class Sass::Tree::Visitors::ToCss < Sass::Tree::Visitors::Base
222
222
  first = false
223
223
  elsif node.style == :compressed
224
224
  unless had_children
225
- output(";") unless ends_with?(";")
225
+ output(";") unless trailing_semicolon?
226
226
  end
227
227
  with_tabs(0) {visit(child)}
228
228
  had_children = child.has_children
@@ -232,7 +232,7 @@ class Sass::Tree::Visitors::ToCss < Sass::Tree::Visitors::Base
232
232
  end
233
233
  end
234
234
  rstrip!
235
- if node.style == :compressed && ends_with?(";")
235
+ if node.style == :compressed && trailing_semicolon?
236
236
  erase! 1
237
237
  end
238
238
  if node.style == :expanded
@@ -295,10 +295,13 @@ class Sass::Tree::Visitors::ToCss < Sass::Tree::Visitors::Base
295
295
 
296
296
  joined_rules = node.resolved_rules.members.map do |seq|
297
297
  next if seq.has_placeholder?
298
- rule_part = seq.to_s
298
+ rule_part = seq.to_s(:style => node.style)
299
299
  if node.style == :compressed
300
300
  rule_part.gsub!(/([^,])\s*\n\s*/m, '\1 ')
301
- rule_part.gsub!(/\s*([-,+>])\s*/m, '\1')
301
+ rule_part.gsub!(/\s*([+>])\s*/m, '\1')
302
+ rule_part.gsub!(/nth([^( ]*)\(([^)]*)\)/m) do |match|
303
+ match.tr(" \t\n", "")
304
+ end
302
305
  rule_part.strip!
303
306
  end
304
307
  rule_part
@@ -337,7 +340,7 @@ class Sass::Tree::Visitors::ToCss < Sass::Tree::Visitors::Base
337
340
  end
338
341
  end
339
342
 
340
- end_props, trailer, tabs = '', '', 0
343
+ end_props, trailer, tabs = '', '', 0
341
344
  if node.style == :compact
342
345
  separator, end_props, bracket = ' ', ' ', ' { '
343
346
  trailer = "\n" if node.group_end
@@ -356,7 +359,7 @@ class Sass::Tree::Visitors::ToCss < Sass::Tree::Visitors::Base
356
359
  with_tabs(tabs) do
357
360
  node.children.each_with_index do |child, i|
358
361
  if i > 0
359
- if separator.start_with?(";") && ends_with?(";")
362
+ if separator.start_with?(";") && trailing_semicolon?
360
363
  erase! 1
361
364
  end
362
365
  output(separator)
@@ -364,7 +367,7 @@ class Sass::Tree::Visitors::ToCss < Sass::Tree::Visitors::Base
364
367
  visit(child)
365
368
  end
366
369
  end
367
- if node.style == :compressed && ends_with?(";")
370
+ if node.style == :compressed && trailing_semicolon?
368
371
  erase! 1
369
372
  end
370
373
 
@@ -387,10 +390,10 @@ class Sass::Tree::Visitors::ToCss < Sass::Tree::Visitors::Base
387
390
  rule = Sass::Tree::RuleNode.new([""])
388
391
  rule.resolved_rules = Sass::Selector::CommaSequence.new(
389
392
  [Sass::Selector::Sequence.new(
390
- [Sass::Selector::SimpleSequence.new(
391
- [Sass::Selector::Element.new(k.to_s.gsub(/[^\w-]/, "\\\\\\0"), nil)],
392
- false)
393
- ])
393
+ [Sass::Selector::SimpleSequence.new(
394
+ [Sass::Selector::Element.new(k.to_s.gsub(/[^\w-]/, "\\\\\\0"), nil)],
395
+ false)
396
+ ])
394
397
  ])
395
398
  prop = Sass::Tree::PropNode.new([""], Sass::Script::Value::String.new(''), :new)
396
399
  prop.resolved_name = "font-family"
@@ -13,6 +13,8 @@ require 'sass/util/subset_map'
13
13
 
14
14
  module Sass
15
15
  # A module containing various useful functions.
16
+ # @comment
17
+ # rubocop:disable ModuleLength
16
18
  module Util
17
19
  extend self
18
20
 
@@ -310,7 +312,7 @@ module Sass
310
312
  # @return [Array]
311
313
  def hash_to_a(hash)
312
314
  return hash.to_a unless ruby1_8? || defined?(Test::Unit)
313
- hash.sort_by {|k, v| k}
315
+ hash.sort_by {|k, _v| k}
314
316
  end
315
317
 
316
318
  # Performs the equivalent of `enum.group_by.to_a`, but with a guaranteed
@@ -643,7 +645,7 @@ module Sass
643
645
  #
644
646
  # @param path [String]
645
647
  def glob(path)
646
- path = path.gsub('\\', '/') if windows?
648
+ path = path.tr('\\', '/') if windows?
647
649
  if block_given?
648
650
  Dir.glob(path) {|f| yield(f)}
649
651
  else
@@ -1125,7 +1127,7 @@ module Sass
1125
1127
  VLQ_BASE_MASK = VLQ_BASE - 1
1126
1128
  VLQ_CONTINUATION_BIT = VLQ_BASE
1127
1129
 
1128
- BASE64_DIGITS = ('A'..'Z').to_a + ('a'..'z').to_a + ('0'..'9').to_a + ['+', '/']
1130
+ BASE64_DIGITS = ('A'..'Z').to_a + ('a'..'z').to_a + ('0'..'9').to_a + ['+', '/']
1129
1131
  BASE64_DIGIT_MAP = begin
1130
1132
  map = {}
1131
1133
  Sass::Util.enum_with_index(BASE64_DIGITS).map do |digit, i|
@@ -1304,13 +1306,10 @@ module Sass
1304
1306
  return str, str.encoding
1305
1307
  end
1306
1308
 
1307
- # rubocop:disable LineLength
1308
-
1309
1309
  # Calculates the memoization table for the Least Common Subsequence algorithm.
1310
1310
  # Algorithm from [Wikipedia](http://en.wikipedia.org/wiki/Longest_common_subsequence_problem#Computing_the_length_of_the_LCS)
1311
1311
  def lcs_table(x, y)
1312
1312
  # This method does not take a block as an explicit parameter for performance reasons.
1313
- # rubocop:enable LineLength
1314
1313
  c = Array.new(x.size) {[]}
1315
1314
  x.size.times {|i| c[i][0] = 0}
1316
1315
  y.size.times {|j| c[0][j] = 0}
@@ -1326,12 +1325,12 @@ module Sass
1326
1325
  end
1327
1326
  c
1328
1327
  end
1329
- # rubocop:disable ParameterLists, LineLength
1328
+ # rubocop:disable ParameterLists
1330
1329
 
1331
1330
  # Computes a single longest common subsequence for arrays x and y.
1332
1331
  # Algorithm from [Wikipedia](http://en.wikipedia.org/wiki/Longest_common_subsequence_problem#Reading_out_an_LCS)
1333
1332
  def lcs_backtrace(c, x, y, i, j, &block)
1334
- # rubocop:enable ParameterList, LineLengths
1333
+ # rubocop:enable ParameterList
1335
1334
  return [] if i == 0 || j == 0
1336
1335
  if (v = yield(x[i], y[j]))
1337
1336
  return lcs_backtrace(c, x, y, i - 1, j - 1, &block) << v
@@ -1,9 +1,7 @@
1
1
  require 'strscan'
2
2
 
3
3
  if Sass::Util.ruby1_8?
4
- # rubocop:disable ConstantName
5
4
  Sass::Util::MultibyteStringScanner = StringScanner
6
- # rubocop:enable ConstantName
7
5
  else
8
6
  if Sass::Util.rbx?
9
7
  # Rubinius's StringScanner class implements some of its methods in terms of
@@ -2915,7 +2915,7 @@ SASS
2915
2915
  assert_equal <<CSS, render(<<SASS)
2916
2916
  div {
2917
2917
  maximum: 1.00000001;
2918
- too-much: 1.0; }
2918
+ too-much: 1; }
2919
2919
  CSS
2920
2920
  div
2921
2921
  maximum : 1.00000001
@@ -3322,13 +3322,45 @@ CSS
3322
3322
  SASS
3323
3323
  end
3324
3324
 
3325
+ def test_numeric_formatting_of_integers
3326
+ assert_equal(<<CSS, render(<<SASS, :syntax => :scss, :style => :compressed))
3327
+ a{near:3.00001;plus:3;minus:3;negative:-3}
3328
+ CSS
3329
+ a {
3330
+ near: (3 + 0.00001);
3331
+ plus: (3 + 0.0000001);
3332
+ minus: (3 - 0.0000001);
3333
+ negative: (-3 + 0.0000001);
3334
+ }
3335
+ SASS
3336
+ end
3337
+
3338
+ def test_escaped_semicolons_are_not_compressed
3339
+ assert_equal(<<'CSS', render(<<'SASS', :syntax => :scss, :style => :compressed))
3340
+ div{color:#f00000\9\0\;}
3341
+ CSS
3342
+ div {
3343
+ color: #f00000\9\0\;
3344
+ }
3345
+ SASS
3346
+ end
3347
+
3325
3348
  def test_compressed_output_of_nth_selectors
3326
3349
  assert_equal(<<CSS, render(<<SASS, :syntax => :scss, :style => :compressed))
3327
- :nth-of-type(2n-1),:nth-of-type(2n-1),:nth-of-type(2n-1),:nth-of-type(2n-1),:nth-of-type(2n-1){color:red}:nth-of-type(2n+1),:nth-of-type(2n+1),:nth-of-type(2n+1),:nth-of-type(2n+1),:nth-of-type(2n+1){color:red}
3350
+ :nth-of-type(2n-1),:nth-child(2n-1),:nth(2n-1),:nth-of-type(2n-1),:nth-of-type(2n-1){color:red}:nth-of-type(2n+1),:nth-child(2n+1),:nth(2n+1),:nth-of-type(2n+1),:nth-of-type(2n+1){color:red}
3328
3351
  CSS
3329
- :nth-of-type(2n-1), :nth-of-type(2n- 1), :nth-of-type(2n -1), :nth-of-type(2n - 1), :nth-of-type( 2n - 1 ) {
3352
+ :nth-of-type(2n-1), :nth-child(2n- 1), :nth(2n -1), :nth-of-type(2n - 1), :nth-of-type( 2n - 1 ) {
3330
3353
  color: red }
3331
- :nth-of-type(2n+1), :nth-of-type(2n+ 1), :nth-of-type(2n +1), :nth-of-type(2n + 1), :nth-of-type( 2n + 1 ) {
3354
+ :nth-of-type(2n+1), :nth-child(2n+ 1), :nth(2n +1), :nth-of-type(2n + 1), :nth-of-type( 2n + 1 ) {
3355
+ color: red }
3356
+ SASS
3357
+ end
3358
+
3359
+ def test_descendant_selectors_with_leading_dash
3360
+ assert_equal(<<CSS, render(<<SASS, :syntax => :scss, :style => :compressed))
3361
+ a -b{color:red}
3362
+ CSS
3363
+ a -b {
3332
3364
  color: red }
3333
3365
  SASS
3334
3366
  end
@@ -3350,6 +3382,15 @@ CSS
3350
3382
  SASS
3351
3383
  end
3352
3384
 
3385
+ def test_compressed_commas_in_attribute_selectors
3386
+ assert_equal(<<CSS, render(<<SASS, :style => :compressed))
3387
+ .classname[a="1, 2, 3"],.another[b="4, 5, 6"]{color:red}
3388
+ CSS
3389
+ .classname[a="1, 2, 3"], .another[b="4, 5, 6"]
3390
+ color: red
3391
+ SASS
3392
+ end
3393
+
3353
3394
  private
3354
3395
 
3355
3396
  def assert_hash_has(hash, expected)