sass 3.4.0 → 3.4.25

Sign up to get free protection for your applications and to get access to all the features.
Files changed (142) hide show
  1. checksums.yaml +4 -4
  2. data/.yardopts +3 -1
  3. data/CODE_OF_CONDUCT.md +10 -0
  4. data/CONTRIBUTING.md +148 -0
  5. data/MIT-LICENSE +1 -1
  6. data/README.md +26 -20
  7. data/Rakefile +103 -20
  8. data/VERSION +1 -1
  9. data/VERSION_DATE +1 -1
  10. data/extra/sass-spec-ref.sh +32 -0
  11. data/extra/update_watch.rb +1 -1
  12. data/lib/sass/cache_stores/filesystem.rb +7 -7
  13. data/lib/sass/cache_stores/memory.rb +4 -5
  14. data/lib/sass/callbacks.rb +2 -2
  15. data/lib/sass/css.rb +11 -10
  16. data/lib/sass/deprecation.rb +55 -0
  17. data/lib/sass/engine.rb +83 -38
  18. data/lib/sass/environment.rb +26 -2
  19. data/lib/sass/error.rb +12 -12
  20. data/lib/sass/exec/base.rb +15 -3
  21. data/lib/sass/exec/sass_convert.rb +34 -15
  22. data/lib/sass/exec/sass_scss.rb +23 -7
  23. data/lib/sass/features.rb +2 -2
  24. data/lib/sass/importers/base.rb +1 -1
  25. data/lib/sass/importers/deprecated_path.rb +51 -0
  26. data/lib/sass/importers/filesystem.rb +24 -16
  27. data/lib/sass/importers.rb +1 -0
  28. data/lib/sass/logger/base.rb +8 -2
  29. data/lib/sass/logger/delayed.rb +50 -0
  30. data/lib/sass/logger.rb +8 -3
  31. data/lib/sass/plugin/compiler.rb +42 -25
  32. data/lib/sass/plugin/configuration.rb +38 -22
  33. data/lib/sass/plugin/merb.rb +2 -2
  34. data/lib/sass/plugin/rack.rb +3 -3
  35. data/lib/sass/plugin/rails.rb +1 -1
  36. data/lib/sass/plugin/staleness_checker.rb +3 -3
  37. data/lib/sass/plugin.rb +3 -2
  38. data/lib/sass/script/css_parser.rb +2 -3
  39. data/lib/sass/script/css_variable_warning.rb +52 -0
  40. data/lib/sass/script/functions.rb +140 -73
  41. data/lib/sass/script/lexer.rb +37 -22
  42. data/lib/sass/script/parser.rb +235 -40
  43. data/lib/sass/script/tree/funcall.rb +12 -5
  44. data/lib/sass/script/tree/interpolation.rb +109 -4
  45. data/lib/sass/script/tree/list_literal.rb +31 -4
  46. data/lib/sass/script/tree/literal.rb +4 -0
  47. data/lib/sass/script/tree/node.rb +21 -3
  48. data/lib/sass/script/tree/operation.rb +54 -1
  49. data/lib/sass/script/tree/string_interpolation.rb +58 -37
  50. data/lib/sass/script/tree/variable.rb +1 -1
  51. data/lib/sass/script/value/base.rb +10 -9
  52. data/lib/sass/script/value/color.rb +42 -24
  53. data/lib/sass/script/value/helpers.rb +16 -6
  54. data/lib/sass/script/value/map.rb +1 -1
  55. data/lib/sass/script/value/number.rb +52 -19
  56. data/lib/sass/script/value/string.rb +46 -5
  57. data/lib/sass/script.rb +3 -3
  58. data/lib/sass/scss/css_parser.rb +16 -2
  59. data/lib/sass/scss/parser.rb +120 -75
  60. data/lib/sass/scss/rx.rb +9 -10
  61. data/lib/sass/scss/static_parser.rb +19 -14
  62. data/lib/sass/scss.rb +0 -2
  63. data/lib/sass/selector/abstract_sequence.rb +8 -6
  64. data/lib/sass/selector/comma_sequence.rb +25 -9
  65. data/lib/sass/selector/pseudo.rb +45 -35
  66. data/lib/sass/selector/sequence.rb +54 -18
  67. data/lib/sass/selector/simple.rb +11 -11
  68. data/lib/sass/selector/simple_sequence.rb +34 -15
  69. data/lib/sass/selector.rb +7 -10
  70. data/lib/sass/shared.rb +1 -1
  71. data/lib/sass/source/map.rb +7 -4
  72. data/lib/sass/source/position.rb +4 -4
  73. data/lib/sass/stack.rb +2 -2
  74. data/lib/sass/supports.rb +8 -10
  75. data/lib/sass/tree/comment_node.rb +1 -1
  76. data/lib/sass/tree/css_import_node.rb +9 -1
  77. data/lib/sass/tree/function_node.rb +8 -3
  78. data/lib/sass/tree/import_node.rb +6 -5
  79. data/lib/sass/tree/node.rb +5 -3
  80. data/lib/sass/tree/prop_node.rb +5 -6
  81. data/lib/sass/tree/rule_node.rb +14 -4
  82. data/lib/sass/tree/visitors/check_nesting.rb +18 -22
  83. data/lib/sass/tree/visitors/convert.rb +43 -26
  84. data/lib/sass/tree/visitors/cssize.rb +5 -1
  85. data/lib/sass/tree/visitors/deep_copy.rb +1 -1
  86. data/lib/sass/tree/visitors/extend.rb +15 -13
  87. data/lib/sass/tree/visitors/perform.rb +42 -17
  88. data/lib/sass/tree/visitors/set_options.rb +1 -1
  89. data/lib/sass/tree/visitors/to_css.rb +58 -30
  90. data/lib/sass/util/multibyte_string_scanner.rb +0 -2
  91. data/lib/sass/util/normalized_map.rb +0 -1
  92. data/lib/sass/util/subset_map.rb +1 -2
  93. data/lib/sass/util.rb +125 -68
  94. data/lib/sass/version.rb +2 -2
  95. data/lib/sass.rb +10 -3
  96. data/test/sass/compiler_test.rb +6 -2
  97. data/test/sass/conversion_test.rb +187 -53
  98. data/test/sass/css2sass_test.rb +50 -1
  99. data/test/sass/css_variable_test.rb +132 -0
  100. data/test/sass/engine_test.rb +207 -61
  101. data/test/sass/exec_test.rb +10 -0
  102. data/test/sass/extend_test.rb +101 -29
  103. data/test/sass/functions_test.rb +60 -9
  104. data/test/sass/importer_test.rb +9 -0
  105. data/test/sass/more_templates/more1.sass +10 -10
  106. data/test/sass/more_templates/more_import.sass +2 -2
  107. data/test/sass/plugin_test.rb +10 -8
  108. data/test/sass/results/script.css +3 -3
  109. data/test/sass/script_conversion_test.rb +58 -29
  110. data/test/sass/script_test.rb +430 -53
  111. data/test/sass/scss/css_test.rb +73 -7
  112. data/test/sass/scss/rx_test.rb +4 -0
  113. data/test/sass/scss/scss_test.rb +309 -4
  114. data/test/sass/source_map_test.rb +152 -74
  115. data/test/sass/superselector_test.rb +19 -0
  116. data/test/sass/templates/_partial.sass +1 -1
  117. data/test/sass/templates/basic.sass +10 -10
  118. data/test/sass/templates/bork1.sass +1 -1
  119. data/test/sass/templates/bork5.sass +1 -1
  120. data/test/sass/templates/compact.sass +10 -10
  121. data/test/sass/templates/complex.sass +187 -187
  122. data/test/sass/templates/compressed.sass +10 -10
  123. data/test/sass/templates/expanded.sass +10 -10
  124. data/test/sass/templates/import.sass +2 -2
  125. data/test/sass/templates/importee.sass +3 -3
  126. data/test/sass/templates/mixins.sass +22 -22
  127. data/test/sass/templates/multiline.sass +4 -4
  128. data/test/sass/templates/nested.sass +13 -13
  129. data/test/sass/templates/parent_ref.sass +12 -12
  130. data/test/sass/templates/script.sass +70 -70
  131. data/test/sass/templates/subdir/nested_subdir/_nested_partial.sass +1 -1
  132. data/test/sass/templates/subdir/nested_subdir/nested_subdir.sass +2 -2
  133. data/test/sass/templates/subdir/subdir.sass +3 -3
  134. data/test/sass/templates/units.sass +10 -10
  135. data/test/sass/util/multibyte_string_scanner_test.rb +10 -2
  136. data/test/sass/util_test.rb +15 -44
  137. data/test/sass-spec.yml +3 -0
  138. data/test/test_helper.rb +5 -4
  139. metadata +302 -295
  140. data/CONTRIBUTING +0 -3
  141. data/lib/sass/scss/script_lexer.rb +0 -15
  142. data/lib/sass/scss/script_parser.rb +0 -25
