sass 3.4.24 → 3.7.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (244) hide show
  1. checksums.yaml +4 -4
  2. data/CODE_OF_CONDUCT.md +1 -1
  3. data/CONTRIBUTING.md +3 -3
  4. data/README.md +17 -9
  5. data/VERSION +1 -1
  6. data/VERSION_DATE +1 -1
  7. data/VERSION_NAME +1 -1
  8. data/extra/sass-spec-ref.sh +9 -1
  9. data/lib/sass/cache_stores/filesystem.rb +1 -1
  10. data/lib/sass/css.rb +2 -3
  11. data/lib/sass/deprecation.rb +55 -0
  12. data/lib/sass/engine.rb +52 -34
  13. data/lib/sass/environment.rb +27 -6
  14. data/lib/sass/error.rb +2 -2
  15. data/lib/sass/exec/base.rb +2 -13
  16. data/lib/sass/exec/sass_scss.rb +1 -5
  17. data/lib/sass/features.rb +1 -0
  18. data/lib/sass/importers/filesystem.rb +6 -4
  19. data/lib/sass/logger/base.rb +11 -0
  20. data/lib/sass/plugin/compiler.rb +21 -51
  21. data/lib/sass/plugin/configuration.rb +2 -2
  22. data/lib/sass/plugin/rack.rb +2 -2
  23. data/lib/sass/plugin/staleness_checker.rb +1 -1
  24. data/lib/sass/plugin.rb +1 -1
  25. data/lib/sass/railtie.rb +1 -1
  26. data/lib/sass/script/css_parser.rb +4 -1
  27. data/lib/sass/script/functions.rb +310 -83
  28. data/lib/sass/script/lexer.rb +64 -10
  29. data/lib/sass/script/parser.rb +291 -121
  30. data/lib/sass/script/tree/funcall.rb +35 -34
  31. data/lib/sass/script/tree/interpolation.rb +0 -3
  32. data/lib/sass/script/tree/list_literal.rb +23 -8
  33. data/lib/sass/script/tree/map_literal.rb +2 -2
  34. data/lib/sass/script/tree/node.rb +1 -9
  35. data/lib/sass/script/tree/operation.rb +43 -23
  36. data/lib/sass/script/value/arg_list.rb +1 -1
  37. data/lib/sass/script/value/base.rb +18 -1
  38. data/lib/sass/script/value/callable.rb +25 -0
  39. data/lib/sass/script/value/color.rb +8 -2
  40. data/lib/sass/script/value/function.rb +19 -0
  41. data/lib/sass/script/value/helpers.rb +37 -11
  42. data/lib/sass/script/value/list.rb +35 -14
  43. data/lib/sass/script/value/map.rb +2 -2
  44. data/lib/sass/script/value/number.rb +3 -2
  45. data/lib/sass/script/value/string.rb +5 -12
  46. data/lib/sass/script/value.rb +2 -0
  47. data/lib/sass/script.rb +1 -1
  48. data/lib/sass/scss/css_parser.rb +6 -1
  49. data/lib/sass/scss/parser.rb +145 -56
  50. data/lib/sass/scss/rx.rb +5 -11
  51. data/lib/sass/scss/static_parser.rb +27 -42
  52. data/lib/sass/selector/abstract_sequence.rb +7 -6
  53. data/lib/sass/selector/comma_sequence.rb +21 -5
  54. data/lib/sass/selector/pseudo.rb +20 -3
  55. data/lib/sass/selector/sequence.rb +35 -10
  56. data/lib/sass/selector/simple.rb +10 -2
  57. data/lib/sass/selector/simple_sequence.rb +8 -4
  58. data/lib/sass/selector.rb +4 -0
  59. data/lib/sass/source/map.rb +2 -6
  60. data/lib/sass/stack.rb +21 -1
  61. data/lib/sass/tree/charset_node.rb +1 -1
  62. data/lib/sass/tree/node.rb +2 -2
  63. data/lib/sass/tree/prop_node.rb +45 -53
  64. data/lib/sass/tree/rule_node.rb +13 -6
  65. data/lib/sass/tree/visitors/check_nesting.rb +1 -1
  66. data/lib/sass/tree/visitors/convert.rb +2 -3
  67. data/lib/sass/tree/visitors/cssize.rb +4 -15
  68. data/lib/sass/tree/visitors/deep_copy.rb +2 -2
  69. data/lib/sass/tree/visitors/extend.rb +2 -8
  70. data/lib/sass/tree/visitors/perform.rb +26 -17
  71. data/lib/sass/tree/visitors/set_options.rb +1 -1
  72. data/lib/sass/tree/visitors/to_css.rb +49 -22
  73. data/lib/sass/util/multibyte_string_scanner.rb +127 -131
  74. data/lib/sass/util/normalized_map.rb +1 -8
  75. data/lib/sass/util.rb +72 -310
  76. data/lib/sass/version.rb +0 -4
  77. data/lib/sass.rb +3 -10
  78. metadata +60 -206
  79. data/Rakefile +0 -424
  80. data/lib/sass/script/css_variable_warning.rb +0 -52
  81. data/lib/sass/util/cross_platform_random.rb +0 -19
  82. data/lib/sass/util/ordered_hash.rb +0 -192
  83. data/test/sass/cache_test.rb +0 -131
  84. data/test/sass/callbacks_test.rb +0 -61
  85. data/test/sass/compiler_test.rb +0 -236
  86. data/test/sass/conversion_test.rb +0 -2188
  87. data/test/sass/css2sass_test.rb +0 -526
  88. data/test/sass/css_variable_test.rb +0 -132
  89. data/test/sass/data/hsl-rgb.txt +0 -319
  90. data/test/sass/encoding_test.rb +0 -219
  91. data/test/sass/engine_test.rb +0 -3441
  92. data/test/sass/exec_test.rb +0 -96
  93. data/test/sass/extend_test.rb +0 -1727
  94. data/test/sass/fixtures/test_staleness_check_across_importers.css +0 -1
  95. data/test/sass/fixtures/test_staleness_check_across_importers.scss +0 -1
  96. data/test/sass/functions_test.rb +0 -1974
  97. data/test/sass/importer_test.rb +0 -421
  98. data/test/sass/logger_test.rb +0 -58
  99. data/test/sass/mock_importer.rb +0 -49
  100. data/test/sass/more_results/more1.css +0 -9
  101. data/test/sass/more_results/more1_with_line_comments.css +0 -26
  102. data/test/sass/more_results/more_import.css +0 -29
  103. data/test/sass/more_templates/_more_partial.sass +0 -2
  104. data/test/sass/more_templates/more1.sass +0 -23
  105. data/test/sass/more_templates/more_import.sass +0 -11
  106. data/test/sass/plugin_test.rb +0 -556
  107. data/test/sass/results/alt.css +0 -4
  108. data/test/sass/results/basic.css +0 -9
  109. data/test/sass/results/cached_import_option.css +0 -3
  110. data/test/sass/results/compact.css +0 -5
  111. data/test/sass/results/complex.css +0 -86
  112. data/test/sass/results/compressed.css +0 -1
  113. data/test/sass/results/expanded.css +0 -19
  114. data/test/sass/results/filename_fn.css +0 -3
  115. data/test/sass/results/if.css +0 -3
  116. data/test/sass/results/import.css +0 -31
  117. data/test/sass/results/import_charset.css +0 -5
  118. data/test/sass/results/import_charset_1_8.css +0 -5
  119. data/test/sass/results/import_charset_ibm866.css +0 -5
  120. data/test/sass/results/import_content.css +0 -1
  121. data/test/sass/results/line_numbers.css +0 -49
  122. data/test/sass/results/mixins.css +0 -95
  123. data/test/sass/results/multiline.css +0 -24
  124. data/test/sass/results/nested.css +0 -22
  125. data/test/sass/results/options.css +0 -1
  126. data/test/sass/results/parent_ref.css +0 -13
  127. data/test/sass/results/script.css +0 -16
  128. data/test/sass/results/scss_import.css +0 -31
  129. data/test/sass/results/scss_importee.css +0 -2
  130. data/test/sass/results/subdir/nested_subdir/nested_subdir.css +0 -1
  131. data/test/sass/results/subdir/subdir.css +0 -3
  132. data/test/sass/results/units.css +0 -11
  133. data/test/sass/results/warn.css +0 -0
  134. data/test/sass/results/warn_imported.css +0 -0
  135. data/test/sass/script_conversion_test.rb +0 -357
  136. data/test/sass/script_test.rb +0 -1422
  137. data/test/sass/scss/css_test.rb +0 -1281
  138. data/test/sass/scss/rx_test.rb +0 -160
  139. data/test/sass/scss/scss_test.rb +0 -4190
  140. data/test/sass/scss/test_helper.rb +0 -37
  141. data/test/sass/source_map_test.rb +0 -1055
  142. data/test/sass/superselector_test.rb +0 -210
  143. data/test/sass/templates/_cached_import_option_partial.scss +0 -1
  144. data/test/sass/templates/_double_import_loop2.sass +0 -1
  145. data/test/sass/templates/_filename_fn_import.scss +0 -11
  146. data/test/sass/templates/_imported_charset_ibm866.sass +0 -4
  147. data/test/sass/templates/_imported_charset_utf8.sass +0 -4
  148. data/test/sass/templates/_imported_content.sass +0 -3
  149. data/test/sass/templates/_partial.sass +0 -2
  150. data/test/sass/templates/_same_name_different_partiality.scss +0 -1
  151. data/test/sass/templates/alt.sass +0 -16
  152. data/test/sass/templates/basic.sass +0 -23
  153. data/test/sass/templates/bork1.sass +0 -2
  154. data/test/sass/templates/bork2.sass +0 -2
  155. data/test/sass/templates/bork3.sass +0 -2
  156. data/test/sass/templates/bork4.sass +0 -2
  157. data/test/sass/templates/bork5.sass +0 -3
  158. data/test/sass/templates/cached_import_option.scss +0 -3
  159. data/test/sass/templates/compact.sass +0 -17
  160. data/test/sass/templates/complex.sass +0 -305
  161. data/test/sass/templates/compressed.sass +0 -15
  162. data/test/sass/templates/double_import_loop1.sass +0 -1
  163. data/test/sass/templates/expanded.sass +0 -17
  164. data/test/sass/templates/filename_fn.scss +0 -18
  165. data/test/sass/templates/if.sass +0 -11
  166. data/test/sass/templates/import.sass +0 -12
  167. data/test/sass/templates/import_charset.sass +0 -9
  168. data/test/sass/templates/import_charset_1_8.sass +0 -6
  169. data/test/sass/templates/import_charset_ibm866.sass +0 -11
  170. data/test/sass/templates/import_content.sass +0 -4
  171. data/test/sass/templates/importee.less +0 -2
  172. data/test/sass/templates/importee.sass +0 -19
  173. data/test/sass/templates/line_numbers.sass +0 -13
  174. data/test/sass/templates/mixin_bork.sass +0 -5
  175. data/test/sass/templates/mixins.sass +0 -76
  176. data/test/sass/templates/multiline.sass +0 -20
  177. data/test/sass/templates/nested.sass +0 -25
  178. data/test/sass/templates/nested_bork1.sass +0 -2
  179. data/test/sass/templates/nested_bork2.sass +0 -2
  180. data/test/sass/templates/nested_bork3.sass +0 -2
  181. data/test/sass/templates/nested_bork4.sass +0 -2
  182. data/test/sass/templates/nested_import.sass +0 -2
  183. data/test/sass/templates/nested_mixin_bork.sass +0 -6
  184. data/test/sass/templates/options.sass +0 -2
  185. data/test/sass/templates/parent_ref.sass +0 -25
  186. data/test/sass/templates/same_name_different_ext.sass +0 -2
  187. data/test/sass/templates/same_name_different_ext.scss +0 -1
  188. data/test/sass/templates/same_name_different_partiality.scss +0 -1
  189. data/test/sass/templates/script.sass +0 -101
  190. data/test/sass/templates/scss_import.scss +0 -12
  191. data/test/sass/templates/scss_importee.scss +0 -1
  192. data/test/sass/templates/single_import_loop.sass +0 -1
  193. data/test/sass/templates/subdir/import_up1.scss +0 -1
  194. data/test/sass/templates/subdir/import_up2.scss +0 -1
  195. data/test/sass/templates/subdir/nested_subdir/_nested_partial.sass +0 -2
  196. data/test/sass/templates/subdir/nested_subdir/nested_subdir.sass +0 -3
  197. data/test/sass/templates/subdir/subdir.sass +0 -6
  198. data/test/sass/templates/units.sass +0 -11
  199. data/test/sass/templates/warn.sass +0 -3
  200. data/test/sass/templates/warn_imported.sass +0 -4
  201. data/test/sass/test_helper.rb +0 -8
  202. data/test/sass/util/multibyte_string_scanner_test.rb +0 -147
  203. data/test/sass/util/normalized_map_test.rb +0 -51
  204. data/test/sass/util/subset_map_test.rb +0 -91
  205. data/test/sass/util_test.rb +0 -438
  206. data/test/sass/value_helpers_test.rb +0 -179
  207. data/test/sass-spec.yml +0 -3
  208. data/test/test_helper.rb +0 -110
  209. data/vendor/listen/CHANGELOG.md +0 -1
  210. data/vendor/listen/CONTRIBUTING.md +0 -38
  211. data/vendor/listen/Gemfile +0 -20
  212. data/vendor/listen/Guardfile +0 -8
  213. data/vendor/listen/LICENSE +0 -20
  214. data/vendor/listen/README.md +0 -349
  215. data/vendor/listen/Rakefile +0 -5
  216. data/vendor/listen/Vagrantfile +0 -96
  217. data/vendor/listen/lib/listen/adapter.rb +0 -327
  218. data/vendor/listen/lib/listen/adapters/bsd.rb +0 -75
  219. data/vendor/listen/lib/listen/adapters/darwin.rb +0 -48
  220. data/vendor/listen/lib/listen/adapters/linux.rb +0 -81
  221. data/vendor/listen/lib/listen/adapters/polling.rb +0 -58
  222. data/vendor/listen/lib/listen/adapters/windows.rb +0 -91
  223. data/vendor/listen/lib/listen/directory_record.rb +0 -406
  224. data/vendor/listen/lib/listen/listener.rb +0 -323
  225. data/vendor/listen/lib/listen/turnstile.rb +0 -32
  226. data/vendor/listen/lib/listen/version.rb +0 -3
  227. data/vendor/listen/lib/listen.rb +0 -54
  228. data/vendor/listen/listen.gemspec +0 -28
  229. data/vendor/listen/spec/listen/adapter_spec.rb +0 -149
  230. data/vendor/listen/spec/listen/adapters/bsd_spec.rb +0 -36
  231. data/vendor/listen/spec/listen/adapters/darwin_spec.rb +0 -37
  232. data/vendor/listen/spec/listen/adapters/linux_spec.rb +0 -47
  233. data/vendor/listen/spec/listen/adapters/polling_spec.rb +0 -68
  234. data/vendor/listen/spec/listen/adapters/windows_spec.rb +0 -30
  235. data/vendor/listen/spec/listen/directory_record_spec.rb +0 -1250
  236. data/vendor/listen/spec/listen/listener_spec.rb +0 -258
  237. data/vendor/listen/spec/listen/turnstile_spec.rb +0 -56
  238. data/vendor/listen/spec/listen_spec.rb +0 -67
  239. data/vendor/listen/spec/spec_helper.rb +0 -25
  240. data/vendor/listen/spec/support/adapter_helper.rb +0 -666
  241. data/vendor/listen/spec/support/directory_record_helper.rb +0 -57
  242. data/vendor/listen/spec/support/fixtures_helper.rb +0 -29
  243. data/vendor/listen/spec/support/listeners_helper.rb +0 -179
  244. data/vendor/listen/spec/support/platform_helper.rb +0 -15
