sass 3.4.0 → 3.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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