haml-edge 3.1.41 → 3.1.42

Sign up to get free protection for your applications and to get access to all the features.
data/EDGE_GEM_VERSION CHANGED
@@ -1 +1 @@
1
- 3.1.41
1
+ 3.1.42
data/VERSION CHANGED
@@ -1 +1 @@
1
- 3.1.41
1
+ 3.1.42
data/lib/sass/engine.rb CHANGED
@@ -509,16 +509,7 @@ WARNING
509
509
  # If value begins with url( or ",
510
510
  # it's a CSS @import rule and we don't want to touch it.
511
511
  if directive == "import"
512
- raise SyntaxError.new("Illegal nesting: Nothing may be nested beneath import directives.",
513
- :line => @line + 1) unless line.children.empty?
514
- if (match = value.match(Sass::SCSS::RX::STRING) || value.match(Sass::SCSS::RX::URI)) &&
515
- !match.post_match.strip.empty? && match.post_match.strip[0] != ?,
516
- return Tree::DirectiveNode.new("@import #{value}")
517
- end
518
- value.split(/,\s*/).map do |f|
519
- f = $1 || $2 || $3 if f =~ Sass::SCSS::RX::STRING || f =~ Sass::SCSS::RX::URI
520
- Tree::ImportNode.new(f)
521
- end
512
+ parse_import(line, value)
522
513
  elsif directive == "mixin"
523
514
  parse_mixin_definition(line)
524
515
  elsif directive == "include"
@@ -597,6 +588,32 @@ WARNING
597
588
  nil
598
589
  end
599
590
 
