sass 3.2.7 → 3.3.0.rc.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 (184) hide show
  1. data/MIT-LICENSE +2 -2
  2. data/README.md +14 -2
  3. data/Rakefile +25 -1
  4. data/VERSION +1 -1
  5. data/VERSION_DATE +1 -1
  6. data/VERSION_NAME +1 -1
  7. data/lib/sass/cache_stores/base.rb +4 -2
  8. data/lib/sass/cache_stores/chain.rb +2 -1
  9. data/lib/sass/cache_stores/filesystem.rb +2 -6
  10. data/lib/sass/cache_stores/memory.rb +1 -1
  11. data/lib/sass/cache_stores/null.rb +2 -2
  12. data/lib/sass/callbacks.rb +1 -0
  13. data/lib/sass/css.rb +10 -10
  14. data/lib/sass/engine.rb +403 -150
  15. data/lib/sass/environment.rb +136 -57
  16. data/lib/sass/error.rb +7 -7
  17. data/lib/sass/exec.rb +123 -39
  18. data/lib/sass/features.rb +41 -0
  19. data/lib/sass/importers/base.rb +33 -2
  20. data/lib/sass/importers/deprecated_path.rb +45 -0
  21. data/lib/sass/importers/filesystem.rb +25 -14
  22. data/lib/sass/importers.rb +1 -0
  23. data/lib/sass/logger/base.rb +3 -3
  24. data/lib/sass/logger/log_level.rb +4 -6
  25. data/lib/sass/media.rb +19 -19
  26. data/lib/sass/plugin/compiler.rb +141 -101
  27. data/lib/sass/plugin/configuration.rb +18 -22
  28. data/lib/sass/plugin/merb.rb +1 -1
  29. data/lib/sass/plugin/staleness_checker.rb +24 -8
  30. data/lib/sass/plugin.rb +4 -2
  31. data/lib/sass/repl.rb +3 -3
  32. data/lib/sass/script/css_lexer.rb +9 -4
  33. data/lib/sass/script/css_parser.rb +6 -2
  34. data/lib/sass/script/functions.rb +1343 -590
  35. data/lib/sass/script/lexer.rb +84 -52
  36. data/lib/sass/script/parser.rb +217 -97
  37. data/lib/sass/script/tree/funcall.rb +290 -0
  38. data/lib/sass/script/{interpolation.rb → tree/interpolation.rb} +34 -13
  39. data/lib/sass/script/tree/list_literal.rb +80 -0
  40. data/lib/sass/script/tree/literal.rb +47 -0
  41. data/lib/sass/script/tree/map_literal.rb +64 -0
  42. data/lib/sass/script/{node.rb → tree/node.rb} +22 -12
  43. data/lib/sass/script/{operation.rb → tree/operation.rb} +17 -25
  44. data/lib/sass/script/tree/selector.rb +30 -0
  45. data/lib/sass/script/{string_interpolation.rb → tree/string_interpolation.rb} +5 -4
  46. data/lib/sass/script/{unary_operation.rb → tree/unary_operation.rb} +14 -9
  47. data/lib/sass/script/tree/variable.rb +57 -0
  48. data/lib/sass/script/tree.rb +16 -0
  49. data/lib/sass/script/{arg_list.rb → value/arg_list.rb} +4 -24
  50. data/lib/sass/script/value/base.rb +248 -0
  51. data/lib/sass/script/value/bool.rb +36 -0
  52. data/lib/sass/script/{color.rb → value/color.rb} +239 -195
  53. data/lib/sass/script/value/helpers.rb +155 -0
  54. data/lib/sass/script/value/list.rb +119 -0
  55. data/lib/sass/script/value/map.rb +70 -0
  56. data/lib/sass/script/value/null.rb +45 -0
  57. data/lib/sass/script/{number.rb → value/number.rb} +91 -65
  58. data/lib/sass/script/{string.rb → value/string.rb} +9 -11
  59. data/lib/sass/script/value.rb +11 -0
  60. data/lib/sass/script.rb +35 -8
  61. data/lib/sass/scss/css_parser.rb +2 -1
  62. data/lib/sass/scss/parser.rb +338 -170
  63. data/lib/sass/scss/rx.rb +5 -6
  64. data/lib/sass/scss/script_lexer.rb +1 -0
  65. data/lib/sass/scss/script_parser.rb +1 -0
  66. data/lib/sass/scss/static_parser.rb +23 -6
  67. data/lib/sass/selector/abstract_sequence.rb +2 -2
  68. data/lib/sass/selector/comma_sequence.rb +21 -16
  69. data/lib/sass/selector/sequence.rb +60 -34
  70. data/lib/sass/selector/simple.rb +11 -12
  71. data/lib/sass/selector/simple_sequence.rb +55 -33
  72. data/lib/sass/selector.rb +52 -48
  73. data/lib/sass/source/map.rb +211 -0
  74. data/lib/sass/source/position.rb +39 -0
  75. data/lib/sass/source/range.rb +41 -0
  76. data/lib/sass/stack.rb +120 -0
  77. data/lib/sass/supports.rb +12 -13
  78. data/lib/sass/tree/at_root_node.rb +82 -0
  79. data/lib/sass/tree/comment_node.rb +3 -3
  80. data/lib/sass/tree/css_import_node.rb +11 -11
  81. data/lib/sass/tree/debug_node.rb +2 -2
  82. data/lib/sass/tree/directive_node.rb +13 -2
  83. data/lib/sass/tree/each_node.rb +8 -8
  84. data/lib/sass/tree/extend_node.rb +13 -6
  85. data/lib/sass/tree/for_node.rb +4 -4
  86. data/lib/sass/tree/function_node.rb +5 -4
  87. data/lib/sass/tree/if_node.rb +1 -1
  88. data/lib/sass/tree/import_node.rb +4 -5
  89. data/lib/sass/tree/media_node.rb +4 -14
  90. data/lib/sass/tree/mixin_def_node.rb +4 -4
  91. data/lib/sass/tree/mixin_node.rb +21 -8
  92. data/lib/sass/tree/node.rb +29 -12
  93. data/lib/sass/tree/prop_node.rb +38 -18
  94. data/lib/sass/tree/return_node.rb +3 -2
  95. data/lib/sass/tree/root_node.rb +19 -3
  96. data/lib/sass/tree/rule_node.rb +25 -17
  97. data/lib/sass/tree/supports_node.rb +0 -13
  98. data/lib/sass/tree/trace_node.rb +2 -1
  99. data/lib/sass/tree/variable_node.rb +9 -3
  100. data/lib/sass/tree/visitors/base.rb +6 -6
  101. data/lib/sass/tree/visitors/check_nesting.rb +12 -9
  102. data/lib/sass/tree/visitors/convert.rb +63 -38
  103. data/lib/sass/tree/visitors/cssize.rb +63 -23
  104. data/lib/sass/tree/visitors/deep_copy.rb +6 -5
  105. data/lib/sass/tree/visitors/extend.rb +7 -7
  106. data/lib/sass/tree/visitors/perform.rb +256 -151
  107. data/lib/sass/tree/visitors/set_options.rb +6 -6
  108. data/lib/sass/tree/visitors/to_css.rb +231 -81
  109. data/lib/sass/tree/warn_node.rb +2 -2
  110. data/lib/sass/tree/while_node.rb +2 -2
  111. data/lib/sass/util/multibyte_string_scanner.rb +2 -0
  112. data/lib/sass/util/normalized_map.rb +65 -0
  113. data/lib/sass/util/ordered_hash.rb +188 -0
  114. data/lib/sass/util/subset_map.rb +3 -2
  115. data/lib/sass/util/test.rb +9 -0
  116. data/lib/sass/util.rb +220 -34
  117. data/lib/sass/version.rb +9 -9
  118. data/lib/sass.rb +14 -7
  119. data/test/sass/compiler_test.rb +213 -0
  120. data/test/sass/conversion_test.rb +235 -9
  121. data/test/sass/engine_test.rb +230 -60
  122. data/test/sass/exec_test.rb +86 -0
  123. data/test/sass/extend_test.rb +215 -147
  124. data/test/sass/functions_test.rb +584 -99
  125. data/test/sass/importer_test.rb +165 -17
  126. data/test/sass/plugin_test.rb +19 -13
  127. data/test/sass/script_conversion_test.rb +40 -0
  128. data/test/sass/script_test.rb +231 -21
  129. data/test/sass/scss/css_test.rb +14 -5
  130. data/test/sass/scss/scss_test.rb +1266 -66
  131. data/test/sass/source_map_test.rb +879 -0
  132. data/test/sass/templates/bork5.sass +3 -0
  133. data/test/sass/util/normalized_map_test.rb +30 -0
  134. data/test/sass/util_test.rb +90 -0
  135. data/test/sass/value_helpers_test.rb +181 -0
  136. data/test/test_helper.rb +7 -2
  137. metadata +316 -291
  138. data/lib/sass/script/bool.rb +0 -18
  139. data/lib/sass/script/funcall.rb +0 -231
  140. data/lib/sass/script/list.rb +0 -84
  141. data/lib/sass/script/literal.rb +0 -239
  142. data/lib/sass/script/null.rb +0 -34
  143. data/lib/sass/script/variable.rb +0 -58
  144. data/test/Gemfile +0 -3
  145. data/vendor/listen/CHANGELOG.md +0 -221
  146. data/vendor/listen/CONTRIBUTING.md +0 -38
  147. data/vendor/listen/Gemfile +0 -30
  148. data/vendor/listen/Guardfile +0 -8
  149. data/vendor/listen/LICENSE +0 -20
  150. data/vendor/listen/README.md +0 -315
  151. data/vendor/listen/Rakefile +0 -47
  152. data/vendor/listen/Vagrantfile +0 -96
  153. data/vendor/listen/lib/listen/adapter.rb +0 -214
  154. data/vendor/listen/lib/listen/adapters/bsd.rb +0 -112
  155. data/vendor/listen/lib/listen/adapters/darwin.rb +0 -85
  156. data/vendor/listen/lib/listen/adapters/linux.rb +0 -113
  157. data/vendor/listen/lib/listen/adapters/polling.rb +0 -67
  158. data/vendor/listen/lib/listen/adapters/windows.rb +0 -87
  159. data/vendor/listen/lib/listen/dependency_manager.rb +0 -126
  160. data/vendor/listen/lib/listen/directory_record.rb +0 -371
  161. data/vendor/listen/lib/listen/listener.rb +0 -225
  162. data/vendor/listen/lib/listen/multi_listener.rb +0 -143
  163. data/vendor/listen/lib/listen/turnstile.rb +0 -28
  164. data/vendor/listen/lib/listen/version.rb +0 -3
  165. data/vendor/listen/lib/listen.rb +0 -40
  166. data/vendor/listen/listen.gemspec +0 -22
  167. data/vendor/listen/spec/listen/adapter_spec.rb +0 -183
  168. data/vendor/listen/spec/listen/adapters/bsd_spec.rb +0 -36
  169. data/vendor/listen/spec/listen/adapters/darwin_spec.rb +0 -37
  170. data/vendor/listen/spec/listen/adapters/linux_spec.rb +0 -47
  171. data/vendor/listen/spec/listen/adapters/polling_spec.rb +0 -68
  172. data/vendor/listen/spec/listen/adapters/windows_spec.rb +0 -30
  173. data/vendor/listen/spec/listen/dependency_manager_spec.rb +0 -107
  174. data/vendor/listen/spec/listen/directory_record_spec.rb +0 -1225
  175. data/vendor/listen/spec/listen/listener_spec.rb +0 -169
  176. data/vendor/listen/spec/listen/multi_listener_spec.rb +0 -174
  177. data/vendor/listen/spec/listen/turnstile_spec.rb +0 -56
  178. data/vendor/listen/spec/listen_spec.rb +0 -73
  179. data/vendor/listen/spec/spec_helper.rb +0 -21
  180. data/vendor/listen/spec/support/adapter_helper.rb +0 -629
  181. data/vendor/listen/spec/support/directory_record_helper.rb +0 -55
  182. data/vendor/listen/spec/support/fixtures_helper.rb +0 -29
  183. data/vendor/listen/spec/support/listeners_helper.rb +0 -156
  184. data/vendor/listen/spec/support/platform_helper.rb +0 -15
