sass 3.7.4 → 4.0.0.alpha.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (257) hide show
  1. checksums.yaml +13 -5
  2. data/.yardopts +1 -1
  3. data/CODE_OF_CONDUCT.md +1 -1
  4. data/CONTRIBUTING.md +1 -146
  5. data/MIT-LICENSE +1 -1
  6. data/README.md +25 -39
  7. data/Rakefile +274 -0
  8. data/VERSION +1 -1
  9. data/VERSION_DATE +1 -1
  10. data/lib/sass.rb +3 -3
  11. data/lib/sass/cache_stores/filesystem.rb +2 -2
  12. data/lib/sass/cache_stores/memory.rb +5 -4
  13. data/lib/sass/callbacks.rb +2 -2
  14. data/lib/sass/css.rb +12 -12
  15. data/lib/sass/engine.rb +44 -62
  16. data/lib/sass/environment.rb +7 -35
  17. data/lib/sass/error.rb +14 -14
  18. data/lib/sass/exec/base.rb +14 -3
  19. data/lib/sass/exec/sass_convert.rb +6 -20
  20. data/lib/sass/exec/sass_scss.rb +29 -5
  21. data/lib/sass/features.rb +2 -3
  22. data/lib/sass/importers/filesystem.rb +6 -11
  23. data/lib/sass/logger.rb +3 -8
  24. data/lib/sass/logger/base.rb +2 -19
  25. data/lib/sass/plugin.rb +2 -3
  26. data/lib/sass/plugin/compiler.rb +67 -48
  27. data/lib/sass/plugin/configuration.rb +3 -3
  28. data/lib/sass/plugin/merb.rb +1 -1
  29. data/lib/sass/plugin/rack.rb +3 -3
  30. data/lib/sass/plugin/staleness_checker.rb +3 -3
  31. data/lib/sass/railtie.rb +1 -1
  32. data/lib/sass/script.rb +3 -3
  33. data/lib/sass/script/css_parser.rb +15 -5
  34. data/lib/sass/script/functions.rb +121 -337
  35. data/lib/sass/script/lexer.rb +36 -102
  36. data/lib/sass/script/parser.rb +153 -529
  37. data/lib/sass/script/tree/funcall.rb +34 -42
  38. data/lib/sass/script/tree/interpolation.rb +26 -171
  39. data/lib/sass/script/tree/list_literal.rb +8 -23
  40. data/lib/sass/script/tree/map_literal.rb +2 -2
  41. data/lib/sass/script/tree/node.rb +3 -3
  42. data/lib/sass/script/tree/operation.rb +16 -43
  43. data/lib/sass/script/tree/string_interpolation.rb +43 -64
  44. data/lib/sass/script/tree/variable.rb +1 -1
  45. data/lib/sass/script/value.rb +0 -2
  46. data/lib/sass/script/value/arg_list.rb +1 -1
  47. data/lib/sass/script/value/base.rb +9 -27
  48. data/lib/sass/script/value/color.rb +18 -26
  49. data/lib/sass/script/value/helpers.rb +18 -44
  50. data/lib/sass/script/value/list.rb +14 -35
  51. data/lib/sass/script/value/map.rb +2 -2
  52. data/lib/sass/script/value/number.rb +16 -26
  53. data/lib/sass/script/value/string.rb +1 -30
  54. data/lib/sass/scss.rb +2 -0
  55. data/lib/sass/scss/css_parser.rb +3 -7
  56. data/lib/sass/scss/parser.rb +78 -196
  57. data/lib/sass/scss/rx.rb +14 -7
  58. data/lib/sass/scss/script_lexer.rb +15 -0
  59. data/lib/sass/scss/script_parser.rb +25 -0
  60. data/lib/sass/scss/static_parser.rb +55 -38
  61. data/lib/sass/selector.rb +10 -7
  62. data/lib/sass/selector/abstract_sequence.rb +12 -15
  63. data/lib/sass/selector/comma_sequence.rb +6 -24
  64. data/lib/sass/selector/pseudo.rb +6 -19
  65. data/lib/sass/selector/sequence.rb +16 -14
  66. data/lib/sass/selector/simple.rb +7 -9
  67. data/lib/sass/selector/simple_sequence.rb +12 -16
  68. data/lib/sass/shared.rb +1 -1
  69. data/lib/sass/source/map.rb +9 -7
  70. data/lib/sass/source/position.rb +4 -4
  71. data/lib/sass/stack.rb +3 -23
  72. data/lib/sass/tree/charset_node.rb +1 -1
  73. data/lib/sass/tree/comment_node.rb +1 -1
  74. data/lib/sass/tree/function_node.rb +3 -2
  75. data/lib/sass/tree/node.rb +3 -5
  76. data/lib/sass/tree/prop_node.rb +58 -49
  77. data/lib/sass/tree/rule_node.rb +8 -15
  78. data/lib/sass/tree/visitors/check_nesting.rb +23 -19
  79. data/lib/sass/tree/visitors/convert.rb +13 -15
  80. data/lib/sass/tree/visitors/cssize.rb +15 -4
  81. data/lib/sass/tree/visitors/deep_copy.rb +2 -2
  82. data/lib/sass/tree/visitors/extend.rb +14 -10
  83. data/lib/sass/tree/visitors/perform.rb +18 -29
  84. data/lib/sass/tree/visitors/set_options.rb +2 -2
  85. data/lib/sass/tree/visitors/to_css.rb +47 -77
  86. data/lib/sass/util.rb +311 -98
  87. data/lib/sass/util/cross_platform_random.rb +19 -0
  88. data/lib/sass/util/multibyte_string_scanner.rb +133 -127
  89. data/lib/sass/util/normalized_map.rb +8 -1
  90. data/lib/sass/util/ordered_hash.rb +192 -0
  91. data/lib/sass/version.rb +6 -2
  92. data/test/sass/cache_test.rb +131 -0
  93. data/test/sass/callbacks_test.rb +61 -0
  94. data/test/sass/compiler_test.rb +236 -0
  95. data/test/sass/conversion_test.rb +2171 -0
  96. data/test/sass/css2sass_test.rb +526 -0
  97. data/test/sass/data/hsl-rgb.txt +319 -0
  98. data/test/sass/encoding_test.rb +219 -0
  99. data/test/sass/engine_test.rb +3400 -0
  100. data/test/sass/exec_test.rb +86 -0
  101. data/test/sass/extend_test.rb +1719 -0
  102. data/test/sass/fixtures/test_staleness_check_across_importers.css +1 -0
  103. data/test/sass/fixtures/test_staleness_check_across_importers.scss +1 -0
  104. data/test/sass/functions_test.rb +1984 -0
  105. data/test/sass/importer_test.rb +421 -0
  106. data/test/sass/logger_test.rb +58 -0
  107. data/test/sass/mock_importer.rb +49 -0
  108. data/test/sass/more_results/more1.css +9 -0
  109. data/test/sass/more_results/more1_with_line_comments.css +26 -0
  110. data/test/sass/more_results/more_import.css +29 -0
  111. data/test/sass/more_templates/_more_partial.sass +2 -0
  112. data/test/sass/more_templates/more1.sass +23 -0
  113. data/test/sass/more_templates/more_import.sass +11 -0
  114. data/test/sass/plugin_test.rb +556 -0
  115. data/test/sass/results/alt.css +4 -0
  116. data/test/sass/results/basic.css +9 -0
  117. data/test/sass/results/cached_import_option.css +3 -0
  118. data/test/sass/results/compact.css +5 -0
  119. data/test/sass/results/complex.css +86 -0
  120. data/test/sass/results/compressed.css +1 -0
  121. data/test/sass/results/expanded.css +19 -0
  122. data/test/sass/results/filename_fn.css +3 -0
  123. data/test/sass/results/if.css +3 -0
  124. data/test/sass/results/import.css +31 -0
  125. data/test/sass/results/import_charset.css +5 -0
  126. data/test/sass/results/import_charset_1_8.css +5 -0
  127. data/test/sass/results/import_charset_ibm866.css +5 -0
  128. data/test/sass/results/import_content.css +1 -0
  129. data/test/sass/results/line_numbers.css +49 -0
  130. data/test/sass/results/mixins.css +95 -0
  131. data/test/sass/results/multiline.css +24 -0
  132. data/test/sass/results/nested.css +22 -0
  133. data/test/sass/results/options.css +1 -0
  134. data/test/sass/results/parent_ref.css +13 -0
  135. data/test/sass/results/script.css +16 -0
  136. data/test/sass/results/scss_import.css +31 -0
  137. data/test/sass/results/scss_importee.css +2 -0
  138. data/test/sass/results/subdir/nested_subdir/nested_subdir.css +1 -0
  139. data/test/sass/results/subdir/subdir.css +3 -0
  140. data/test/sass/results/units.css +11 -0
  141. data/test/sass/results/warn.css +0 -0
  142. data/test/sass/results/warn_imported.css +0 -0
  143. data/test/sass/script_conversion_test.rb +306 -0
  144. data/test/sass/script_test.rb +1206 -0
  145. data/test/sass/scss/css_test.rb +1281 -0
  146. data/test/sass/scss/rx_test.rb +160 -0
  147. data/test/sass/scss/scss_test.rb +4147 -0
  148. data/test/sass/scss/test_helper.rb +37 -0
  149. data/test/sass/source_map_test.rb +1055 -0
  150. data/test/sass/superselector_test.rb +210 -0
  151. data/test/sass/templates/_cached_import_option_partial.scss +1 -0
  152. data/test/sass/templates/_double_import_loop2.sass +1 -0
  153. data/test/sass/templates/_filename_fn_import.scss +11 -0
  154. data/test/sass/templates/_imported_charset_ibm866.sass +4 -0
  155. data/test/sass/templates/_imported_charset_utf8.sass +4 -0
  156. data/test/sass/templates/_imported_content.sass +3 -0
  157. data/test/sass/templates/_partial.sass +2 -0
  158. data/test/sass/templates/_same_name_different_partiality.scss +1 -0
  159. data/test/sass/templates/alt.sass +16 -0
  160. data/test/sass/templates/basic.sass +23 -0
  161. data/test/sass/templates/bork1.sass +2 -0
  162. data/test/sass/templates/bork2.sass +2 -0
  163. data/test/sass/templates/bork3.sass +2 -0
  164. data/test/sass/templates/bork4.sass +2 -0
  165. data/test/sass/templates/bork5.sass +3 -0
  166. data/test/sass/templates/cached_import_option.scss +3 -0
  167. data/test/sass/templates/compact.sass +17 -0
  168. data/test/sass/templates/complex.sass +305 -0
  169. data/test/sass/templates/compressed.sass +15 -0
  170. data/test/sass/templates/double_import_loop1.sass +1 -0
  171. data/test/sass/templates/expanded.sass +17 -0
  172. data/test/sass/templates/filename_fn.scss +18 -0
  173. data/test/sass/templates/if.sass +11 -0
  174. data/test/sass/templates/import.sass +12 -0
  175. data/test/sass/templates/import_charset.sass +9 -0
  176. data/test/sass/templates/import_charset_1_8.sass +6 -0
  177. data/test/sass/templates/import_charset_ibm866.sass +11 -0
  178. data/test/sass/templates/import_content.sass +4 -0
  179. data/test/sass/templates/importee.less +2 -0
  180. data/test/sass/templates/importee.sass +19 -0
  181. data/test/sass/templates/line_numbers.sass +13 -0
  182. data/test/sass/templates/mixin_bork.sass +5 -0
  183. data/test/sass/templates/mixins.sass +76 -0
  184. data/test/sass/templates/multiline.sass +20 -0
  185. data/test/sass/templates/nested.sass +25 -0
  186. data/test/sass/templates/nested_bork1.sass +2 -0
  187. data/test/sass/templates/nested_bork2.sass +2 -0
  188. data/test/sass/templates/nested_bork3.sass +2 -0
  189. data/test/sass/templates/nested_bork4.sass +2 -0
  190. data/test/sass/templates/nested_import.sass +2 -0
  191. data/test/sass/templates/nested_mixin_bork.sass +6 -0
  192. data/test/sass/templates/options.sass +2 -0
  193. data/test/sass/templates/parent_ref.sass +25 -0
  194. data/test/sass/templates/same_name_different_ext.sass +2 -0
  195. data/test/sass/templates/same_name_different_ext.scss +1 -0
  196. data/test/sass/templates/same_name_different_partiality.scss +1 -0
  197. data/test/sass/templates/script.sass +101 -0
  198. data/test/sass/templates/scss_import.scss +12 -0
  199. data/test/sass/templates/scss_importee.scss +1 -0
  200. data/test/sass/templates/single_import_loop.sass +1 -0
  201. data/test/sass/templates/subdir/import_up1.scss +1 -0
  202. data/test/sass/templates/subdir/import_up2.scss +1 -0
  203. data/test/sass/templates/subdir/nested_subdir/_nested_partial.sass +2 -0
  204. data/test/sass/templates/subdir/nested_subdir/nested_subdir.sass +3 -0
  205. data/test/sass/templates/subdir/subdir.sass +6 -0
  206. data/test/sass/templates/units.sass +11 -0
  207. data/test/sass/templates/warn.sass +3 -0
  208. data/test/sass/templates/warn_imported.sass +4 -0
  209. data/test/sass/test_helper.rb +8 -0
  210. data/test/sass/util/multibyte_string_scanner_test.rb +147 -0
  211. data/test/sass/util/normalized_map_test.rb +51 -0
  212. data/test/sass/util/subset_map_test.rb +91 -0
  213. data/test/sass/util_test.rb +438 -0
  214. data/test/sass/value_helpers_test.rb +179 -0
  215. data/test/test_helper.rb +110 -0
  216. data/vendor/listen/CHANGELOG.md +1 -0
  217. data/vendor/listen/CONTRIBUTING.md +38 -0
  218. data/vendor/listen/Gemfile +20 -0
  219. data/vendor/listen/Guardfile +8 -0
  220. data/vendor/listen/LICENSE +20 -0
  221. data/vendor/listen/README.md +349 -0
  222. data/vendor/listen/Rakefile +5 -0
  223. data/vendor/listen/Vagrantfile +96 -0
  224. data/vendor/listen/lib/listen.rb +54 -0
  225. data/vendor/listen/lib/listen/adapter.rb +327 -0
  226. data/vendor/listen/lib/listen/adapters/bsd.rb +75 -0
  227. data/vendor/listen/lib/listen/adapters/darwin.rb +48 -0
  228. data/vendor/listen/lib/listen/adapters/linux.rb +81 -0
  229. data/vendor/listen/lib/listen/adapters/polling.rb +58 -0
  230. data/vendor/listen/lib/listen/adapters/windows.rb +91 -0
  231. data/vendor/listen/lib/listen/directory_record.rb +406 -0
  232. data/vendor/listen/lib/listen/listener.rb +323 -0
  233. data/vendor/listen/lib/listen/turnstile.rb +32 -0
  234. data/vendor/listen/lib/listen/version.rb +3 -0
  235. data/vendor/listen/listen.gemspec +28 -0
  236. data/vendor/listen/spec/listen/adapter_spec.rb +149 -0
  237. data/vendor/listen/spec/listen/adapters/bsd_spec.rb +36 -0
  238. data/vendor/listen/spec/listen/adapters/darwin_spec.rb +37 -0
  239. data/vendor/listen/spec/listen/adapters/linux_spec.rb +47 -0
  240. data/vendor/listen/spec/listen/adapters/polling_spec.rb +68 -0
  241. data/vendor/listen/spec/listen/adapters/windows_spec.rb +30 -0
  242. data/vendor/listen/spec/listen/directory_record_spec.rb +1250 -0
  243. data/vendor/listen/spec/listen/listener_spec.rb +258 -0
  244. data/vendor/listen/spec/listen/turnstile_spec.rb +56 -0
  245. data/vendor/listen/spec/listen_spec.rb +67 -0
  246. data/vendor/listen/spec/spec_helper.rb +25 -0
  247. data/vendor/listen/spec/support/adapter_helper.rb +666 -0
  248. data/vendor/listen/spec/support/directory_record_helper.rb +57 -0
  249. data/vendor/listen/spec/support/fixtures_helper.rb +29 -0
  250. data/vendor/listen/spec/support/listeners_helper.rb +179 -0
  251. data/vendor/listen/spec/support/platform_helper.rb +15 -0
  252. metadata +217 -76
  253. data/extra/sass-spec-ref.sh +0 -40
  254. data/lib/sass/deprecation.rb +0 -55
  255. data/lib/sass/logger/delayed.rb +0 -50
  256. data/lib/sass/script/value/callable.rb +0 -25
  257. data/lib/sass/script/value/function.rb +0 -19
