sass 3.2.0.alpha.57 → 3.2.0.alpha.59

Sign up to get free protection for your applications and to get access to all the features.
@@ -119,9 +119,7 @@ class Sass::Tree::Visitors::Cssize < Sass::Tree::Visitors::Base
119
119
 
120
120
  media = node.children.select {|c| c.is_a?(Sass::Tree::MediaNode)}
121
121
  node.children.reject! {|c| c.is_a?(Sass::Tree::MediaNode)}
122
- media.each do |n|
123
- n.query = node.query.map {|pq| n.query.map {|cq| "#{pq} and #{cq}"}}.flatten
124
- end
122
+ media = media.select {|n| n.query = n.query.merge(node.query)}
125
123
  (node.children.empty? ? [] : [node]) + media
126
124
  end
127
125
 
@@ -84,4 +84,14 @@ class Sass::Tree::Visitors::DeepCopy < Sass::Tree::Visitors::Base
84
84
  node.expr = node.expr.deep_copy
85
85
  yield
86
86
  end
87
+
88
+ def visit_directive(node)
89
+ node.value = node.value.map {|c| c.is_a?(Sass::Script::Node) ? c.deep_copy : c}
90
+ yield
91
+ end
92
+
93
+ def visit_media(node)
94
+ node.query = query.deep_copy
95
+ yield
96
+ end
87
97
  end
@@ -135,7 +135,7 @@ class Sass::Tree::Visitors::Perform < Sass::Tree::Visitors::Base
135
135
  # or parses and includes the imported Sass file.
136
136
  def visit_import(node)
137
137
  if path = node.css_import?
138
- return Sass::Tree::DirectiveNode.new("@import url(#{path})")
138
+ return Sass::Tree::DirectiveNode.resolved("@import url(#{path})")
139
139
  end
140
140
  file = node.imported_file
141
141
  handle_import_loop!(node) if @stack.any? {|e| e[:filename] == file.options[:filename]}
@@ -247,6 +247,8 @@ END
247
247
  # Runs SassScript interpolation in the selector,
248
248
  # and then parses the result into a {Sass::Selector::CommaSequence}.
249
249
  def visit_rule(node)
250
+ rule = node.rule
251
+ rule = rule.map {|e| e.is_a?(String) && e != ' ' ? e.strip : e} if node.style == :compressed
250
252
  parser = Sass::SCSS::StaticParser.new(run_interp(node.rule), node.filename, node.line)
251
253
  node.parsed_rules ||= parser.parse_selector
252
254
  if node.options[:trace_selectors]
@@ -290,11 +292,14 @@ END
290
292
  end
291
293
 
292
294
  def visit_directive(node)
293
- if node.value['#{']
294
- node.value = run_interp(Sass::Engine.parse_interp(node.value, node.line, 0, node.options))
295
- end
295
+ node.resolved_value = run_interp(node.value)
296
+ yield
297
+ end
298
+
299
+ def visit_media(node)
300
+ node.query = node.query.deep_copy
301
+ node.query.perform {|interp| run_interp(interp)}
296
302
  yield
297
- node
298
303
  end
299
304
 
300
305
  private
@@ -94,4 +94,14 @@ class Sass::Tree::Visitors::SetOptions < Sass::Tree::Visitors::Base
94
94
  node.expr.options = @options
95
95
  yield
96
96
  end
97
+
98
+ def visit_directive(node)
99
+ node.value.each {|c| c.options = @options if c.is_a?(Sass::Script::Node)}
100
+ yield
101
+ end
102
+
103
+ def visit_media(node)
104
+ node.query.options = @options
105
+ yield
106
+ end
97
107
  end
@@ -67,12 +67,14 @@ class Sass::Tree::Visitors::ToCss < Sass::Tree::Visitors::Base
67
67
  end
68
68
 
69
69
  def visit_directive(node)
70
- return node.value + ";" unless node.has_children
71
- return node.value + " {}" if node.children.empty?
70
+ was_in_directive = @in_directive
71
+ return node.resolved_value + ";" unless node.has_children
72
+ return node.resolved_value + " {}" if node.children.empty?
73
+ @in_directive = @in_directive || !node.is_a?(Sass::Tree::MediaNode)
72
74
  result = if node.style == :compressed
