sass 3.3.0 → 3.4.25

Sign up to get free protection for your applications and to get access to all the features.
Files changed (208) 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 +76 -62
  7. data/Rakefile +104 -24
  8. data/VERSION +1 -1
  9. data/VERSION_DATE +1 -1
  10. data/VERSION_NAME +1 -1
  11. data/bin/sass +1 -1
  12. data/bin/scss +1 -1
  13. data/extra/sass-spec-ref.sh +32 -0
  14. data/extra/update_watch.rb +1 -1
  15. data/lib/sass/cache_stores/filesystem.rb +9 -5
  16. data/lib/sass/cache_stores/memory.rb +4 -5
  17. data/lib/sass/callbacks.rb +2 -2
  18. data/lib/sass/css.rb +12 -13
  19. data/lib/sass/deprecation.rb +55 -0
  20. data/lib/sass/engine.rb +106 -70
  21. data/lib/sass/environment.rb +39 -19
  22. data/lib/sass/error.rb +17 -20
  23. data/lib/sass/exec/base.rb +199 -0
  24. data/lib/sass/exec/sass_convert.rb +283 -0
  25. data/lib/sass/exec/sass_scss.rb +440 -0
  26. data/lib/sass/exec.rb +5 -771
  27. data/lib/sass/features.rb +9 -2
  28. data/lib/sass/importers/base.rb +8 -3
  29. data/lib/sass/importers/filesystem.rb +30 -38
  30. data/lib/sass/logger/base.rb +8 -2
  31. data/lib/sass/logger/delayed.rb +50 -0
  32. data/lib/sass/logger.rb +8 -3
  33. data/lib/sass/media.rb +1 -4
  34. data/lib/sass/plugin/compiler.rb +224 -90
  35. data/lib/sass/plugin/configuration.rb +38 -22
  36. data/lib/sass/plugin/merb.rb +2 -2
  37. data/lib/sass/plugin/rack.rb +3 -3
  38. data/lib/sass/plugin/rails.rb +1 -1
  39. data/lib/sass/plugin/staleness_checker.rb +4 -4
  40. data/lib/sass/plugin.rb +6 -5
  41. data/lib/sass/script/css_lexer.rb +1 -1
  42. data/lib/sass/script/css_parser.rb +2 -3
  43. data/lib/sass/script/css_variable_warning.rb +52 -0
  44. data/lib/sass/script/functions.rb +739 -318
  45. data/lib/sass/script/lexer.rb +134 -54
  46. data/lib/sass/script/parser.rb +252 -56
  47. data/lib/sass/script/tree/funcall.rb +13 -6
  48. data/lib/sass/script/tree/interpolation.rb +127 -4
  49. data/lib/sass/script/tree/list_literal.rb +31 -4
  50. data/lib/sass/script/tree/literal.rb +4 -0
  51. data/lib/sass/script/tree/node.rb +21 -3
  52. data/lib/sass/script/tree/operation.rb +54 -1
  53. data/lib/sass/script/tree/selector.rb +26 -0
  54. data/lib/sass/script/tree/string_interpolation.rb +59 -38
  55. data/lib/sass/script/tree/variable.rb +1 -1
  56. data/lib/sass/script/tree.rb +1 -0
  57. data/lib/sass/script/value/base.rb +17 -14
  58. data/lib/sass/script/value/bool.rb +0 -5
  59. data/lib/sass/script/value/color.rb +78 -42
  60. data/lib/sass/script/value/helpers.rb +119 -2
  61. data/lib/sass/script/value/list.rb +0 -15
  62. data/lib/sass/script/value/map.rb +1 -1
  63. data/lib/sass/script/value/null.rb +0 -5
  64. data/lib/sass/script/value/number.rb +112 -31
  65. data/lib/sass/script/value/string.rb +102 -13
  66. data/lib/sass/script/value.rb +0 -1
  67. data/lib/sass/script.rb +3 -3
  68. data/lib/sass/scss/css_parser.rb +24 -4
  69. data/lib/sass/scss/parser.rb +290 -383
  70. data/lib/sass/scss/rx.rb +17 -9
  71. data/lib/sass/scss/static_parser.rb +306 -4
  72. data/lib/sass/scss.rb +0 -2
  73. data/lib/sass/selector/abstract_sequence.rb +35 -18
  74. data/lib/sass/selector/comma_sequence.rb +114 -19
  75. data/lib/sass/selector/pseudo.rb +266 -0
  76. data/lib/sass/selector/sequence.rb +146 -40
  77. data/lib/sass/selector/simple.rb +22 -33
  78. data/lib/sass/selector/simple_sequence.rb +122 -39
  79. data/lib/sass/selector.rb +57 -197
  80. data/lib/sass/shared.rb +2 -2
  81. data/lib/sass/source/map.rb +31 -14
  82. data/lib/sass/source/position.rb +4 -4
  83. data/lib/sass/stack.rb +2 -8
  84. data/lib/sass/supports.rb +10 -13
  85. data/lib/sass/tree/at_root_node.rb +1 -0
  86. data/lib/sass/tree/charset_node.rb +1 -1
  87. data/lib/sass/tree/comment_node.rb +1 -1
  88. data/lib/sass/tree/css_import_node.rb +9 -1
  89. data/lib/sass/tree/directive_node.rb +8 -2
  90. data/lib/sass/tree/error_node.rb +18 -0
  91. data/lib/sass/tree/extend_node.rb +1 -1
  92. data/lib/sass/tree/function_node.rb +9 -0
  93. data/lib/sass/tree/import_node.rb +6 -5
  94. data/lib/sass/tree/keyframe_rule_node.rb +15 -0
  95. data/lib/sass/tree/node.rb +5 -3
  96. data/lib/sass/tree/prop_node.rb +6 -7
  97. data/lib/sass/tree/rule_node.rb +26 -11
  98. data/lib/sass/tree/visitors/check_nesting.rb +56 -32
  99. data/lib/sass/tree/visitors/convert.rb +59 -44
  100. data/lib/sass/tree/visitors/cssize.rb +34 -30
  101. data/lib/sass/tree/visitors/deep_copy.rb +6 -1
  102. data/lib/sass/tree/visitors/extend.rb +15 -13
  103. data/lib/sass/tree/visitors/perform.rb +87 -50
  104. data/lib/sass/tree/visitors/set_options.rb +15 -1
  105. data/lib/sass/tree/visitors/to_css.rb +72 -43
  106. data/lib/sass/util/multibyte_string_scanner.rb +0 -2
  107. data/lib/sass/util/normalized_map.rb +0 -1
  108. data/lib/sass/util/subset_map.rb +2 -3
  109. data/lib/sass/util.rb +334 -154
  110. data/lib/sass/version.rb +7 -7
  111. data/lib/sass.rb +10 -8
  112. data/test/sass/cache_test.rb +62 -20
  113. data/test/sass/callbacks_test.rb +1 -1
  114. data/test/sass/compiler_test.rb +24 -11
  115. data/test/sass/conversion_test.rb +241 -50
  116. data/test/sass/css2sass_test.rb +73 -5
  117. data/test/sass/css_variable_test.rb +132 -0
  118. data/test/sass/encoding_test.rb +219 -0
  119. data/test/sass/engine_test.rb +343 -260
  120. data/test/sass/exec_test.rb +12 -2
  121. data/test/sass/extend_test.rb +333 -44
  122. data/test/sass/functions_test.rb +353 -260
  123. data/test/sass/importer_test.rb +40 -21
  124. data/test/sass/logger_test.rb +1 -1
  125. data/test/sass/more_results/more_import.css +1 -1
  126. data/test/sass/more_templates/more1.sass +10 -10
  127. data/test/sass/more_templates/more_import.sass +2 -2
  128. data/test/sass/plugin_test.rb +24 -21
  129. data/test/sass/results/compact.css +1 -1
  130. data/test/sass/results/complex.css +4 -4
  131. data/test/sass/results/expanded.css +1 -1
  132. data/test/sass/results/import.css +1 -1
  133. data/test/sass/results/import_charset_ibm866.css +2 -2
  134. data/test/sass/results/mixins.css +17 -17
  135. data/test/sass/results/nested.css +1 -1
  136. data/test/sass/results/parent_ref.css +2 -2
  137. data/test/sass/results/script.css +5 -5
  138. data/test/sass/results/scss_import.css +1 -1
  139. data/test/sass/script_conversion_test.rb +71 -39
  140. data/test/sass/script_test.rb +714 -123
  141. data/test/sass/scss/css_test.rb +213 -30
  142. data/test/sass/scss/rx_test.rb +8 -4
  143. data/test/sass/scss/scss_test.rb +766 -22
  144. data/test/sass/source_map_test.rb +263 -95
  145. data/test/sass/superselector_test.rb +210 -0
  146. data/test/sass/templates/_partial.sass +1 -1
  147. data/test/sass/templates/basic.sass +10 -10
  148. data/test/sass/templates/bork1.sass +1 -1
  149. data/test/sass/templates/bork5.sass +1 -1
  150. data/test/sass/templates/compact.sass +10 -10
  151. data/test/sass/templates/complex.sass +187 -187
  152. data/test/sass/templates/compressed.sass +10 -10
  153. data/test/sass/templates/expanded.sass +10 -10
  154. data/test/sass/templates/import.sass +2 -2
  155. data/test/sass/templates/importee.sass +3 -3
  156. data/test/sass/templates/mixins.sass +22 -22
  157. data/test/sass/templates/multiline.sass +4 -4
  158. data/test/sass/templates/nested.sass +13 -13
  159. data/test/sass/templates/parent_ref.sass +12 -12
  160. data/test/sass/templates/script.sass +70 -70
  161. data/test/sass/templates/scss_import.scss +2 -1
  162. data/test/sass/templates/subdir/nested_subdir/_nested_partial.sass +1 -1
  163. data/test/sass/templates/subdir/nested_subdir/nested_subdir.sass +2 -2
  164. data/test/sass/templates/subdir/subdir.sass +3 -3
  165. data/test/sass/templates/units.sass +10 -10
  166. data/test/sass/test_helper.rb +1 -1
  167. data/test/sass/util/multibyte_string_scanner_test.rb +11 -3
  168. data/test/sass/util/normalized_map_test.rb +1 -1
  169. data/test/sass/util/subset_map_test.rb +2 -2
  170. data/test/sass/util_test.rb +46 -45
  171. data/test/sass/value_helpers_test.rb +5 -7
  172. data/test/sass-spec.yml +3 -0
  173. data/test/test_helper.rb +7 -6
  174. data/vendor/listen/CHANGELOG.md +1 -228
  175. data/vendor/listen/Gemfile +5 -15
  176. data/vendor/listen/README.md +111 -77
  177. data/vendor/listen/Rakefile +0 -42
  178. data/vendor/listen/lib/listen/adapter.rb +195 -82
  179. data/vendor/listen/lib/listen/adapters/bsd.rb +27 -64
  180. data/vendor/listen/lib/listen/adapters/darwin.rb +21 -58
  181. data/vendor/listen/lib/listen/adapters/linux.rb +23 -55
  182. data/vendor/listen/lib/listen/adapters/polling.rb +25 -34
  183. data/vendor/listen/lib/listen/adapters/windows.rb +50 -46
  184. data/vendor/listen/lib/listen/directory_record.rb +96 -61
  185. data/vendor/listen/lib/listen/listener.rb +135 -37
  186. data/vendor/listen/lib/listen/turnstile.rb +9 -5
  187. data/vendor/listen/lib/listen/version.rb +1 -1
  188. data/vendor/listen/lib/listen.rb +33 -19
  189. data/vendor/listen/listen.gemspec +6 -0
  190. data/vendor/listen/spec/listen/adapter_spec.rb +43 -77
  191. data/vendor/listen/spec/listen/adapters/polling_spec.rb +8 -8
  192. data/vendor/listen/spec/listen/directory_record_spec.rb +81 -56
  193. data/vendor/listen/spec/listen/listener_spec.rb +128 -39
  194. data/vendor/listen/spec/listen_spec.rb +15 -21
  195. data/vendor/listen/spec/spec_helper.rb +4 -0
  196. data/vendor/listen/spec/support/adapter_helper.rb +52 -15
  197. data/vendor/listen/spec/support/directory_record_helper.rb +7 -5
  198. data/vendor/listen/spec/support/listeners_helper.rb +30 -7
  199. metadata +310 -300
  200. data/CONTRIBUTING +0 -3
  201. data/ext/mkrf_conf.rb +0 -27
  202. data/lib/sass/script/value/deprecated_false.rb +0 -55
  203. data/lib/sass/scss/script_lexer.rb +0 -15
  204. data/lib/sass/scss/script_parser.rb +0 -25
  205. data/vendor/listen/lib/listen/dependency_manager.rb +0 -126
  206. data/vendor/listen/lib/listen/multi_listener.rb +0 -143
  207. data/vendor/listen/spec/listen/dependency_manager_spec.rb +0 -107
  208. data/vendor/listen/spec/listen/multi_listener_spec.rb +0 -174