@@ -56,7 +56,8 @@ class Sass::Tree::Visitors::Cssize < Sass::Tree::Visitors::Base
56
56
  @parents.pop
57
57
  end
58
58
 
59
- # Converts the entire document to CSS.
59
+ # In Ruby 1.8, ensures that there's only one `@charset` directive
60
+ # and that it's at the top of the document.
60
61
  #
61
62
  # @return [(Tree::Node, Sass::Util::SubsetMap)] The resulting tree of static nodes
62
63
  # *and* the extensions defined for this tree
@@ -64,6 +65,14 @@ class Sass::Tree::Visitors::Cssize < Sass::Tree::Visitors::Base
64
65
  yield
65
66
 
66
67
  if parent.nil?
68
+ # In Ruby 1.9 we can make all @charset nodes invisible
69
+ # and infer the final @charset from the encoding of the final string.
70
+ if Sass::Util.ruby1_8?
71
+ charset = node.children.find {|c| c.is_a?(Sass::Tree::CharsetNode)}
72
+ node.children.reject! {|c| c.is_a?(Sass::Tree::CharsetNode)}
73
+ node.children.unshift charset if charset
74
+ end
75
+
67
76
  imports_to_move = []
68
77
  import_limit = nil
69
78
  i = -1
@@ -106,9 +115,11 @@ class Sass::Tree::Visitors::Cssize < Sass::Tree::Visitors::Base
106
115
  # @attr node [Sass::Tree::ExtendNode] The node that produced this extend.