@@ -1,14 +1,14 @@
1
1
  module Sass::Tree
2
- # A static node reprenting a CSS property.
2
+ # A static node representing a CSS property.
3
3
  #
4
4
  # @see Sass::Tree
5
5
  class PropNode < Node
6
6
  # The name of the property,
7
- # interspersed with {Sass::Script::Node}s
7
+ # interspersed with {Sass::Script::Tree::Node}s
8
8
  # representing `#{}`-interpolation.
9
9
  # Any adjacent strings will be merged together.
10
10
  #
11
- # @return [Array<String, Sass::Script::Node>]
11
+ # @return [Array<String, Sass::Script::Tree::Node>]
12
12
  attr_accessor :name
13
13
 
14
14
  # The name of the property
@@ -20,7 +20,7 @@ module Sass::Tree
20
20
 
21
21
  # The value of the property.
22
22
  #
23
- # @return [Sass::Script::Node]
23
+ # @return [Sass::Script::Tree::Node]
24
24
  attr_accessor :value
25
25
 
26
26
  # The value of the property
@@ -42,8 +42,18 @@ module Sass::Tree
42
42
  # @return [Fixnum]
43
43
  attr_accessor :tabs
44
44
 
45
- # @param name [Array<String, Sass::Script::Node>] See \{#name}
46
- # @param value [Sass::Script::Node] See \{#value}
45
+ # The source range in which the property name appears.
46
+ #
47
+ # @return [Sass::Source::Range]
48
+ attr_accessor :name_source_range
49
+
50
+ # The source range in which the property value appears.
51
+ #
52
+ # @return [Sass::Source::Range]
53
+ attr_accessor :value_source_range
54
+
55
+ # @param name [Array<String, Sass::Script::Tree::Node>] See \{#name}
56
+ # @param value [Sass::Script::Tree::Node] See \{#value}
47
57
  # @param prop_syntax [Symbol] `:new` if this property uses `a: b`-style syntax,