@@ -51,10 +51,7 @@ module Sass
51
51
  # @see Parser#initialize
52
52
  # @param allow_parent_ref [Boolean] Whether to allow the
53
53
  # parent-reference selector, `&`, when parsing the document.
54
- # @comment
55
- # rubocop:disable ParameterLists
56
54
  def initialize(str, filename, importer, line = 1, offset = 1, allow_parent_ref = true)
57
- # rubocop:enable ParameterLists
58
55
  super(str, filename, importer, line, offset)
59
56
  @allow_parent_ref = allow_parent_ref
60
57
  end
@@ -74,7 +71,7 @@ module Sass
74
71
  def var_expr; nil; end
75
72
  def interp_string; (s = tok(STRING)) && [s]; end
76
73
  def interp_uri; (s = tok(URI)) && [s]; end
77
- def interp_ident(ident = IDENT); (s = tok(ident)) && [s]; end
74
+ def interp_ident; (s = ident) && [s]; end
78
75
  def use_css_import?; true; end
79
76
 
80
77
  def special_directive(name, start_pos)
@@ -144,6 +141,13 @@ MESSAGE
144
141
  ns, name = expr!(:qualified_name)
145
142
  res << ns << '|' if ns
146
143
  res << name << tok!(%r{/})
144
+
145
+ location = " of #{@filename}" if @filename
146
+ Sass::Util.sass_warn <<MESSAGE
147
+ DEPRECATION WARNING on line #{@line}, column #{@offset}#{location}:
148
+ The reference combinator #{res} is deprecated and will be removed in a future release.
149
+ MESSAGE
150
+
147
151
  res