107
116
  # @attr directives [Array<Sass::Tree::DirectiveNode>]
108
117
  # The directives containing the `@extend`.
109
- # @attr success [Boolean]
110
- # Whether this extend successfully matched a selector.
111
- Extend = Struct.new(:extender, :target, :node, :directives, :success)
118
+ # @attr result [Symbol]
119
+ # The result of this extend. One of `:not_found` (the target doesn't exist
120
+ # in the document), `:failed_to_unify` (the target exists but cannot be
121
+ # unified with the extender), or `:succeeded`.
122
+ Extend = Struct.new(:extender, :target, :node, :directives, :result)
112
123
 
113
124
  # Registers an extension in the `@extends` subset map.
114
125
  def visit_extend(node)
@@ -55,13 +55,13 @@ class Sass::Tree::Visitors::DeepCopy < Sass::Tree::Visitors::Base
55
55
 
56
56
  def visit_mixin(node)
57
57
  node.args = node.args.map {|a| a.deep_copy}
58
- node.keywords = Sass::Util::NormalizedMap.new(Hash[node.keywords.map {|k, v| [k, v.deep_copy]}])
58
+ node.keywords = Hash[node.keywords.map {|k, v| [k, v.deep_copy]}]
59
59
  yield
60
60
  end
61
61
 