48
58
  # `:old` if it uses `:a b`-style syntax
49
59
  def initialize(name, value, prop_syntax)
@@ -70,7 +80,13 @@ module Sass::Tree
70
80
  #
71
81
  # @return [String] The message
72
82
  def pseudo_class_selector_message
73
- return "" if @prop_syntax == :new || !value.is_a?(Sass::Script::String) || !value.value.empty?
83
+ if @prop_syntax == :new ||
84
+ !value.is_a?(Sass::Script::Tree::Literal) ||
85
+ !value.value.is_a?(Sass::Script::Value::String) ||
86
+ !value.value.value.empty?
87
+ return ""
88
+ end
89
+
74
90
  "\nIf #{declaration.dump} should be a selector, use \"\\#{declaration}\" instead."
75
91
  end
76
92
 
@@ -83,7 +99,8 @@ module Sass::Tree
83
99
  def declaration(opts = {:old => @prop_syntax == :old}, fmt = :sass)
84
100
  name = self.name.map {|n| n.is_a?(String) ? n : "\#{#{n.to_sass(opts)}}"}.join
85
101
  if name[0] == ?:
86
- raise Sass::SyntaxError.new("The \"#{name}: #{self.class.val_to_sass(value, opts)}\" hack is not allowed in the Sass indented syntax")
102
+ raise Sass::SyntaxError.new("The \"#{name}: #{self.class.val_to_sass(value, opts)}\"" +
103
+ " hack is not allowed in the Sass indented syntax")
87
104
  end
88
105
 
89
106
  old = opts[:old] && fmt == :sass
@@ -104,7 +121,8 @@ module Sass::Tree
104
121
  def check!
105
122
  if @options[:property_syntax] && @options[:property_syntax] != @prop_syntax
106
123
  raise Sass::SyntaxError.new(
107
- "Illegal property syntax: can't use #{@prop_syntax} syntax when :property_syntax => #{@options[:property_syntax].inspect} is set.")
124
+ "Illegal property syntax: can't use #{@prop_syntax} syntax when " +
125
+ ":property_syntax => #{@options[:property_syntax].inspect} is set.")
108
126
  end
109
127
  end
110
128
 