148
152
  end
149
153
 
@@ -181,25 +185,25 @@ MESSAGE
181
185
 
182
186
  def parent_selector
183
187
  return unless @allow_parent_ref && tok(/&/)
184
- Selector::Parent.new(tok(NAME))
188
+ Selector::Parent.new(name)
185
189
  end
186
190
 
187
191
  def class_selector
188
192
  return unless tok(/\./)
189
193
  @expected = "class name"
190
- Selector::Class.new(tok!(IDENT))
194
+ Selector::Class.new(ident!)
191
195
  end
192
196
 
193
197
  def id_selector
194
198
  return unless tok(/#(?!\{)/)
195
199
  @expected = "id name"
196
- Selector::Id.new(tok!(NAME))
200
+ Selector::Id.new(name!)
197
201
  end
198
202
 
199
203
  def placeholder_selector
200
204
  return unless tok(/%/)
201
205
  @expected = "placeholder name"
202
- Selector::Placeholder.new(tok!(IDENT))
206
+ Selector::Placeholder.new(ident!)
203
207
  end
204
208
 
205
209
  def element_name
@@ -214,13 +218,13 @@ MESSAGE
214
218
  end
215
219
 
216
220
  def qualified_name(allow_star_name = false)
217
- name = tok(IDENT) || tok(/\*/) || (tok?(/\|/) && "")
221
+ name = ident || tok(/\*/) || (tok?(/\|/) && "")
218
222
  return unless name
219
223
  return nil, name unless tok(/\|/)
220
224
 
221
- return name, tok!(IDENT) unless allow_star_name
225
+ return name, ident! unless allow_star_name
222
226
  @expected = "identifier or *"
223
- return name, tok(IDENT) || tok!(/\*/)
227
+ return name, ident || tok!(/\*/)
224
228
  end
225
229
 
226
230
  def attrib
@@ -238,21 +242,21 @@ MESSAGE
238
242
  if op
239
243
  @expected = "identifier or string"
240
244
  ss
241
- val = tok(IDENT) || tok!(STRING)
245
+ val = ident || tok!(STRING)
242
246
  ss
243
247
  end
244
- flags = tok(IDENT) || tok(STRING)
248
+ flags = ident || tok(STRING)
245
249
  tok!(/\]/)