591
+ def parse_import(line, value)
592
+ raise SyntaxError.new("Illegal nesting: Nothing may be nested beneath import directives.",
593
+ :line => @line + 1) unless line.children.empty?
594
+
595
+ if (match = value.match(Sass::SCSS::RX::STRING) || value.match(Sass::SCSS::RX::URI)) &&
596
+ match.offset(0).first == 0 && !match.post_match.strip.empty? &&
597
+ match.post_match.strip[0] != ?,
598
+ # @import "filename" media-type
599
+ return Tree::DirectiveNode.new("@import #{value}")
600
+ end
601
+
602
+ value.split(/,\s*/).map do |f|
603
+ if f =~ Sass::SCSS::RX::URI
604
+ # All url()s are literal CSS @imports
605
+ next Tree::DirectiveNode.new("@import #{f}")
606
+ elsif f =~ Sass::SCSS::RX::STRING
607
+ f = $1 || $2
608
+ end
609
+
610
+ # http:// URLs are always literal CSS imports
611
+ next Tree::DirectiveNode.new("@import url(#{f})") if f =~ /^http:\/\//
612
+
613
+ Tree::ImportNode.new(f)
614
+ end
615
+ end
616
+
600
617
  MIXIN_DEF_RE = /^(?:=|@mixin)\s*(#{Sass::SCSS::RX::IDENT})(.*)$/
601
618
  def parse_mixin_definition(line)
602
619
  name, arg_string = line.text.scan(MIXIN_DEF_RE).first
@@ -292,7 +292,7 @@ MESSAGE
292
292
  end
293
293
 
294
294
  def special_fun
295
- return unless str1 = scan(/(calc|expression|progid:[a-z\.]*)\(/i)
295
+ return unless str1 = scan(/((-[\w-]+-)?calc|expression|progid:[a-z\.]*)\(/i)
296
296
  str2, _ = Haml::Shared.balance(@scanner, ?(, ?), 1)
297
297
  c = str2.count("\n")
298
298
  old_line = @line
@@ -200,13 +200,13 @@ module Sass
200
200
 
201
201
  def import_directive
202
202
  @expected = "string or url()"
203
- arg = tok(STRING) || tok!(URI)
203
+ arg = tok(STRING) || (uri = tok!(URI))
204
204
  path = @scanner[1] || @scanner[2] || @scanner[3]
205
205
  ss
206
206
 
207
207
  media = str {media_query_list}.strip
208
208
 
209
- if !media.strip.empty? || use_css_import?
209
+ if uri || path =~ /^http:\/\// || !media.strip.empty? || use_css_import?
210
210
  return node(Sass::Tree::DirectiveNode.new("@import #{arg} #{media}".strip))
211
211
  end
212
212
 
@@ -381,6 +381,17 @@ module Sass
381
381
  sel.to_a
382
382
  end
383
383
 
384
+ def selector_comma_sequence
385
+ return unless sel = _selector
386
+ selectors = [sel]
387
+ while tok(/,/)
388
+ ws = str{ss}
389
+ selectors << expr!(:_selector)
390
+ selectors[-1] = Selector::Sequence.new(["\n"] + selectors.last.members) if ws.include?("\n")
391
+ end
392
+ Selector::CommaSequence.new(selectors)
393
+ end
394
+
384
395
  def _selector
385
396
  # The combinator here allows the "> E" hack
386
397
  return unless val = combinator || simple_selector_sequence
@@ -533,12 +544,12 @@ MESSAGE
533
544
  end
534
545
 
535
546
  def negation
536
- return unless tok(NOT)
547
+ return unless name = tok(NOT) || tok(MOZ_ANY)
537
548
  ss
538
549
  @expected = "selector"
539
- sel = element_name || id_selector || class_selector || attrib || expr!(:pseudo)
550
+ sel = selector_comma_sequence
540
551
  tok!(/\)/)
541
- Selector::Negation.new(sel)
552
+ Selector::SelectorPseudoClass.new(name[1...-1], sel)
542
553
  end
543
554
 
544
555
  def declaration
@@ -722,7 +733,7 @@ MESSAGE
722
733
  :interp_ident => "identifier",
723
734
  :interp_name => "identifier",
724
735
  :expr => "expression (e.g. 1px, bold)",
725
- :_selector => "selector",
736
+ :selector_comma_sequence => "selector",
726
737
  :simple_selector_sequence => "selector",
727
738
  }
728
739
 
data/lib/sass/scss/rx.rb CHANGED
@@ -109,6 +109,7 @@ module Sass
109
109
  # Custom
110
110
  HEXCOLOR = /\#[0-9a-fA-F]+/
111
111
  INTERP_START = /#\{/
112
+ MOZ_ALL = quote(":-moz-any(", Regexp::IGNORECASE)
112
113
 
113
114
  STRING1_NOINTERP = /\"((?:[^\n\r\f\\"#]|#(?!\{)|\\#{NL}|#{ESCAPE})*)\"/
114
115
  STRING2_NOINTERP = /\'((?:[^\n\r\f\\'#]|#(?!\{)|\\#{NL}|#{ESCAPE})*)\'/
@@ -17,14 +17,8 @@ module Sass
17
17
  # @raise [Sass::SyntaxError] if there's a syntax error in the selector
18
18
  def parse_selector(filename)
19
19
  init_scanner!
20
- selectors = [expr!(:_selector)]
21
- while tok(/,/)
22
- ws = str{ss}
23
- selectors << expr!(:_selector)
24
- selectors[-1] = Selector::Sequence.new(["\n"] + selectors.last.members) if ws.include?("\n")
25
- end
20
+ seq = expr!(:selector_comma_sequence)
26
21
  expected("selector") unless @scanner.eos?
27
- seq = Selector::CommaSequence.new(selectors)
28
22
  seq.line = @line
29
23
  seq.filename = filename
30
24
  seq
@@ -61,6 +61,13 @@ module Sass
61
61
  members.map {|m| m.inspect}.join(", ")
62
62
  end
63
63
 
64
+ # @see Simple#to_a
65
+ def to_a
66
+ arr = Haml::Util.intersperse(@members.map {|m| m.to_a}, ", ").flatten
67
+ arr.delete("\n")
68
+ arr
69
+ end
70
+
64
71
  private
65
72
 
66
73
  def _hash
@@ -78,10 +78,10 @@ module Sass
78
78
  return sels if sels.any? {|sel2| eql?(sel2)}
79
79
  sels_with_ix = Haml::Util.enum_with_index(sels)
80
80
  _, i =
81
- if self.is_a?(Pseudo) || self.is_a?(Negation)
81
+ if self.is_a?(Pseudo) || self.is_a?(SelectorPseudoClass)
82
82
  sels_with_ix.find {|sel, _| sel.is_a?(Pseudo) && sels.last.type == :element}
83
83
  else
84
- sels_with_ix.find {|sel, _| sel.is_a?(Pseudo) || sel.is_a?(Negation)}
84
+ sels_with_ix.find {|sel, _| sel.is_a?(Pseudo) || sel.is_a?(SelectorPseudoClass)}
85
85
  end
86
86
  return sels + [self] unless i
87
87
  return sels[0...i] + [self] + sels[i..-1]
data/lib/sass/selector.rb CHANGED
@@ -332,21 +332,29 @@ module Sass
332
332
  end
333
333
  end
334
334
 
335
- # A negation pseudoclass selector (e.g. `:not(.foo)`).
336
- class Negation < Simple
337
- # The selector to negate.
335
+ # A pseudoclass selector whose argument is itself a selector
336
+ # (e.g. `:not(.foo)` or `:-moz-all(.foo, .bar)`).
337
+ class SelectorPseudoClass < Simple
338
+ # The name of the pseudoclass.
338
339
  #
339
- # @return [Selector]
340
+ # @return [String]
341
+ attr_reader :name
342
+
343
+ # The selector argument.
344
+ #
345
+ # @return [Selector::Sequence]
340
346
  attr_reader :selector
341
347
 
342
- # @param [Selector] The selector to negate
343
- def initialize(selector)
348
+ # @param [String] The name of the pseudoclass
349
+ # @param [Selector::Sequence] The selector argument
350
+ def initialize(name, selector)
351
+ @name = name
344
352
  @selector = selector
345
353
  end
346
354
 
347
355
  # @see Selector#to_a
348
356
  def to_a
349
- [":not("] + @selector.to_a + [")"]
357
+ [":", @name, "("] + @selector.to_a + [")"]
350
358
  end
351
359
  end
352
360
  end
@@ -671,11 +671,15 @@ SCSS
671
671
  assert_renders <<SASS, <<SCSS
672
672
  @import foo
673
673
 
674
+ @import url(bar.css)
675
+
674
676
  foo
675
677
  bar: baz
676
678
  SASS
677
679
  @import "foo";
678
680
 
681
+ @import url(bar.css);
682
+
679
683
  foo {
680
684
  bar: baz; }
681
685
  SCSS
@@ -683,11 +687,15 @@ SCSS
683
687
  assert_renders <<SASS, <<SCSS
684
688
  @import foo.css
685
689
 
690
+ @import url(bar.css)
691
+
686
692
  foo
687
693
  bar: baz
688
694
  SASS
689
695
  @import "foo.css";
690
696
 
697
+ @import url(bar.css);
698
+
691
699
  foo {
692
700
  bar: baz; }
693
701
  SCSS
@@ -695,7 +703,6 @@ SCSS
695
703
 
696
704
  def test_import_as_directive_in_sass
697
705
  assert_equal "@import foo.css\n", to_sass('@import "foo.css"')
698
- assert_equal "@import foo.css\n", to_sass('@import url(foo.css)')
699
706
  end
700
707
 
701
708
  def test_import_as_directive_in_scss
@@ -487,8 +487,21 @@ CSS
487
487
  end
488
488
 
489
489
  def test_css_import
490
- assert_equal("@import url(./fonts.css) screen;\n", render("@import url(./fonts.css) screen"))
491
- assert_equal("@import \"./fonts.css\" screen;\n", render("@import \"./fonts.css\" screen"))
490
+ assert_equal("@import url(./fonts.css);\n", render("@import \"./fonts.css\""))
491
+ end
492
+
493
+ def test_media_import
494
+ assert_equal("@import \"./fonts.sass\" all;\n",
495
+ render("@import \"./fonts.sass\" all"))
496
+ end
497
+
498
+ def test_http_import
499
+ assert_equal("@import url(http://fonts.googleapis.com/css?family=Droid+Sans);\n",
500
+ render("@import \"http://fonts.googleapis.com/css?family=Droid+Sans\""))
501
+ end
502
+
503
+ def test_url_import
504
+ assert_equal("@import url(fonts.sass);\n", render("@import url(fonts.sass)"))
492
505
  end
493
506
 
494
507
  def test_sass_import
@@ -382,7 +382,10 @@ SCSS
382
382
  def test_calc_function
383
383
  assert_parses <<SCSS
384
384
  foo {
385
- a: 12px calc(100%/3 - 2*1em - 2*1px); }
385
+ a: 12px calc(100%/3 - 2*1em - 2*1px);
386
+ b: 12px -moz-calc(100%/3 - 2*1em - 2*1px);
387
+ b: 12px -webkit-calc(100%/3 - 2*1em - 2*1px);
388
+ b: 12px -foobar-calc(100%/3 - 2*1em - 2*1px); }
386
389
  SCSS