@@ -9,7 +9,7 @@ module Sass
9
9
  # selectors.
10
10
  #
11
11
  # @return [Set<String>]
12
- ACTUALLY_ELEMENTS = %w[after before first-line first-letter].to_set
12
+ ACTUALLY_ELEMENTS = %w(after before first-line first-letter).to_set
13
13
 
14
14
  # Like \{#type}, but returns the type of selector this looks like, rather
15
15
  # than the type it is semantically. This only differs from type for
@@ -51,40 +51,50 @@ module Sass
51
51
  # Returns a copy of this with \{#selector} set to \{#new\_selector}.
52
52
  #
53
53
  # @param new_selector [CommaSequence]
54
- # @return [CommaSequence]
54
+ # @return [Array<Simple>]
55
55
  def with_selector(new_selector)
56
- Pseudo.new(syntactic_type, name, arg, CommaSequence.new(new_selector.members.map do |seq|
57
- next seq unless seq.members.length == 1
58
- sseq = seq.members.first
59
- next seq unless sseq.is_a?(SimpleSequence) && sseq.members.length == 1
60
- sel = sseq.members.first
61
- next seq unless sel.is_a?(Pseudo) && sel.selector
56
+ result = Pseudo.new(syntactic_type, name, arg,
57
+ CommaSequence.new(new_selector.members.map do |seq|
58
+ next seq unless seq.members.length == 1
59
+ sseq = seq.members.first
60
+ next seq unless sseq.is_a?(SimpleSequence) && sseq.members.length == 1
61
+ sel = sseq.members.first
62
+ next seq unless sel.is_a?(Pseudo) && sel.selector
62
63
 
63
- case normalized_name
64
- when 'not'
65
- # In theory, if there's a nested :not its contents should be
66
- # unified with the return value. For example, if :not(.foo)
67
- # extends .bar, :not(.bar) should become .foo:not(.bar). However,
68
- # this is a narrow edge case and supporting it properly would make
69
- # this code and the code calling it a lot more complicated, so
70
- # it's not supported for now.
71
- next [] unless sel.normalized_name == 'matches'
72
- sel.selector.members
73
- when 'matches', 'any', 'current', 'nth-child', 'nth-last-child'
74
- # As above, we could theoretically support :not within :matches, but
75
- # doing so would require this method and its callers to handle much
76
- # more complex cases that likely aren't worth the pain.
77
- next [] unless sel.name == name && sel.arg == arg
78
- sel.selector.members
79
- when 'has', 'host', 'host-context'
80
- # We can't expand nested selectors here, because each layer adds an
81
- # additional layer of semantics. For example, `:has(:has(img))`
82
- # doesn't match `<div><img></div>` but `:has(img)` does.
83
- sel
84
- else
85
- []
86
- end
87
- end.flatten))
64
+ case normalized_name
65
+ when 'not'
66
+ # In theory, if there's a nested :not its contents should be
67
+ # unified with the return value. For example, if :not(.foo)
68
+ # extends .bar, :not(.bar) should become .foo:not(.bar). However,
69
+ # this is a narrow edge case and supporting it properly would make
70
+ # this code and the code calling it a lot more complicated, so
71
+ # it's not supported for now.
72
+ next [] unless sel.normalized_name == 'matches'
73
+ sel.selector.members
74
+ when 'matches', 'any', 'current', 'nth-child', 'nth-last-child'
75
+ # As above, we could theoretically support :not within :matches, but
76
+ # doing so would require this method and its callers to handle much
77
+ # more complex cases that likely aren't worth the pain.
78
+ next [] unless sel.name == name && sel.arg == arg
79
+ sel.selector.members
80
+ when 'has', 'host', 'host-context'
81
+ # We can't expand nested selectors here, because each layer adds an
82
+ # additional layer of semantics. For example, `:has(:has(img))`
83
+ # doesn't match `<div><img></div>` but `:has(img)` does.
84
+ sel
85
+ else
86
+ []
87
+ end
88
+ end.flatten))
89
+
90
+ # Older browsers support :not but only with a single complex selector.
91
+ # In order to support those browsers, we break up the contents of a :not
92
+ # unless it originally contained a selector list.
93
+ return [result] unless normalized_name == 'not'
94
+ return [result] if selector.members.length > 1
95
+ result.selector.members.map do |seq|
96
+ Pseudo.new(syntactic_type, name, arg, CommaSequence.new([seq]))
97
+ end
88
98
  end