246
250
 
247
251
  Selector::Attribute.new(name, ns, op, val, flags)
248
252
  end
249
253
 
250
254
  def attrib_name!
251
- if (name_or_ns = tok(IDENT))
255
+ if (name_or_ns = ident)
252
256
  # E, E|E
253
257
  if tok(/\|(?!=)/)
254
258
  ns = name_or_ns
255
- name = tok(IDENT)
259
+ name = ident
256
260
  else
257
261
  name = name_or_ns
258
262
  end
@@ -260,7 +264,7 @@ MESSAGE
260
264
  # *|E or |E
261
265
  ns = tok(/\*/) || ""
262
266
  tok!(/\|/)
263
- name = tok!(IDENT)
267
+ name = ident!
264
268
  end
265
269
  return ns, name
266
270
  end
@@ -269,11 +273,13 @@ MESSAGE
269
273
 
270
274
  PREFIXED_SELECTOR_PSEUDO_CLASSES = %w(nth-child nth-last-child).to_set
271
275
 
276
+ SELECTOR_PSEUDO_ELEMENTS = %w(slotted).to_set
277
+
272
278
  def pseudo
273
279
  s = tok(/::?/)
274
280
  return unless s
275
281
  @expected = "pseudoclass or pseudoelement"
276
- name = tok!(IDENT)
282
+ name = ident!
277
283
  if tok(/\(/)
278
284
  ss
279
285
  deprefixed = deprefix(name)
@@ -281,8 +287,10 @@ MESSAGE
281
287
  sel = selector_comma_sequence
282
288
  elsif s == ':' && PREFIXED_SELECTOR_PSEUDO_CLASSES.include?(deprefixed)
283
289
  arg, sel = prefixed_selector_pseudo
290
+ elsif s == '::' && SELECTOR_PSEUDO_ELEMENTS.include?(deprefixed)
291
+ sel = selector_comma_sequence
284
292
  else
285
- arg = expr!(:pseudo_args)
293
+ arg = expr!(:declaration_value).join
286
294
  end
287
295
 
288
296
  tok!(/\)/)