62
62
  def visit_prop(node)
63
63
  node.name = node.name.map {|c| c.is_a?(Sass::Script::Tree::Node) ? c.deep_copy : c}
64
- node.value = node.value.map {|c| c.is_a?(Sass::Script::Tree::Node) ? c.deep_copy : c}
64
+ node.value = node.value.deep_copy
65
65
  yield
66
66
  end
67
67
 
@@ -44,21 +44,25 @@ class Sass::Tree::Visitors::Extend < Sass::Tree::Visitors::Base
44
44
  node.resolved_rules = node.resolved_rules.do_extend(@extends, @parent_directives)
45
45
  end
46
46
 
47
- class << self
48
- private
47
+ private
49
48
 
50
- def check_extends_fired!(extends)
51
- extends.each_value do |ex|
52
- next if ex.success || ex.node.optional?
53
- message = "\"#{ex.extender}\" failed to @extend \"#{ex.target.join}\"."
49
+ def self.check_extends_fired!(extends)
50
+ extends.each_value do |ex|
51
+ next if ex.result == :succeeded || ex.node.optional?
52
+ message = "\"#{ex.extender}\" failed to @extend \"#{ex.target.join}\"."
53
+ reason =
54
+ if ex.result == :not_found
55
+ "The selector \"#{ex.target.join}\" was not found."
56
+ else
57
+ "No selectors matching \"#{ex.target.join}\" could be unified with \"#{ex.extender}\"."
58
+ end
54
59
 