89
99
 
90
100
  # The type of the selector. `:class` if this is a pseudoclass selector,
@@ -103,13 +113,13 @@ module Sass
103
113
  end
104
114
 
105
115
  # @see Selector#to_s
106
- def to_s
116
+ def to_s(opts = {})
107
117
  res = (syntactic_type == :class ? ":" : "::") + @name
108
118
  if @arg || @selector
109
119
  res << "("
110
120
  res << @arg.strip if @arg
111
121
  res << " " if @arg && @selector
112
- res << @selector.to_s if @selector
122
+ res << @selector.to_s(opts) if @selector
113
123
  res << ")"
114
124
  end
115
125
  res
@@ -6,11 +6,11 @@ module Sass
6
6
  # Sets the line of the Sass template on which this selector was declared.
7
7
  # This also sets the line for all child selectors.
8
8
  #
9
- # @param line [Fixnum]
10
- # @return [Fixnum]
9
+ # @param line [Integer]
10
+ # @return [Integer]
11
11
  def line=(line)
12
12
  members.each {|m| m.line = line if m.is_a?(SimpleSequence)}
13
- line
13
+ @line = line
14
14
  end
15
15
 
16
16
  # Sets the name of the file in which this selector was declared,
@@ -52,9 +52,7 @@ module Sass
52
52
  def resolve_parent_refs(super_cseq, implicit_parent)