387
390
  end
388
391
 
@@ -703,6 +706,18 @@ SCSS
703
706
 
704
707
  assert_selector_parses(':not(:hover)')
705
708
  assert_selector_parses(':not(:nth-child(2n + 3))')
709
+
710
+ # Not technically allowed, but what the heck
711
+ assert_selector_parses(':not(:not(#foo))')
712
+ assert_selector_parses(':not(a#foo.bar)')
713
+ assert_selector_parses(':not(#foo .bar > baz)')
714
+ assert_selector_parses(':not(h1, h2, h3)')
715
+ end
716
+
717
+ def test_moz_any_selector
718
+ assert_selector_parses(':-moz-any(h1, h2, h3)')
719
+ assert_selector_parses(':-moz-any(.foo)')
720
+ assert_selector_parses(':-moz-any(foo bar, .baz > .bang)')
706
721
  end
707
722
 
708
723
  def test_namespaced_selectors
@@ -212,11 +212,24 @@ SCSS
212
212
  def test_css_import_directive
213
213
  assert_equal "@import url(foo.css);\n", render('@import "foo.css";')
214
214
  assert_equal "@import url(foo.css);\n", render("@import 'foo.css';")
215
- assert_equal "@import url(foo.css);\n", render('@import url("foo.css");')
216
- assert_equal "@import url(foo.css);\n", render("@import url('foo.css');")
215
+ assert_equal "@import url(\"foo.css\");\n", render('@import url("foo.css");')
216
+ assert_equal "@import url('foo.css');\n", render("@import url('foo.css');")
217
217
  assert_equal "@import url(foo.css);\n", render('@import url(foo.css);')
218
218
  end
219
219
 
220
+ def test_media_import
221
+ assert_equal("@import \"./fonts.sass\" all;\n", render("@import \"./fonts.sass\" all;"))
222
+ end
223
+
224
+ def test_http_import
225
+ assert_equal("@import \"http://fonts.googleapis.com/css?family=Droid+Sans\";\n",
226
+ render("@import \"http://fonts.googleapis.com/css?family=Droid+Sans\";"))
227
+ end
228
+
229
+ def test_url_import
230
+ assert_equal("@import url(fonts.sass);\n", render("@import url(fonts.sass);"))
231
+ end
232
+
220
233
  def test_block_comment_in_script
221
234
  assert_equal <<CSS, render(<<SCSS)
222
235
  foo {
@@ -4,7 +4,7 @@ $preconst: hello
4
4
  pre-mixin: here
5
5
 
6
6
  @import importee.sass, scss_importee, "basic.sass", basic.css, ../results/complex.css
7
- @import url(partial.sass)
7
+ @import partial.sass
8
8
 
9
9
  nonimported
10
10
  :myconst $preconst
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: haml-edge
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.1.41
4
+ version: 3.1.42
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nathan Weizenbaum