sass 3.4.0 → 3.4.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: ddad801e37fc518f7e65d22001ccfd3953ed038c
4
- data.tar.gz: a14f945fcf23bd0fc3c34c9cd3b74c5c108fef78
3
+ metadata.gz: 0a14f29ae01795aa104c2385d85709b6267b1b6b
4
+ data.tar.gz: 963ba1a01ebe057c873468590e7d1a1721d4186f
5
5
  SHA512:
6
- metadata.gz: f50f5f87c434e97dfb5b97fa9bd3489836f3a59a1026c95d849f0248185528ecb9f36b7436e101517d35c37814023312f58a9c111a15525164165b173313c3da
7
- data.tar.gz: e214a6daa25e3de564b65c6443bcbfc85134c9757b1c314f98176db53c7e3fcdd119af6adc64fc99e0566dc451ad59efef89f5cbd64de46ed0d080c714ddbaf9
6
+ metadata.gz: 9383d9ce058f5fb03da4fa72a4535e211a5e1581a9f36b1394433133b63b984b3dd693f5b12781895c1c280abf3eee6266869bf557a3652d4002bd83b0d1854c
7
+ data.tar.gz: 0a7aa3edaf6050308a8d399672648ba41a6eaee9f2ba9517d9a99346442b07ba16fbc34b37596efb1e159a546125a53062171cc059289ff2f791b545a8fe0812
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # Sass [![Gem Version](https://badge.fury.io/rb/sass.png)](http://badge.fury.io/rb/sass)
1
+ # Sass [![Gem Version](https://badge.fury.io/rb/sass.png)](http://badge.fury.io/rb/sass) [![Inline docs](http://inch-ci.org/github/sass/sass.svg)](http://inch-ci.org/github/sass/sass)
2
2
 
3
3
  **Sass makes CSS fun again**. Sass is an extension of CSS3,
4
4
  adding nested rules, variables, mixins, selector inheritance, and more.
data/VERSION CHANGED
@@ -1 +1 @@
1
- 3.4.0
1
+ 3.4.1
@@ -1 +1 @@
1
- 19 August 2014 00:38:04 UTC
1
+ 23 August 2014 00:21:00 UTC
@@ -188,4 +188,21 @@ module Sass
188
188
  @content ||= env.is_a?(ReadOnlyEnvironment) ? env : ReadOnlyEnvironment.new(env, env.options)
189
189
  end
190
190
  end
191
+
192
+ # An environment that can write to in-scope global variables, but doesn't
193
+ # create new variables in the global scope. Useful for top-level control
194
+ # directives.
195
+ class SemiGlobalEnvironment < Environment
196
+ def try_set_var(name, value)
197
+ @vars ||= {}
198
+ if @vars.include?(name)
199
+ @vars[name] = value
200
+ true
201
+ elsif @parent
202
+ @parent.try_set_var(name, value)
203
+ else
204
+ false
205
+ end
206
+ end
207
+ end
191
208
  end
@@ -33,6 +33,7 @@ module Sass::Plugin
33
33
  # @param opts [{Symbol => Object}]
34
34
  # See {file:SASS_REFERENCE.md#sass_options the Sass options documentation}.
35
35
  def initialize(opts = {})
36
+ @watched_files = Set.new
36
37
  options.merge!(opts)
37
38
  end
38
39
 
@@ -238,10 +239,12 @@ module Sass::Plugin
238
239
  # of the directories being updated.
239
240
  def file_list(individual_files = [])
240
241
  files = individual_files.map do |tuple|
241
- if tuple.size < 3
242
+ if engine_options[:sourcemap] == :none
243
+ tuple[0..1]
244
+ elsif tuple.size < 3
242
245
  [tuple[0], tuple[1], Sass::Util.sourcemap_name(tuple[1])]
243
246
  else
244
- tuple
247
+ tuple.dup
245
248
  end
246
249
  end
247
250
 
@@ -292,7 +295,9 @@ module Sass::Plugin
292
295
 
293
296
  directories = watched_paths
294
297
  individual_files.each do |(source, _, _)|
295
- directories << File.dirname(File.expand_path(source))
298
+ source = File.expand_path(source)
299
+ @watched_files << source
300
+ directories << File.dirname(source)
296
301
  end
297
302
  directories = remove_redundant_directories(directories)
298
303
 
@@ -435,6 +440,7 @@ module Sass::Plugin
435
440
  end
