sass 3.2.0.alpha.76 → 3.2.0.alpha.85

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -175,16 +175,15 @@ See `sass-convert --help` for further information and options.
175
175
 
176
176
  Sass was envisioned by [Hampton Catlin](http://hamptoncatlin.com) (hcatlin).
177
177
  However, Hampton doesn't even know his way around the code anymore and now
178
- occasionally consults on the language issues. Hampton lives in Jacksonville,
179
- Florida and is the lead mobile developer for Wikimedia.
178
+ occasionally consults on the language issues. Hampton lives in Cambridge, UK and
179
+ is the owner of [Catlin Software](http://www.catlinsoftware.com/).
180
180
 
181
181
  [Nathan Weizenbaum](http://nex-3.com) is the primary developer and architect of
182
182
  Sass. His hard work has kept the project alive by endlessly answering forum
183
183
  posts, fixing bugs, refactoring, finding speed improvements, writing
184
184
  documentation, implementing new features, and getting Hampton coffee (a fitting
185
- task for a boy-genius). Nathan lives in Seattle, Washington and while not being
186
- a student at the University of Washington or working at an internship, he
187
- consults for Unspace Interactive.
185
+ task for a boy-genius). Nathan lives in Seattle, Washington and works on
186
+ [Dart](http://dartlang.org) application libraries at Google.
188
187
 
189
188
  [Chris Eppstein](http://acts-as-architect.blogspot.com) is a core contributor to
190
189
  Sass and the creator of Compass, the first Sass-based framework. Chris focuses
data/REVISION CHANGED
@@ -1 +1 @@
1
- 02ece03560e12575005f7583a43d4e999823447d
1
+ f563a965a5a876cc8228bbca3cae0be28585ad43
data/VERSION CHANGED
@@ -1 +1 @@
1
- 3.2.0.alpha.76
1
+ 3.2.0.alpha.85
data/lib/sass/css.rb CHANGED
@@ -329,7 +329,7 @@ module Sass
329
329
  root.children.each do |child|
330
330
  next dump_selectors(child) if child.is_a?(Tree::DirectiveNode)
331
331
  next unless child.is_a?(Tree::RuleNode)
332
- child.rule = child.parsed_rules.to_s
332
+ child.rule = [child.parsed_rules.to_s]
333
333
  dump_selectors(child)
334
334
  end
335
335
  end
data/lib/sass/engine.rb CHANGED
@@ -8,6 +8,7 @@ require 'sass/tree/comment_node'
8
8
  require 'sass/tree/prop_node'
9
9
  require 'sass/tree/directive_node'
10
10
  require 'sass/tree/media_node'
11
+ require 'sass/tree/css_import_node'
11
12
  require 'sass/tree/variable_node'
12
13
  require 'sass/tree/mixin_def_node'
13
14
  require 'sass/tree/mixin_node'
@@ -572,7 +573,7 @@ WARNING
572
573
  def parse_property_or_rule(line)
573
574
  scanner = Sass::Util::MultibyteStringScanner.new(line.text)
574
575
  hack_char = scanner.scan(/[:\*\.]|\#(?!\{)/)
575
- parser = Sass::SCSS::SassParser.new(scanner, @options[:filename], @line)
576
+ parser = Sass::SCSS::Parser.new(scanner, @options[:filename], @line)
576
577
 
577
578
  unless res = parser.parse_interp_ident
578
579
  return Tree::RuleNode.new(parse_interp(line.text))
@@ -692,7 +693,7 @@ WARNING
692
693
  :line => @line + 1) unless line.children.empty?
693
694
  Tree::CharsetNode.new(name)
694
695
  elsif directive == "media"
695
- parser = Sass::SCSS::SassParser.new(value, @options[:filename], @line)
696
+ parser = Sass::SCSS::Parser.new(value, @options[:filename], @line)
696
697
  Tree::MediaNode.new(parser.parse_media_query_list)
697
698
  else
698
699
  Tree::DirectiveNode.new(
@@ -784,11 +785,11 @@ WARNING
784
785
  return if scanner.eos?
785
786
 
786
787
  if scanner.match?(/url\(/i)
787
- parser = Sass::Script::Parser.new(scanner, @line, offset, @options)
788
- str = parser.parse_string
789
- media = scanner.scan(/\s*[^,;].*/)
790
- media &&= " #{media}"
791
- return Tree::DirectiveNode.new(["@import ", str, media || ''])
788
+ script_parser = Sass::Script::Parser.new(scanner, @line, offset, @options)
789
+ str = script_parser.parse_string
790
+ media_parser = Sass::SCSS::Parser.new(scanner, @options[:filename], @line)
791
+ media = media_parser.parse_media_query_list
792
+ return Tree::CssImportNode.new(str, media)
792
793
  end
793
794
 
794
795
  unless str = scanner.scan(Sass::SCSS::RX::STRING)
@@ -797,10 +798,12 @@ WARNING
797
798
 
798
799
  val = scanner[1] || scanner[2]
799
800
  scanner.scan(/\s*/)
800
- if media = scanner.scan(/[^,;].*/)
801
- Tree::DirectiveNode.new(["@import #{str || uri} #{media}"])
801
+ if !scanner.match?(/[,;]|$/)
802
+ media_parser = Sass::SCSS::Parser.new(scanner, @options[:filename], @line)
803
+ media = media_parser.parse_media_query_list
804
+ Tree::CssImportNode.new(str || uri, media)
802
805
  elsif val =~ /^http:\/\//
803
- Tree::DirectiveNode.new(["@import url(#{val})"])
806
+ Tree::CssImportNode.new("url(#{val})")
804
807
  else
805
808
  Tree::ImportNode.new(val)
806
809
  end
data/lib/sass/media.rb CHANGED
@@ -216,7 +216,7 @@ module Sass::Media
216
216
 
217
217
  # The value of the feature.
218
218
  #
219
- # @return [Array<String, Sass::Script::Node>]
219
+ # @return [Sass::Script::Node]
220
220
  attr_accessor :value
221
221
 
222
222
  # The value of the feature after any SassScript has been resolved.
@@ -226,7 +226,7 @@ module Sass::Media
226
226
  attr_accessor :resolved_value
227
227
 
228
228
  # @param name [Array<String, Sass::Script::Node>] See \{#name}
229
- # @param value [Array<String, Sass::Script::Node>] See \{#value}
229
+ # @param value [Sass::Script::Node] See \{#value}
230
230
  def initialize(name, value)
231
231
  @name = name
232
232
  @value = value
@@ -240,7 +240,7 @@ module Sass::Media
240
240
  # @yieldreturn [String] The interpolated value.
241
241
  def perform
242
242
  @resolved_name = yield name
243
- @resolved_value = yield value
243
+ @resolved_value = yield value ? [value] : []
244
244
  end
245
245
 
246
246
  # Returns the CSS for the expression.
@@ -261,7 +261,7 @@ module Sass::Media
261
261
  def to_src(options)
262
262
  src = '('
263
263
  src << Sass::Media._interp_or_var_to_src(name, options)
264
- src << ': ' << Sass::Media._interp_or_var_to_src(value, options) unless value.empty?
264
+ src << ': ' << value.to_sass(options) if value
265
265
  src << ')'
266
266
  src
267
267
  end
@@ -272,7 +272,7 @@ module Sass::Media
272
272
  def deep_copy
273
273
  Expression.new(
274
274
  name.map {|c| c.is_a?(Sass::Script::Node) ? c.deep_copy : c},
275
- value.map {|c| c.is_a?(Sass::Script::Node) ? c.deep_copy : c})
275
+ value && value.deep_copy)
276
276
  end
277
277
 
278
278
  # Sets the options hash for the script nodes in the expression.
@@ -280,7 +280,7 @@ module Sass::Media
280
280
  # @param options [{Symbol => Object}] The options has to set.
281
281
  def options=(options)
282
282
  name.each {|n| n.options = options if n.is_a?(Sass::Script::Node)}
283
- value.each {|v| v.options = options if v.is_a?(Sass::Script::Node)}
283
+ value.options = options if value
284
284
  end
285
285
  end
286
286
 
data/lib/sass/scss.rb CHANGED
@@ -2,7 +2,6 @@ require 'sass/scss/rx'
2
2
  require 'sass/scss/script_lexer'
3
3
  require 'sass/scss/script_parser'
4
4
  require 'sass/scss/parser'
5
- require 'sass/scss/sass_parser'
6
5
  require 'sass/scss/static_parser'
7
6
  require 'sass/scss/css_parser'
8
7
 
@@ -293,18 +293,17 @@ module Sass
293
293
  return unless (str = tok(STRING)) || (uri = tok?(/url\(/i))
294
294
  if uri
295
295
  str = sass_script(:parse_string)
296
- media = str {media_query_list}.strip
297
- media = " #{media}" unless media.empty?
296
+ media = media_query_list
298
297
  ss
299
- return node(Tree::DirectiveNode.new(["@import ", str, media]))
298
+ return node(Tree::CssImportNode.new(str, media))
300
299
  end
301
300
 
302
301
  path = @scanner[1] || @scanner[2]
303
302
  ss
304
303
 
305
- media = str {media_query_list}.strip
306
- if path =~ /^http:\/\// || !media.empty? || use_css_import?
307
- return node(Sass::Tree::DirectiveNode.new(["@import #{str} #{media}"]))
304
+ media = media_query_list
305
+ if path =~ /^http:\/\// || media || use_css_import?
306
+ return node(Sass::Tree::CssImportNode.new(str, media))
308
307
  end
309
308
 
310
309
  node(Sass::Tree::ImportNode.new(path.strip))
@@ -372,12 +371,12 @@ module Sass
372
371
  ss
373
372
 
374
373
  if tok(/:/)
375
- ss; value = expr!(:expr)
374
+ ss; value = sass_script(:parse)
376
375
  end
377
376
  tok!(/\)/)
378
377
  ss
379
378
 
380
- Sass::Media::Expression.new(name, value || [])
379
+ Sass::Media::Expression.new(name, value)
381
380
  end
382
381
 
383
382
  def charset_directive
@@ -835,11 +834,11 @@ MESSAGE
835
834
  @strs.pop
836
835
  end
837
836
 
838
- def str?(&block)
837
+ def str?
839
838
  pos = @scanner.pos
840
839
  line = @line
841
840
  @strs.push ""
842
- throw_error(&block) && @strs.last
841
+ throw_error {yield} && @strs.last
843
842
  rescue Sass::SyntaxError => e
844
843
  @scanner.pos = pos
845
844
  @line = line
@@ -862,6 +861,11 @@ MESSAGE
862
861
  parser = self.class.sass_script_parser.new(@scanner, @line,
863
862
  @scanner.pos - (@scanner.string[0...@scanner.pos].rindex("\n") || 0))
864
863
  result = parser.send(*args)
864
+ unless @strs.empty?
865
+ # Convert to CSS manually so that comments are ignored.
866
+ src = result.to_sass
867
+ @strs.each {|s| s << src}
868
+ end
865
869
  @line = parser.line
866
870
  result
867
871
  rescue Sass::SyntaxError => e
@@ -0,0 +1,52 @@
1
+ module Sass::Tree
2
+ # A node representing an `@import` rule that's importing plain CSS.
3
+ #
4
+ # @see Sass::Tree
5
+ class CssImportNode < DirectiveNode
6
+ # The URI being imported, either as a plain string or an interpolated
7
+ # script string.
8
+ #
9
+ # @return [String, Sass::Script::Node]
10
+ attr_accessor :uri
11
+
12
+ # The text of the URI being imported after any interpolated SassScript has
13
+ # been resolved. Only set once \{Tree::Visitors::Perform} has been run.
14
+ #
15
+ # @return [String]
16
+ attr_accessor :resolved_uri
17
+
18
+ # The media query, or nil.
19
+ #
20
+ # @return [Sass::Media::Query?]
21
+ attr_accessor :query
22
+
23
+ # @param uri [String, Sass::Script::Node] See \{#uri}
24
+ # @param query [Sass::Media::Query] See \{#query}
25
+ def initialize(uri, query = nil)
26
+ @uri = uri
27
+ @query = query
28
+ super('')
29
+ end
30
+
31
+ # @param uri [String] See \{#resolved_uri}
32
+ # @return [CssImportNode]
33
+ def self.resolved(uri)
34
+ node = new(uri)
35
+ node.resolved_uri = uri
36
+ node
37
+ end
38
+
39
+ # @see DirectiveNode#value
40
+ def value; raise NotImplementedError; end
41
+
42
+ # @see DirectiveNode#resolved_value
43
+ def resolved_value
44
+ @resolved_value ||=
45
+ begin
46
+ str = "@import #{resolved_uri}"
47
+ str << " #{query.to_css}" if query
48
+ str
49
+ end
50
+ end
51
+ end
52
+ end
@@ -31,5 +31,12 @@ module Sass::Tree
31
31
  def resolved_value
32
32
  @resolved_value ||= "@media #{query.to_css}"
33
33
  end
34
+
35
+ # True when the directive has no visible children.
36
+ #
37
+ # @return [Boolean]
38
+ def invisible?
39
+ children.all? {|c| c.invisible?}
40
+ end
34
41
  end
35
42
  end
@@ -159,9 +159,9 @@ module Sass
159
159
  #
160
160
  # @yield node
161
161
  # @yieldparam node [Node] a node in the tree
162
- def each(&block)
162
+ def each
163
163
  yield self
164
- children.each {|c| c.each(&block)}
164
+ children.each {|c| c.each {|n| yield n}}
165
165
  end
166
166
 
167
167
  # Converts a node to Sass code that will generate it.
@@ -143,9 +143,9 @@ class Sass::Tree::Visitors::CheckNesting < Sass::Tree::Visitors::Base
143
143
  return false
144
144
  end
145
145
 
146
- def try_send(method, *args, &block)
146
+ def try_send(method, *args)
147
147
  return unless respond_to?(method)
148
- send(method, *args, &block)
148
+ send(method, *args)
149
149
  end
150
150
  end
151
151
 
@@ -150,6 +150,16 @@ class Sass::Tree::Visitors::Convert < Sass::Tree::Visitors::Base
150
150
  "#{tab_str}@media #{node.query.to_src(@options)}#{yield}"
151
151
  end
152
152
 
153
+ def visit_cssimport(node)
154
+ if node.uri.is_a?(Sass::Script::Node)
155
+ str = "#{tab_str}@import #{node.uri.to_sass(@options)}"
156
+ else
157
+ str = "#{tab_str}@import #{node.uri}"
158
+ end
159
+ str << " #{node.query.to_src(@options)}" if node.query
160
+ "#{str}#{semi}\n"
161
+ end
162
+
153
163
  def visit_mixindef(node)
154
164
  args =
155
165
  if node.args.empty?
@@ -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.resolved("@import url(#{path})")
138
+ return Sass::Tree::CssImportNode.resolved("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]}
@@ -302,6 +302,15 @@ END
302
302
  yield
303
303
  end
304
304
 
305
+ def visit_cssimport(node)
306
+ node.resolved_uri = run_interp([node.uri])
307
+ if node.query
308
+ node.query = node.query.deep_copy
309
+ node.query.perform {|interp| run_interp(interp)}
310
+ end
311
+ yield
312
+ end
313
+
305
314
  private
306
315
 
307
316
  def stack_trace
@@ -113,6 +113,10 @@ class Sass::Tree::Visitors::ToCss < Sass::Tree::Visitors::Base
113
113
  str
114
114
  end
115
115
 
116
+ def visit_cssimport(node)
117
+ visit_directive(node)
118
+ end
119
+
116
120
  def visit_prop(node)
117
121
  tab_str = ' ' * (@tabs + node.tabs)
118
122
  if node.style == :compressed
@@ -150,6 +150,7 @@ MSG
150
150
  "@content" => '@content may only be used within a mixin.',
151
151
  "=simple\n .simple\n color: red\n+simple\n color: blue" => ['Mixin "simple" does not accept a content block.', 4],
152
152
  "=foo\n @content\n+foo" => ["No @content passed.", 2],
153
+ "@import \"foo\" // bar" => "Invalid CSS after \"\"foo\" \": expected media query list, was \"// bar\"",
153
154
 
154
155
  # Regression tests
155
156
  "a\n b:\n c\n d" => ["Illegal nesting: Only properties may be nested beneath properties.", 3],
@@ -631,6 +632,17 @@ $family: unquote("Droid+Sans")
631
632
  SASS
632
633
  end
633
634
 
635
+ def test_import_with_dynamic_media_query
636
+ assert_equal(<<CSS, render(<<SASS))
637
+ @import "foo" print and (-webkit-min-device-pixel-ratio: 20);
638
+ CSS
639
+ $media: print
640
+ $key: -webkit-min-device-pixel-ratio
641
+ $value: 20
642
+ @import "foo" $media and ($key: $value)
643
+ SASS
644
+ end
645
+
634
646
  def test_url_import
635
647
  assert_equal("@import url(fonts.sass);\n", render("@import url(fonts.sass)"))
636
648
  end
@@ -1914,6 +1914,16 @@ $foo: foo;
1914
1914
  SCSS
1915
1915
  end
1916
1916
 
1917
+ def test_media_in_placeholder_selector
1918
+ assert_equal <<CSS, render(<<SCSS)
1919
+ .baz {
1920
+ c: d; }
1921
+ CSS
1922
+ %foo {bar {@media screen {a: b}}}
1923
+ .baz {c: d}
1924
+ SCSS
1925
+ end
1926
+
1917
1927
  # Regression Tests
1918
1928
 
1919
1929
  def test_newline_near_combinator
@@ -274,6 +274,17 @@ SCSS
274
274
  assert_equal("@import \"./fonts.sass\" all;\n", render("@import \"./fonts.sass\" all;"))
275
275
  end
276
276
 
277
+ def test_dynamic_media_import
278
+ assert_equal(<<CSS, render(<<SCSS))
279
+ @import "foo" print and (-webkit-min-device-pixel-ratio: 20);
280
+ CSS
281
+ $media: print;
282
+ $key: -webkit-min-device-pixel-ratio;
283
+ $value: 20;
284
+ @import "foo" $media and ($key: $value);
285
+ SCSS
286
+ end
287
+
277
288
  def test_http_import
278
289
  assert_equal("@import \"http://fonts.googleapis.com/css?family=Droid+Sans\";\n",
279
290
  render("@import \"http://fonts.googleapis.com/css?family=Droid+Sans\";"))
@@ -894,7 +905,7 @@ $baz: 12;
894
905
  SCSS
895
906
  end
896
907
 
897
- def test_variables_in_media
908
+ def test_script_in_media
898
909
  assert_equal <<CSS, render(<<SCSS)
899
910
  @media screen and (-webkit-min-device-pixel-ratio: 20), only print {
900
911
  a: b; }
@@ -904,6 +915,14 @@ $media2: print;
904
915
  $var: -webkit-min-device-pixel-ratio;
905
916
  $val: 20;
906
917
  @media $media1 and ($var: $val), only $media2 {a: b}
918
+ SCSS
919
+
920
+ assert_equal <<CSS, render(<<SCSS)
921
+ @media screen and (-webkit-min-device-pixel-ratio: 13) {
922
+ a: b; }
923
+ CSS
924
+ $vals: 1 2 3;
925
+ @media screen and (-webkit-min-device-pixel-ratio: 5 + 6 + nth($vals, 2)) {a: b}
907
926
  SCSS
908
927
  end
909
928
 
metadata CHANGED
@@ -1,15 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sass
3
3
  version: !ruby/object:Gem::Version
4
- hash: 592302981
4
+ hash: 592303031
5
5
  prerelease: 6
6
6
  segments:
7
7
  - 3
8
8
  - 2
9
9
  - 0
10
10
  - alpha
11
- - 76
12
- version: 3.2.0.alpha.76
11
+ - 85
12
+ version: 3.2.0.alpha.85
13
13
  platform: ruby
14
14
  authors:
15
15
  - Nathan Weizenbaum
@@ -19,7 +19,7 @@ autorequire:
19
19
  bindir: bin
20
20
  cert_chain: []
21
21
 
22
- date: 2012-02-17 00:00:00 -05:00
22
+ date: 2012-02-28 00:00:00 -05:00
23
23
  default_executable:
24
24
  dependencies:
25
25
  - !ruby/object:Gem::Dependency
@@ -86,7 +86,7 @@ files:
86
86
  - lib/sass/logger.rb
87
87
  - lib/sass/logger/base.rb
88
88
  - lib/sass/logger/log_level.rb
89
- - lib/sass/util.rb
89
+ - lib/sass/scss.rb
90
90
  - lib/sass/plugin.rb
91
91
  - lib/sass/plugin/compiler.rb
92
92
  - lib/sass/plugin/configuration.rb
@@ -117,11 +117,10 @@ files:
117
117
  - lib/sass/script/string_interpolation.rb
118
118
  - lib/sass/script/unary_operation.rb
119
119
  - lib/sass/script/variable.rb
120
- - lib/sass/scss.rb
120
+ - lib/sass/util.rb
121
121
  - lib/sass/scss/css_parser.rb
122
122
  - lib/sass/scss/parser.rb
123
123
  - lib/sass/scss/rx.rb
124
- - lib/sass/scss/sass_parser.rb
125
124
  - lib/sass/scss/script_lexer.rb
126
125
  - lib/sass/scss/script_parser.rb
127
126
  - lib/sass/scss/static_parser.rb
@@ -151,6 +150,7 @@ files:
151
150
  - lib/sass/tree/root_node.rb
152
151
  - lib/sass/tree/rule_node.rb
153
152
  - lib/sass/tree/content_node.rb
153
+ - lib/sass/tree/trace_node.rb
154
154
  - lib/sass/tree/variable_node.rb
155
155
  - lib/sass/tree/visitors/base.rb
156
156
  - lib/sass/tree/visitors/check_nesting.rb
@@ -162,7 +162,7 @@ files:
162
162
  - lib/sass/tree/visitors/to_css.rb
163
163
  - lib/sass/tree/warn_node.rb
164
164
  - lib/sass/tree/while_node.rb
165
- - lib/sass/tree/trace_node.rb
165
+ - lib/sass/tree/css_import_node.rb
166
166
  - lib/sass/media.rb
167
167
  - lib/sass/util/multibyte_string_scanner.rb
168
168
  - lib/sass/util/subset_map.rb
@@ -1,11 +0,0 @@
1
- module Sass
2
- module SCSS
3
- # A subclass of {Parser} that parses code in Sass documents
4
- # using some SCSS constructs.
5
- # This is necessary because SassScript in Sass supports `!`-style variables,
6
- # whereas in SCSS it doesn't.
7
- class SassParser < Parser
8
- @sass_script_parser = Sass::Script::Parser
9
- end
10
- end
11
- end