sass 3.1.15 → 3.1.16

Sign up to get free protection for your applications and to get access to all the features.
Files changed (94) hide show
  1. data/README.md +4 -5
  2. data/Rakefile +2 -2
  3. data/VERSION +1 -1
  4. data/lib/sass/css.rb +144 -48
  5. data/lib/sass/engine.rb +3 -1
  6. data/lib/sass/plugin/compiler.rb +25 -32
  7. data/lib/sass/plugin/listener.rb +59 -0
  8. data/lib/sass/script/lexer.rb +1 -1
  9. data/lib/sass/script/list.rb +1 -0
  10. data/lib/sass/scss/parser.rb +90 -4
  11. data/lib/sass/scss/rx.rb +5 -0
  12. data/lib/sass/scss/static_parser.rb +1 -1
  13. data/lib/sass/selector/abstract_sequence.rb +11 -2
  14. data/lib/sass/selector/simple.rb +6 -0
  15. data/lib/sass/tree/comment_node.rb +1 -1
  16. data/lib/sass/tree/node.rb +2 -2
  17. data/lib/sass/tree/visitors/check_nesting.rb +2 -2
  18. data/lib/sass/tree/visitors/cssize.rb +1 -1
  19. data/lib/sass/util.rb +3 -2
  20. data/test/sass/conversion_test.rb +10 -0
  21. data/test/sass/css2sass_test.rb +24 -0
  22. data/test/sass/engine_test.rb +1 -0
  23. data/test/sass/scss/css_test.rb +53 -0
  24. data/vendor/listen/CHANGELOG.md +72 -0
  25. data/vendor/listen/Gemfile +35 -0
  26. data/vendor/listen/Guardfile +8 -0
  27. data/vendor/{fssm → listen}/LICENSE +1 -1
  28. data/vendor/listen/README.md +297 -0
  29. data/vendor/listen/Rakefile +47 -0
  30. data/vendor/listen/Vagrantfile +96 -0
  31. data/vendor/listen/lib/listen.rb +38 -0
  32. data/vendor/listen/lib/listen/adapter.rb +159 -0
  33. data/vendor/listen/lib/listen/adapters/darwin.rb +84 -0
  34. data/vendor/listen/lib/listen/adapters/linux.rb +99 -0
  35. data/vendor/listen/lib/listen/adapters/polling.rb +66 -0
  36. data/vendor/listen/lib/listen/adapters/windows.rb +82 -0
  37. data/vendor/listen/lib/listen/directory_record.rb +257 -0
  38. data/vendor/listen/lib/listen/listener.rb +186 -0
  39. data/vendor/listen/lib/listen/multi_listener.rb +121 -0
  40. data/vendor/listen/lib/listen/turnstile.rb +28 -0
  41. data/vendor/listen/lib/listen/version.rb +3 -0
  42. data/vendor/listen/listen.gemspec +26 -0
  43. data/vendor/listen/spec/listen/adapter_spec.rb +142 -0
  44. data/vendor/listen/spec/listen/adapters/darwin_spec.rb +31 -0
  45. data/vendor/listen/spec/listen/adapters/linux_spec.rb +30 -0
  46. data/vendor/listen/spec/listen/adapters/polling_spec.rb +68 -0
  47. data/vendor/listen/spec/listen/adapters/windows_spec.rb +24 -0
  48. data/vendor/listen/spec/listen/directory_record_spec.rb +807 -0
  49. data/vendor/listen/spec/listen/listener_spec.rb +151 -0
  50. data/vendor/listen/spec/listen/multi_listener_spec.rb +151 -0
  51. data/vendor/listen/spec/listen/turnstile_spec.rb +56 -0
  52. data/vendor/listen/spec/listen_spec.rb +73 -0
  53. data/vendor/listen/spec/spec_helper.rb +16 -0
  54. data/vendor/listen/spec/support/adapter_helper.rb +538 -0
  55. data/vendor/listen/spec/support/directory_record_helper.rb +35 -0
  56. data/vendor/listen/spec/support/fixtures_helper.rb +29 -0
  57. data/vendor/listen/spec/support/listeners_helper.rb +133 -0
  58. data/vendor/listen/spec/support/platform_helper.rb +11 -0
  59. metadata +40 -40
  60. data/vendor/fssm/Gemfile +0 -3
  61. data/vendor/fssm/README.markdown +0 -83
  62. data/vendor/fssm/Rakefile +0 -11
  63. data/vendor/fssm/example.rb +0 -12
  64. data/vendor/fssm/ext/rakefile.rb +0 -14
  65. data/vendor/fssm/fssm.gemspec +0 -27
  66. data/vendor/fssm/lib/fssm.rb +0 -74
  67. data/vendor/fssm/lib/fssm/backends/fsevents.rb +0 -36
  68. data/vendor/fssm/lib/fssm/backends/inotify.rb +0 -26
  69. data/vendor/fssm/lib/fssm/backends/polling.rb +0 -25
  70. data/vendor/fssm/lib/fssm/backends/rbfsevent.rb +0 -42
  71. data/vendor/fssm/lib/fssm/backends/rubycocoa/fsevents.rb +0 -131
  72. data/vendor/fssm/lib/fssm/monitor.rb +0 -36
  73. data/vendor/fssm/lib/fssm/path.rb +0 -94
  74. data/vendor/fssm/lib/fssm/pathname.rb +0 -36
  75. data/vendor/fssm/lib/fssm/state/directory.rb +0 -75
  76. data/vendor/fssm/lib/fssm/state/file.rb +0 -24
  77. data/vendor/fssm/lib/fssm/support.rb +0 -87
  78. data/vendor/fssm/lib/fssm/tree.rb +0 -176
  79. data/vendor/fssm/lib/fssm/version.rb +0 -3
  80. data/vendor/fssm/profile/prof-cache.rb +0 -40
  81. data/vendor/fssm/profile/prof-fssm-pathname.html +0 -1231
  82. data/vendor/fssm/profile/prof-pathname-rubinius.rb +0 -35
  83. data/vendor/fssm/profile/prof-pathname.rb +0 -68
  84. data/vendor/fssm/profile/prof-plain-pathname.html +0 -988
  85. data/vendor/fssm/profile/prof.html +0 -2379
  86. data/vendor/fssm/spec/count_down_latch.rb +0 -151
  87. data/vendor/fssm/spec/monitor_spec.rb +0 -202
  88. data/vendor/fssm/spec/path_spec.rb +0 -96
  89. data/vendor/fssm/spec/root/duck/quack.txt +0 -0
  90. data/vendor/fssm/spec/root/file.css +0 -0
  91. data/vendor/fssm/spec/root/file.rb +0 -0
  92. data/vendor/fssm/spec/root/file.yml +0 -0
  93. data/vendor/fssm/spec/root/moo/cow.txt +0 -0
  94. data/vendor/fssm/spec/spec_helper.rb +0 -14