@@ -290,29 +298,6 @@ MESSAGE
290
298
  Selector::Pseudo.new(s == ':' ? :class : :element, name, arg, sel)
291
299
  end
292
300
 
293
- def pseudo_args
294
- arg = expr!(:pseudo_expr)
295
- while tok(/,/)
296
- arg << ',' << str {ss}
297
- arg.concat expr!(:pseudo_expr)
298
- end
299
- arg
300
- end
301
-
302
- def pseudo_expr
303
- res = pseudo_expr_token
304
- return unless res
305
- res << str {ss}
306
- while (e = pseudo_expr_token)
307
- res << e << str {ss}
308
- end
309
- res
310
- end
311
-
312
- def pseudo_expr_token
313
- tok(PLUS) || tok(/[-*]/) || tok(NUMBER) || tok(STRING) || tok(IDENT)
314
- end
315
-
316
301
  def prefixed_selector_pseudo
317
302
  prefix = str do
318
303
  expr = str {expr!(:a_n_plus_b)}
@@ -357,7 +342,7 @@ MESSAGE
357
342
  end
358
343
 
359
344
  def keyframes_selector_component
360
- tok(IDENT) || tok(PERCENTAGE)
345
+ ident || tok(PERCENTAGE)
361
346
  end
362
347
 
363
348
  @sass_script_parser = Class.new(Sass::Script::CssParser)
@@ -59,12 +59,11 @@ module Sass
59
59
  end
60
60
  alias_method :==, :eql?
61
61
 
62
- # Whether or not this selector sequence contains a placeholder selector.
63
- # Checks recursively.
64
- def has_placeholder?
65
- @has_placeholder ||= members.any? do |m|
66
- next m.has_placeholder? if m.is_a?(AbstractSequence)
67
- next m.selector && m.selector.has_placeholder? if m.is_a?(Pseudo)
62
+ # Whether or not this selector should be hidden due to containing a
63
+ # placeholder.
64
+ def invisible?
65
+ @invisible ||= members.any? do |m|
66
+ next m.invisible? if m.is_a?(AbstractSequence) || m.is_a?(Pseudo)
68
67
  m.is_a?(Placeholder)
69
68
  end
70
69
  end
@@ -73,6 +72,8 @@ module Sass
73
72
  #
74
73
  # @param opts [Hash] rendering options.
75
74
  # @option opts [Symbol] :style The css rendering style.
75
+ # @option placeholders [Boolean] :placeholders
76
+ # Whether to include placeholder selectors. Defaults to `true`.
76
77
  # @return [String]
77
78
  def to_s(opts = {})
78
79
  Sass::Util.abstract(self)
@@ -2,6 +2,8 @@ module Sass
2
2
  module Selector
3
3
  # A comma-separated sequence of selectors.
4
4
  class CommaSequence < AbstractSequence
5
+ @@compound_extend_deprecation = Sass::Deprecation.new
6
+
5
7
  # The comma-separated selector sequences
6
8
  # represented by this class.
7
9
  #
@@ -96,8 +98,11 @@ module Sass
96
98
  # The node that caused this extension.
97
99
  # @param parent_directives [Array<Sass::Tree::DirectiveNode>]
98
100
  # The parent directives containing `extend_node`.
101
+ # @param allow_compound_target [Boolean]
102
+ # Whether `extendee` is allowed to contain compound selectors.
99
103
  # @raise [Sass::SyntaxError] if this extension is invalid.
100
- def populate_extends(extends, extendee, extend_node = nil, parent_directives = [])
104
+ def populate_extends(extends, extendee, extend_node = nil, parent_directives = [],
105
+ allow_compound_target = false)
101
106
  extendee.members.each do |seq|
102
107
  if seq.members.size > 1
103
108
  raise Sass::SyntaxError.new("Can't extend #{seq}: can't extend nested selectors")
@@ -111,13 +116,21 @@ module Sass
111
116
  end
112
117
 
113
118
  sel = sseq.members
119
+ if !allow_compound_target && sel.length > 1
120
+ @@compound_extend_deprecation.warn(sseq.filename, sseq.line, <<WARNING)
121
+ Extending a compound selector, #{sseq}, is deprecated and will not be supported in a future release.
122
+ Consider "@extend #{sseq.members.join(', ')}" instead.
123
+ See http://bit.ly/ExtendCompound for details.
124
+ WARNING
125
+ end
126
+
114
127
  members.each do |member|
115
128
  unless member.members.last.is_a?(Sass::Selector::SimpleSequence)
116
129
  raise Sass::SyntaxError.new("#{member} can't extend: invalid selector")
117
130
  end
118
131
 
119
132
  extends[sel] = Sass::Tree::Visitors::Cssize::Extend.new(
120
- member, sel, extend_node, parent_directives, :not_found)
133
+ member, sel, extend_node, parent_directives, false)
121
134
  end
122
135
  end
123
136
  end