@@ -117,34 +135,36 @@ module Sass::Tree
117
135
  private
118
136
 
119
137
  def val_to_sass_comma(node, opts)
120
- return node unless node.is_a?(Sass::Script::Operation)
138
+ return node unless node.is_a?(Sass::Script::Tree::Operation)
121
139
  return val_to_sass_concat(node, opts) unless node.operator == :comma
122
140
 
123
- Sass::Script::Operation.new(
141
+ Sass::Script::Tree::Operation.new(
124
142
  val_to_sass_concat(node.operand1, opts),
125
143
  val_to_sass_comma(node.operand2, opts),
126
144
  node.operator)
127
145
  end
128
146
 
129
147
  def val_to_sass_concat(node, opts)
130
- return node unless node.is_a?(Sass::Script::Operation)
148
+ return node unless node.is_a?(Sass::Script::Tree::Operation)
131
149
  return val_to_sass_div(node, opts) unless node.operator == :space
132
150
 
133
- Sass::Script::Operation.new(
151
+ Sass::Script::Tree::Operation.new(
134
152
  val_to_sass_div(node.operand1, opts),
135
153
  val_to_sass_concat(node.operand2, opts),
136
154
  node.operator)
137
155
  end
138
156
 
139
157
  def val_to_sass_div(node, opts)
140
- unless node.is_a?(Sass::Script::Operation) && node.operator == :div &&
141
- node.operand1.is_a?(Sass::Script::Number) &&
142
- node.operand2.is_a?(Sass::Script::Number) &&
143
- (!node.operand1.original || !node.operand2.original)
158
+ unless node.is_a?(Sass::Script::Tree::Operation) && node.operator == :div &&
159
+ node.operand1.is_a?(Sass::Script::Tree::Literal) &&
160
+ node.operand1.value.is_a?(Sass::Script::Value::Number) &&
161
+ node.operand2.is_a?(Sass::Script::Tree::Literal) &&
162
+ node.operand2.value.is_a?(Sass::Script::Value::Number) &&
163
+ (!node.operand1.value.original || !node.operand2.value.original)
144
164
  return node
145
165
  end
146
166
 
147
- Sass::Script::String.new("(#{node.to_sass(opts)})")
167
+ Sass::Script::Value::String.new("(#{node.to_sass(opts)})")
148
168
  end
149
169
 
150
170
  end
@@ -5,10 +5,11 @@ module Sass
5
5
  # @see Sass::Tree
6
6
  class ReturnNode < Node
7
7
  # The expression to return.
8
- # @type [Script::Node]
8
+ #
9
+ # @return [Script::Tree::Node]
9
10
  attr_accessor :expr
10
11
 
11
- # @param expr [Script::Node] The expression to return
12
+ # @param expr [Script::Tree::Node] The expression to return
12
13
  def initialize(expr)
13
14
  @expr = expr
14
15
  super()
@@ -13,15 +13,31 @@ module Sass
13
13
  @template = template
14
14
  end
15
15
 
16
- # Runs the dynamic Sass code *and* computes the CSS for the tree.
17
- # @see #to_s
16
+ # Runs the dynamic Sass code and computes the CSS for the tree.
17
+ #
18
+ # @return [String] The compiled CSS.
18
19
  def render
20
+ css_tree.css
21
+ end
22
+
23
+ # Runs the dynamic Sass code and computes the CSS for the tree, along with
24
+ # the sourcemap.
25
+ #
26
+ # @return [(String, Sass::Source::Map)] The compiled CSS, as well as
27
+ # the source map. @see #render
28
+ def render_with_sourcemap
29
+ css_tree.css_with_sourcemap
30
+ end
31
+
32
+ private
33
+
34
+ def css_tree
19
35
  Visitors::CheckNesting.visit(self)
20
36
  result = Visitors::Perform.visit(self)
21
37
  Visitors::CheckNesting.visit(result) # Check again to validate mixins
22
38
  result, extends = Visitors::Cssize.visit(result)
23
39
  Visitors::Extend.visit(result, extends)
24
- result.to_s
40
+ result
25
41
  end
26
42
  end
27
43
  end
@@ -1,5 +1,4 @@
1
1
  require 'pathname'
2
- require 'uri'
3
2
 
4
3
  module Sass::Tree
5
4
  # A static node reprenting a CSS rule.
@@ -10,24 +9,24 @@ module Sass::Tree
10
9
  PARENT = '&'
11
10
 
12
11
  # The CSS selector for this rule,
13
- # interspersed with {Sass::Script::Node}s
12
+ # interspersed with {Sass::Script::Tree::Node}s
14
13
  # representing `#{}`-interpolation.
15
14
  # Any adjacent strings will be merged together.
16
15
  #
17
- # @return [Array<String, Sass::Script::Node>]
16
+ # @return [Array<String, Sass::Script::Tree::Node>]
18
17
  attr_accessor :rule
19
18
 
20
- # The CSS selector for this rule,
21
- # without any unresolved interpolation
22
- # but with parent references still intact.
23
- # It's only set once {Tree::Node#perform} has been called.
19
+ # The CSS selector for this rule, without any unresolved
20
+ # interpolation but with parent references still intact. It's only
21
+ # guaranteed to be set once {Tree::Visitors::Perform} has been
22
+ # run, but it may be set before then for optimization reasons.
24
23
  #
25
24
  # @return [Selector::CommaSequence]
26
25
  attr_accessor :parsed_rules
27
26
 
28
- # The CSS selector for this rule,
29
- # without any unresolved interpolation or parent references.
30
- # It's only set once {Tree::Visitors::Cssize} has been run.
27
+ # The CSS selector for this rule, without any unresolved
28
+ # interpolation or parent references. It's only set once
29
+ # {Tree::Visitors::Perform} has been run.
31
30
  #
32
31
  # @return [Selector::CommaSequence]
33
32
  attr_accessor :resolved_rules
@@ -44,6 +43,10 @@ module Sass::Tree
44
43
  # @return [Fixnum]
45
44
  attr_accessor :tabs
46
45
 
46
+ # The entire selector source range for this rule.
47
+ # @return [Sass::Source::Range]
48
+ attr_accessor :selector_source_range
49
+
47
50
  # Whether or not this rule is the last rule in a nested group.
48
51
  # This is only set in a CSS tree.
49
52
  #
@@ -54,14 +57,16 @@ module Sass::Tree
54
57
  # This is only readable in a CSS tree as it is written during the perform step
55
58
  # and only when the :trace_selectors option is set.
56
59
  #
57
- # @return [Array<String>]
60
+ # @return [String]
58
61
  attr_accessor :stack_trace
59
62
 
60
- # @param rule [Array<String, Sass::Script::Node>]
63
+ # @param rule [Array<String, Sass::Script::Tree::Node>]
64
+ # @param selector_source_range [Sass::Source::Range]
61
65
  # The CSS rule. See \{#rule}
62
- def initialize(rule)
66
+ def initialize(rule, selector_source_range = nil)
63
67
  merged = Sass::Util.merge_adjacent_strings(rule)
64
68
  @rule = Sass::Util.strip_string_array(merged)
69
+ @selector_source_range = selector_source_range
65
70
  @tabs = 0
66
71
  try_to_parse_non_interpolated_rules
67
72
  super()
@@ -105,12 +110,13 @@ module Sass::Tree
105
110
 
106
111
  # A hash that will be associated with this rule in the CSS document
107
112
  # if the {file:SASS_REFERENCE.md#debug_info-option `:debug_info` option} is enabled.
108
- # This data is used by e.g. [the FireSass Firebug extension](https://addons.mozilla.org/en-US/firefox/addon/103988).
113
+ # This data is used by e.g. [the FireSass Firebug
114
+ # extension](https://addons.mozilla.org/en-US/firefox/addon/103988).
109
115
  #
110
116
  # @return [{#to_s => #to_s}]
111
117
  def debug_info
112
- {:filename => filename && ("file://" + URI.escape(File.expand_path(filename))),
113
- :line => self.line}
118
+ {:filename => filename && ("file://" + Sass::Util.escape_uri(File.expand_path(filename))),
119
+ :line => line}
114
120
  end
115
121
 
116
122
  # A rule node is invisible if it has only placeholder selectors.
@@ -124,8 +130,10 @@ module Sass::Tree
124
130
  if @rule.all? {|t| t.kind_of?(String)}
125
131
  # We don't use real filename/line info because we don't have it yet.
126
132
  # When we get it, we'll set it on the parsed rules if possible.
127
- parser = Sass::SCSS::StaticParser.new(@rule.join.strip, '', 1)
133
+ parser = Sass::SCSS::StaticParser.new(@rule.join.strip, '', nil, 1)
134
+ # rubocop:disable RescueModifier
128
135
  @parsed_rules = parser.parse_selector rescue nil
136
+ # rubocop:enable RescueModifier
129
137
  end
130
138
  end
131
139
  end
@@ -1,8 +1,5 @@
1
1
  module Sass::Tree
2
2
  # A static node representing a `@supports` rule.
3
- # `@supports` rules behave differently from other directives
4
- # in that when they're nested within rules,
5
- # they bubble up to top-level.
6
3
  #
7
4
  # @see Sass::Tree
8
5
  class SupportsNode < DirectiveNode
@@ -16,17 +13,10 @@ module Sass::Tree
16
13
  # @return [Sass::Supports::Condition]
17
14
  attr_accessor :condition
18
15
 
19
- # @see RuleNode#tabs
20
- attr_accessor :tabs
21
-
22
- # @see RuleNode#group_end
23
- attr_accessor :group_end
24
-
25
16
  # @param condition [Sass::Supports::Condition] See \{#condition}
26
17
  def initialize(name, condition)
27
18
  @name = name
28
19
  @condition = condition
29
- @tabs = 0
30
20
  super('')
31
21
  end
32
22
 
@@ -44,8 +34,5 @@ module Sass::Tree
44
34
  def invisible?
45
35
  children.all? {|c| c.invisible?}
46
36
  end
47
-
48
- # @see Node#bubbles?
49
- def bubbles?; true; end
50
37
  end
51
38
  end
@@ -7,6 +7,7 @@ module Sass::Tree
7
7
  # @see Sass::Tree
8
8
  class TraceNode < Node
9
9
  # The name of the trace entry to add.
10
+ #
10
11
  # @return [String]
11
12
  attr_reader :name
12
13
 
@@ -19,7 +20,7 @@ module Sass::Tree
19
20
 
20
21
  # Initializes this node from an existing node.
21
22
  # @param name [String] The name of the trace entry to add.
22
- # @param mixin [Node] The node to copy information from.
23
+ # @param node [Node] The node to copy information from.
23
24
  # @return [TraceNode]
24
25
  def self.from_node(name, node)
25
26
  trace = new(name)
@@ -9,20 +9,26 @@ module Sass
9
9
  attr_reader :name
10
10
 
11
11
  # The parse tree for the variable value.
12
- # @return [Script::Node]
12
+ # @return [Script::Tree::Node]
13
13
  attr_accessor :expr
14
14
 
15
15
  # Whether this is a guarded variable assignment (`!default`).
16
16
  # @return [Boolean]
17
17
  attr_reader :guarded
18
18
 
19
+ # Whether this is a global variable assignment (`!global`).
20
+ # @return [Boolean]
21
+ attr_reader :global
22
+
19
23
  # @param name [String] The name of the variable
20
- # @param expr [Script::Node] See \{#expr}
24
+ # @param expr [Script::Tree::Node] See \{#expr}
21
25
  # @param guarded [Boolean] See \{#guarded}
22
- def initialize(name, expr, guarded)
26
+ # @param global [Boolean] See \{#global}
27
+ def initialize(name, expr, guarded, global)
23
28
  @name = name
24
29
  @expr = expr
25
30
  @guarded = guarded
31
+ @global = global
26
32
  super()
27
33
  end
28
34
  end
@@ -32,9 +32,9 @@ module Sass::Tree::Visitors
32
32
  # @param node [Tree::Node] The node to visit.
33
33
  # @return [Object] The return value of the `visit_*` method for this node.
34
34
  def visit(node)
35
- method = "visit_#{node_name node}"
36
- if self.respond_to?(method, true)
37
- self.send(method, node) {visit_children(node)}
35
+ method = "visit_#{self.class.node_name node}"
36
+ if respond_to?(method, true)
37
+ send(method, node) {visit_children(node)}
38
38
  else
39
39
  visit_children(node)
40
40
  end
@@ -59,9 +59,9 @@ module Sass::Tree::Visitors
59
59
  #
60
60
  # @param [Tree::Node] node The node.
61
61
  # @return [String] The name.
62
- def node_name(node)
63
- @@node_names ||= {}
64
- @@node_names[node.class.name] ||= node.class.name.gsub(NODE_NAME_RE, '\\1').downcase
62
+ def self.node_name(node)
63
+ @node_names ||= {}
64
+ @node_names[node.class.name] ||= node.class.name.gsub(NODE_NAME_RE, '\\1').downcase
65
65
  end
66
66
 
67
67
  # `yield`s, then runs the visitor on the `@else` clause if the node has one.
@@ -1,5 +1,6 @@
1
1
  # A visitor for checking that all nodes are properly nested.
2
2
  class Sass::Tree::Visitors::CheckNesting < Sass::Tree::Visitors::Base
3
+
3
4
  protected
4
5
 
5
6
  def initialize
@@ -7,9 +8,9 @@ class Sass::Tree::Visitors::CheckNesting < Sass::Tree::Visitors::Base
7
8
  end
8
9
 
9
10
  def visit(node)
10
- if error = @parent && (
11
- try_send("invalid_#{node_name @parent}_child?", @parent, node) ||
12
- try_send("invalid_#{node_name node}_parent?", @parent, node))
11
+ if (error = @parent && (
12
+ try_send("invalid_#{self.class.node_name @parent}_child?", @parent, node) ||
13
+ try_send("invalid_#{self.class.node_name node}_parent?", @parent, node)))
13
14
  raise Sass::SyntaxError.new(error)
14
15
  end
15
16
  super
@@ -19,7 +20,7 @@ class Sass::Tree::Visitors::CheckNesting < Sass::Tree::Visitors::Base
19
20
  end
20
21
 
21
22
  CONTROL_NODES = [Sass::Tree::EachNode, Sass::Tree::ForNode, Sass::Tree::IfNode,
22
- Sass::Tree::WhileNode, Sass::Tree::TraceNode]
23
+ Sass::Tree::WhileNode, Sass::Tree::TraceNode]
23
24
  SCRIPT_NODES = [Sass::Tree::ImportNode] + CONTROL_NODES
24
25
  def visit_children(parent)
25
26
  old_parent = @parent
@@ -110,7 +111,9 @@ class Sass::Tree::Visitors::CheckNesting < Sass::Tree::Visitors::Base
110
111
  end
111
112
  end
112
113
 
113
- VALID_PROP_CHILDREN = [Sass::Tree::CommentNode, Sass::Tree::PropNode, Sass::Tree::MixinNode] + CONTROL_NODES
114
+ VALID_PROP_CHILDREN = CONTROL_NODES + [Sass::Tree::CommentNode,
115
+ Sass::Tree::PropNode,
116
+ Sass::Tree::MixinNode]
114
117
  def invalid_prop_child?(parent, child)
115
118
  unless is_any_of?(child, VALID_PROP_CHILDREN)
116
119
  "Illegal nesting: Only properties may be nested beneath properties."
@@ -122,7 +125,8 @@ class Sass::Tree::Visitors::CheckNesting < Sass::Tree::Visitors::Base
122
125
  Sass::Tree::MixinNode]