@@ -0,0 +1,59 @@
1
+ # A wrapper around the Listen gem. Adds support for listening to individual
2
+ # files, as well as a somewhat cleaner event dispatch API.
3
+ #
4
+ # @private
5
+ class Sass::Plugin::Listener
6
+ def initialize
7
+ @directories = {}
8
+ yield self
9
+ begin
10
+ start!
11
+ rescue Exception => e
12
+ raise e unless e.is_a?(Interrupt)
13
+ end
14
+ end
15
+
16
+ def directory(path, events)
17
+ (@directories[path] ||= []) << events
18
+ end
19
+
20
+ def file(path, events)
21
+ file_base = File.basename(path)
22
+ directory(File.dirname(path), {
23
+ :modified => file_event_fn(events[:modified], file_base),
24
+ :added => file_event_fn(events[:added], file_base),
25
+ :removed => file_event_fn(events[:removed], file_base)
26
+ })
27
+ end
28
+
29
+ def start!
30
+ listener = Listen::MultiListener.new(*@directories.keys) do |modified, added, removed|
31
+ modified = modified.group_by {|path| File.dirname(path)}
32
+ added = added.group_by {|path| File.dirname(path)}
33
+ removed = removed.group_by {|path| File.dirname(path)}
34
+
35
+ @directories.each do |dir, events|
36
+ events.each do |e|
37
+ run_events(modified[dir], e[:modified], dir)
38
+ run_events(added[dir], e[:added], dir)
39
+ run_events(removed[dir], e[:removed], dir)
40
+ end
41
+ end
42
+ end.start
43
+ end
44
+
45
+ private
46
+
47
+ def file_event_fn(event, file_base)
48
+ lambda do |dir, base|
49
+ next unless event
50
+ next unless base == file_base
51
+ event.call
52
+ end
53
+ end
54
+
55
+ def run_events(paths, event, path)
56
+ return if paths.nil? || event.nil?
57
+ paths.each {|p| event[File.dirname(p), File.basename(p)]}
58
+ end
59
+ end
@@ -287,7 +287,7 @@ MESSAGE
287
287
  end