53
53
  members = @members.dup
54
54
  nl = (members.first == "\n" && members.shift)
55
- contains_parent_ref = members.any? do |seq_or_op|
56
- seq_or_op.is_a?(SimpleSequence) && seq_or_op.members.first.is_a?(Parent)
57
- end
55
+ contains_parent_ref = contains_parent_ref?
58
56
  return CommaSequence.new([self]) if !implicit_parent && !contains_parent_ref
59
57
 
60
58
  unless contains_parent_ref
@@ -75,6 +73,19 @@ module Sass
75
73
  end)
76
74
  end
77
75
 
76
+ # Returns whether there's a {Parent} selector anywhere in this sequence.
77
+ #
78
+ # @return [Boolean]
79
+ def contains_parent_ref?
80
+ members.any? do |sseq_or_op|
81
+ next false unless sseq_or_op.is_a?(SimpleSequence)
82
+ next true if sseq_or_op.members.first.is_a?(Parent)
83
+ sseq_or_op.members.any? do |sel|
84
+ sel.is_a?(Pseudo) && sel.selector && sel.selector.contains_parent_ref?
85
+ end
86
+ end
87
+ end
88
+
78
89
  # Non-destructively extends this selector with the extensions specified in a hash
79
90
  # (which should come from {Sass::Tree::Visitors::Cssize}).
80
91
  #
@@ -146,8 +157,8 @@ module Sass
146
157
  end
147
158
 
148
159
  # @see AbstractSequence#to_s
149
- def to_s
150
- @members.join(" ").gsub(/ ?\n ?/, "\n")
160
+ def to_s(opts = {})
161
+ @members.map {|m| m.is_a?(String) ? m : m.to_s(opts)}.join(" ").gsub(/ ?\n ?/, "\n")
151
162
  end
152
163
 
153
164
  # Returns a string representation of the sequence.
@@ -217,11 +228,11 @@ module Sass
217
228
  next if current.empty?
218
229
  current = current.dup
219
230
  last_current = [current.pop]
220
- prefixes = Sass::Util.flatten(prefixes.map do |prefix|
231
+ prefixes = prefixes.map do |prefix|
221
232
  sub = subweave(prefix, current)
222
233
  next [] unless sub
223
234
  sub.map {|seqs| seqs + last_current}
224
- end, 1)
235
+ end.flatten(1)
225
236
  end
226
237
  prefixes
227
238
  end
@@ -249,10 +260,22 @@ module Sass
249
260
  return [seq1] if seq2.empty?
250
261
 
251
262
  seq1, seq2 = seq1.dup, seq2.dup
252
- init = merge_initial_ops(seq1, seq2)
253
- return unless init
254
- fin = merge_final_ops(seq1, seq2)
255
- return unless fin
263
+ return unless (init = merge_initial_ops(seq1, seq2))
264
+ return unless (fin = merge_final_ops(seq1, seq2))
265
+
266
+ # Make sure there's only one root selector in the output.
267
+ root1 = has_root?(seq1.first) && seq1.shift
268
+ root2 = has_root?(seq2.first) && seq2.shift
269
+ if root1 && root2
270
+ return unless (root = root1.unify(root2))
271
+ seq1.unshift root
272
+ seq2.unshift root
273
+ elsif root1
274
+ seq2.unshift root1
275
+ elsif root2
276
+ seq1.unshift root2
277
+ end
278
+
256
279
  seq1 = group_selectors(seq1)
257
280
  seq2 = group_selectors(seq2)
258
281
  lcs = Sass::Util.lcs(seq2, seq1) do |s1, s2|
@@ -263,6 +286,7 @@ module Sass
263
286
  end
264
287
 
265
288
  diff = [[init]]
289
+
266
290
  until lcs.empty?
267
291
  diff << chunks(seq1, seq2) {|s| parent_superselector?(s.first, lcs.first)} << [lcs.shift]
268
292
  seq1.shift
@@ -371,10 +395,10 @@ module Sass
371
395
  ([merged, '+'] if merged)
372
396
  ].compact
373
397
  end