123
126
  def invalid_prop_parent?(parent, child)
124
127
  unless is_any_of?(parent, VALID_PROP_PARENTS)
125
- "Properties are only allowed within rules, directives, mixin includes, or other properties." + child.pseudo_class_selector_message
128
+ "Properties are only allowed within rules, directives, mixin includes, or other properties." +
129
+ child.pseudo_class_selector_message
126
130
  end
127
131
  end
128
132
 
@@ -133,10 +137,10 @@ class Sass::Tree::Visitors::CheckNesting < Sass::Tree::Visitors::Base
133
137
  private
134
138
 
135
139
  def is_any_of?(val, classes)
136
- for c in classes
140
+ classes.each do |c|
137
141
  return true if val.is_a?(c)
138
142
  end
139
- return false
143
+ false
140
144
  end
141
145
 
142
146
  def try_send(method, *args)
@@ -144,4 +148,3 @@ class Sass::Tree::Visitors::CheckNesting < Sass::Tree::Visitors::Base
144
148
  send(method, *args)
145
149
  end
146
150
  end
147
-
@@ -23,7 +23,11 @@ class Sass::Tree::Visitors::Convert < Sass::Tree::Visitors::Base
23
23
  def visit_children(parent)
24
24
  @tabs += 1
25
25
  return @format == :sass ? "\n" : " {}\n" if parent.children.empty?