@@ -1,9 +1,10 @@
1
1
  #!/usr/bin/env ruby
2
2
  require File.dirname(__FILE__) + '/../test_helper'
3
+ require 'fileutils'
3
4
  require 'sass/util/test'
4
5
  require 'tmpdir'
5
6
 
6
- class ExecTest < Test::Unit::TestCase
7
+ class ExecTest < MiniTest::Test
7
8
  include Sass::Util::Test
8
9
 
9
10
  def setup
@@ -19,7 +20,7 @@ class ExecTest < Test::Unit::TestCase
19
20
  src = get_path("src.scss")
20
21
  dest = get_path("dest.css")
21
22
  write(src, ".ruleset { margin: 0 }")
22
- assert(exec(*%w[scss -t expanded --unix-newlines].push(src, dest)))
23
+ assert(exec(*%w[scss --sourcemap=none -t expanded --unix-newlines].push(src, dest)))
23
24
  assert_equal(".ruleset {\n margin: 0;\n}\n", read(dest))
24
25
  end
25
26
 
@@ -64,6 +65,14 @@ class ExecTest < Test::Unit::TestCase
64
65
  assert_equal(".ruleset\r\n margin: 0\r\n", read(src))
65
66
  end
66
67
 
68
+ def test_sass_convert_R
69
+ Dir.chdir(@dir) do
70
+ src = get_path("styles/src.css")
71
+ write(src, ".ruleset { margin: 0 }")
72
+ assert(exec(*%w[sass-convert -Rq --from css --to scss --trace styles]))
73
+ end
74
+ end
75
+
67
76
  private