374
- elsif op1 == '>' && %w[~ +].include?(op2)
398
+ elsif op1 == '>' && %w(~ +).include?(op2)
375
399
  res.unshift sel2, op2
376
400
  seq1.push sel1, op1
377
- elsif op2 == '>' && %w[~ +].include?(op1)
401
+ elsif op2 == '>' && %w(~ +).include?(op1)
378
402
  res.unshift sel1, op1
379
403
  seq2.push sel2, op2
380
404
  elsif op1 == op2
@@ -479,8 +503,15 @@ module Sass
479
503
 
480
504
  if seq1[1].is_a?(String)
481
505
  return unless seq2[si + 1].is_a?(String)
506
+
482
507
  # .foo ~ .bar is a superselector of .foo + .bar
483
508
  return unless seq1[1] == "~" ? seq2[si + 1] != ">" : seq1[1] == seq2[si + 1]
509
+
510
+ # .foo > .baz is not a superselector of .foo > .bar > .baz or .foo >
511
+ # .bar .baz, despite the fact that .baz is a superselector of .bar >
512
+ # .baz and .bar .baz. Same goes for + and ~.
513
+ return if seq1.length == 3 && seq2.length > 3
514
+
484
515
  return _superselector?(seq1[2..-1], seq2[si + 2..-1])
485
516
  elsif seq2[si + 1].is_a?(String)
486
517
  return unless seq2[si + 1] == ">"
@@ -520,7 +551,7 @@ module Sass
520
551
  def trim(seqses)
521
552
  # Avoid truly horrific quadratic behavior. TODO: I think there
522
553
  # may be a way to get perfect trimming without going quadratic.
523
- return Sass::Util.flatten(seqses, 1) if seqses.size > 100
554
+ return seqses.flatten(1) if seqses.size > 100
524
555
 
525
556
  # Keep the results in a separate array so we can be sure we aren't
526
557
  # comparing against an already-trimmed selector. This ensures that two
@@ -555,7 +586,7 @@ module Sass
555
586
  end
556
587
  end
557
588
  end
558
- Sass::Util.flatten(result, 1)
589
+ result.flatten(1)
559
590
  end
560
591
 
561
592
  def _hash
@@ -595,6 +626,11 @@ module Sass
595
626
  "(#{choices.join ', '})"
596
627
  end.join ' '
597
628
  end
629
+
630
+ def has_root?(sseq)
631
+ sseq.is_a?(SimpleSequence) &&
632
+ sseq.members.any? {|sel| sel.is_a?(Pseudo) && sel.normalized_name == "root"}
633
+ end
598
634
  end
599
635
  end
600
636
  end
@@ -5,7 +5,7 @@ module Sass
5
5
  class Simple
6
6
  # The line of the Sass template on which this selector was declared.
7
7
  #
8
- # @return [Fixnum]
8
+ # @return [Integer]
9
9
  attr_accessor :line
10
10
 
11
11
  # The name of the file in which this selector was declared,
@@ -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
 
@@ -34,7 +36,7 @@ module Sass
34
36
  # so if that contains information irrelevant to the identity of the selector,
35
37
  # this should be overridden.
36
38
  #
37
- # @return [Fixnum]
39
+ # @return [Integer]
38
40
  def hash
39
41
  @_hash ||= equality_key.hash
40
42
  end
@@ -70,14 +72,12 @@ module Sass
70
72
  # by the time extension and unification happen,
71
73
  # this exception will only ever be raised as a result of programmer error
72
74
  def unify(sels)
75
+ return sels.first.unify([self]) if sels.length == 1 && sels.first.is_a?(Universal)
73
76
  return sels if sels.any? {|sel2| eql?(sel2)}
74
77
  sels_with_ix = Sass::Util.enum_with_index(sels)
75
- _, i =
76
- if is_a?(Pseudo)
77
- sels_with_ix.find {|sel, _| sel.is_a?(Pseudo) && (sels.last.type == :element)}
78
- else
79
- sels_with_ix.find {|sel, _| sel.is_a?(Pseudo)}
80
- end
78
+ if !is_a?(Pseudo) || (sels.last.is_a?(Pseudo) && sels.last.type == :element)
79
+ _, i = sels_with_ix.find {|sel, _| sel.is_a?(Pseudo)}
80
+ end
81
81
  return sels + [self] unless i
82
82
  sels[0...i] + [self] + sels[i..-1]
83
83
  end
@@ -107,10 +107,10 @@ module Sass
107
107
  # could be found at all.
108
108
  # If the second value is `false`, the first should be ignored.
109
109
  def unify_namespaces(ns1, ns2)
110
- return nil, false unless ns1 == ns2 || ns1.nil? || ns1 == '*' || ns2.nil? || ns2 == '*'
111
110
  return ns2, true if ns1 == '*'