@@ -146,8 +159,8 @@ module Sass
146
159
  Sass::Script::Value::List.new(seq.members.map do |component|
147
160
  next if component == "\n"
148
161
  Sass::Script::Value::String.new(component.to_s)
149
- end.compact, :space)
150
- end, :comma)
162
+ end.compact, separator: :space)
163
+ end, separator: :comma)
151
164
  end
152
165
 
153
166
  # Returns a string representation of the sequence.
@@ -160,7 +173,10 @@ module Sass
160
173
 
161
174
  # @see AbstractSequence#to_s
162
175
  def to_s(opts = {})
163
- @members.map {|m| m.to_s(opts)}.
176
+ @members.map do |m|
177
+ next if opts[:placeholder] == false && m.invisible?
178
+ m.to_s(opts)
179
+ end.compact.
164
180
  join(opts[:style] == :compressed ? "," : ", ").
165
181
  gsub(", \n", ",\n")
166
182
  end
@@ -1,3 +1,4 @@
1
+ # coding: utf-8
1
2
  module Sass
2
3
  module Selector
3
4
  # A pseudoclass (e.g. `:visited`) or pseudoelement (e.g. `::first-line`)
@@ -48,6 +49,18 @@ module Sass
48
49
  @selector = selector
49
50
  end
50
51
 
52
+ def unique?
53
+ type == :class && normalized_name == 'root'
54
+ end
55
+
56
+ # Whether or not this selector should be hidden due to containing a
57
+ # placeholder.
58
+ def invisible?
59
+ # :not() is a special case—if you eliminate all the placeholders from
60
+ # it, it should match anything.
61
+ name != 'not' && @selector && @selector.members.all? {|s| s.invisible?}
62
+ end
63
+
51
64
  # Returns a copy of this with \{#selector} set to \{#new\_selector}.
52
65
  #
53
66
  # @param new_selector [CommaSequence]
@@ -77,7 +90,7 @@ module Sass
77
90
  # more complex cases that likely aren't worth the pain.
78
91
  next [] unless sel.name == name && sel.arg == arg
79
92
  sel.selector.members
80
- when 'has', 'host', 'host-context'
93
+ when 'has', 'host', 'host-context', 'slotted'
81
94
  # We can't expand nested selectors here, because each layer adds an
82
95
  # additional layer of semantics. For example, `:has(:has(img))`
83
96
  # doesn't match `<div><img></div>` but `:has(img)` does.
@@ -114,10 +127,14 @@ module Sass
114
127
 
115
128
  # @see Selector#to_s
116
129
  def to_s(opts = {})
130
+ # :not() is a special case, because :not(<nothing>) should match
131
+ # everything.
132
+ return '' if name == 'not' && @selector && @selector.members.all? {|m| m.invisible?}
133
+
117
134
  res = (syntactic_type == :class ? ":" : "::") + @name
118
135
  if @arg || @selector
119
136
  res << "("
120
- res << @arg.strip if @arg
137
+ res << Sass::Util.strip_except_escapes(@arg) if @arg
121
138
  res << " " if @arg && @selector
122
139
  res << @selector.to_s(opts) if @selector
123
140
  res << ")"
@@ -161,7 +178,7 @@ module Sass
161
178
  their_seq = Sequence.new(parents + [their_sseq])
162
179
  our_seq.superselector?(their_seq)
163
180
  end
164
- when 'has', 'host', 'host-context'
181
+ when 'has', 'host', 'host-context', 'slotted'
165
182
  # Like :matches, :has (et al) can be a superselector of another
166
183
  # selector if its constituent selectors are a superset of those of
167
184
  # another :has in the other selector. However, the :matches other case
@@ -66,10 +66,14 @@ module Sass
66
66
  next [sseq_or_op] unless sseq_or_op.is_a?(SimpleSequence)
67
67
  sseq_or_op.resolve_parent_refs(super_cseq).members
68
68
  end).map do |path|
69
- Sequence.new(path.map do |seq_or_op|
69
+ path_members = path.map do |seq_or_op|
70
70
  next seq_or_op unless seq_or_op.is_a?(Sequence)
71
71
  seq_or_op.members
72
- end.flatten)
72
+ end
73
+ if path_members.length == 2 && path_members[1][0] == "\n"
74
+ path_members[0].unshift path_members[1].shift
75
+ end
76
+ Sequence.new(path_members.flatten)
73
77
  end)
74
78
  end
75
79
 
@@ -115,7 +119,7 @@ module Sass
115
119
  # specificity greater than or equal to that of the original selector.
116
120
  # In order to ensure that, we record the original selector's
117
121
  # (`extended.first`) original specificity.
118
- extended.first.add_sources!([self]) if original && !has_placeholder?
122
+ extended.first.add_sources!([self]) if original && !invisible?
119
123
 
120
124
  extended.map {|seq| seq.members}
121
125
  end
@@ -283,6 +287,9 @@ module Sass
283
287
  next unless s1.first.is_a?(SimpleSequence) && s2.first.is_a?(SimpleSequence)
284
288
  next s2 if parent_superselector?(s1, s2)
285
289
  next s1 if parent_superselector?(s2, s1)
290
+ next unless must_unify?(s1, s2)
291
+ next unless (unified = Sequence.new(s1).unify(Sequence.new(s2)))
292
+ unified.members.first.members if unified.members.length == 1
286
293
  end
287
294
 
288
295
  diff = [[init]]