73
- "#{node.value}{"
75
+ "#{node.resolved_value}{"
74
76
  else
75
- "#{' ' * @tabs}#{node.value} {" + (node.style == :compact ? ' ' : "\n")
77
+ "#{' ' * @tabs}#{node.resolved_value} {" + (node.style == :compact ? ' ' : "\n")
76
78
  end
77
79
  was_prop = false
78
80
  first = true
@@ -101,6 +103,8 @@ class Sass::Tree::Visitors::ToCss < Sass::Tree::Visitors::Base
101
103
  else
102
104
  (node.style == :expanded ? "\n" : " ") + "}\n"
103
105
  end
106
+ ensure
107
+ @in_directive = was_in_directive
104
108
  end
105
109
 
106
110
  def visit_media(node)
@@ -133,7 +137,11 @@ class Sass::Tree::Visitors::ToCss < Sass::Tree::Visitors::Base
133
137
  joined_rules = node.resolved_rules.members.map do |seq|
134
138
  next if seq.has_placeholder?
135
139
  rule_part = seq.to_a.join
136
- rule_part.gsub!(/\s*([^,])\s*\n\s*/m, '\1 ') if node.style == :compressed
140
+ if node.style == :compressed
141
+ rule_part.gsub!(/([^,])\s*\n\s*/m, '\1 ')
142
+ rule_part.gsub!(/\s*([,+>])\s*/m, '\1')
143
+ rule_part.strip!
144
+ end
137
145
  rule_part
138
146
  end.compact.join(rule_separator)
139
147
 
@@ -145,7 +153,7 @@ class Sass::Tree::Visitors::ToCss < Sass::Tree::Visitors::Base
145
153
  old_spaces = ' ' * @tabs
146
154
  spaces = ' ' * (@tabs + 1)
147
155
  if node.style != :compressed
148
- if node.options[:debug_info]
156
+ if node.options[:debug_info] && !@in_directive
149
157
  to_return << visit(debug_info_rule(node.debug_info, node.options)) << "\n"
150
158
  elsif node.options[:trace_selectors]
151
159
  to_return << "#{old_spaces}/* "
@@ -190,8 +198,8 @@ class Sass::Tree::Visitors::ToCss < Sass::Tree::Visitors::Base
190
198
  private
191
199
 
192
200
  def debug_info_rule(debug_info, options)
193
- node = Sass::Tree::DirectiveNode.new("@media -sass-debug-info")
194
- debug_info.map {|k, v| [k.to_s, v.to_s]}.sort.each do |k, v|
201
+ node = Sass::Tree::DirectiveNode.resolved("@media -sass-debug-info")
202
+ Sass::Util.hash_to_a(debug_info.map {|k, v| [k.to_s, v.to_s]}).each do |k, v|
195
203
  rule = Sass::Tree::RuleNode.new([""])