112
111
  return ns1, true if ns2 == '*'
113
- [ns1 || ns2, true]
112
+ return nil, false unless ns1 == ns2
113
+ [ns1, true]
114
114
  end
115
115
  end
116
116
  end
@@ -86,9 +86,14 @@ module Sass
86
86
  # @return [CommaSequence] This selector, with parent references resolved
87
87
  # @raise [Sass::SyntaxError] If a parent selector is invalid
88
88
  def resolve_parent_refs(super_cseq)
89
+ resolved_members = @members.map do |sel|
90
+ next sel unless sel.is_a?(Pseudo) && sel.selector
91
+ sel.with_selector(sel.selector.resolve_parent_refs(super_cseq, false))
92
+ end.flatten
93
+
89
94
  # Parent selector only appears as the first selector in the sequence
90
- unless (parent = @members.first).is_a?(Parent)
91
- return CommaSequence.new([Sequence.new([self])])
95
+ unless (parent = resolved_members.first).is_a?(Parent)
96
+ return CommaSequence.new([Sequence.new([SimpleSequence.new(resolved_members, subject?)])])
92
97
  end
93
98
 
94
99
  return super_cseq if @members.size == 1 && parent.suffix.nil?
@@ -128,9 +133,9 @@ module Sass
128
133
  end
129
134
 
130
135
  Sequence.new(members[0...-1] +
131
- [SimpleSequence.new(parent_sub + @members[1..-1], subject?)] +
136
+ [SimpleSequence.new(parent_sub + resolved_members[1..-1], subject?)] +
132
137
  [newline].compact)
133
- end)
138
+ end)
134
139
  end
135
140
 
136
141
  # Non-destructively extends this selector with the extensions specified in a hash
@@ -153,17 +158,31 @@ module Sass
153
158
  seen_with_pseudo_selectors = seen.dup
154
159
 
155
160
  modified_original = false
156
- members = Sass::Util.enum_with_index(self.members).map do |sel, i|
161
+ members = self.members.map do |sel|
157
162
  next sel unless sel.is_a?(Pseudo) && sel.selector
158
163
  next sel if seen.include?([sel])
159
- extended = sel.selector.do_extend(extends, parent_directives, replace, seen, !:original)
164
+ extended = sel.selector.do_extend(extends, parent_directives, replace, seen, false)
160
165
  next sel if extended == sel.selector
161
166
  extended.members.reject! {|seq| seq.has_placeholder?}
167
+
168
+ # For `:not()`, we usually want to get rid of any complex
169
+ # selectors because that will cause the selector to fail to
170
+ # parse on all browsers at time of writing. We can keep them
171
+ # if either the original selector had a complex selector, or
172
+ # the result of extending has only complex selectors,
173
+ # because either way we aren't breaking anything that isn't
174
+ # already broken.
175
+ if sel.normalized_name == 'not' &&
176
+ (sel.selector.members.none? {|seq| seq.members.length > 1} &&
177
+ extended.members.any? {|seq| seq.members.length == 1})
178
+ extended.members.reject! {|seq| seq.members.length > 1}
179
+ end
180
+
162
181
  modified_original = true
163
182
  result = sel.with_selector(extended)
164
- seen_with_pseudo_selectors << [result]
183
+ result.each {|new_sel| seen_with_pseudo_selectors << [new_sel]}
165
184
  result
166
- end
185
+ end.flatten
167
186
 
168
187
  groups = Sass::Util.group_by_to_a(extends[members.to_set]) {|ex| ex.extender}
169
188
  groups.map! do |seq, group|
@@ -185,7 +204,7 @@ module Sass
185
204
  groups.map! do |sels, seq|
186
205
  next [] if seen.include?(sels)
187
206
  seq.do_extend(
188
- extends, parent_directives, !:replace, seen_with_pseudo_selectors + [sels], !:original)
207
+ extends, parent_directives, false, seen_with_pseudo_selectors + [sels], false)
189
208
  end
190
209
  groups.flatten!
191
210
 
@@ -241,7 +260,7 @@ module Sass
241
260
 
242
261
  # Some psuedo-selectors can be subselectors of non-pseudo selectors.
243
262
  # Pull those out here so we can efficiently check against them below.
244
- their_subselector_pseudos = %w[matches any nth-child nth-last-child].
263
+ their_subselector_pseudos = %w(matches any nth-child nth-last-child).
245
264
  map {|name| their_spcs[name] || []}.flatten
246
265
 
247
266
  # If `self`'s non-pseudo simple selectors aren't a subset of `their_sseq`'s,
@@ -260,14 +279,14 @@ module Sass
260
279
  end
261
280
  end
262
281
 