55
- # TODO(nweiz): this should use the Sass stack trace of the extend node.
56
- raise Sass::SyntaxError.new(<<MESSAGE, :filename => ex.node.filename, :line => ex.node.line)
60
+ # TODO(nweiz): this should use the Sass stack trace of the extend node.
61
+ raise Sass::SyntaxError.new(<<MESSAGE, :filename => ex.node.filename, :line => ex.node.line)
57
62
  #{message}
58
- The selector "#{ex.target.join}" was not found.
63
+ #{reason}
59
64
  Use "@extend #{ex.target.join} !optional" if the extend should be able to fail.
60
65
  MESSAGE
61
- end
62
66
  end
63
67
  end
64
68
  end
@@ -1,7 +1,5 @@
1
1
  # A visitor for converting a dynamic Sass tree into a static Sass tree.
2
2
  class Sass::Tree::Visitors::Perform < Sass::Tree::Visitors::Base
3
- @@function_name_deprecation = Sass::Deprecation.new
4
-
5
3
  class << self
6
4
  # @param root [Tree::Node] The root node of the tree to visit.
7
5
  # @param environment [Sass::Environment] The lexical environment.
@@ -11,6 +9,8 @@ class Sass::Tree::Visitors::Perform < Sass::Tree::Visitors::Base
11
9
  end
12
10
 
13
11
  # @api private
12
+ # @comment
13
+ # rubocop:disable MethodLength
14
14
  def perform_arguments(callable, args, splat, environment)
15
15
  desc = "#{callable.type.capitalize} #{callable.name}"
16
16
  downcase_desc = "#{callable.type} #{callable.name}"
@@ -143,13 +143,13 @@ class Sass::Tree::Visitors::Perform < Sass::Tree::Visitors::Base
143
143
  end
144
144
  end
145
145
  end
146
+ # @comment
147
+ # rubocop:enable MethodLength
146
148
 
147
149
  protected
148
150
 
149
151
  def initialize(env)
150
152
  @environment = env
151
- @in_keyframes = false
152
- @at_root_without_rule = false
153
153
  end
154
154
 
155
155
  # If an exception is raised, this adds proper metadata to the backtrace.
@@ -278,7 +278,8 @@ class Sass::Tree::Visitors::Perform < Sass::Tree::Visitors::Base
278
278
 
279
279
  if node.normalized_name == 'calc' || node.normalized_name == 'element' ||
280
280
  node.name == 'expression' || node.name == 'url'
281
- @@function_name_deprecation.warn(node.filename, node.line, <<WARNING)
281
+ Sass::Util.sass_warn <<WARNING
282
+ DEPRECATION WARNING on line #{node.line}#{" of #{node.filename}" if node.filename}:
282
283
  Naming a function "#{node.name}" is disallowed and will be an error in future versions of Sass.
283
284
  This name conflicts with an existing CSS function with special parse rules.
284
285
  WARNING
@@ -286,7 +287,7 @@ WARNING
286
287
 
287
288
  @environment.set_local_function(node.name,
288
289
  Sass::Callable.new(node.name, node.args, node.splat, env,
289
- node.children, false, "function", :stylesheet))
290
+ node.children, !:has_content, "function"))
290
291
  []
291
292
  end
292
293
 
@@ -337,7 +338,7 @@ WARNING
337
338
  env = Sass::Environment.new(@environment, node.options)
338
339
  @environment.set_local_mixin(node.name,
339
340
  Sass::Callable.new(node.name, node.args, node.splat, env,
340
- node.children, node.has_content, "mixin", :stylesheet))
341
+ node.children, node.has_content, "mixin"))
341
342
  []
342
343
  end
343
344
 
@@ -347,8 +348,8 @@ WARNING
347
348
  mixin = @environment.mixin(node.name)
348
349
  raise Sass::SyntaxError.new("Undefined mixin '#{node.name}'.") unless mixin
349
350
 
350
- if node.has_children && !mixin.has_content
351
- raise Sass::SyntaxError.new(%(Mixin "#{node.name}" does not accept a content block.))
351
+ if node.children.any? && !mixin.has_content
352
+ raise Sass::SyntaxError.new(%Q{Mixin "#{node.name}" does not accept a content block.})
352
353
  end
353
354
 
354
355
  args = node.args.map {|a| a.perform(@environment)}
@@ -391,19 +392,9 @@ WARNING
391
392
  # Runs any SassScript that may be embedded in a property.
392
393
  def visit_prop(node)
393
394
  node.resolved_name = run_interp(node.name)