288
288
 
289
289
  def special_fun
290
- return unless str1 = scan(/((-[\w-]+-)?calc|expression|progid:[a-z\.]*)\(/i)
290
+ return unless str1 = scan(/((-[\w-]+-)?(calc|element)|expression|progid:[a-z\.]*)\(/i)
291
291
  str2, _ = Sass::Shared.balance(@scanner, ?(, ?), 1)
292
292
  c = str2.count("\n")
293
293
  old_line = @line
@@ -46,6 +46,7 @@ module Sass::Script
46
46
 
47
47
  # @see Node#to_sass
48
48
  def to_sass(opts = {})
49
+ return "()" if value.empty?
49
50
  precedence = Sass::Script::Parser.precedence_of(separator)
50
51
  value.map do |v|
51
52
  if v.is_a?(List) && Sass::Script::Parser.precedence_of(v.separator) <= precedence
@@ -114,7 +114,9 @@ module Sass
114
114
  end
115
115
 
116
116
  DIRECTIVES = Set[:mixin, :include, :function, :return, :debug, :warn, :for,
117
- :each, :while, :if, :else, :extend, :import, :media, :charset]
117
+ :each, :while, :if, :else, :extend, :import, :media, :charset, :_moz_document]
118
+
119
+ PREFIXED_DIRECTIVES = Set[:supports]
118
120
 
119
121
  def directive
120
122
  return unless tok(/@/)
@@ -123,13 +125,19 @@ module Sass
123
125
 
124
126
  if dir = special_directive(name)
125
127
  return dir
128
+ elsif dir = prefixed_directive(name)
129
+ return dir
126
130
  end
127
131
 
128
132
  # Most at-rules take expressions (e.g. @import),
129
133
  # but some (e.g. @page) take selector-like arguments
130
134
  val = str {break unless expr}
131
135
  val ||= CssParser.new(@scanner, @line).parse_selector_string
132
- node = node(Sass::Tree::DirectiveNode.new("@#{name} #{val}".strip))
136
+ directive_body("@#{name} #{val}")
137
+ end
138
+
139
+ def directive_body(value)
140
+ node = node(Sass::Tree::DirectiveNode.new(value.strip))
133
141
 
134
142
  if tok(/\{/)
135
143
  node.has_children = true
@@ -145,6 +153,11 @@ module Sass
145
153
  DIRECTIVES.include?(sym) && send("#{sym}_directive")
146
154
  end
147
155
 
156
+ def prefixed_directive(name)
157
+ sym = name.gsub(/^-[a-z0-9]+-/i, '').gsub('-', '_').to_sym
158
+ PREFIXED_DIRECTIVES.include?(sym) && send("#{sym}_directive", name)
159
+ end
160
+
148
161
  def mixin_directive
149
162
  name = tok! IDENT
150
163
  args = sass_script(:parse_mixin_definition_arglist)
@@ -346,6 +359,76 @@ module Sass
346
359
  node(Sass::Tree::CharsetNode.new(name))
347
360
  end
348
361
 
362
+ # The document directive is specified in
363
+ # http://www.w3.org/TR/css3-conditional/, but Gecko allows the
364
+ # `url-prefix` and `domain` functions to omit quotation marks, contrary to
365
+ # the standard.
366
+ #
367
+ # We could parse all document directives according to Mozilla's syntax,
368
+ # but if someone's using e.g. @-webkit-document we don't want them to
369
+ # think WebKit works sans quotes.
370
+ def _moz_document_directive
371
+ value = str do
372
+ begin
373
+ ss
374
+ expr!(:moz_document_function)
375
+ end while tok(/,/)
376
+ end
377
+ directive_body("@-moz-document #{value}")
378
+ end
379
+
380
+ def moz_document_function
381
+ return unless tok(URI) || tok(URL_PREFIX) || tok(DOMAIN) || function
382
+ ss
383
+ end
384
+
385
+ # http://www.w3.org/TR/css3-conditional/
386
+ def supports_directive(name)
387
+ value = str {expr!(:supports_condition)}
388
+ directive_body("@#{name} #{value}")
389
+ end
390
+
391
+ def supports_condition
392
+ supports_negation || supports_operator || supports_declaration_condition
393
+ end
394
+
395
+ def supports_negation
396
+ return unless tok(/not/i)
397
+ ss
398
+ expr!(:supports_condition_in_parens)
399
+ end
400
+
401
+ def supports_operator
402
+ return unless supports_condition_in_parens
403
+ tok!(/and|or/i)
404
+ begin
405
+ ss
406
+ expr!(:supports_condition_in_parens)
407
+ end while tok(/and|or/i)
408
+ true
409
+ end
410
+
411
+ def supports_condition_in_parens
412
+ return unless tok(/\(/); ss
413
+ if supports_condition
414
+ tok!(/\)/); ss
415
+ else
416
+ supports_declaration_body
417
+ end
418
+ end
419
+
420
+ def supports_declaration_condition
421
+ return unless tok(/\(/); ss
422
+ supports_declaration_body
423
+ end
424
+
425
+ def supports_declaration_body
426
+ tok!(IDENT); ss
427
+ tok!(/:/); ss
428
+ expr!(:expr); ss
429
+ tok!(/\)/); ss
430
+ end
431
+
349
432
  def variable
350
433
  return unless tok(/\$/)
351
434
  name = tok!(IDENT)
@@ -792,11 +875,11 @@ MESSAGE
792
875
  @strs.pop
793
876
  end
794
877
 
795
- def str?(&block)
878
+ def str?
796
879
  pos = @scanner.pos
797
880
  line = @line
798
881
  @strs.push ""
799
- throw_error(&block) && @strs.last
882
+ throw_error {yield} && @strs.last
800
883
  rescue Sass::SyntaxError => e
801
884
  @scanner.pos = pos
802
885
  @line = line
@@ -841,6 +924,9 @@ MESSAGE
841
924
  :selector_comma_sequence => "selector",
842
925
  :simple_selector_sequence => "selector",
843
926
  :import_arg => "file to import (string or url())",
927
+ :moz_document_function => "matching function (e.g. url-prefix(), domain())",
928
+ :supports_condition => "@supports condition (e.g. (display: flexbox))",
929
+ :supports_condition_in_parens => "@supports condition (e.g. (display: flexbox))",
844
930
  }
845
931
 
846
932
  TOK_NAMES = Sass::Util.to_hash(
@@ -107,6 +107,11 @@ module Sass
107
107
  TILDE = /#{W}~/
108
108
  NOT = quote(":not(", Regexp::IGNORECASE)
109
109
 
110
+ # Defined in https://developer.mozilla.org/en/CSS/@-moz-document as a
111
+ # non-standard version of http://www.w3.org/TR/css3-conditional/
112
+ URL_PREFIX = /url-prefix\(#{W}(?:#{STRING}|#{URL})#{W}\)/i
113
+ DOMAIN = /domain\(#{W}(?:#{STRING}|#{URL})#{W}\)/i
114
+
110
115
  # Custom
111
116
  HEXCOLOR = /\#[0-9a-fA-F]+/
112
117
  INTERP_START = /#\{/
@@ -32,7 +32,7 @@ module Sass
32
32
  def use_css_import?; true; end
33
33
 
34
34
  def special_directive(name)
35
- return unless %w[media import charset].include?(name)
35
+ return unless %w[media import charset -moz-document].include?(name)
36
36
  super
37
37
  end
38
38
  end
@@ -2,8 +2,9 @@ module Sass
2
2
  module Selector
3
3
  # The abstract parent class of the various selector sequence classes.
4
4
  #
5
- # All subclasses should implement a `members` method
6
- # that returns an array of object that respond to `#line=` and `#filename=`.
5
+ # All subclasses should implement a `members` method that returns an array
6
+ # of object that respond to `#line=` and `#filename=`, as well as a `to_a`
7
+ # method that returns an array of strings and script nodes.
7
8
  class AbstractSequence
8
9
  # The line of the Sass template on which this selector was declared.
9
10
  #
@@ -57,6 +58,14 @@ module Sass
57
58
  other.class == self.class && other.hash == self.hash && _eql?(other)
58
59
  end
59
60
  alias_method :==, :eql?
61
+
62
+ # Converts the selector into a string. This is the standard selector
63
+ # string, along with any SassScript interpolation that may exist.
64
+ #
65
+ # @return [String]
66
+ def to_s
67
+ to_a.map {|e| e.is_a?(Sass::Script::Node) ? "\#{#{e.to_sass}}" : e}.join
68
+ end
60
69
  end
61
70
  end
62
71
  end
@@ -33,6 +33,12 @@ module Sass
33
33
  to_a.map {|e| e.is_a?(Sass::Script::Node) ? "\#{#{e.to_sass}}" : e}.join
34
34
  end
35
35
 
36
+ # @see \{#inspect}
37
+ # @return [String]
38
+ def to_s
39
+ inspect
40
+ end
41
+
36
42
  # Returns a hash code for this selector object.
37
43
  #
38
44
  # By default, this is based on the value of \{#to\_a},
@@ -81,7 +81,7 @@ module Sass::Tree
81
81
  pre = str.split("\n").inject(str[/^[ \t]*/].split("")) do |pre, line|
82
82
  line[/^[ \t]*/].split("").zip(pre).inject([]) do |arr, (a, b)|
83
83
  break arr if a != b
84
- arr + [a]
84
+ arr << a
85
85
  end
86
86
  end.join
87
87
  str.gsub(/^#{pre}/, '')
@@ -158,9 +158,9 @@ module Sass
158
158
  #
159
159
  # @yield node
160
160
  # @yieldparam node [Node] a node in the tree
161
- def each(&block)
161
+ def each
162
162
  yield self
163
- children.each {|c| c.each(&block)}
163
+ children.each {|c| c.each {|n| yield n}}
164
164
  end
165
165
 
166
166
  # Converts a node to Sass code that will generate it.
@@ -125,9 +125,9 @@ class Sass::Tree::Visitors::CheckNesting < Sass::Tree::Visitors::Base
125
125
  return false
126
126
  end
127
127
 
128
- def try_send(method, *args, &block)
128
+ def try_send(method, *args)
129
129
  return unless respond_to?(method)
130
- send(method, *args, &block)
130
+ send(method, *args)
131
131
  end
132
132
  end
133
133
 
@@ -17,7 +17,7 @@ class Sass::Tree::Visitors::Cssize < Sass::Tree::Visitors::Base
17
17
 
18
18
  # If an exception is raised, this adds proper metadata to the backtrace.
19
19
  def visit(node)
20
- super(node.dup)
20
+ super(node)
21
21
  rescue Sass::SyntaxError => e
22
22
  e.modify_backtrace(:filename => node.filename, :line => node.line)
23
23
  raise e
@@ -85,8 +85,9 @@ module Sass
85
85
  # @return [Hash] The mapped hash
86
86
  # @see #map_keys
87
87
  # @see #map_vals
88
- def map_hash(hash, &block)
89
- to_hash(hash.map(&block))
88
+ def map_hash(hash)
89
+ # Using &block here completely hoses performance on 1.8.
90
+ to_hash(hash.map {|k, v| yield k, v})
90
91
  end
91
92
 
92
93
  # Computes the powerset of the given array.
@@ -1158,6 +1158,16 @@ SASS
1158
1158
  SCSS
1159
1159
  end
1160
1160
 
1161
+ ## Regression Tests
1162
+
1163
+ def test_empty_lists
1164
+ assert_renders(<<SASS, <<SCSS)
1165
+ $foo: ()
1166
+ SASS
1167
+ $foo: ();
1168
+ SCSS
1169
+ end
1170
+
1161
1171
  private
1162
1172
 
1163
1173
  def assert_sass_to_sass(sass, options = {})
@@ -277,6 +277,30 @@ foo, , bar { a: b }
277
277
  CSS
278
278
  end
279
279
 
280
+ def test_selector_splitting
281
+ assert_equal(<<SASS, css2sass(<<CSS))
282
+ .foo >
283
+ .bar
284
+ a: b
285
+ .baz
286
+ c: d
287
+ SASS
288
+ .foo>.bar {a: b}
289
+ .foo>.baz {c: d}
290
+ CSS
291
+
292
+ assert_equal(<<SASS, css2sass(<<CSS))
293
+ .foo
294
+ &::bar
295
+ a: b
296
+ &::baz
297
+ c: d
298
+ SASS
299
+ .foo::bar {a: b}
300
+ .foo::baz {c: d}
301
+ CSS
302
+ end
303
+
280
304
  # Error reporting
281
305
 
282
306
  def test_error_reporting
@@ -140,6 +140,7 @@ MSG
140
140
  "$var: true\n@while $var\n @extend .bar\n $var: false" => ["Extend directives may only be used within rules.", 3],
141
141
  "@for $i from 0 to 1\n @extend .bar" => ["Extend directives may only be used within rules.", 2],
142
142
  "@mixin foo\n @extend .bar\n@include foo" => ["Extend directives may only be used within rules.", 2],
143
+ "@import \"foo\" // bar" => "Invalid @import: \"\"foo\" // bar\"",
143
144
 
144
145
  # Regression tests
145
146
  "a\n b:\n c\n d" => ["Illegal nesting: Only properties may be nested beneath properties.", 3],
@@ -412,6 +412,15 @@ foo {
412
412
  SCSS
413
413
  end
414
414
 
415
+ def test_element_function
416
+ assert_parses <<SCSS
417
+ foo {
418
+ a: -moz-element(#foo);
419
+ b: -webkit-element(#foo);
420
+ b: -foobar-element(#foo); }
421
+ SCSS
422
+ end
423
+
415
424
  def test_unary_ops
416
425
  assert_equal <<CSS, render(<<SCSS)
417
426
  foo {
@@ -586,6 +595,50 @@ CSS
586
595
  SCSS
587
596
  end
588
597
 
598
+ def test_moz_document_directive
599
+ assert_equal <<CSS, render(<<SCSS)
600
+ @-moz-document url(http://www.w3.org/),
601
+ url-prefix(http://www.w3.org/Style/),
602
+ domain(mozilla.org),
603
+ regexp("^https:.*") {
604
+ .foo {
605
+ a: b; } }
606
+ CSS
607
+ @-moz-document url(http://www.w3.org/),
608
+ url-prefix(http://www.w3.org/Style/),
609
+ domain(mozilla.org),
610
+ regexp("^https:.*") {
611
+ .foo {a: b}
612
+ }
613
+ SCSS
614
+ end
615
+
616
+ def test_supports
617
+ assert_equal <<CSS, render(<<SCSS)
618
+ @supports (a: b) and (c: d) or (not (d: e)) and ((not (f: g)) or (not ((h: i) and (j: k)))) {
619
+ .foo {
620
+ a: b; } }
621
+ CSS
622
+ @supports (a: b) and (c: d) or (not (d: e)) and ((not (f: g)) or (not ((h: i) and (j: k)))) {
623
+ .foo {
624
+ a: b;
625
+ }
626
+ }
627
+ SCSS
628
+
629
+ assert_equal <<CSS, render(<<SCSS)
630
+ @-prefix-supports (a: b) and (c: d) or (not (d: e)) and ((not (f: g)) or (not ((h: i) and (j: k)))) {
631
+ .foo {
632
+ a: b; } }
633
+ CSS
634
+ @-prefix-supports (a: b) and (c: d) or (not (d: e)) and ((not (f: g)) or (not ((h: i) and (j: k)))) {
635
+ .foo {
636
+ a: b;
637
+ }
638
+ }
639
+ SCSS
640
+ end
641
+
589
642
  ## Selectors
590
643
 
591
644
  # Taken from http://www.w3.org/TR/css3-selectors/#selectors