263
- our_spcs.all? do |name, pseudos|
282
+ our_spcs.all? do |_name, pseudos|
264
283
  pseudos.all? {|pseudo| pseudo.superselector?(their_sseq, parents)}
265
284
  end
266
285
  end
267
286
 
268
287
  # @see Simple#to_s
269
- def to_s
270
- res = @members.join
288
+ def to_s(opts = {})
289
+ res = @members.map {|m| m.to_s(opts)}.join
271
290
  res << '!' if subject?
272
291
  res
273
292
  end
@@ -313,12 +332,12 @@ MESSAGE
313
332
  end
314
333
 
315
334
  def _hash
316
- [base, Sass::Util.set_hash(rest)].hash
335
+ [base, rest.hash].hash
317
336
  end
318
337
 
319
338
  def _eql?(other)
320
339
  other.base.eql?(base) && other.pseudo_elements == pseudo_elements &&
321
- Sass::Util.set_eql?(other.rest, rest) && other.subject? == subject?
340
+ other.rest.eql?(rest) && other.subject? == subject?
322
341
  end
323
342
  end
324
343
  end
data/lib/sass/selector.rb CHANGED
@@ -39,7 +39,7 @@ module Sass
39
39
  end
40
40
 
41
41
  # @see Selector#to_s
42
- def to_s
42
+ def to_s(opts = {})
43
43
  "&" + (@suffix || '')
44
44
  end
45
45
 
@@ -65,7 +65,7 @@ module Sass
65
65
  end
66
66
 
67
67
  # @see Selector#to_s
68
- def to_s
68
+ def to_s(opts = {})
69
69
  "." + @name
70
70
  end
71
71
 
@@ -88,7 +88,7 @@ module Sass
88
88
  end
89
89
 
90
90
  # @see Selector#to_s
91
- def to_s
91
+ def to_s(opts = {})
92
92
  "#" + @name
93
93
  end
94
94
 
@@ -123,7 +123,7 @@ module Sass
123
123
  end
124
124
 
125
125
  # @see Selector#to_s
126
- def to_s
126
+ def to_s(opts = {})
127
127
  "%" + @name
128
128
  end
129
129
 
@@ -147,7 +147,7 @@ module Sass
147
147
  end
148
148
 
149
149
  # @see Selector#to_s
150
- def to_s
150
+ def to_s(opts = {})
151
151
  @namespace ? "#{@namespace}|*" : "*"
152
152
  end
153
153
 
@@ -219,7 +219,7 @@ module Sass
219
219
  end
220
220
 
221
221
  # @see Selector#to_s
222
- def to_s
222
+ def to_s(opts = {})
223
223
  @namespace ? "#{@namespace}|#{@name}" : @name
224
224
  end
225
225
 
@@ -296,10 +296,7 @@ module Sass
296
296
  # @param operator [String] The matching operator, e.g. `"="` or `"^="`
297
297
  # @param value [String] See \{#value}
298
298
  # @param flags [String] See \{#flags}
299
- # @comment
300
- # rubocop:disable ParameterLists
301
299
  def initialize(name, namespace, operator, value, flags)
302
- # rubocop:enable ParameterLists
303
300
  @name = name
304
301
  @namespace = namespace
305
302
  @operator = operator
@@ -308,7 +305,7 @@ module Sass
308
305
  end
309
306
 
310
307
  # @see Selector#to_s
311
- def to_s
308
+ def to_s(opts = {})
312
309
  res = "["
313
310
  res << @namespace << "|" if @namespace
314
311
  res << @name
data/lib/sass/shared.rb CHANGED
@@ -31,7 +31,7 @@ module Sass
31
31
  # A `Fixnum` in 1.8, a `String` in 1.9
32
32
  # @param finish [Character] The character closing the balanced pair.
33
33
  # A `Fixnum` in 1.8, a `String` in 1.9
34
- # @param count [Fixnum] The number of opening characters matched
34
+ # @param count [Integer] The number of opening characters matched
35
35
  # before calling this method
36
36
  # @return [(String, String)] The string matched within the balanced pair
37
37
  # and the rest of the string.
@@ -37,7 +37,7 @@ module Sass::Source
37
37
 
38
38
  # Shifts all output source ranges forward one or more lines.
39
39
  #
40
- # @param delta [Fixnum] The number of lines to shift the ranges forward.
40
+ # @param delta [Integer] The number of lines to shift the ranges forward.
41
41
  def shift_output_lines(delta)
42
42
  return if delta == 0
43
43
  @data.each do |m|
@@ -49,7 +49,7 @@ module Sass::Source
49
49
  # Shifts any output source ranges that lie on the first line forward one or
50
50
  # more characters on that line.
51
51
  #