394
-
395
- # If the node's value is just a variable or similar, we may get a useful
396
- # source range from evaluating it.
397
- if node.value.length == 1 && node.value.first.is_a?(Sass::Script::Tree::Node)
398
- result = node.value.first.perform(@environment)
399
- node.resolved_value = result.to_s
400
- node.value_source_range = result.source_range if result.source_range
401
- elsif node.custom_property?
402
- node.resolved_value = run_interp_no_strip(node.value)
403
- else
404
- node.resolved_value = run_interp(node.value)
405
- end
406
-
395
+ val = node.value.perform(@environment)
396
+ node.resolved_value = val.to_s
397
+ node.value_source_range = val.source_range if val.source_range
407
398
  yield
408
399
  end
409
400
 
@@ -489,11 +480,9 @@ WARNING
489
480
  def visit_warn(node)
490
481
  res = node.expr.perform(@environment)
491
482
  res = res.value if res.is_a?(Sass::Script::Value::String)
492
- @environment.stack.with_directive(node.filename, node.line, "@warn") do
493
- msg = "WARNING: #{res}\n "
494
- msg << @environment.stack.to_s.gsub("\n", "\n ") << "\n"
495
- Sass::Util.sass_warn msg
496
- end
483
+ msg = "WARNING: #{res}\n "
484
+ msg << @environment.stack.to_s.gsub("\n", "\n ") << "\n"
485
+ Sass::Util.sass_warn msg
497
486
  []
498
487
  end
499
488
 
@@ -553,7 +542,7 @@ WARNING
553
542
  end
554
543
 
555
544
  def run_interp(text)
556
- Sass::Util.strip_except_escapes(run_interp_no_strip(text))
545
+ run_interp_no_strip(text).strip
557
546
  end
558
547
 
559
548
  def handle_import_loop!(node)
@@ -564,7 +553,7 @@ WARNING
564
553
  end
565
554
 
566
555
  files << node.filename << node.imported_file.options[:filename]
567
- msg << "\n" << files.each_cons(2).map do |m1, m2|
556
+ msg << "\n" << Sass::Util.enum_cons(files, 2).map do |m1, m2|
568
557
  " #{m1} imports #{m2}"
569
558
  end.join("\n")
570
559
  raise Sass::SyntaxError.new(msg)
@@ -80,7 +80,7 @@ class Sass::Tree::Visitors::SetOptions < Sass::Tree::Visitors::Base
80
80
 
81
81
  def visit_mixin(node)
82
82
  node.args.each {|a| a.options = @options}
83
- node.keywords.each {|_k, v| v.options = @options}
83
+ node.keywords.each {|k, v| v.options = @options}
84
84
  node.splat.options = @options if node.splat
85
85
  node.kwarg_splat.options = @options if node.kwarg_splat
86
86
  yield
@@ -88,7 +88,7 @@ class Sass::Tree::Visitors::SetOptions < Sass::Tree::Visitors::Base
88
88
 
89
89
  def visit_prop(node)
90
90
  node.name.each {|c| c.options = @options if c.is_a?(Sass::Script::Tree::Node)}
91
- node.value.each {|c| c.options = @options if c.is_a?(Sass::Script::Tree::Node)}
91
+ node.value.options = @options
92
92
  yield
93
93
  end
94
94
 
@@ -12,10 +12,8 @@ class Sass::Tree::Visitors::ToCss < Sass::Tree::Visitors::Base
12
12
  @tabs = 0
13
13
  @line = 1
14
14
  @offset = 1
15
- @result = String.new("")
16
- @source_mapping = build_source_mapping ? Sass::Source::Map.new : nil
17
- @lstrip = nil
18
- @in_directive = false
15
+ @result = ""
16
+ @source_mapping = Sass::Source::Map.new if build_source_mapping
19
17
  end
20
18
 
21
19
  # Runs the visitor on `node`.
@@ -53,8 +51,8 @@ class Sass::Tree::Visitors::ToCss < Sass::Tree::Visitors::Base
53
51
  @source_mapping.add(source_range, target_range)
54
52
  end
55
53
 
56
- def trailing_semicolon?
57
- @result.end_with?(";") && !@result.end_with?('\;')
54
+ def ends_with?(str)
55
+ @result.end_with?(str)
58
56
  end
59
57
 
60
58
  # Move the output cursor back `chars` characters.
@@ -104,7 +102,7 @@ class Sass::Tree::Visitors::ToCss < Sass::Tree::Visitors::Base
104
102
  @lstrip = true
105
103
  yield
106
104
  ensure
107
- @lstrip &&= old_lstrip
105
+ @lstrip = @lstrip && old_lstrip
108
106
  end
109
107
 
110
108
  # Prepend `prefix` to the output string.
@@ -122,20 +120,22 @@ class Sass::Tree::Visitors::ToCss < Sass::Tree::Visitors::Base
122
120
  node.children.each do |child|
123
121
  next if child.invisible?
124
122
  visit(child)
125
- next if node.style == :compressed
126
- output "\n"
127
- next unless child.is_a?(Sass::Tree::DirectiveNode) && child.has_children && !child.bubbles?
128
- output "\n"
123
+ unless node.style == :compressed
124
+ output "\n"
125
+ if child.is_a?(Sass::Tree::DirectiveNode) && child.has_children && !child.bubbles?
126
+ output "\n"
127
+ end
128
+ end
129
129
  end
130
130
  rstrip!
131
- if node.style == :compressed && trailing_semicolon?
131
+ if node.style == :compressed && ends_with?(";")
132
132
  erase! 1