@@ -337,8 +344,6 @@ module Sass
337
344
  # be nil. Otherwise, this will contained the merged selector. Array
338
345
  # elements are [Sass::Util#paths]-style options; conceptually, an "or"
339
346
  # of multiple selectors.
340
- # @comment
341
- # rubocop:disable MethodLength
342
347
  def merge_final_ops(seq1, seq2, res = [])
343
348
  ops1, ops2 = [], []
344
349
  ops1 << seq1.pop while seq1.last.is_a?(String)
@@ -420,8 +425,6 @@ module Sass
420
425
  return merge_final_ops(seq1, seq2, res)
421
426
  end
422
427
  end
423
- # @comment
424
- # rubocop:enable MethodLength
425
428
 
426
429
  # Takes initial subsequences of `seq1` and `seq2` and returns all
427
430
  # orderings of those subsequences. The initial subsequences are determined
@@ -494,7 +497,7 @@ module Sass
494
497
  return if seq1.size > seq2.size
495
498
  return seq1.first.superselector?(seq2.last, seq2[0...-1]) if seq1.size == 1
496
499
 
497
- _, si = Sass::Util.enum_with_index(seq2).find do |e, i|
500
+ _, si = seq2.each_with_index.find do |e, i|
498
501
  return if i == seq2.size - 1
499
502
  next if e.is_a?(String)
500
503
  seq1.first.superselector?(e, seq2[0...i])
@@ -537,6 +540,30 @@ module Sass
537
540
  _superselector?(seq1 + [base], seq2 + [base])
538
541
  end
539
542
 
543
+ # Returns whether two selectors must be unified to produce a valid
544
+ # combined selector. This is true when both selectors contain the same
545
+ # unique simple selector such as an id.
546
+ #
547
+ # @param seq1 [Array<SimpleSequence or String>]
548
+ # @param seq2 [Array<SimpleSequence or String>]
549
+ # @return [Boolean]
550
+ def must_unify?(seq1, seq2)
551
+ unique_selectors = seq1.map do |sseq|
552
+ next [] if sseq.is_a?(String)
553
+ sseq.members.select {|sel| sel.unique?}
554
+ end.flatten.to_set
555
+
556
+ return false if unique_selectors.empty?
557
+
558
+ seq2.any? do |sseq|
559
+ next false if sseq.is_a?(String)
560
+ sseq.members.any? do |sel|
561
+ next unless sel.unique?
562
+ unique_selectors.include?(sel)
563
+ end
564
+ end
565
+ end
566
+
540
567
  # Removes redundant selectors from between multiple lists of
541
568
  # selectors. This takes a list of lists of selector sequences;
542
569
  # each individual list is assumed to have no redundancy within
@@ -597,8 +624,6 @@ module Sass
597
624
  other.members.reject {|m| m == "\n"}.eql?(members.reject {|m| m == "\n"})
598
625
  end
599
626
 
600
- private
601
-
602
627
  def path_has_two_subjects?(path)
603
628
  subject = false
604
629
  path.each do |sseq_or_op|
@@ -14,6 +14,14 @@ module Sass
14
14
  # @return [String, nil]
15
15
  attr_accessor :filename
16
16
 
17
+ # Whether only one instance of this simple selector is allowed in a given
18
+ # complex selector.
19
+ #
20
+ # @return [Boolean]
21
+ def unique?
22
+ false
23
+ end
24
+
17
25
  # @see #to_s
18
26
  #
19
27
  # @return [String]
@@ -72,10 +80,10 @@ module Sass
72
80
  # by the time extension and unification happen,
73
81
  # this exception will only ever be raised as a result of programmer error
74
82
  def unify(sels)
83
+ return sels.first.unify([self]) if sels.length == 1 && sels.first.is_a?(Universal)
75
84
  return sels if sels.any? {|sel2| eql?(sel2)}
76
- sels_with_ix = Sass::Util.enum_with_index(sels)
77
85
  if !is_a?(Pseudo) || (sels.last.is_a?(Pseudo) && sels.last.type == :element)
78
- _, i = sels_with_ix.find {|sel, _| sel.is_a?(Pseudo)}
86
+ _, i = sels.each_with_index.find {|sel, _| sel.is_a?(Pseudo)}
79
87
  end
80
88
  return sels + [self] unless i
81
89
  sels[0...i] + [self] + sels[i..-1]
@@ -163,7 +163,7 @@ module Sass
163
163
  next sel if seen.include?([sel])
164
164
  extended = sel.selector.do_extend(extends, parent_directives, replace, seen, false)
165
165
  next sel if extended == sel.selector
166
- extended.members.reject! {|seq| seq.has_placeholder?}
166
+ extended.members.reject! {|seq| seq.invisible?}
167
167
 
168
168
  # For `:not()`, we usually want to get rid of any complex
169
169
  # selectors because that will cause the selector to fail to
@@ -184,17 +184,16 @@ module Sass
184
184
  result
185
185
  end.flatten
186
186
 
187
- groups = Sass::Util.group_by_to_a(extends[members.to_set]) {|ex| ex.extender}
187
+ groups = extends[members.to_set].group_by {|ex| ex.extender}.to_a
188
188
  groups.map! do |seq, group|
189
189
  sels = group.map {|e| e.target}.flatten
190
190
  # If A {@extend B} and C {...},
191
191
  # seq is A, sels is B, and self is C
192
192
 
193
193
  self_without_sel = Sass::Util.array_minus(members, sels)