52
- # @param delta [Fixnum] The number of characters to shift the ranges
52
+ # @param delta [Integer] The number of characters to shift the ranges
53
53
  # forward.
54
54
  def shift_output_offsets(delta)
55
55
  return if delta == 0
@@ -95,7 +95,8 @@ module Sass::Source
95
95
  end
96
96
  css_path &&= Sass::Util.pathname(Sass::Util.absolute_path(css_path))
97
97
  sourcemap_path &&= Sass::Util.pathname(Sass::Util.absolute_path(sourcemap_path))
98
- css_uri ||= Sass::Util.file_uri_from_path(css_path.relative_path_from(sourcemap_path.dirname))
98
+ css_uri ||= Sass::Util.file_uri_from_path(
99
+ Sass::Util.relative_path_from(css_path, sourcemap_path.dirname))
99
100
 
100
101
  result = "{\n"
101
102
  write_json_field(result, "version", 3, true)
@@ -117,12 +118,14 @@ module Sass::Source
117
118
  @data.each do |m|
118
119
  file, importer = m.input.file, m.input.importer
119
120
 
121
+ next unless importer
122
+
120
123
  if options[:type] == :inline
121
124
  source_uri = file
122
125
  else
123
126
  sourcemap_dir = sourcemap_path && sourcemap_path.dirname.to_s
124
127
  sourcemap_dir = nil if options[:type] == :file
125
- source_uri = importer && importer.public_url(file, sourcemap_dir)
128
+ source_uri = importer.public_url(file, sourcemap_dir)
126
129
  next unless source_uri
127
130
  end
128
131
 
@@ -2,17 +2,17 @@ module Sass::Source
2
2
  class Position
3
3
  # The one-based line of the document associated with the position.
4
4
  #
5
- # @return [Fixnum]
5
+ # @return [Integer]
6
6
  attr_accessor :line
7
7
 
8
8
  # The one-based offset in the line of the document associated with the
9
9
  # position.
10
10
  #
11
- # @return [Fixnum]
11
+ # @return [Integer]
12
12
  attr_accessor :offset
13
13
 
14
- # @param line [Fixnum] The source line
15
- # @param offset [Fixnum] The source offset
14
+ # @param line [Integer] The source line
15
+ # @param offset [Integer] The source offset
16
16
  def initialize(line, offset)
17
17
  @line = line
18
18
  @offset = offset
data/lib/sass/stack.rb CHANGED
@@ -101,8 +101,8 @@ module Sass
101
101
  def to_s
102
102
  Sass::Util.enum_with_index(Sass::Util.enum_cons(frames.reverse + [nil], 2)).
103
103
  map do |(frame, caller), i|
104
- "#{i == 0 ? "on" : "from"} line #{frame.line}" +
105
- " of #{frame.filename || "an unknown file"}" +
104
+ "#{i == 0 ? 'on' : 'from'} line #{frame.line}" +
105
+ " of #{frame.filename || 'an unknown file'}" +
106
106
  (caller && caller.name ? ", in `#{caller.name}'" : "")
107
107
  end.join("\n")
108
108
  end
data/lib/sass/supports.rb CHANGED
@@ -58,11 +58,11 @@ module Sass::Supports
58
58
  end
59
59
 
60
60
  def to_css
61
- "#{left_parens @left.to_css} #{op} #{right_parens @right.to_css}"
61
+ "#{parens @left, @left.to_css} #{op} #{parens @right, @right.to_css}"
62
62
  end
63
63
 
64
64
  def to_src(options)
65
- "#{left_parens @left.to_src(options)} #{op} #{right_parens @right.to_src(options)}"
65
+ "#{parens @left, @left.to_src(options)} #{op} #{parens @right, @right.to_src(options)}"
66
66
  end
67
67
 
68
68
  def deep_copy
@@ -79,14 +79,12 @@ module Sass::Supports
79
79
 
80
80
  private
81
81
 
82
- def left_parens(str)
83
- return "(#{str})" if @left.is_a?(Negation)
84
- str
85
- end
86
-
87
- def right_parens(str)
88
- return "(#{str})" if @right.is_a?(Negation) || @right.is_a?(Operator)
89
- str
82
+ def parens(condition, str)
83
+ if condition.is_a?(Negation) || (condition.is_a?(Operator) && condition.op != op)
84
+ return "(#{str})"
85
+ else
86
+ return str
87
+ end
90
88
  end
91
89
  end
92
90
 
@@ -59,7 +59,7 @@ module Sass::Tree
59
59
 
60
60
  # Returns the number of lines in the comment.
61
61
  #
62
- # @return [Fixnum]
62
+ # @return [Integer]
63
63
  def lines
64
64
  @value.inject(0) do |s, e|
65
65
  next s + e.count("\n") if e.is_a?(String)