26
- (@format == :sass ? "\n" : " {\n") + super.join.rstrip + (@format == :sass ? "\n" : "\n#{ @tab_chars * (@tabs-1)}}\n")
26
+ if @format == :sass
27
+ "\n" + super.join.rstrip + "\n"
28
+ else
29
+ " {\n" + super.join.rstrip + "\n#{ @tab_chars * (@tabs - 1)}}\n"
30
+ end
27
31
  ensure
28
32
  @tabs -= 1
29
33
  end
@@ -52,7 +56,7 @@ class Sass::Tree::Visitors::Convert < Sass::Tree::Visitors::Base
52
56
 
53
57
  def visit_comment(node)
54
58
  value = interp_to_src(node.value)
55
- content = if @format == :sass
59
+ if @format == :sass
56
60
  content = value.gsub(/\*\/$/, '').rstrip
57
61
  if content =~ /\A[ \t]/
58
62
  # Re-indent SCSS comments like this:
@@ -63,33 +67,28 @@ class Sass::Tree::Visitors::Convert < Sass::Tree::Visitors::Base
63
67
  content.sub!(/\A([ \t]*)\/\*/, '/*\1')
64
68
  end
65
69
 
66
- content =
67
- unless content.include?("\n")
68
- content
70
+ if content.include?("\n")
71
+ content.gsub!(%r{\n( \*|//)}, "\n ")
72
+ spaces = content.scan(/\n( *)/).map {|s| s.first.size}.min
73
+ sep = node.type == :silent ? "\n//" : "\n *"
74
+ if spaces >= 2
75
+ content.gsub!(/\n /, sep)
69
76
  else
70
- content.gsub!(/\n( \*|\/\/)/, "\n ")
71
- spaces = content.scan(/\n( *)/).map {|s| s.first.size}.min
72
- sep = node.type == :silent ? "\n//" : "\n *"
73
- if spaces >= 2
74
- content.gsub(/\n /, sep)
75
- else
76
- content.gsub(/\n#{' ' * spaces}/, sep)
77
- end
77
+ content.gsub!(/\n#{' ' * spaces}/, sep)
78
78
  end
79
+ end
79
80
 
80
81
  content.gsub!(/\A\/\*/, '//') if node.type == :silent
81
82
  content.gsub!(/^/, tab_str)
82
- content.rstrip + "\n"
83
+ content = content.rstrip + "\n"
83
84
  else
84
85
  spaces = (@tab_chars * [@tabs - value[/^ */].size, 0].max)
85
86
  content = if node.type == :silent
86
- value.gsub(/^[\/ ]\*/, '//').gsub(/ *\*\/$/, '')
87
- else
88
- value
89
- end.gsub(/^/, spaces) + "\n"
90
- content
87
+ value.gsub(/^[\/ ]\*/, '//').gsub(/ *\*\/$/, '')
88
+ else
89
+ value
90
+ end.gsub(/^/, spaces) + "\n"
91
91
  end
92
- content.sub!(%r{^\s*(/\*)}, '/*!') if node.type == :loud #'
93
92
  content
94
93
  end
95
94
 
@@ -99,17 +98,19 @@ class Sass::Tree::Visitors::Convert < Sass::Tree::Visitors::Base
99
98
 
100
99
  def visit_directive(node)
101
100
  res = "#{tab_str}#{interp_to_src(node.value)}"
102
- res.gsub!(/^@import \#\{(.*)\}([^}]*)$/, '@import \1\2');
101
+ res.gsub!(/^@import \#\{(.*)\}([^}]*)$/, '@import \1\2')
103
102
  return res + "#{semi}\n" unless node.has_children
104
103
  res + yield + "\n"
105
104
  end
106
105
 
107
106
  def visit_each(node)
108
- "#{tab_str}@each $#{dasherize(node.var)} in #{node.list.to_sass(@options)}#{yield}"
107
+ vars = node.vars.map {|var| "$#{dasherize(var)}"}.join(", ")
108
+ "#{tab_str}@each #{vars} in #{node.list.to_sass(@options)}#{yield}"
109
109
  end
110
110
 
111
111
  def visit_extend(node)
112
- "#{tab_str}@extend #{selector_to_src(node.selector).lstrip}#{semi}#{" !optional" if node.optional?}\n"
112
+ "#{tab_str}@extend #{selector_to_src(node.selector).lstrip}#{semi}" +
113
+ "#{" !optional" if node.optional?}\n"
113
114
  end
114
115
 
115
116
  def visit_for(node)
@@ -131,9 +132,12 @@ class Sass::Tree::Visitors::Convert < Sass::Tree::Visitors::Base
131
132
 
132
133
  def visit_if(node)
133
134
  name =
134
- if !@is_else; "if"
135
- elsif node.expr; "else if"
136
- else; "else"
135
+ if !@is_else
136
+ "if"
137
+ elsif node.expr
138
+ "else if"
139
+ else
140
+ "else"
137
141
  end
138
142
  @is_else = false
139
143
  str = "#{tab_str}@#{name}"
@@ -152,7 +156,7 @@ class Sass::Tree::Visitors::Convert < Sass::Tree::Visitors::Base
152
156
  end
153
157
 
154
158
  def visit_media(node)
155
- "#{tab_str}@media #{media_interp_to_src(node.query)}#{yield}"
159
+ "#{tab_str}@media #{query_interp_to_src(node.query)}#{yield}"
156
160
  end
157
161
 
158
162
  def visit_supports(node)
@@ -160,7 +164,7 @@ class Sass::Tree::Visitors::Convert < Sass::Tree::Visitors::Base
160
164
  end
161
165
 
162
166
  def visit_cssimport(node)
163
- if node.uri.is_a?(Sass::Script::Node)
167
+ if node.uri.is_a?(Sass::Script::Tree::Node)
164
168
  str = "#{tab_str}@import #{node.uri.to_sass(@options)}"
165
169
  else
166
170
  str = "#{tab_str}@import #{node.uri}"
@@ -195,17 +199,26 @@ class Sass::Tree::Visitors::Convert < Sass::Tree::Visitors::Base
195
199
  end
196
200
 
197
201
  def visit_mixin(node)
202
+ arg_to_sass = lambda do |arg|
203
+ sass = arg.to_sass(@options)
204
+ sass = "(#{sass})" if arg.is_a?(Sass::Script::Tree::ListLiteral) && arg.separator == :comma
205
+ sass
206
+ end
207
+
198
208
  unless node.args.empty? && node.keywords.empty? && node.splat.nil?
199
- args = node.args.map {|a| a.to_sass(@options)}.join(", ")
209
+ args = node.args.map(&arg_to_sass)
200
210
  keywords = Sass::Util.hash_to_a(node.keywords).
201
- map {|k, v| "$#{dasherize(k)}: #{v.to_sass(@options)}"}.join(', ')
211
+ map {|k, v| "$#{dasherize(k)}: #{arg_to_sass[v]}"}
212
+
202
213
  if node.splat
203
- splat = (args.empty? && keywords.empty?) ? "" : ", "
204
- splat = "#{splat}#{node.splat.to_sass(@options)}..."
214
+ splat = "#{arg_to_sass[node.splat]}..."
215
+ kwarg_splat = "#{arg_to_sass[node.kwarg_splat]}..." if node.kwarg_splat
205
216
  end
206
- arglist = "(#{args}#{', ' unless args.empty? || keywords.empty?}#{keywords}#{splat})"
217
+
218
+ arglist = "(#{[args, splat, keywords, kwarg_splat].flatten.compact.join(', ')})"
207
219
  end
208
- "#{tab_str}#{@format == :sass ? '+' : '@include '}#{dasherize(node.name)}#{arglist}#{node.has_children ? yield : semi}\n"
220
+ "#{tab_str}#{@format == :sass ? '+' : '@include '}" +
221
+ "#{dasherize(node.name)}#{arglist}#{node.has_children ? yield : semi}\n"
209
222
  end
210
223
 
211
224
  def visit_content(node)
@@ -239,7 +252,8 @@ class Sass::Tree::Visitors::Convert < Sass::Tree::Visitors::Base
239
252
  end
240
253
 
241
254
  def visit_variable(node)
242
- "#{tab_str}$#{dasherize(node.name)}: #{node.expr.to_sass(@options)}#{' !default' if node.guarded}#{semi}\n"
255
+ "#{tab_str}$#{dasherize(node.name)}: #{node.expr.to_sass(@options)}" +
256
+ "#{' !global' if node.global}#{' !default' if node.guarded}#{semi}\n"
243
257
  end
244
258
 
245
259
  def visit_warn(node)
@@ -250,6 +264,17 @@ class Sass::Tree::Visitors::Convert < Sass::Tree::Visitors::Base
250
264
  "#{tab_str}@while #{node.expr.to_sass(@options)}#{yield}"
251
265
  end
252
266
 
267
+ def visit_atroot(node)
268
+ if node.query
269
+ "#{tab_str}@at-root #{query_interp_to_src(node.query)}#{yield}"
270
+ elsif node.children.length == 1 && node.children.first.is_a?(Sass::Tree::RuleNode)
271
+ rule = node.children.first
272
+ "#{tab_str}@at-root #{selector_to_src(rule.rule)}#{visit_children(rule)}"
273
+ else
274
+ "#{tab_str}@at-root#{yield}"
275
+ end
276
+ end
277
+
253
278
  private
254
279
 
255
280
  def interp_to_src(interp)
@@ -260,11 +285,11 @@ class Sass::Tree::Visitors::Convert < Sass::Tree::Visitors::Base
260
285
  end
261
286
 
262
287
  # Like interp_to_src, but removes the unnecessary `#{}` around the keys and
263
- # values in media expressions.
264
- def media_interp_to_src(interp)
288
+ # values in query expressions.
289
+ def query_interp_to_src(interp)
265
290
  Sass::Util.enum_with_index(interp).map do |r, i|
266
291
  next r if r.is_a?(String)
267
- before, after = interp[i-1], interp[i+1]
292
+ before, after = interp[i - 1], interp[i + 1]
268
293
  if before.is_a?(String) && after.is_a?(String) &&
269
294
  ((before[-1] == ?( && after[0] == ?:) ||
270
295
  (before =~ /:\s*/ && after[0] == ?)))