194
- group.each {|e| e.result = :failed_to_unify unless e.result == :succeeded}
194
+ group.each {|e| e.success = true}
195
195
  unified = seq.members.last.unify(SimpleSequence.new(self_without_sel, subject?))
196
196
  next unless unified
197
- group.each {|e| e.result = :succeeded}
198
197
  group.each {|e| check_directives_match!(e, parent_directives)}
199
198
  new_seq = Sequence.new(seq.members[0...-1] + [unified])
200
199
  new_seq.add_sources!(sources + [seq])
@@ -287,6 +286,11 @@ module Sass
287
286
  # @see Simple#to_s
288
287
  def to_s(opts = {})
289
288
  res = @members.map {|m| m.to_s(opts)}.join
289
+
290
+ # :not(%foo) may resolve to the empty string, but it should match every
291
+ # selector so we replace it with "*".
292
+ res = '*' if res.empty?
293
+
290
294
  res << '!' if subject?
291
295
  res
292
296
  end
data/lib/sass/selector.rb CHANGED
@@ -87,6 +87,10 @@ module Sass
87
87
  @name = name
88
88
  end
89
89
 
90
+ def unique?
91
+ true
92
+ end
93
+
90
94
  # @see Selector#to_s
91
95
  def to_s(opts = {})
92
96
  "#" + @name
@@ -84,8 +84,6 @@ module Sass::Source
84
84
  # @return [String] The JSON string.
85
85
  # @raise [ArgumentError] If neither `:css_uri` nor `:css_path` and
86
86
  # `:sourcemap_path` are specified.
87
- # @comment
88
- # rubocop:disable MethodLength
89
87
  def to_json(options)
90
88
  css_uri, css_path, sourcemap_path =
91
89
  options[:css_uri], options[:css_path], options[:sourcemap_path]
@@ -93,8 +91,8 @@ module Sass::Source
93
91
  raise ArgumentError.new("Sass::Source::Map#to_json requires either " \
94
92
  "the :css_uri option or both the :css_path and :soucemap_path options.")
95
93
  end
96
- css_path &&= Sass::Util.pathname(Sass::Util.absolute_path(css_path))
97
- sourcemap_path &&= Sass::Util.pathname(Sass::Util.absolute_path(sourcemap_path))
94
+ css_path &&= Sass::Util.pathname(File.absolute_path(css_path))
95
+ sourcemap_path &&= Sass::Util.pathname(File.absolute_path(sourcemap_path))
98
96
  css_uri ||= Sass::Util.file_uri_from_path(
99
97
  Sass::Util.relative_path_from(css_path, sourcemap_path.dirname))
100
98
 
@@ -197,8 +195,6 @@ module Sass::Source
197
195
  result << "\n}"
198
196
  result
199
197
  end
200
- # @comment
201
- # rubocop:enable MethodLength
202
198
 
203
199
  private
204
200
 
data/lib/sass/stack.rb CHANGED
@@ -98,8 +98,28 @@ module Sass
98
98
  with_frame(filename, line, :mixin, name) {yield}
99
99
  end
100
100
 
101
+ # Pushes a function frame onto the stack.
102
+ #
103
+ # @param filename [String] See \{Frame#filename}.
104
+ # @param line [String] See \{Frame#line}.
105
+ # @param name [String] See \{Frame#name}.
106
+ # @yield [] A block in which the new frame is on the stack.
107
+ def with_function(filename, line, name)
108
+ with_frame(filename, line, :function, name) {yield}
109
+ end
110
+
111
+ # Pushes a function frame onto the stack.
112
+ #
113
+ # @param filename [String] See \{Frame#filename}.
114
+ # @param line [String] See \{Frame#line}.
115
+ # @param name [String] See \{Frame#name}.
116
+ # @yield [] A block in which the new frame is on the stack.
117
+ def with_directive(filename, line, name)
118
+ with_frame(filename, line, :directive, name) {yield}
119
+ end
120
+
101
121
  def to_s
102
- Sass::Util.enum_with_index(Sass::Util.enum_cons(frames.reverse + [nil], 2)).
122
+ (frames.reverse + [nil]).each_cons(2).each_with_index.
103
123
  map do |(frame, caller), i|
104
124
  "#{i == 0 ? 'on' : 'from'} line #{frame.line}" +
105
125
  " of #{frame.filename || 'an unknown file'}" +
@@ -16,7 +16,7 @@ module Sass::Tree
16
16
 
17
17
  # @see Node#invisible?
18
18
  def invisible?
19
- !Sass::Util.ruby1_8?
19
+ true
20
20
  end
21
21
  end
22
22
  end
@@ -83,7 +83,7 @@ module Sass
83
83
  attr_writer :filename
84
84
 
85
85
  # The options hash for the node.
86
- # See {file:SASS_REFERENCE.md#sass_options the Sass options documentation}.
86
+ # See {file:SASS_REFERENCE.md#Options the Sass options documentation}.
87
87
  #
88
88
  # @return [{Symbol => Object}]
89
89
  attr_reader :options
@@ -151,7 +151,7 @@ module Sass
151
151
  # @return [Boolean]
152
152
  def invisible?; false; end
153
153
 
154
- # The output style. See {file:SASS_REFERENCE.md#sass_options the Sass options documentation}.
154
+ # The output style. See {file:SASS_REFERENCE.md#Options the Sass options documentation}.
155
155
  #
156
156
  # @return [Symbol]
157
157
  def style