133
133
  end
134
134
  return "" if @result.empty?
135
135
 
136
136
  output "\n"
137
137
 
138
- unless @result.ascii_only?
138
+ unless Sass::Util.ruby1_8? || @result.ascii_only?
139
139
  if node.style == :compressed
140
140
  # A byte order mark is sufficient to tell browsers that this
141
141
  # file is UTF-8 encoded, and will override any other detection
@@ -163,14 +163,16 @@ class Sass::Tree::Visitors::ToCss < Sass::Tree::Visitors::Base
163
163
 
164
164
  content = node.resolved_value.split("\n").join("\n" + spaces)
165
165
  if node.type == :silent
166
- content.gsub!(%r{^(\s*)//(.*)$}) {"#{$1}/*#{$2} */"}
166
+ content.gsub!(%r{^(\s*)//(.*)$}) {|md| "#{$1}/*#{$2} */"}
167
167
  end
168
168
  if (node.style == :compact || node.style == :compressed) && node.type != :loud
169
- content.gsub!(%r{\n +(\* *(?!/))?}, ' ')
169
+ content.gsub!(/\n +(\* *(?!\/))?/, ' ')
170
170
  end
171
171
  for_node(node) {output(content)}
172
172
  end
173
173
 
174
+ # @comment
175
+ # rubocop:disable MethodLength
174
176
  def visit_directive(node)
175
177
  was_in_directive = @in_directive
176
178
  tab_str = ' ' * @tabs
@@ -185,7 +187,7 @@ class Sass::Tree::Visitors::ToCss < Sass::Tree::Visitors::Base
185
187
  return
186
188
  end
187
189
 
188
- @in_directive ||= !node.is_a?(Sass::Tree::MediaNode)
190
+ @in_directive = @in_directive || !node.is_a?(Sass::Tree::MediaNode)
189
191
  output(tab_str) if node.style != :compressed
190
192
  for_node(node) {output(node.resolved_value)}
191
193
  output(node.style == :compressed ? "{" : " {")
@@ -220,7 +222,7 @@ class Sass::Tree::Visitors::ToCss < Sass::Tree::Visitors::Base
220
222
  first = false
221
223
  elsif node.style == :compressed
222
224
  unless had_children
223
- output(";") unless trailing_semicolon?
225
+ output(";") unless ends_with?(";")
224
226
  end
225
227
  with_tabs(0) {visit(child)}
226
228
  had_children = child.has_children
@@ -230,7 +232,7 @@ class Sass::Tree::Visitors::ToCss < Sass::Tree::Visitors::Base
230
232
  end
231
233
  end
232
234
  rstrip!
233
- if node.style == :compressed && trailing_semicolon?
235
+ if node.style == :compressed && ends_with?(";")
234
236
  erase! 1
235
237
  end
236
238
  if node.style == :expanded
@@ -242,6 +244,8 @@ class Sass::Tree::Visitors::ToCss < Sass::Tree::Visitors::Base
242
244
  ensure
243
245
  @in_directive = was_in_directive
244
246
  end
247
+ # @comment
248
+ # rubocop:enable MethodLength
245
249
 
246
250
  def visit_media(node)
247
251
  with_tabs(@tabs + node.tabs) {visit_directive(node)}
@@ -257,22 +261,22 @@ class Sass::Tree::Visitors::ToCss < Sass::Tree::Visitors::Base
257
261
  end
258
262
 
259
263
  def visit_prop(node)
260
- return if node.resolved_value.empty? && !node.custom_property?
264
+ return if node.resolved_value.empty?
261
265
  tab_str = ' ' * (@tabs + node.tabs)
262
266
  output(tab_str)
263
267
  for_node(node, :name) {output(node.resolved_name)}
264
- output(":")
265
- output(" ") unless node.style == :compressed || node.custom_property?
266
- for_node(node, :value) do
267
- output(if node.custom_property?
268
- format_custom_property_value(node)
269
- else
270
- node.resolved_value
271
- end)
268
+ if node.style == :compressed
269
+ output(":")
270
+ for_node(node, :value) {output(node.resolved_value)}
271
+ else
272
+ output(": ")
273
+ for_node(node, :value) {output(node.resolved_value)}
274
+ output(";")
272
275
  end
273
- output(";") unless node.style == :compressed
274
276
  end
275
277
 
278
+ # @comment
279
+ # rubocop:disable MethodLength
276
280
  def visit_rule(node)
277
281
  with_tabs(@tabs + node.tabs) do
278
282
  rule_separator = node.style == :compressed ? ',' : ', '
@@ -290,15 +294,12 @@ class Sass::Tree::Visitors::ToCss < Sass::Tree::Visitors::Base
290
294
  end
291
295
 
292
296
  joined_rules = node.resolved_rules.members.map do |seq|
293
- next if seq.invisible?
294
- rule_part = seq.to_s(style: node.style, placeholder: false)
297
+ next if seq.has_placeholder?
298
+ rule_part = seq.to_s
295
299
  if node.style == :compressed
296
300
  rule_part.gsub!(/([^,])\s*\n\s*/m, '\1 ')
297
- rule_part.gsub!(/\s*([+>])\s*/m, '\1')
298
- rule_part.gsub!(/nth([^( ]*)\(([^)]*)\)/m) do |match|
299
- match.tr(" \t\n", "")
300
- end
301
- rule_part = Sass::Util.strip_except_escapes(rule_part)
301
+ rule_part.gsub!(/\s*([-,+>])\s*/m, '\1')
302
+ rule_part.strip!
302
303
  end
303
304
  rule_part
304
305
  end.compact.join(rule_separator)
@@ -336,7 +337,7 @@ class Sass::Tree::Visitors::ToCss < Sass::Tree::Visitors::Base
336
337
  end
337
338
  end
338
339
 
339
- end_props, trailer, tabs = '', '', 0
340
+ end_props, trailer, tabs = '', '', 0
340
341
  if node.style == :compact
341
342
  separator, end_props, bracket = ' ', ' ', ' { '
342
343
  trailer = "\n" if node.group_end
@@ -355,7 +356,7 @@ class Sass::Tree::Visitors::ToCss < Sass::Tree::Visitors::Base
355
356
  with_tabs(tabs) do
356
357
  node.children.each_with_index do |child, i|
357
358
  if i > 0
358
- if separator.start_with?(";") && trailing_semicolon?
359
+ if separator.start_with?(";") && ends_with?(";")
359
360
  erase! 1
360
361
  end
361
362
  output(separator)
@@ -363,7 +364,7 @@ class Sass::Tree::Visitors::ToCss < Sass::Tree::Visitors::Base
363
364
  visit(child)
364
365
  end
365
366
  end
366
- if node.style == :compressed && trailing_semicolon?
367
+ if node.style == :compressed && ends_with?(";")
367
368
  erase! 1
368
369
  end
369
370
 
@@ -371,6 +372,8 @@ class Sass::Tree::Visitors::ToCss < Sass::Tree::Visitors::Base
371
372
  output("}" + trailer)
372
373
  end
373
374
  end
375
+ # @comment
376
+ # rubocop:enable MethodLength
374
377
 
375
378
  def visit_keyframerule(node)
376
379
  visit_directive(node)
@@ -378,51 +381,18 @@ class Sass::Tree::Visitors::ToCss < Sass::Tree::Visitors::Base
378
381
 
379
382
  private
380
383
 
381
- # Reformats the value of `node` so that it's nicely indented, preserving its
382
- # existing relative indentation.
383
- #
384
- # @param node [Sass::Script::Tree::PropNode] A custom property node.
385
- # @return [String]
386
- def format_custom_property_value(node)
387
- value = node.resolved_value.sub(/\n[ \t\r\f\n]*\Z/, ' ')
388
- if node.style == :compact || node.style == :compressed || !value.include?("\n")
389
- # Folding not involving newlines was done in the parser. We can safely
390
- # fold newlines here because tokens like strings can't contain literal
391
- # newlines, so we know any adjacent whitespace is tokenized as whitespace.
392
- return node.resolved_value.gsub(/[ \t\r\f]*\n[ \t\r\f\n]*/, ' ')
393
- end
394
-
395
- # Find the smallest amount of indentation in the custom property and use
396
- # that as the base indentation level.
397
- lines = value.split("\n")
398
- indented_lines = lines[1..-1]
399
- min_indentation = indented_lines.
400
- map {|line| line[/^[ \t]*/]}.
401
- reject {|line| line.empty?}.
402
- min_by {|line| line.length}
403
-
404
- # Limit the base indentation to the same indentation level as the node name
405
- # so that if *every* line is indented relative to the property name that's
406
- # preserved.
407
- if node.name_source_range
408
- base_indentation = min_indentation[0...node.name_source_range.start_pos.offset - 1]
409
- end
410
-
411
- lines.first + "\n" + indented_lines.join("\n").gsub(/^#{base_indentation}/, ' ' * @tabs)
412
- end
413
-
414
384
  def debug_info_rule(debug_info, options)
415
385
  node = Sass::Tree::DirectiveNode.resolved("@media -sass-debug-info")
416
- debug_info.map {|k, v| [k.to_s, v.to_s]}.to_a.each do |k, v|
386
+ Sass::Util.hash_to_a(debug_info.map {|k, v| [k.to_s, v.to_s]}).each do |k, v|
417
387
  rule = Sass::Tree::RuleNode.new([""])
418
388
  rule.resolved_rules = Sass::Selector::CommaSequence.new(
419
389
  [Sass::Selector::Sequence.new(
420
- [Sass::Selector::SimpleSequence.new(
421
- [Sass::Selector::Element.new(k.to_s.gsub(/[^\w-]/, "\\\\\\0"), nil)],
422
- false)
423
- ])
390
+ [Sass::Selector::SimpleSequence.new(
391
+ [Sass::Selector::Element.new(k.to_s.gsub(/[^\w-]/, "\\\\\\0"), nil)],
392
+ false)
393
+ ])
424
394
  ])
425
- prop = Sass::Tree::PropNode.new([""], [""], :new)
395
+ prop = Sass::Tree::PropNode.new([""], Sass::Script::Value::String.new(''), :new)
426
396
  prop.resolved_name = "font-family"
427
397
  prop.resolved_value = Sass::SCSS::RX.escape_ident(v.to_s)
428
398
  rule << prop