436
441
 
437
442
  removed.uniq.each do |f|
443
+ next unless watched_file?(f)
438
444
  run_template_deleted(relative_to_pwd(f))
439
445
  if (files = individual_files.find {|(source, _, _)| File.expand_path(source) == f})
440
446
  recompile_required = true
@@ -522,7 +528,7 @@ module Sass::Plugin
522
528
  end
523
529
 
524
530
  def watched_file?(file)
525
- normalized_load_paths.find {|lp| lp.watched_file?(file)}
531
+ @watched_files.include?(file) || normalized_load_paths.any? {|lp| lp.watched_file?(file)}
526
532
  end
527
533
 
528
534
  def watched_paths
@@ -809,7 +809,7 @@ module Sass
809
809
  tok(%r{
810
810
  (
811
811
  (?!url\()
812
- [^"/\#!;\{\}] # "
812
+ [^"'/\#!;\{\}] # "
813
813
  |
814
814
  /(?![/*])
815
815
  |
@@ -51,40 +51,50 @@ module Sass
51
51
  # Returns a copy of this with \{#selector} set to \{#new\_selector}.
52
52
  #
53
53
  # @param new_selector [CommaSequence]
54
- # @return [CommaSequence]
54
+ # @return [Array<Simple>]
55
55
  def with_selector(new_selector)
56
- Pseudo.new(syntactic_type, name, arg, CommaSequence.new(new_selector.members.map do |seq|
57
- next seq unless seq.members.length == 1
58
- sseq = seq.members.first
59
- next seq unless sseq.is_a?(SimpleSequence) && sseq.members.length == 1
60
- sel = sseq.members.first
61
- next seq unless sel.is_a?(Pseudo) && sel.selector
56
+ result = Pseudo.new(syntactic_type, name, arg,
57
+ CommaSequence.new(new_selector.members.map do |seq|
58
+ next seq unless seq.members.length == 1
59
+ sseq = seq.members.first
60
+ next seq unless sseq.is_a?(SimpleSequence) && sseq.members.length == 1
61
+ sel = sseq.members.first
62
+ next seq unless sel.is_a?(Pseudo) && sel.selector
62
63
 
63
- case normalized_name
64
- when 'not'
65
- # In theory, if there's a nested :not its contents should be
66
- # unified with the return value. For example, if :not(.foo)
67
- # extends .bar, :not(.bar) should become .foo:not(.bar). However,
68
- # this is a narrow edge case and supporting it properly would make
69
- # this code and the code calling it a lot more complicated, so
70
- # it's not supported for now.
71
- next [] unless sel.normalized_name == 'matches'
72
- sel.selector.members
73
- when 'matches', 'any', 'current', 'nth-child', 'nth-last-child'
74
- # As above, we could theoretically support :not within :matches, but
75
- # doing so would require this method and its callers to handle much
76
- # more complex cases that likely aren't worth the pain.
77
- next [] unless sel.name == name && sel.arg == arg
78
- sel.selector.members
79
- when 'has', 'host', 'host-context'
80
- # We can't expand nested selectors here, because each layer adds an
81
- # additional layer of semantics. For example, `:has(:has(img))`
82
- # doesn't match `<div><img></div>` but `:has(img)` does.
83
- sel
84
- else
85
- []
86
- end
87
- end.flatten))
64
+ case normalized_name
65
+ when 'not'
66
+ # In theory, if there's a nested :not its contents should be
67
+ # unified with the return value. For example, if :not(.foo)
68
+ # extends .bar, :not(.bar) should become .foo:not(.bar). However,
69
+ # this is a narrow edge case and supporting it properly would make
70
+ # this code and the code calling it a lot more complicated, so
71
+ # it's not supported for now.
72
+ next [] unless sel.normalized_name == 'matches'
73
+ sel.selector.members
74
+ when 'matches', 'any', 'current', 'nth-child', 'nth-last-child'
75
+ # As above, we could theoretically support :not within :matches, but
76
+ # doing so would require this method and its callers to handle much
77
+ # more complex cases that likely aren't worth the pain.
78
+ next [] unless sel.name == name && sel.arg == arg
79
+ sel.selector.members
80
+ when 'has', 'host', 'host-context'
81
+ # We can't expand nested selectors here, because each layer adds an
82
+ # additional layer of semantics. For example, `:has(:has(img))`
83
+ # doesn't match `<div><img></div>` but `:has(img)` does.
84
+ sel
85
+ else
86
+ []
87
+ end
88
+ end.flatten))
89
+
90
+ # Older browsers support :not but only with a single complex selector.
91
+ # In order to support those browsers, we break up the contents of a :not
92
+ # unless it originally contained a selector list.
93
+ return [result] unless normalized_name == 'not'
94
+ return [result] if selector.members.length > 1
95
+ result.selector.members.map do |seq|
96
+ Pseudo.new(syntactic_type, name, arg, CommaSequence.new([seq]))
97
+ end
88
98
  end
89
99
 
90
100
  # The type of the selector. `:class` if this is a pseudoclass selector,
@@ -161,9 +161,9 @@ module Sass
161
161
  extended.members.reject! {|seq| seq.has_placeholder?}
162
162
  modified_original = true
163
163
  result = sel.with_selector(extended)
164
- seen_with_pseudo_selectors << [result]
164
+ result.each {|new_sel| seen_with_pseudo_selectors << [new_sel]}
165
165
  result
166
- end
166
+ end.flatten
167
167
 
168
168
  groups = Sass::Util.group_by_to_a(extends[members.to_set]) {|ex| ex.extender}
169
169
  groups.map! do |seq, group|
@@ -222,7 +222,11 @@ class Sass::Tree::Visitors::Cssize < Sass::Tree::Visitors::Base
222
222
  # Bubbles a directive up through RuleNodes.
223
223
  def visit_directive(node)
224
224
  return node unless node.has_children
225
- return bubble(node) if parent.is_a?(Sass::Tree::RuleNode)
225
+ if parent.is_a?(Sass::Tree::RuleNode)
226
+ # @keyframes shouldn't include the rule nodes, so we manually create a
227
+ # bubble that doesn't have the parent's contents for them.
228
+ return node.normalized_name == '@keyframes' ? Bubble.new(node) : bubble(node)
229
+ end
226
230
 
227
231
  yield
228
232
 
@@ -222,7 +222,7 @@ class Sass::Tree::Visitors::Perform < Sass::Tree::Visitors::Base
222
222
  def visit_each(node)
223
223
  list = node.list.perform(@environment)
224
224
 
225
- with_environment Sass::Environment.new(@environment) do
225
+ with_environment Sass::SemiGlobalEnvironment.new(@environment) do
226
226
  list.to_a.map do |value|
227
227
  if node.vars.length == 1
228
228
  @environment.set_local_var(node.vars.first, value)
@@ -256,7 +256,7 @@ class Sass::Tree::Visitors::Perform < Sass::Tree::Visitors::Base
256
256
  direction = from.to_i > to.to_i ? -1 : 1
257
257
  range = Range.new(direction * from.to_i, direction * to.to_i, node.exclusive)
258
258
 
259
- with_environment Sass::Environment.new(@environment) do
259
+ with_environment Sass::SemiGlobalEnvironment.new(@environment) do
260
260
  range.map do |i|
261
261
  @environment.set_local_var(node.var,
262
262
  Sass::Script::Value::Number.new(direction * i,
@@ -279,8 +279,9 @@ class Sass::Tree::Visitors::Perform < Sass::Tree::Visitors::Base
279
279
  # otherwise, tries the else nodes.
280
280
  def visit_if(node)
281
281
  if node.expr.nil? || node.expr.perform(@environment).to_bool
282
- yield
283
- node.children
282
+ with_environment Sass::SemiGlobalEnvironment.new(@environment) do
283
+ node.children.map {|c| visit(c)}
284
+ end.flatten
284
285
  elsif node.else
285
286
  visit(node.else)
286
287
  else
@@ -397,6 +398,7 @@ class Sass::Tree::Visitors::Perform < Sass::Tree::Visitors::Base
397
398
  keyframe_rule_node.line = node.line
398
399
  keyframe_rule_node.filename = node.filename
399
400
  keyframe_rule_node.source_range = node.source_range
401
+ keyframe_rule_node.has_children = node.has_children
400
402
  with_environment Sass::Environment.new(@environment, node.options) do
401
403
  keyframe_rule_node.children = node.children.map {|c| visit(c)}.flatten
402
404
  end
@@ -470,7 +472,7 @@ class Sass::Tree::Visitors::Perform < Sass::Tree::Visitors::Base
470
472
  # Runs the child nodes until the continuation expression becomes false.
471
473
  def visit_while(node)
472
474
  children = []
473
- with_environment Sass::Environment.new(@environment) do
475
+ with_environment Sass::SemiGlobalEnvironment.new(@environment) do
474
476
  children += node.children.map {|c| visit(c)} while node.expr.perform(@environment).to_bool
475
477
  end
476
478
  children.flatten
@@ -333,8 +333,8 @@ SCSS
333
333
  end
334
334
 
335
335
  def test_extend_into_not
336
- assert_extends(':not(.foo)', '.x {@extend .foo}', ':not(.foo, .x)')
337
- assert_extends(':not(.foo.bar)', '.x {@extend .bar}', ':not(.foo.bar, .foo.x)')
336
+ assert_extends(':not(.foo)', '.x {@extend .foo}', ':not(.foo):not(.x)')
337
+ assert_extends(':not(.foo.bar)', '.x {@extend .bar}', ':not(.foo.bar):not(.foo.x)')
338
338
  assert_extends(
339
339
  ':not(.foo.bar, .baz.bar)',
340
340
  '.x {@extend .bar}',
@@ -362,7 +362,7 @@ SCSS
362
362
  end
363
363
 
364
364
  def test_complex_extend_into_pseudoclass
365
- assert_extends(':not(.bar)', '.x .y {@extend .bar}', ':not(.bar, .x .y)')
365
+ assert_extends(':not(.bar)', '.x .y {@extend .bar}', ':not(.bar):not(.x .y)')
366
366
  assert_extends(':matches(.bar)', '.x .y {@extend .bar}', ':matches(.bar, .x .y)')
367
367
  assert_extends(':current(.bar)', '.x .y {@extend .bar}', ':current(.bar, .x .y)')
368
368
  assert_extends(':has(.bar)', '.x .y {@extend .bar}', ':has(.bar, .x .y)')
@@ -458,7 +458,7 @@ SCSS
458
458
 
459
459
  def test_extend_into_not_and_normal_extend
460
460
  assert_equal <<CSS, render(<<SCSS)
461
- .x:not(.y, .bar), .foo:not(.y, .bar) {
461
+ .x:not(.y):not(.bar), .foo:not(.y):not(.bar) {
462
462
  a: b; }
463
463
  CSS
464
464
  .x:not(.y) {a: b}
@@ -781,6 +781,112 @@ CSS
781
781
  SCSS
782
782
  end
783
783
 
784
+ def test_if_can_assign_to_global_variables
785
+ assert_equal <<CSS, render(<<SCSS, :syntax => :scss)
786
+ .a {
787
+ b: 2; }
788
+ CSS
789
+ $var: 1;
790
+ @if true {$var: 2}
791
+ .a {b: $var}
792
+ SCSS
793
+ end
794
+
795
+ def test_else_can_assign_to_global_variables
796
+ assert_equal <<CSS, render(<<SCSS, :syntax => :scss)
797
+ .a {
798
+ b: 2; }
799
+ CSS
800
+ $var: 1;
801
+ @if false {}
802
+ @else {$var: 2}
803
+ .a {b: $var}
804
+ SCSS
805
+ end
806
+
807
+ def test_for_can_assign_to_global_variables
808
+ assert_equal <<CSS, render(<<SCSS, :syntax => :scss)
809
+ .a {
810
+ b: 2; }
811
+ CSS
812
+ $var: 1;
813
+ @for $i from 1 to 2 {$var: 2}
814
+ .a {b: $var}
815
+ SCSS
816
+ end
817
+
818
+ def test_each_can_assign_to_global_variables
819
+ assert_equal <<CSS, render(<<SCSS, :syntax => :scss)
820
+ .a {
821
+ b: 2; }
822
+ CSS
823
+ $var: 1;
824
+ @each $a in 1 {$var: 2}
825
+ .a {b: $var}
826
+ SCSS
827
+ end
828
+
829
+ def test_while_can_assign_to_global_variables
830
+ assert_equal <<CSS, render(<<SCSS, :syntax => :scss)
831
+ .a {
832
+ b: 2; }
833
+ CSS
834
+ $var: 1;
835
+ @while $var != 2 {$var: 2}
836
+ .a {b: $var}
837
+ SCSS
838
+ end
839
+
840
+ def test_if_doesnt_leak_local_variables
841
+ assert_raise_message(Sass::SyntaxError, 'Undefined variable: "$var".') do
842
+ render(<<SCSS, :syntax => :scss)
843
+ @if true {$var: 1}
844
+ .a {b: $var}
845
+ SCSS
846
+ end
847
+ end
848
+
849
+ def test_else_doesnt_leak_local_variables
850
+ assert_raise_message(Sass::SyntaxError, 'Undefined variable: "$var".') do
851
+ render(<<SCSS, :syntax => :scss)
852
+ @if false {}
853
+ @else {$var: 1}
854
+ .a {b: $var}
855
+ SCSS
856
+ end
857
+ end
858
+
859
+ def test_for_doesnt_leak_local_variables
860
+ assert_raise_message(Sass::SyntaxError, 'Undefined variable: "$var".') do
861
+ render(<<SCSS, :syntax => :scss)
862
+ @for $i from 1 to 2 {$var: 1}
863
+ .a {b: $var}
864
+ SCSS
865
+ end
866
+ end
867
+
868
+ def test_each_doesnt_leak_local_variables
869
+ assert_raise_message(Sass::SyntaxError, 'Undefined variable: "$var".') do
870
+ render(<<SCSS, :syntax => :scss)
871
+ @each $a in 1 {$var: 1}
872
+ .a {b: $var}
873
+ SCSS
874
+ end
875
+ end
876
+
877
+ def test_while_doesnt_leak_local_variables
878
+ assert_raise_message(Sass::SyntaxError, 'Undefined variable: "$var".') do
879
+ render(<<SCSS, :syntax => :scss)
880
+ $iter: true;
881
+ @while $iter {
882
+ $var: 1;
883
+ $iter: false;
884
+ }
885
+ .a {b: $var}
886
+ SCSS
887
+ end
888
+ end
889
+
784
890
  def test_color_format_is_preserved_by_default
785
891
  assert_equal "blue", resolve("blue")
786
892
  assert_equal "bLuE", resolve("bLuE")
@@ -690,6 +690,20 @@ CSS
690
690
  SCSS
691
691
  end
692
692
 
693
+ def test_keyframes_with_empty_rules
694
+ assert_equal <<CSS, render(<<SCSS)
695
+ @keyframes identifier {
696
+ 50% {
697
+ background-color: black; } }
698
+ CSS
699
+ @keyframes identifier {
700
+ 0% {}
701
+ 50% {background-color: black}
702
+ 100% {}
703
+ }
704
+ SCSS
705
+ end
706
+
693
707
  ## Selectors
694
708
 
695
709
  # Taken from http://dev.w3.org/csswg/selectors4/#overview
@@ -715,6 +715,26 @@ CSS
715
715
  SCSS
716
716
  end
717
717
 
718
+ def test_keyframe_bubbling
719
+ assert_equal(<<CSS, render(<<SCSS, :style => :nested))
720
+ @keyframes spin {
721
+ 0% {
722
+ transform: rotate(0deg); } }
723
+ @-webkit-keyframes spin {
724
+ 0% {
725
+ transform: rotate(0deg); } }
726
+ CSS
727
+ .foo {
728
+ @keyframes spin {
729
+ 0% {transform: rotate(0deg)}
730
+ }
731
+ @-webkit-keyframes spin {
732
+ 0% {transform: rotate(0deg)}
733
+ }
734
+ }
735
+ SCSS
736
+ end
737
+
718
738
  ## Namespace Properties
719
739
 
720
740
  def test_namespace_properties
@@ -3528,6 +3548,19 @@ SCSS
3528
3548
 
3529
3549
  # Regression
3530
3550
 
3551
+ def test_attribute_selector_in_selector_pseudoclass
3552
+ # Even though this is plain CSS, it only failed when given to the SCSS
3553
+ # parser.
3554
+ assert_equal(<<CSS, render(<<SCSS))
3555
+ [href^='http://'] {
3556
+ color: red; }
3557
+ CSS
3558
+ [href^='http://'] {
3559
+ color: red;
3560
+ }
3561
+ SCSS
3562
+ end
3563
+
3531
3564
  def test_top_level_unknown_directive_in_at_root
3532
3565
  assert_equal(<<CSS, render(<<SCSS))
3533
3566
  @fblthp {
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sass
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.4.0
4
+ version: 3.4.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Natalie Weizenbaum
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2014-08-19 00:00:00.000000000 Z
13
+ date: 2014-08-23 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: yard