68
77
 
69
78
  def get_path(name)
@@ -75,6 +84,7 @@ class ExecTest < Test::Unit::TestCase
75
84
  end
76
85
 
77
86
  def write(file, content)
87
+ FileUtils.mkdir_p(File.dirname(file))
78
88
  open(file, 'wb') {|f| f.write(content)}
79
89
  end
80
90
 
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env ruby
2
2
  require File.dirname(__FILE__) + '/../test_helper'
3
3
 
4
- class ExtendTest < Test::Unit::TestCase
4
+ class ExtendTest < MiniTest::Test
5
5
  def test_basic
6
6
  assert_equal <<CSS, render(<<SCSS)
7
7
  .foo, .bar {
@@ -145,8 +145,8 @@ SCSS
145
145
  end
146
146
 
147
147
  def test_class_unification
148
- assert_unification '.foo.bar', '.baz {@extend .foo}', '.foo.bar, .bar.baz'
149
- assert_unification '.foo.baz', '.baz {@extend .foo}', '.baz'
148
+ assert_unification '.foo.bar', '.baz {@extend .foo}', '.foo.bar, .bar.baz'
149
+ assert_unification '.foo.baz', '.baz {@extend .foo}', '.baz'
150
150
  end
151
151
 
152
152
  def test_id_unification
@@ -167,42 +167,52 @@ SCSS
167
167
  end
168
168
 
169
169
  def test_universal_unification_with_namespaceless_universal_target
170
+ assert_extend_doesnt_match('ns|*', '.foo', :failed_to_unify, 2) do
171
+ render_unification '*.foo', 'ns|* {@extend .foo}'
172
+ end
173
+
170
174
  assert_unification '*.foo', '* {@extend .foo}', '*'
171
175
  assert_unification '*.foo', '*|* {@extend .foo}', '*'
172
176
  assert_unification '*|*.foo', '* {@extend .foo}', '*|*.foo, *'
173
177
  assert_unification '*|*.foo', '*|* {@extend .foo}', '*|*'
174
- assert_unification '*.foo', 'ns|* {@extend .foo}', '*.foo, ns|*'
175
178
  assert_unification '*|*.foo', 'ns|* {@extend .foo}', '*|*.foo, ns|*'
176
179
  end
177
180
 
178
181
  def test_universal_unification_with_namespaced_universal_target
179
- assert_unification 'ns|*.foo', '* {@extend .foo}', 'ns|*'
180
- assert_unification 'ns|*.foo', '*|* {@extend .foo}', 'ns|*'
182
+ assert_extend_doesnt_match('*', '.foo', :failed_to_unify, 2) do
183
+ render_unification 'ns|*.foo', '* {@extend .foo}'
184
+ end
181
185
 
182
186
  assert_extend_doesnt_match('ns2|*', '.foo', :failed_to_unify, 2) do
183
187
  render_unification 'ns1|*.foo', 'ns2|* {@extend .foo}'
184
188
  end
185
189
 
190
+ assert_unification 'ns|*.foo', '*|* {@extend .foo}', 'ns|*'
186
191
  assert_unification 'ns|*.foo', 'ns|* {@extend .foo}', 'ns|*'
187
192
  end
188
193
 
189
194
  def test_universal_unification_with_namespaceless_element_target
195
+ assert_extend_doesnt_match('ns|*', '.foo', :failed_to_unify, 2) do
196
+ render_unification 'a.foo', 'ns|* {@extend .foo}'
197
+ end
198
+
190
199
  assert_unification 'a.foo', '* {@extend .foo}', 'a'
191
200
  assert_unification 'a.foo', '*|* {@extend .foo}', 'a'
192
201
  assert_unification '*|a.foo', '* {@extend .foo}', '*|a.foo, a'
193
202
  assert_unification '*|a.foo', '*|* {@extend .foo}', '*|a'
194
- assert_unification 'a.foo', 'ns|* {@extend .foo}', 'a.foo, ns|a'
195
203
  assert_unification '*|a.foo', 'ns|* {@extend .foo}', '*|a.foo, ns|a'
196
204
  end
197
205
 
198
206
  def test_universal_unification_with_namespaced_element_target
199
- assert_unification 'ns|a.foo', '* {@extend .foo}', 'ns|a'
200
- assert_unification 'ns|a.foo', '*|* {@extend .foo}', 'ns|a'
207
+ assert_extend_doesnt_match('*', '.foo', :failed_to_unify, 2) do
208
+ render_unification 'ns|a.foo', '* {@extend .foo}'
209
+ end
201
210
 
202
211
  assert_extend_doesnt_match('ns2|*', '.foo', :failed_to_unify, 2) do
203
212
  render_unification 'ns1|a.foo', 'ns2|* {@extend .foo}'
204
213
  end
205
214
 
215
+ assert_unification 'ns|a.foo', '*|* {@extend .foo}', 'ns|a'
206
216
  assert_unification 'ns|a.foo', 'ns|* {@extend .foo}', 'ns|a'
207
217
  end
208
218
 
@@ -214,46 +224,56 @@ SCSS
214
224
  end
215
225
 
216
226
  def test_element_unification_with_namespaceless_universal_target
227
+ assert_extend_doesnt_match('ns|a', '.foo', :failed_to_unify, 2) do
228
+ render_unification '*.foo', 'ns|a {@extend .foo}'
229
+ end
230
+
217
231
  assert_unification '*.foo', 'a {@extend .foo}', '*.foo, a'
218
232
  assert_unification '*.foo', '*|a {@extend .foo}', '*.foo, a'
219
233
  assert_unification '*|*.foo', 'a {@extend .foo}', '*|*.foo, a'
220
234
  assert_unification '*|*.foo', '*|a {@extend .foo}', '*|*.foo, *|a'
221
- assert_unification '*.foo', 'ns|a {@extend .foo}', '*.foo, ns|a'
222
235
  assert_unification '*|*.foo', 'ns|a {@extend .foo}', '*|*.foo, ns|a'
223
236
  end
224
237
 
225
238
  def test_element_unification_with_namespaced_universal_target
226
- assert_unification 'ns|*.foo', 'a {@extend .foo}', 'ns|*.foo, ns|a'
227
- assert_unification 'ns|*.foo', '*|a {@extend .foo}', 'ns|*.foo, ns|a'
239
+ assert_extend_doesnt_match('a', '.foo', :failed_to_unify, 2) do
240
+ render_unification 'ns|*.foo', 'a {@extend .foo}'
241
+ end
228
242
 
229
243
  assert_extend_doesnt_match('ns2|a', '.foo', :failed_to_unify, 2) do
230
244
  render_unification 'ns1|*.foo', 'ns2|a {@extend .foo}'
231
245
  end
232
246
 
247
+ assert_unification 'ns|*.foo', '*|a {@extend .foo}', 'ns|*.foo, ns|a'
233
248
  assert_unification 'ns|*.foo', 'ns|a {@extend .foo}', 'ns|*.foo, ns|a'
234
249
  end
235
250
 
236
251
  def test_element_unification_with_namespaceless_element_target
252
+ assert_extend_doesnt_match('ns|a', '.foo', :failed_to_unify, 2) do
253
+ render_unification 'a.foo', 'ns|a {@extend .foo}'
254
+ end
255
+
256
+ assert_extend_doesnt_match('h1', '.foo', :failed_to_unify, 2) do
257
+ render_unification 'a.foo', 'h1 {@extend .foo}'
258
+ end
259
+
237
260
  assert_unification 'a.foo', 'a {@extend .foo}', 'a'
238
261
  assert_unification 'a.foo', '*|a {@extend .foo}', 'a'
239
262
  assert_unification '*|a.foo', 'a {@extend .foo}', '*|a.foo, a'
240
263
  assert_unification '*|a.foo', '*|a {@extend .foo}', '*|a'
241
- assert_unification 'a.foo', 'ns|a {@extend .foo}', 'a.foo, ns|a'
242
264
  assert_unification '*|a.foo', 'ns|a {@extend .foo}', '*|a.foo, ns|a'
243
-
244
- assert_extend_doesnt_match('h1', '.foo', :failed_to_unify, 2) do
245
- render_unification 'a.foo', 'h1 {@extend .foo}'
246
- end
247
265
  end
248
266
 
249
267
  def test_element_unification_with_namespaced_element_target
250
- assert_unification 'ns|a.foo', 'a {@extend .foo}', 'ns|a'
251
- assert_unification 'ns|a.foo', '*|a {@extend .foo}', 'ns|a'
268
+ assert_extend_doesnt_match('a', '.foo', :failed_to_unify, 2) do
269
+ render_unification 'ns|a.foo', 'a {@extend .foo}'
270
+ end
252
271
 
253
272
  assert_extend_doesnt_match('ns2|a', '.foo', :failed_to_unify, 2) do
254
273
  render_unification 'ns1|a.foo', 'ns2|a {@extend .foo}'
255
274
  end
256
275
 
276
+ assert_unification 'ns|a.foo', '*|a {@extend .foo}', 'ns|a'
257
277
  assert_unification 'ns|a.foo', 'ns|a {@extend .foo}', 'ns|a'
258
278
  end
259
279
 
@@ -310,9 +330,207 @@ SCSS
310
330
  end
311
331
 
312
332
  def test_negation_unification
313
- assert_unification ':not(.foo).baz', ':not(.bar) {@extend .baz}', ':not(.foo).baz, :not(.foo):not(.bar)'
314
- assert_unification ':not(.foo).baz', ':not(.foo) {@extend .baz}', ':not(.foo)'
315
- assert_unification ':not([a=b]).baz', ':not([a = b]) {@extend .baz}', ':not([a=b])'
333
+ assert_extends ':not(.foo).baz', ':not(.bar) {@extend .baz}', ':not(.foo).baz, :not(.foo):not(.bar)'
334
+ # Unifying to :not(.foo) here would reduce the specificity of the original selector.
335
+ assert_extends ':not(.foo).baz', ':not(.foo) {@extend .baz}', ':not(.foo).baz, :not(.foo)'
336
+ end
337
+
338
+ def test_prefixed_pseudoclass_unification
339
+ assert_unification(
340
+ ':nth-child(2n+1 of .foo).baz',
341
+ ':nth-child(2n of .foo) {@extend .baz}',
342
+ ':nth-child(2n+1 of .foo).baz, :nth-child(2n+1 of .foo):nth-child(2n of .foo)')
343
+
344
+ assert_unification(
345
+ ':nth-child(2n+1 of .foo).baz',
346
+ ':nth-child(2n+1 of .bar) {@extend .baz}',
347
+ ':nth-child(2n+1 of .foo).baz, :nth-child(2n+1 of .foo):nth-child(2n+1 of .bar)')
348
+
349
+ assert_unification(
350
+ ':nth-child(2n+1 of .foo).baz',
351
+ ':nth-child(2n+1 of .foo) {@extend .baz}',
352
+ ':nth-child(2n+1 of .foo)')
353
+ end
354
+
355
+ def test_extend_into_not
356
+ assert_extends(':not(.foo)', '.x {@extend .foo}', ':not(.foo):not(.x)')
357
+ assert_extends(':not(.foo.bar)', '.x {@extend .bar}', ':not(.foo.bar):not(.foo.x)')
358
+ assert_extends(
359
+ ':not(.foo.bar, .baz.bar)',
360
+ '.x {@extend .bar}',
361
+ ':not(.foo.bar, .foo.x, .baz.bar, .baz.x)')
362
+ end
363
+
364
+ def test_extend_into_mergeable_pseudoclasses
365
+ assert_extends(':matches(.foo)', '.x {@extend .foo}', ':matches(.foo, .x)')
366
+ assert_extends(':matches(.foo.bar)', '.x {@extend .bar}', ':matches(.foo.bar, .foo.x)')
367
+ assert_extends(
368
+ ':matches(.foo.bar, .baz.bar)',
369
+ '.x {@extend .bar}',
370
+ ':matches(.foo.bar, .foo.x, .baz.bar, .baz.x)')
371
+
372
+ assert_extends(':-moz-any(.foo)', '.x {@extend .foo}', ':-moz-any(.foo, .x)')
373
+ assert_extends(':current(.foo)', '.x {@extend .foo}', ':current(.foo, .x)')
374
+ assert_extends(':has(.foo)', '.x {@extend .foo}', ':has(.foo, .x)')
375
+ assert_extends(':host(.foo)', '.x {@extend .foo}', ':host(.foo, .x)')
376
+ assert_extends(':host-context(.foo)', '.x {@extend .foo}', ':host-context(.foo, .x)')
377
+ assert_extends(':nth-child(n of .foo)', '.x {@extend .foo}', ':nth-child(n of .foo, .x)')
378
+ assert_extends(
379
+ ':nth-last-child(n of .foo)',
380
+ '.x {@extend .foo}',
381
+ ':nth-last-child(n of .foo, .x)')
382
+ end
383
+
384
+ def test_complex_extend_into_pseudoclass
385
+ # Unlike other selectors, we don't allow complex selectors to be
386
+ # added to `:not` if they weren't there before. At time of
387
+ # writing, most browsers don't support that and will throw away
388
+ # the entire selector if it exists.
389
+ #assert_extends(':not(.bar)', '.x .y {@extend .bar}', ':not(.bar)')
390
+
391
+ # If the `:not()` already has a complex selector, we won't break
392
+ # anything by adding a new one.
393
+ assert_extends(':not(.baz .bar)', '.x .y {@extend .bar}',
394
+ ':not(.baz .bar):not(.baz .x .y):not(.x .baz .y)')
395
+
396
+ # If the `:not()` would only contain complex selectors, there's no
397
+ # harm in letting it continue to exist.
398
+ assert_extends(':not(%bar)', '.x .y {@extend %bar}', ':not(.x .y)')
399
+
400
+ assert_extends(':matches(.bar)', '.x .y {@extend .bar}', ':matches(.bar, .x .y)')
401
+ assert_extends(':current(.bar)', '.x .y {@extend .bar}', ':current(.bar, .x .y)')
402
+ assert_extends(':has(.bar)', '.x .y {@extend .bar}', ':has(.bar, .x .y)')
403
+ assert_extends(':host(.bar)', '.x .y {@extend .bar}', ':host(.bar, .x .y)')
404
+ assert_extends(':host-context(.bar)', '.x .y {@extend .bar}', ':host-context(.bar, .x .y)')
405
+ assert_extends(
406
+ ':-moz-any(.bar)',
407
+ '.x .y {@extend .bar}',
408
+ ':-moz-any(.bar, .x .y)')
409
+ assert_extends(
410
+ ':nth-child(n of .bar)',
411
+ '.x .y {@extend .bar}',
412
+ ':nth-child(n of .bar, .x .y)')
413
+ assert_extends(
414
+ ':nth-last-child(n of .bar)',
415
+ '.x .y {@extend .bar}',
416
+ ':nth-last-child(n of .bar, .x .y)')
417
+ end
418
+
419
+ def test_extend_over_selector_pseudoclass
420
+ assert_extends(':not(.foo)', '.x {@extend :not(.foo)}', ':not(.foo), .x')
421
+ assert_extends(
422
+ ':matches(.foo, .bar)',
423
+ '.x {@extend :matches(.foo, .bar)}',
424
+ ':matches(.foo, .bar), .x')
425
+ end
426
+
427
+ def test_matches_within_not
428
+ assert_extends(
429
+ ':not(.foo, .bar)',
430
+ ':matches(.x, .y) {@extend .foo}',
431
+ ':not(.foo, .x, .y, .bar)')
432
+ end
433
+
434
+ def test_pseudoclasses_merge
435
+ assert_extends(':matches(.foo)', ':matches(.bar) {@extend .foo}', ':matches(.foo, .bar)')
436
+ assert_extends(':-moz-any(.foo)', ':-moz-any(.bar) {@extend .foo}', ':-moz-any(.foo, .bar)')
437
+ assert_extends(':current(.foo)', ':current(.bar) {@extend .foo}', ':current(.foo, .bar)')
438
+ assert_extends(
439
+ ':nth-child(n of .foo)',
440
+ ':nth-child(n of .bar) {@extend .foo}',
441
+ ':nth-child(n of .foo, .bar)')
442
+ assert_extends(
443
+ ':nth-last-child(n of .foo)',
444
+ ':nth-last-child(n of .bar) {@extend .foo}',
445
+ ':nth-last-child(n of .foo, .bar)')
446
+ end
447
+
448
+ def test_nesting_pseudoclasses_merge
449
+ assert_extends(':has(.foo)', ':has(.bar) {@extend .foo}', ':has(.foo, :has(.bar))')
450
+ assert_extends(':host(.foo)', ':host(.bar) {@extend .foo}', ':host(.foo, :host(.bar))')
451
+ assert_extends(
452
+ ':host-context(.foo)',
453
+ ':host-context(.bar) {@extend .foo}',
454
+ ':host-context(.foo, :host-context(.bar))')
455
+ end
456
+
457
+ def test_not_unifies_with_unique_values
458
+ assert_unification('foo', ':not(bar) {@extend foo}', ':not(bar)')
459
+ assert_unification('#foo', ':not(#bar) {@extend #foo}', ':not(#bar)')
460
+ end
461
+
462
+ def test_not_adds_no_specificity
463
+ assert_specificity_equals(':not(.foo)', '.foo')
464
+ end
465
+
466
+ def test_matches_has_a_specificity_range
467
+ # `:matches(.foo, #bar)` has minimum specificity equal to that of `.foo`,
468
+ # which means `:matches(.foo, #bar) .a` can have less specificity than
469
+ # `#b.a`. Thus the selector generated by `#b.a` should be preserved.
470
+ assert_equal <<CSS, render(<<SCSS)
471
+ :matches(.foo, #bar) .a, :matches(.foo, #bar) #b.a {
472
+ a: b; }
473
+ CSS
474
+ :matches(.foo, #bar) %x {a: b}
475
+ .a {@extend %x}
476
+ #b.a {@extend %x}
477
+ SCSS
478
+
479
+ # `:matches(.foo, #bar)` has maximum specificity equal to that of `#bar`,
480
+ # which means `:matches(.foo, #bar).b` can have greater specificity than `.a
481
+ # .b`. Thus the selector generated by `:matches(.foo, #bar).b` should be
482
+ # preserved.
483
+ assert_equal <<CSS, render(<<SCSS)
484
+ .a .b, .a .b:matches(.foo, #bar) {
485
+ a: b; }
486
+ CSS
487
+ .a %x {a: b}
488
+ .b {@extend %x}
489
+ .b:matches(.foo, #bar) {@extend %x}
490
+ SCSS
491
+ end
492
+
493
+ def test_extend_into_not_and_normal_extend
494
+ assert_equal <<CSS, render(<<SCSS)
495
+ .x:not(.y):not(.bar), .foo:not(.y):not(.bar) {
496
+ a: b; }
497
+ CSS
498
+ .x:not(.y) {a: b}
499
+ .foo {@extend .x}
500
+ .bar {@extend .y}
501
+ SCSS
502
+ end
503
+
504
+ def test_extend_into_matches_and_normal_extend
505
+ assert_equal <<CSS, render(<<SCSS)
506
+ .x:matches(.y, .bar), .foo:matches(.y, .bar) {
507
+ a: b; }
508
+ CSS
509
+ .x:matches(.y) {a: b}
510
+ .foo {@extend .x}
511
+ .bar {@extend .y}
512
+ SCSS
513
+ end
514
+
515
+ def test_multilayer_pseudoclass_extend
516
+ assert_equal <<CSS, render(<<SCSS)
517
+ :matches(.x, .foo, .bar) {
518
+ a: b; }
519
+ CSS
520
+ :matches(.x) {a: b}
521
+ .foo {@extend .x}
522
+ .bar {@extend .foo}
523
+ SCSS
524
+ end
525
+
526
+ def test_root_only_allowed_at_root
527
+ assert_extends(':root .foo', '.bar .baz {@extend .foo}',
528
+ ':root .foo, :root .bar .baz')
529
+ assert_extends('.foo:root .bar', '.baz:root .bang {@extend .bar}',
530
+ '.foo:root .bar, .baz.foo:root .bang')
531
+ assert_extends('html:root .bar', 'xml:root .bang {@extend .bar}', 'html:root .bar')
532
+ assert_extends('.foo:root > .bar .x', '.baz:root .bang .y {@extend .x}',
533
+ '.foo:root > .bar .x, .baz.foo:root > .bar .bang .y')
316
534
  end
317
535
 
318
536
  def test_comma_extendee
@@ -340,24 +558,42 @@ CSS
340
558
  SCSS
341
559
  end
342
560
 
561
+ def test_nested_pseudo_selectors
562
+ assert_equal <<CSS, render(<<SCSS)
563
+ .foo .bar:not(.baz), .bang .bar:not(.baz) {
564
+ a: b; }
565
+ CSS
566
+ .foo {
567
+ .bar:not(.baz) {a: b}
568
+ }
569
+ .bang {@extend .foo}
570
+ SCSS
571
+ end
572
+
343
573
  ## Long Extendees
344
574
 
345
575
  def test_long_extendee
346
- assert_extends '.foo.bar', '.baz {@extend .foo.bar}', '.foo.bar, .baz'
576
+ assert_warning(<<WARNING) {assert_extends '.foo.bar', '.baz {@extend .foo.bar}', '.foo.bar, .baz'}
577
+ DEPRECATION WARNING on line 2 of test_long_extendee_inline.scss:
578
+ Extending a compound selector, .foo.bar, is deprecated and will not be supported in a future release.
579
+ See https://github.com/sass/sass/issues/1599 for details.
580
+ WARNING
347
581
  end
348
582
 
349
583
  def test_long_extendee_requires_all_selectors
350
- assert_extend_doesnt_match('.baz', '.foo.bar', :not_found, 2) do
351
- render_extends '.foo', '.baz {@extend .foo.bar}'
584
+ silence_warnings do
585
+ assert_extend_doesnt_match('.baz', '.foo.bar', :not_found, 2) do
586
+ render_extends '.foo', '.baz {@extend .foo.bar}'
587
+ end
352
588
  end
353
589
  end
354
590
 
355
591
  def test_long_extendee_matches_supersets
356
- assert_extends '.foo.bar.bap', '.baz {@extend .foo.bar}', '.foo.bar.bap, .bap.baz'
592
+ silence_warnings {assert_extends '.foo.bar.bap', '.baz {@extend .foo.bar}', '.foo.bar.bap, .bap.baz'}
357
593
  end
358
594
 
359
595
  def test_long_extendee_runs_unification
360
- assert_extends 'ns|*.foo.bar', 'a.baz {@extend .foo.bar}', 'ns|*.foo.bar, ns|a.baz'
596
+ silence_warnings {assert_extends 'ns|*.foo.bar', '*|a.baz {@extend .foo.bar}', 'ns|*.foo.bar, ns|a.baz'}
361
597
  end
362
598
 
363
599
  ## Long Extenders
@@ -367,7 +603,7 @@ SCSS
367
603
  end
368
604
 
369
605
  def test_long_extender_runs_unification
370
- assert_extends 'ns|*.foo.bar', 'a.baz {@extend .foo}', 'ns|*.foo.bar, ns|a.bar.baz'
606
+ assert_extends 'ns|*.foo.bar', '*|a.baz {@extend .foo}', 'ns|*.foo.bar, ns|a.bar.baz'
371
607
  end
372
608
 
373
609
  def test_long_extender_aborts_unification
@@ -453,9 +689,9 @@ SCSS
453
689
  end
454
690
 
455
691
  def test_nested_extender_doesnt_find_common_selectors_around_reference_selector
456
- assert_extends 'a /for/ b c .c1', 'a c .c2 {@extend .c1}', 'a /for/ b c .c1, a /for/ b a c .c2, a a /for/ b c .c2'
457
- assert_extends 'a /for/ b c .c1', 'a b .c2 {@extend .c1}', 'a /for/ b c .c1, a a /for/ b c .c2'
458
- assert_extends 'a /for/ b c .c1', 'b c .c2 {@extend .c1}', 'a /for/ b c .c1, a /for/ b c .c2'
692
+ silence_warnings {assert_extends 'a /for/ b c .c1', 'a c .c2 {@extend .c1}', 'a /for/ b c .c1, a /for/ b a c .c2, a a /for/ b c .c2'}
693
+ silence_warnings {assert_extends 'a /for/ b c .c1', 'a b .c2 {@extend .c1}', 'a /for/ b c .c1, a a /for/ b c .c2'}
694
+ silence_warnings {assert_extends 'a /for/ b c .c1', 'b c .c2 {@extend .c1}', 'a /for/ b c .c1, a /for/ b c .c2'}
459
695
  end
460
696
 
461
697
  def test_nested_extender_with_early_child_selectors_doesnt_subseq_them
@@ -516,7 +752,7 @@ SCSS
516
752
  end
517
753
 
518
754
  def test_nested_extender_with_trailing_child_selector
519
- assert_raise(Sass::SyntaxError, "bar > can't extend: invalid selector") do
755
+ assert_raises(Sass::SyntaxError, "bar > can't extend: invalid selector") do
520
756
  render("bar > {@extend .baz}")
521
757
  end
522
758
  end
@@ -650,10 +886,10 @@ SCSS
650
886
 
651
887
  def test_basic_extend_loop
652
888
  assert_equal <<CSS, render(<<SCSS)
653
- .bar, .foo {
889
+ .foo, .bar {
654
890
  a: b; }
655
891
 
656
- .foo, .bar {
892
+ .bar, .foo {
657
893
  c: d; }
658
894
  CSS
659
895
  .foo {a: b; @extend .bar}
@@ -663,13 +899,13 @@ SCSS
663
899
 
664
900
  def test_three_level_extend_loop
665
901
  assert_equal <<CSS, render(<<SCSS)
666
- .baz, .bar, .foo {
902
+ .foo, .baz, .bar {
667
903
  a: b; }
668
904
 
669
- .foo, .baz, .bar {
905
+ .bar, .foo, .baz {
670
906
  c: d; }
671
907
 
672
- .bar, .foo, .baz {
908
+ .baz, .bar, .foo {
673
909
  e: f; }
674
910
  CSS
675
911
  .foo {a: b; @extend .bar}
@@ -692,6 +928,18 @@ CSS
692
928
  SCSS
693
929
  end
694
930
 
931
+ def test_cross_loop
932
+ # The first law of extend means the selector should stick around.
933
+ assert_equal <<CSS, render(<<SCSS)
934
+ .foo.bar, .foo, .bar {
935
+ a: b; }
936
+ CSS
937
+ .foo.bar {a: b}
938
+ .foo {@extend .bar}
939
+ .bar {@extend .foo}
940
+ SCSS
941
+ end
942
+
695
943
  def test_multiple_extender_merges_with_superset_selector
696
944
  assert_equal <<CSS, render(<<SCSS)
697
945
  a.bar.baz, a.foo {
@@ -830,6 +1078,17 @@ $foo: foo;
830
1078
  SCSS
831
1079
  end
832
1080
 
1081
+ def test_placeholder_in_selector_pseudoclass
1082
+ assert_equal <<CSS, render(<<SCSS)
1083
+ :matches(.bar, .baz) {
1084
+ color: blue; }
1085
+ CSS
1086
+ :matches(%foo) {color: blue}
1087
+ .bar {@extend %foo}
1088
+ .baz {@extend %foo}
1089
+ SCSS
1090
+ end
1091
+
833
1092
  def test_media_in_placeholder_selector
834
1093
  assert_equal <<CSS, render(<<SCSS)
835
1094
  .baz {
@@ -1005,7 +1264,7 @@ SCSS
1005
1264
  end
1006
1265
 
1007
1266
  def test_extend_with_subject_transfers_subject_to_extender
1008
- assert_equal(<<CSS, render(<<SCSS))
1267
+ silence_warnings {assert_equal(<<CSS, render(<<SCSS))}
1009
1268
  foo bar! baz, foo .bip .bap! baz, .bip foo .bap! baz {
1010
1269
  a: b; }
1011
1270
  CSS
@@ -1013,7 +1272,7 @@ foo bar! baz {a: b}
1013
1272
  .bip .bap {@extend bar}
1014
1273
  SCSS
1015
1274
 
1016
- assert_equal(<<CSS, render(<<SCSS))
1275
+ silence_warnings {assert_equal(<<CSS, render(<<SCSS))}
1017
1276
  foo.x bar.y! baz.z, foo.x .bip bar.bap! baz.z, .bip foo.x bar.bap! baz.z {
1018
1277
  a: b; }
1019
1278
  CSS
@@ -1023,7 +1282,7 @@ SCSS
1023
1282
  end
1024
1283
 
1025
1284
  def test_extend_with_subject_retains_subject_on_target
1026
- assert_equal(<<CSS, render(<<SCSS))
1285
+ silence_warnings {assert_equal(<<CSS, render(<<SCSS))}
1027
1286
  .foo! .bar, .foo! .bip .bap, .bip .foo! .bap {
1028
1287
  a: b; }
1029
1288
  CSS
@@ -1033,7 +1292,7 @@ SCSS
1033
1292
  end
1034
1293
 
1035
1294
  def test_extend_with_subject_transfers_subject_to_target
1036
- assert_equal(<<CSS, render(<<SCSS))
1295
+ silence_warnings {assert_equal(<<CSS, render(<<SCSS))}
1037
1296
  a.foo .bar, .bip a.bap! .bar {
1038
1297
  a: b; }
1039
1298
  CSS
@@ -1043,7 +1302,7 @@ SCSS
1043
1302
  end
1044
1303
 
1045
1304
  def test_extend_with_subject_retains_subject_on_extender
1046
- assert_equal(<<CSS, render(<<SCSS))
1305
+ silence_warnings {assert_equal(<<CSS, render(<<SCSS))}
1047
1306
  .foo .bar, .foo .bip! .bap, .bip! .foo .bap {
1048
1307
  a: b; }
1049
1308
  CSS
@@ -1053,7 +1312,7 @@ SCSS
1053
1312
  end
1054
1313
 
1055
1314
  def test_extend_with_subject_fails_with_conflicting_subject
1056
- assert_equal(<<CSS, render(<<SCSS))
1315
+ silence_warnings {assert_equal(<<CSS, render(<<SCSS))}
1057
1316
  x! .bar {
1058
1317
  a: b; }
1059
1318
  CSS
@@ -1115,6 +1374,16 @@ SCSS
1115
1374
 
1116
1375
  # Regression Tests
1117
1376
 
1377
+ def test_extend_with_middle_pseudo
1378
+ assert_equal(<<CSS, render(<<SCSS))
1379
+ .btn:active.focus, :active.focus:before {
1380
+ a: b; }
1381
+ CSS
1382
+ .btn:active.focus {a: b}
1383
+ :before {@extend .btn}
1384
+ SCSS
1385
+ end
1386
+
1118
1387
  def test_extend_parent_selector_suffix
1119
1388
  assert_equal <<CSS, render(<<SCSS)
1120
1389
  .a-b, .c {
@@ -1408,7 +1677,7 @@ Use "@extend #{target} !optional" if the extend should be able to fail.
1408
1677
  ERR
1409
1678
  end
1410
1679
 
1411
- def assert_unification(selector, extension, unified)
1680
+ def assert_unification(selector, extension, unified, nested = true)
1412
1681
  # Do some trickery so the first law of extend doesn't get in our way.
1413
1682
  assert_extends(
1414
1683
  "%-a #{selector}",
@@ -1416,6 +1685,22 @@ ERR
1416
1685
  unified.split(', ').map {|s| "-a #{s}"}.join(', '))
1417
1686
  end
1418
1687
 
1688
+ def assert_specificity_equals(sel1, sel2)
1689
+ assert_specificity_gte(sel1, sel2)
1690
+ assert_specificity_gte(sel2, sel1)
1691
+ end
1692
+
1693
+ def assert_specificity_gte(sel1, sel2)
1694
+ assert_equal <<CSS, render(<<SCSS)
1695
+ #{sel1} .a {
1696
+ a: b; }
1697
+ CSS
1698
+ #{sel1} %-a {a: b}
1699
+ .a {@extend %-a}
1700
+ #{sel2}.a {@extend %-a}
1701
+ SCSS
1702
+ end
1703
+
1419
1704
  def render_unification(selector, extension)
1420
1705
  render_extends(
1421
1706
  "%-a #{selector}",
@@ -1429,6 +1714,10 @@ ERR
1429
1714
  CSS
1430
1715
  end
1431
1716
 
1717
+ def assert_extends_to_nothing(selector, extension)
1718
+ assert_equal '', render_extends(selector, extension)
1719
+ end
1720
+
1432
1721
  def render_extends(selector, extension)
1433
1722
  render(<<SCSS)
1434
1723
  #{selector} {a: b}