196
204
  rule.resolved_rules = Sass::Selector::CommaSequence.new(
197
205
  [Sass::Selector::Sequence.new(
@@ -218,6 +218,20 @@ module Sass
218
218
  lcs_backtrace(lcs_table(x, y, &block), x, y, x.size-1, y.size-1, &block)
219
219
  end
220
220
 
221
+ # Converts a Hash to an Array. This is usually identical to `Hash#to_a`,
222
+ # with the following exceptions:
223
+ #
224
+ # * In Ruby 1.8, `Hash#to_a` is not deterministically ordered, but this is.
225
+ # * In Ruby 1.9 when running tests, this is ordered in the same way it would
226
+ # be under Ruby 1.8 (sorted key order rather than insertion order).
227
+ #
228
+ # @param hash [Hash]
229
+ # @return [Array]
230
+ def hash_to_a(hash)
231
+ return has.to_a unless ruby1_8? || defined?(Test::Unit)
232
+ return hash.sort_by {|k, v| k}
233
+ end
234
+
221
235
  # Returns information about the caller of the previous method.
222
236
  #
223
237
  # @param entry [String] An entry in the `#caller` list, or a similarly formatted string
@@ -759,6 +759,18 @@ SASS
759
759
  SCSS
760
760
  end
761
761
 
762
+ def test_import_with_interpolation
763
+ assert_renders <<SASS, <<SCSS
764
+ $family: unquote("Droid+Sans")
765
+
766
+ @import url("http://fonts.googleapis.com/css?family=\#{$family}")
767
+ SASS
768
+ $family: unquote("Droid+Sans");
769
+
770
+ @import url("http://fonts.googleapis.com/css?family=\#{$family}");
771
+ SCSS
772
+ end
773
+
762
774
  def test_extend
763
775
  assert_renders <<SASS, <<SCSS
764
776
  .foo
@@ -1015,6 +1027,54 @@ foo {
1015
1027
  SCSS
1016
1028
  end
1017
1029
 
1030
+ def test_directive_with_interpolation
1031
+ assert_renders <<SASS, <<SCSS
1032
+ $baz: 12
1033
+
1034
+ @foo bar\#{$baz} qux
1035
+ a: b
1036
+ SASS
1037
+ $baz: 12;
1038
+
1039
+ @foo bar\#{$baz} qux {
1040
+ a: b; }
1041
+ SCSS
1042
+ end
1043
+
1044
+ def test_media_with_interpolation
1045
+ assert_renders <<SASS, <<SCSS
1046
+ $baz: 12
1047
+
1048
+ @media bar\#{$baz}
1049
+ a: b
1050
+ SASS
1051
+ $baz: 12;
1052
+
1053
+ @media bar\#{$baz} {
1054
+ a: b; }
1055
+ SCSS
1056
+ end
1057
+
1058
+ def test_media_with_variables
1059
+ assert_renders <<SASS, <<SCSS
1060
+ $media1: screen
1061
+ $media2: print
1062
+ $var: -webkit-min-device-pixel-ratio
1063
+ $val: 20
1064
+
1065
+ @media $media1 and ($var: $val), only $media2
1066
+ a: b
1067
+ SASS
1068
+ $media1: screen;
1069
+ $media2: print;
1070
+ $var: -webkit-min-device-pixel-ratio;
1071
+ $val: 20;
1072
+
1073
+ @media $media1 and ($var: $val), only $media2 {
1074
+ a: b; }
1075
+ SCSS
1076
+ end
1077
+
1018
1078
  # Hacks
1019
1079
 
1020
1080
  def test_declaration_hacks
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env ruby
2
2
  # -*- coding: utf-8 -*-
3
- require 'test_helper'
4
- require 'sass/test_helper'
3
+ require File.dirname(__FILE__) + '/../test_helper'
4
+ require File.dirname(__FILE__) + '/test_helper'
5
5
  require 'sass/engine'
6
6
  require 'stringio'
7
7
  require 'mock_importer'
@@ -622,11 +622,13 @@ CSS
622
622
  render("@import \"http://fonts.googleapis.com/css?family=Droid+Sans\""))
623
623
  end
624
624
 
625
- def test_http_import_with_interpolation
626
- assert_equal("@import url(http://fonts.googleapis.com/css?family=Droid+Sans);\n",
627
- render("$family: unquote(\"Droid+Sans\")\n@import \"http://fonts.googleapis.com/css?family=\#{$family}\"\n"))
628
- assert_equal("@import url(\"http://fonts.googleapis.com/css?family=Droid+Sans\");\n",
629
- render("$family: unquote(\"Droid+Sans\")\n@import url(\"http://fonts.googleapis.com/css?family=\#{$family}\")\n"))
625
+ def test_import_with_interpolation
626
+ assert_equal(<<CSS, render(<<SASS))
627
+ @import url("http://fonts.googleapis.com/css?family=Droid+Sans");
628
+ CSS
629
+ $family: unquote("Droid+Sans")
630
+ @import url("http://fonts.googleapis.com/css?family=\#{$family}")
631
+ SASS
630
632
  end
631
633
 
632
634
  def test_url_import
@@ -1026,6 +1028,23 @@ foo
1026
1028
  SASS
1027
1029
  end
1028
1030
 
1031
+ def test_debug_info_in_keyframes
1032
+ assert_equal(<<CSS, render(<<SASS, :debug_info => true))
1033
+ @-webkit-keyframes warm {
1034
+ from {
1035
+ color: black; }
1036
+
1037
+ to {
1038
+ color: red; } }
1039
+ CSS
1040
+ @-webkit-keyframes warm
1041
+ from
1042
+ color: black
1043
+ to
1044
+ color: red
1045
+ SASS
1046
+ end
1047
+
1029
1048
  def test_empty_first_line
1030
1049
  assert_equal("#a {\n b: c; }\n", render("#a\n\n b: c"))
1031
1050
  end
@@ -2003,12 +2022,12 @@ SASS
2003
2022
 
2004
2023
  def test_double_media_bubbling
2005
2024
  assert_equal <<CSS, render(<<SASS)
2006
- @media bar and baz {
2025
+ @media bar and (a: b) {
2007
2026
  .foo {
2008
2027
  c: d; } }
2009
2028
  CSS
2010
2029
  @media bar
2011
- @media baz
2030
+ @media (a: b)
2012
2031
  .foo
2013
2032
  c: d
2014
2033
  SASS
@@ -2017,26 +2036,26 @@ SASS
2017
2036
  @media bar {
2018
2037
  .foo {
2019
2038
  a: b; } }
2020
- @media bar and baz {
2039
+ @media bar and (a: b) {
2021
2040
  .foo {
2022
2041
  c: d; } }
2023
2042
  CSS
2024
2043
  .foo
2025
2044
  @media bar
2026
2045
  a: b
2027
- @media baz
2046
+ @media (a: b)
2028
2047
  c: d
2029
2048
  SASS
2030
2049
  end
2031
2050
 
2032
2051
  def test_double_media_bubbling_with_commas
2033
2052
  assert_equal <<CSS, render(<<SASS)
2034
- @media foo and baz, foo and bang, bar and baz, bar and bang {
2053
+ @media (a: b) and (e: f), (c: d) and (e: f), (a: b) and (g: h), (c: d) and (g: h) {
2035
2054
  .foo {
2036
2055
  c: d; } }
2037
2056
  CSS
2038
- @media foo, bar
2039
- @media baz, bang
2057
+ @media (a: b), (c: d)
2058
+ @media (e: f), (g: h)
2040
2059
  .foo
2041
2060
  c: d
2042
2061
  SASS
@@ -2068,7 +2087,7 @@ SASS
2068
2087
  @media print {
2069
2088
  .outside {
2070
2089
  color: black; } }
2071
- @media print and nested {
2090
+ @media print and (a: b) {
2072
2091
  .outside .inside {
2073
2092
  border: 1px solid black; } }
2074
2093
  .outside .middle {
@@ -2079,7 +2098,7 @@ CSS
2079
2098
  @media print
2080
2099
  color: black
2081
2100
  .inside
2082
- @media nested
2101
+ @media (a: b)
2083
2102
  border: 1px solid black
2084
2103
  background: blue
2085
2104
  .middle
@@ -2102,8 +2121,135 @@ CSS
2102
2121
  assert_equal css_str, render(sass_str)
2103
2122
  end
2104
2123
 
2124
+ def test_eliminated_media_bubbling
2125
+ assert_equal <<CSS, render(<<SASS)
2126
+ @media screen {
2127
+ a: b; }
2128
+ CSS
2129
+ @media screen
2130
+ a: b
2131
+ @media print
2132
+ c: d
2133
+ SASS
2134
+
2135
+ assert_equal <<CSS, render(<<SASS)
2136
+ @media not print {
2137
+ a: b; }
2138
+ CSS
2139
+ @media not print
2140
+ a: b
2141
+ @media print
2142
+ c: d
2143
+ SASS
2144
+
2145
+ assert_equal <<CSS, render(<<SASS)
2146
+ @media not print {
2147
+ a: b; }
2148
+ CSS
2149
+ @media not print
2150
+ a: b
2151
+ @media not screen
2152
+ c: d
2153
+ SASS
2154
+ end
2155
+
2156
+ def test_non_eliminated_media_bubbling
2157
+ assert_equal <<CSS, render(<<SASS)
2158
+ @media screen {
2159
+ a: b; }
2160
+ @media screen and (a: b) {
2161
+ c: d; }
2162
+ CSS
2163
+ @media screen
2164
+ a: b
2165
+ @media screen and (a: b)
2166
+ c: d
2167
+ SASS
2168
+
2169
+ assert_equal <<CSS, render(<<SASS)
2170
+ @media not print {
2171
+ a: b; }
2172
+ @media screen {
2173
+ c: d; }
2174
+ CSS
2175
+ @media not print
2176
+ a: b
2177
+ @media screen
2178
+ c: d
2179
+ SASS
2180
+
2181
+ assert_equal <<CSS, render(<<SASS)
2182
+ @media only screen {
2183
+ a: b; }
2184
+ @media only screen and (a: b) {
2185
+ c: d; }
2186
+ CSS
2187
+ @media only screen
2188
+ a: b
2189
+ @media screen and (a: b)
2190
+ c: d
2191
+ SASS
2192
+ end
2193
+
2194
+ def test_directive_interpolation
2195
+ assert_equal <<CSS, render(<<SASS)
2196
+ @foo bar12 qux {
2197
+ a: b; }
2198
+ CSS
2199
+ $baz: 12
2200
+ @foo bar\#{$baz} qux
2201
+ a: b
2202
+ SASS
2203
+ end
2204
+
2205
+ def test_media_interpolation
2206
+ assert_equal <<CSS, render(<<SASS)
2207
+ @media bar12 {
2208
+ a: b; }
2209
+ CSS
2210
+ $baz: 12
2211
+ @media bar\#{$baz}
2212
+ a: b
2213
+ SASS
2214
+ end
2215
+
2216
+ def test_variables_in_media
2217
+ assert_equal <<CSS, render(<<SASS)
2218
+ @media screen and (-webkit-min-device-pixel-ratio: 20), only print {
2219
+ a: b; }
2220
+ CSS
2221
+ $media1: screen
2222
+ $media2: print
2223
+ $var: -webkit-min-device-pixel-ratio
2224
+ $val: 20
2225
+ @media $media1 and ($var: $val), only $media2
2226
+ a: b
2227
+ SASS
2228
+ end
2229
+
2105
2230
  # Regression tests
2106
2231
 
2232
+ def test_variable_in_media_in_mixin
2233
+ assert_equal <<CSS, render(<<SASS)
2234
+ @media screen and (min-width: 10px) {
2235
+ body {
2236
+ background: red; } }
2237
+ @media screen and (min-width: 20px) {
2238
+ body {
2239
+ background: blue; } }
2240
+ CSS
2241
+ @mixin respond-to($width)
2242
+ @media screen and (min-width: $width)
2243
+ @content
2244
+
2245
+ body
2246
+ @include respond-to(10px)
2247
+ background: red
2248
+ @include respond-to(20px)
2249
+ background: blue
2250
+ SASS
2251
+ end
2252
+
2107
2253
  def test_tricky_mixin_loop_exception
2108
2254
  render <<SASS
2109
2255
  @mixin foo($a)
@@ -2433,6 +2579,15 @@ CSS
2433
2579
  SASS
2434
2580
  end
2435
2581
 
2582
+ def test_selector_compression
2583
+ assert_equal <<CSS, render(<<SASS, :style => :compressed)
2584
+ a>b,c+d,:-moz-any(e,f,g){h:i}
2585
+ CSS
2586
+ a > b, c + d, :-moz-any(e, f, g)
2587
+ h: i
2588
+ SASS
2589
+ end
2590
+
2436
2591
  # Encodings
2437
2592
 
2438
2593
  unless Sass::Util.ruby1_8?