sass 3.3.14 → 3.4.0.rc.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.
Files changed (110) hide show
  1. checksums.yaml +4 -4
  2. data/MIT-LICENSE +1 -1
  3. data/README.md +5 -5
  4. data/VERSION +1 -1
  5. data/VERSION_DATE +1 -1
  6. data/VERSION_NAME +1 -1
  7. data/bin/sass +1 -1
  8. data/bin/scss +1 -1
  9. data/lib/sass.rb +0 -5
  10. data/lib/sass/css.rb +1 -3
  11. data/lib/sass/engine.rb +28 -39
  12. data/lib/sass/environment.rb +13 -17
  13. data/lib/sass/error.rb +6 -9
  14. data/lib/sass/exec.rb +5 -771
  15. data/lib/sass/exec/base.rb +187 -0
  16. data/lib/sass/exec/sass_convert.rb +264 -0
  17. data/lib/sass/exec/sass_scss.rb +419 -0
  18. data/lib/sass/features.rb +6 -0
  19. data/lib/sass/importers.rb +0 -1
  20. data/lib/sass/importers/base.rb +5 -1
  21. data/lib/sass/importers/filesystem.rb +4 -21
  22. data/lib/sass/media.rb +1 -4
  23. data/lib/sass/plugin/compiler.rb +32 -136
  24. data/lib/sass/script/css_lexer.rb +1 -1
  25. data/lib/sass/script/functions.rb +363 -39
  26. data/lib/sass/script/lexer.rb +68 -50
  27. data/lib/sass/script/parser.rb +29 -14
  28. data/lib/sass/script/tree.rb +1 -0
  29. data/lib/sass/script/tree/funcall.rb +1 -1
  30. data/lib/sass/script/tree/interpolation.rb +19 -1
  31. data/lib/sass/script/tree/selector.rb +26 -0
  32. data/lib/sass/script/value.rb +0 -1
  33. data/lib/sass/script/value/bool.rb +0 -5
  34. data/lib/sass/script/value/color.rb +32 -12
  35. data/lib/sass/script/value/helpers.rb +107 -0
  36. data/lib/sass/script/value/list.rb +0 -15
  37. data/lib/sass/script/value/null.rb +0 -5
  38. data/lib/sass/script/value/number.rb +60 -14
  39. data/lib/sass/script/value/string.rb +53 -9
  40. data/lib/sass/scss/css_parser.rb +8 -2
  41. data/lib/sass/scss/parser.rb +175 -319
  42. data/lib/sass/scss/rx.rb +14 -5
  43. data/lib/sass/scss/static_parser.rb +298 -1
  44. data/lib/sass/selector.rb +56 -193
  45. data/lib/sass/selector/abstract_sequence.rb +28 -13
  46. data/lib/sass/selector/comma_sequence.rb +91 -12
  47. data/lib/sass/selector/pseudo.rb +256 -0
  48. data/lib/sass/selector/sequence.rb +99 -31
  49. data/lib/sass/selector/simple.rb +14 -25
  50. data/lib/sass/selector/simple_sequence.rb +101 -37
  51. data/lib/sass/shared.rb +1 -1
  52. data/lib/sass/source/map.rb +23 -9
  53. data/lib/sass/stack.rb +0 -6
  54. data/lib/sass/supports.rb +1 -1
  55. data/lib/sass/tree/at_root_node.rb +1 -0
  56. data/lib/sass/tree/directive_node.rb +7 -1
  57. data/lib/sass/tree/error_node.rb +18 -0
  58. data/lib/sass/tree/keyframe_rule_node.rb +15 -0
  59. data/lib/sass/tree/prop_node.rb +1 -1
  60. data/lib/sass/tree/rule_node.rb +11 -6
  61. data/lib/sass/tree/visitors/check_nesting.rb +3 -4
  62. data/lib/sass/tree/visitors/convert.rb +8 -17
  63. data/lib/sass/tree/visitors/cssize.rb +12 -24
  64. data/lib/sass/tree/visitors/deep_copy.rb +5 -0
  65. data/lib/sass/tree/visitors/perform.rb +43 -28
  66. data/lib/sass/tree/visitors/set_options.rb +5 -0
  67. data/lib/sass/tree/visitors/to_css.rb +14 -13
  68. data/lib/sass/util.rb +94 -90
  69. data/test/sass/cache_test.rb +1 -1
  70. data/test/sass/callbacks_test.rb +1 -1
  71. data/test/sass/compiler_test.rb +5 -14
  72. data/test/sass/conversion_test.rb +47 -1
  73. data/test/sass/css2sass_test.rb +3 -3
  74. data/test/sass/encoding_test.rb +219 -0
  75. data/test/sass/engine_test.rb +128 -191
  76. data/test/sass/exec_test.rb +2 -2
  77. data/test/sass/extend_test.rb +234 -17
  78. data/test/sass/functions_test.rb +268 -213
  79. data/test/sass/importer_test.rb +31 -21
  80. data/test/sass/logger_test.rb +1 -1
  81. data/test/sass/more_results/more_import.css +1 -1
  82. data/test/sass/plugin_test.rb +12 -11
  83. data/test/sass/results/compact.css +1 -1
  84. data/test/sass/results/complex.css +4 -4
  85. data/test/sass/results/expanded.css +1 -1
  86. data/test/sass/results/import.css +1 -1
  87. data/test/sass/results/import_charset_ibm866.css +2 -2
  88. data/test/sass/results/mixins.css +17 -17
  89. data/test/sass/results/nested.css +1 -1
  90. data/test/sass/results/parent_ref.css +2 -2
  91. data/test/sass/results/script.css +3 -3
  92. data/test/sass/results/scss_import.css +1 -1
  93. data/test/sass/script_conversion_test.rb +7 -4
  94. data/test/sass/script_test.rb +202 -79
  95. data/test/sass/scss/css_test.rb +95 -25
  96. data/test/sass/scss/rx_test.rb +4 -4
  97. data/test/sass/scss/scss_test.rb +363 -19
  98. data/test/sass/source_map_test.rb +48 -41
  99. data/test/sass/superselector_test.rb +191 -0
  100. data/test/sass/templates/scss_import.scss +2 -1
  101. data/test/sass/test_helper.rb +1 -1
  102. data/test/sass/util/multibyte_string_scanner_test.rb +1 -1
  103. data/test/sass/util/normalized_map_test.rb +1 -1
  104. data/test/sass/util/subset_map_test.rb +2 -2
  105. data/test/sass/util_test.rb +1 -1
  106. data/test/sass/value_helpers_test.rb +3 -3
  107. data/test/test_helper.rb +2 -2
  108. metadata +30 -7
  109. data/lib/sass/importers/deprecated_path.rb +0 -51
  110. data/lib/sass/script/value/deprecated_false.rb +0 -55
@@ -6,7 +6,7 @@ require 'sass/scss/css_parser'
6
6
  # These tests just test the parsing of CSS
7
7
  # (both standard and any hacks we intend to support).
8
8
  # Tests of SCSS-specific behavior go in scss_test.rb.
9
- class ScssCssTest < Test::Unit::TestCase
9
+ class ScssCssTest < MiniTest::Test
10
10
  include ScssTestHelper
11
11
 
12
12
  def test_basic_scss
@@ -499,10 +499,24 @@ SCSS
499
499
 
500
500
  def test_import_directive
501
501
  assert_parses '@import "foo.css";'
502
- assert_parses "@import 'foo.css';"
503
502
  assert_parses '@import url("foo.css");'
504
503
  assert_parses "@import url('foo.css');"
505
504
  assert_parses '@import url(foo.css);'
505
+
506
+ assert_equal <<CSS, render(<<SCSS)
507
+ @import "foo.css";
508
+ CSS
509
+ @import 'foo.css';
510
+ SCSS
511
+ end
512
+
513
+ def test_import_directive_with_backslash_newline
514
+ assert_equal <<CSS, render(<<SCSS)
515
+ @import "foobar.css";
516
+ CSS
517
+ @import "foo\\
518
+ bar.css";
519
+ SCSS
506
520
  end
507
521
 
508
522
  def test_string_import_directive_with_media
@@ -659,13 +673,10 @@ SCSS
659
673
  0% {
660
674
  top: 0;
661
675
  left: 0; }
662
-
663
676
  30% {
664
677
  top: 50px; }
665
-
666
678
  68%, 72% {
667
679
  left: 50px; }
668
-
669
680
  100% {
670
681
  top: 100px;
671
682
  left: 100%; } }
@@ -688,6 +699,8 @@ SCSS
688
699
  assert_selector_parses('E:not(s)')
689
700
  assert_selector_parses('E:not(s1, s2)')
690
701
  assert_selector_parses('E:matches(s1, s2)')
702
+ assert_selector_parses('E:has(s1, s2)')
703
+ assert_selector_parses('E:has(> s1, > s2)')
691
704
  assert_selector_parses('E.warning')
692
705
  assert_selector_parses('E#myid')
693
706
  assert_selector_parses('E[foo]')
@@ -738,20 +751,22 @@ SCSS
738
751
  assert_selector_parses('E:last-of-type')
739
752
  assert_selector_parses('E:nth-last-of-type(n)')
740
753
  assert_selector_parses('E:only-of-type')
741
- assert_selector_parses('E:nth-match(n of selector)')
742
- assert_selector_parses('E:nth-last-match(n of selector)')
743
- assert_selector_parses('E:column(selector)')
744
- assert_selector_parses('E:nth-column(n)')
745
- assert_selector_parses('E:nth-last-column(n)')
754
+ assert_selector_parses('E:nth-child(n of selector)')
755
+ assert_selector_parses('E:nth-last-child(n of selector)')
756
+ assert_selector_parses('E:nth-child(n)')
757
+ assert_selector_parses('E:nth-last-child(n)')
746
758
  assert_selector_parses('E F')
747
759
  assert_selector_parses('E > F')
748
760
  assert_selector_parses('E + F')
749
761
  assert_selector_parses('E ~ F')
750
762
  assert_selector_parses('E /foo/ F')
751
- assert_selector_parses('E! > F')
763
+ silence_warnings {assert_selector_parses('E! > F')}
752
764
 
753
765
  assert_selector_parses('E /ns|foo/ F')
754
- assert_selector_parses('E /*|foo/ F')
766
+
767
+ # From http://dev.w3.org/csswg/css-scoping-1/
768
+ assert_selector_parses('E:host(s)')
769
+ assert_selector_parses('E:host-context(s)')
755
770
  end
756
771
 
757
772
  # Taken from http://dev.w3.org/csswg/selectors4/#overview, but without element
@@ -760,6 +775,8 @@ SCSS
760
775
  assert_selector_parses(':not(s)')
761
776
  assert_selector_parses(':not(s1, s2)')
762
777
  assert_selector_parses(':matches(s1, s2)')
778
+ assert_selector_parses(':has(s1, s2)')
779
+ assert_selector_parses(':has(> s1, > s2)')
763
780
  assert_selector_parses('.warning')
764
781
  assert_selector_parses('#myid')
765
782
  assert_selector_parses('[foo]')
@@ -810,11 +827,14 @@ SCSS
810
827
  assert_selector_parses(':last-of-type')
811
828
  assert_selector_parses(':nth-last-of-type(n)')
812
829
  assert_selector_parses(':only-of-type')
813
- assert_selector_parses(':nth-match(n of selector)')
814
- assert_selector_parses(':nth-last-match(n of selector)')
815
- assert_selector_parses(':column(selector)')
816
- assert_selector_parses(':nth-column(n)')
817
- assert_selector_parses(':nth-last-column(n)')
830
+ assert_selector_parses(':nth-child(n of selector)')
831
+ assert_selector_parses(':nth-last-child(n of selector)')
832
+ assert_selector_parses(':nth-child(n)')
833
+ assert_selector_parses(':nth-last-child(n)')
834
+
835
+ # From http://dev.w3.org/csswg/css-scoping-1/
836
+ assert_selector_parses(':host(s)')
837
+ assert_selector_parses(':host-context(s)')
818
838
  end
819
839
 
820
840
  def test_attribute_selectors_with_identifiers
@@ -854,10 +874,13 @@ SCSS
854
874
  def test_selectors_containing_selectors
855
875
  assert_selector_can_contain_selectors(':not(<sel>)')
856
876
  assert_selector_can_contain_selectors(':current(<sel>)')
857
- assert_selector_can_contain_selectors(':nth-match(n of <sel>)')
858
- assert_selector_can_contain_selectors(':nth-last-match(n of <sel>)')
859
- assert_selector_can_contain_selectors(':column(<sel>)')
877
+ assert_selector_can_contain_selectors(':nth-child(n of <sel>)')
878
+ assert_selector_can_contain_selectors(':nth-last-child(n of <sel>)')
860
879
  assert_selector_can_contain_selectors(':-moz-any(<sel>)')
880
+ assert_selector_can_contain_selectors(':has(<sel>)')
881
+ assert_selector_can_contain_selectors(':has(+ <sel>)')
882
+ assert_selector_can_contain_selectors(':host(<sel>)')
883
+ assert_selector_can_contain_selectors(':host-context(<sel>)')
861
884
  end
862
885
 
863
886
  def assert_selector_can_contain_selectors(sel)
@@ -914,11 +937,11 @@ SCSS
914
937
  end
915
938
 
916
939
  def test_expression_fallback_selectors
917
- assert_selector_parses('0%')
918
- assert_selector_parses('60%')
919
- assert_selector_parses('100%')
920
- assert_selector_parses('12px')
921
- assert_selector_parses('"foo"')
940
+ assert_directive_parses('0%')
941
+ assert_directive_parses('60%')
942
+ assert_directive_parses('100%')
943
+ assert_directive_parses('12px')
944
+ assert_directive_parses('"foo"')
922
945
  end
923
946
 
924
947
  def test_functional_pseudo_selectors
@@ -955,6 +978,29 @@ SCSS
955
978
  assert_equal "E + F {\n a: b; }\n", render("E+F { a: b;} ")
956
979
  end
957
980
 
981
+ def test_subject_selector_deprecation
982
+ assert_warning(<<WARNING) {render(".foo .bar! .baz {a: b}")}
983
+ DEPRECATION WARNING on line 1, column 1:
984
+ The subject selector operator "!" is deprecated and will be removed in a future release.
985
+ This operator has been replaced by ":has()" in the CSS spec.
986
+ For example: .foo .bar:has(.baz)
987
+ WARNING
988
+
989
+ assert_warning(<<WARNING) {render(".foo .bar! > .baz {a: b}")}
990
+ DEPRECATION WARNING on line 1, column 1:
991
+ The subject selector operator "!" is deprecated and will be removed in a future release.
992
+ This operator has been replaced by ":has()" in the CSS spec.
993
+ For example: .foo .bar:has(> .baz)
994
+ WARNING
995
+
996
+ assert_warning(<<WARNING) {render(".foo .bar! {a: b}")}
997
+ DEPRECATION WARNING on line 1, column 1:
998
+ The subject selector operator "!" is deprecated and will be removed in a future release.
999
+ This operator has been replaced by ":has()" in the CSS spec.
1000
+ For example: .foo .bar
1001
+ WARNING
1002
+ end
1003
+
958
1004
  ## Errors
959
1005
 
960
1006
  def test_invalid_directives
@@ -1040,6 +1086,18 @@ SCSS
1040
1086
  assert_equal 1, e.sass_line
1041
1087
  end
1042
1088
 
1089
+ def test_newline_in_property_value
1090
+ assert_equal(<<CSS, render(<<SCSS))
1091
+ .foo {
1092
+ bar: "bazbang"; }
1093
+ CSS
1094
+ .foo {
1095
+ bar: "baz\\
1096
+ bang";
1097
+ }
1098
+ SCSS
1099
+ end
1100
+
1043
1101
  ## Regressions
1044
1102
 
1045
1103
  def test_very_long_comment_doesnt_take_forever
@@ -1135,6 +1193,18 @@ SCSS
1135
1193
  #{selector} {
1136
1194
  a: b; }
1137
1195
  SCSS
1196
+
1197
+ assert_parses <<SCSS
1198
+ :not(#{selector}) {
1199
+ a: b; }
1200
+ SCSS
1201
+ end
1202
+
1203
+ def assert_directive_parses(param)
1204
+ assert_parses <<SCSS
1205
+ @keyframes #{param} {
1206
+ a: b; }
1207
+ SCSS
1138
1208
  end
1139
1209
 
1140
1210
  def render(scss, options = {})
@@ -3,7 +3,7 @@
3
3
  require File.dirname(__FILE__) + '/../../test_helper'
4
4
  require 'sass/engine'
5
5
 
6
- class ScssRxTest < Test::Unit::TestCase
6
+ class ScssRxTest < MiniTest::Test
7
7
  include Sass::SCSS::RX
8
8
 
9
9
  def test_identifiers
@@ -26,6 +26,7 @@ class ScssRxTest < Test::Unit::TestCase
26
26
  assert_match IDENT, "_foo" # Can put a _ before anything
27
27
  assert_match IDENT, "_\xC3\xBFoo"
28
28
  assert_match IDENT, "_\\f oo"
29
+ assert_match IDENT, "--foo" # "Custom" identifier
29
30
 
30
31
  assert_match IDENT, "foo-bar"
31
32
  assert_match IDENT, "f012-23"
@@ -59,7 +60,6 @@ class ScssRxTest < Test::Unit::TestCase
59
60
  assert_no_match IDENT, ""
60
61
  assert_no_match IDENT, "1foo"
61
62
  assert_no_match IDENT, "-1foo"
62
- assert_no_match IDENT, "--foo"
63
63
  assert_no_match IDENT, "foo bar"
64
64
  assert_no_match IDENT, "foo~bar"
65
65
 
@@ -144,13 +144,13 @@ class ScssRxTest < Test::Unit::TestCase
144
144
  private
145
145
 
146
146
  def assert_match(rx, str)
147
- assert_not_nil(match = rx.match(str))
147
+ refute_nil(match = rx.match(str))
148
148
  assert_equal str.size, match[0].size
149
149
  end
150
150
 
151
151
  def assert_no_match(rx, str)
152
152
  match = rx.match(str)
153
- assert_not_equal str.size, match && match[0].size
153
+ refute_equal str.size, match && match[0].size
154
154
  end
155
155
 
156
156
  end
@@ -2,7 +2,7 @@
2
2
  # -*- coding: utf-8 -*-
3
3
  require File.dirname(__FILE__) + '/test_helper'
4
4
 
5
- class ScssTest < Test::Unit::TestCase
5
+ class ScssTest < MiniTest::Test
6
6
  include ScssTestHelper
7
7
 
8
8
  ## One-Line Comments
@@ -115,6 +115,14 @@ SCSS
115
115
  end
116
116
  end
117
117
 
118
+ def test_error_directive
119
+ assert_raise_message(Sass::SyntaxError, "hello world!") {render(<<SCSS)}
120
+ foo {a: b}
121
+ @error "hello world!";
122
+ bar {c: d}
123
+ SCSS
124
+ end
125
+
118
126
  def test_warn_directive
119
127
  expected_warning = <<EXPECTATION
120
128
  WARNING: this is a warning
@@ -536,11 +544,17 @@ foo :baz {
536
544
  c: d; }
537
545
  foo bang:bop {
538
546
  e: f; }
547
+ foo ::qux {
548
+ g: h; }
549
+ foo zap::fblthp {
550
+ i: j; }
539
551
  CSS
540
552
  foo {
541
553
  .bar {a: b}
542
554
  :baz {c: d}
543
- bang:bop {e: f}}
555
+ bang:bop {e: f}
556
+ ::qux {g: h}
557
+ zap::fblthp {i: j}}
544
558
  SCSS
545
559
  end
546
560
 
@@ -645,7 +659,7 @@ SCSS
645
659
  end
646
660
 
647
661
  def test_parent_selector_with_subject
648
- assert_equal <<CSS, render(<<SCSS)
662
+ silence_warnings {assert_equal <<CSS, render(<<SCSS)}
649
663
  bar foo.baz! .bip {
650
664
  a: b; }
651
665
 
@@ -799,18 +813,27 @@ SCSS
799
813
  def test_no_namespace_properties_without_space_even_when_its_unambiguous
800
814
  render(<<SCSS)
801
815
  foo {
802
- bar:1px {
816
+ bar:baz calc(1 + 2) {
803
817
  bip: bop }}
804
818
  SCSS
805
819
  assert(false, "Expected syntax error")
806
820
  rescue Sass::SyntaxError => e
807
- assert_equal <<MESSAGE, e.message
808
- Invalid CSS: a space is required between a property and its definition
809
- when it has other properties nested beneath it.
810
- MESSAGE
821
+ assert_equal 'Invalid CSS after "bar:baz calc": expected selector, was "(1 + 2)"', e.message
811
822
  assert_equal 2, e.sass_line
812
823
  end
813
824
 
825
+ def test_namespace_properties_without_space_allowed_for_non_identifier
826
+ assert_equal <<CSS, render(<<SCSS)
827
+ foo {
828
+ bar: 1px;
829
+ bar-bip: bop; }
830
+ CSS
831
+ foo {
832
+ bar:1px {
833
+ bip: bop }}
834
+ SCSS
835
+ end
836
+
814
837
  ## Mixins
815
838
 
816
839
  def test_basic_mixins
@@ -909,13 +932,10 @@ SCSS
909
932
  0% {
910
933
  top: 0;
911
934
  left: 0; }
912
-
913
935
  30% {
914
936
  top: 50px; }
915
-
916
937
  68%, 72% {
917
938
  left: 50px; }
918
-
919
939
  100% {
920
940
  top: 100px;
921
941
  left: 100%; } }
@@ -926,7 +946,7 @@ CSS
926
946
 
927
947
  @include keyframes {
928
948
  0% {top: 0; left: 0}
929
- 30% {top: 50px}
949
+ \#{"30%"} {top: 50px}
930
950
  68%, 72% {left: 50px}
931
951
  100% {top: 100px; left: 100%}
932
952
  }
@@ -1914,10 +1934,10 @@ SCSS
1914
1934
 
1915
1935
  def test_basic_selector_interpolation
1916
1936
  assert_equal <<CSS, render(<<SCSS)
1917
- foo 3 baz {
1937
+ foo ab baz {
1918
1938
  a: b; }
1919
1939
  CSS
1920
- foo \#{1 + 2} baz {a: b}
1940
+ foo \#{'a' + 'b'} baz {a: b}
1921
1941
  SCSS
1922
1942
  assert_equal <<CSS, render(<<SCSS)
1923
1943
  foo.bar baz {
@@ -2043,7 +2063,7 @@ SCSS
2043
2063
  end
2044
2064
 
2045
2065
  def test_parent_selector_with_parent_and_subject
2046
- assert_equal <<CSS, render(<<SCSS)
2066
+ silence_warnings {assert_equal <<CSS, render(<<SCSS)}
2047
2067
  bar foo.baz! .bip {
2048
2068
  c: d; }
2049
2069
  CSS
@@ -2216,6 +2236,69 @@ $domain: "sass-lang.com";
2216
2236
  SCSS
2217
2237
  end
2218
2238
 
2239
+ def test_color_interpolation_warning_in_selector
2240
+ assert_warning(<<WARNING) {assert_equal <<CSS, render(<<SCSS)}
2241
+ WARNING on line 1, column 4 of #{filename_for_test(:scss)}:
2242
+ You probably don't mean to use the color value `blue' in interpolation here.
2243
+ It may end up represented as #0000ff, which will likely produce invalid CSS.
2244
+ Always quote color names when using them as strings (for example, "blue").
2245
+ If you really want to use the color value here, use `"" + blue'.
2246
+ WARNING
2247
+ fooblue {
2248
+ a: b; }
2249
+ CSS
2250
+ foo\#{blue} {a: b}
2251
+ SCSS
2252
+ end
2253
+
2254
+ def test_color_interpolation_warning_in_directive
2255
+ assert_warning(<<WARNING) {assert_equal <<CSS, render(<<SCSS)}
2256
+ WARNING on line 1, column 12 of #{filename_for_test(:scss)}:
2257
+ You probably don't mean to use the color value `blue' in interpolation here.
2258
+ It may end up represented as #0000ff, which will likely produce invalid CSS.
2259
+ Always quote color names when using them as strings (for example, "blue").
2260
+ If you really want to use the color value here, use `"" + blue'.
2261
+ WARNING
2262
+ @fblthp fooblue {
2263
+ a: b; }
2264
+ CSS
2265
+ @fblthp foo\#{blue} {a: b}
2266
+ SCSS
2267
+ end
2268
+
2269
+ def test_color_interpolation_warning_in_property_name
2270
+ assert_warning(<<WARNING) {assert_equal <<CSS, render(<<SCSS)}
2271
+ WARNING on line 1, column 8 of #{filename_for_test(:scss)}:
2272
+ You probably don't mean to use the color value `blue' in interpolation here.
2273
+ It may end up represented as #0000ff, which will likely produce invalid CSS.
2274
+ Always quote color names when using them as strings (for example, "blue").
2275
+ If you really want to use the color value here, use `"" + blue'.
2276
+ WARNING
2277
+ foo {
2278
+ a-blue: b; }
2279
+ CSS
2280
+ foo {a-\#{blue}: b}
2281
+ SCSS
2282
+ end
2283
+
2284
+ def test_no_color_interpolation_warning_in_property_value
2285
+ assert_no_warning {assert_equal <<CSS, render(<<SCSS)}
2286
+ foo {
2287
+ a: b-blue; }
2288
+ CSS
2289
+ foo {a: b-\#{blue}}
2290
+ SCSS
2291
+ end
2292
+
2293
+ def test_no_color_interpolation_warning_for_nameless_color
2294
+ assert_no_warning {assert_equal <<CSS, render(<<SCSS)}
2295
+ foo-#abcdef {
2296
+ a: b; }
2297
+ CSS
2298
+ foo-\#{#abcdef} {a: b}
2299
+ SCSS
2300
+ end
2301
+
2219
2302
  def test_nested_mixin_def
2220
2303
  assert_equal <<CSS, render(<<SCSS)
2221
2304
  foo {
@@ -2878,6 +2961,214 @@ CSS
2878
2961
  SCSS
2879
2962
  end
2880
2963
 
2964
+ def test_at_root_without_keyframes_in_keyframe_rule
2965
+ assert_equal <<CSS, render(<<SCSS)
2966
+ .foo {
2967
+ a: b; }
2968
+ CSS
2969
+ @keyframes identifier {
2970
+ 0% {
2971
+ @at-root (without: keyframes) {
2972
+ .foo {a: b}
2973
+ }
2974
+ }
2975
+ }
2976
+ SCSS
2977
+ end
2978
+
2979
+ def test_at_root_without_rule_in_keyframe_rule
2980
+ assert_equal <<CSS, render(<<SCSS)
2981
+ @keyframes identifier {
2982
+ 0% {
2983
+ a: b; } }
2984
+ CSS
2985
+ @keyframes identifier {
2986
+ 0% {
2987
+ @at-root (without: rule) {a: b}
2988
+ }
2989
+ }
2990
+ SCSS
2991
+ end
2992
+
2993
+ ## Selector Script
2994
+
2995
+ def test_selector_script
2996
+ assert_equal(<<CSS, render(<<SCSS))
2997
+ .foo .bar {
2998
+ content: ".foo .bar"; }
2999
+ CSS
3000
+ .foo .bar {
3001
+ content: "\#{&}";
3002
+ }
3003
+ SCSS
3004
+ end
3005
+
3006
+ def test_nested_selector_script
3007
+ assert_equal(<<CSS, render(<<SCSS))
3008
+ .foo .bar {
3009
+ content: ".foo .bar"; }
3010
+ CSS
3011
+ .foo {
3012
+ .bar {
3013
+ content: "\#{&}";
3014
+ }
3015
+ }
3016
+ SCSS
3017
+ end
3018
+
3019
+ def test_nested_selector_script_with_outer_comma_selector
3020
+ assert_equal(<<CSS, render(<<SCSS))
3021
+ .foo .baz, .bar .baz {
3022
+ content: ".foo .baz, .bar .baz"; }
3023
+ CSS
3024
+ .foo, .bar {
3025
+ .baz {
3026
+ content: "\#{&}";
3027
+ }
3028
+ }
3029
+ SCSS
3030
+ end
3031
+
3032
+ def test_nested_selector_script_with_inner_comma_selector
3033
+ assert_equal(<<CSS, render(<<SCSS))
3034
+ .foo .bar, .foo .baz {
3035
+ content: ".foo .bar, .foo .baz"; }
3036
+ CSS
3037
+ .foo {
3038
+ .bar, .baz {
3039
+ content: "\#{&}";
3040
+ }
3041
+ }
3042
+ SCSS
3043
+ end
3044
+
3045
+ def test_selector_script_through_mixin
3046
+ assert_equal(<<CSS, render(<<SCSS))
3047
+ .foo {
3048
+ content: ".foo"; }
3049
+ CSS
3050
+ @mixin mixin {
3051
+ content: "\#{&}";
3052
+ }
3053
+
3054
+ .foo {
3055
+ @include mixin;
3056
+ }
3057
+ SCSS
3058
+ end
3059
+
3060
+ def test_selector_script_through_content
3061
+ assert_equal(<<CSS, render(<<SCSS))
3062
+ .foo {
3063
+ content: ".foo"; }
3064
+ CSS
3065
+ @mixin mixin {
3066
+ @content;
3067
+ }
3068
+
3069
+ .foo {
3070
+ @include mixin {
3071
+ content: "\#{&}";
3072
+ }
3073
+ }
3074
+ SCSS
3075
+ end
3076
+
3077
+ def test_selector_script_through_function
3078
+ assert_equal(<<CSS, render(<<SCSS))
3079
+ .foo {
3080
+ content: ".foo"; }
3081
+ CSS
3082
+ @function fn() {
3083
+ @return "\#{&}";
3084
+ }
3085
+
3086
+ .foo {
3087
+ content: fn();
3088
+ }
3089
+ SCSS
3090
+ end
3091
+
3092
+ def test_selector_script_through_media
3093
+ assert_equal(<<CSS, render(<<SCSS))
3094
+ .foo {
3095
+ content: "outer"; }
3096
+ @media screen {
3097
+ .foo .bar {
3098
+ content: ".foo .bar"; } }
3099
+ CSS
3100
+ .foo {
3101
+ content: "outer";
3102
+ @media screen {
3103
+ .bar {
3104
+ content: "\#{&}";
3105
+ }
3106
+ }
3107
+ }
3108
+ SCSS
3109
+ end
3110
+
3111
+ def test_selector_script_save_and_reuse
3112
+ assert_equal(<<CSS, render(<<SCSS))
3113
+ .bar {
3114
+ content: ".foo"; }
3115
+ CSS
3116
+ $var: null;
3117
+ .foo {
3118
+ $var: & !global;
3119
+ }
3120
+
3121
+ .bar {
3122
+ content: "\#{$var}";
3123
+ }
3124
+ SCSS
3125
+ end
3126
+
3127
+ def test_selector_script_with_at_root
3128
+ assert_equal(<<CSS, render(<<SCSS))
3129
+ .foo-bar {
3130
+ a: b; }
3131
+ CSS
3132
+ .foo {
3133
+ @at-root \#{&}-bar {
3134
+ a: b;
3135
+ }
3136
+ }
3137
+ SCSS
3138
+ end
3139
+
3140
+ def test_multi_level_at_root_with_inner_selector_script
3141
+ assert_equal <<CSS, render(<<SCSS)
3142
+ .bar {
3143
+ a: b; }
3144
+ CSS
3145
+ .foo {
3146
+ @at-root .bar {
3147
+ @at-root \#{&} {
3148
+ a: b;
3149
+ }
3150
+ }
3151
+ }
3152
+ SCSS
3153
+ end
3154
+
3155
+ def test_at_root_with_at_root_through_mixin
3156
+ assert_equal(<<CSS, render(<<SCSS))
3157
+ .bar-baz {
3158
+ a: b; }
3159
+ CSS
3160
+ @mixin foo {
3161
+ .bar {
3162
+ @at-root \#{&}-baz {
3163
+ a: b;
3164
+ }
3165
+ }
3166
+ }
3167
+
3168
+ @include foo;
3169
+ SCSS
3170
+ end
3171
+
2881
3172
  # See https://github.com/sass/sass/issues/1294
2882
3173
  def test_extend_top_leveled_by_at_root
2883
3174
  render(<<SCSS)
@@ -2924,6 +3215,29 @@ SCSS
2924
3215
 
2925
3216
  ## Errors
2926
3217
 
3218
+ def test_keyframes_rule_outside_of_keyframes
3219
+ render <<SCSS
3220
+ 0% {
3221
+ top: 0; }
3222
+ SCSS
3223
+ assert(false, "Expected syntax error")
3224
+ rescue Sass::SyntaxError => e
3225
+ assert_equal 'Invalid CSS after "": expected selector, was "0%"', e.message
3226
+ assert_equal 1, e.sass_line
3227
+ end
3228
+
3229
+ def test_selector_rule_in_keyframes
3230
+ render <<SCSS
3231
+ @keyframes identifier {
3232
+ .foo {
3233
+ top: 0; } }
3234
+ SCSS
3235
+ assert(false, "Expected syntax error")
3236
+ rescue Sass::SyntaxError => e
3237
+ assert_equal 'Invalid CSS after "": expected keyframes selector (e.g. 10%), was ".foo"', e.message
3238
+ assert_equal 2, e.sass_line
3239
+ end
3240
+
2927
3241
  def test_nested_mixin_def_is_scoped
2928
3242
  render <<SCSS
2929
3243
  foo {
@@ -2978,7 +3292,7 @@ foo {
2978
3292
  SCSS
2979
3293
  assert(false, "Expected syntax error")
2980
3294
  rescue Sass::SyntaxError => e
2981
- assert_equal 'Invalid CSS after " .bar:baz ": expected "{", was "<fail>; }"', e.message
3295
+ assert_equal 'Invalid CSS after " .bar:baz <fail>": expected expression (e.g. 1px, bold), was "; }"', e.message
2982
3296
  assert_equal 2, e.sass_line
2983
3297
  end
2984
3298
 
@@ -3088,7 +3402,7 @@ SCSS
3088
3402
 
3089
3403
  def test_parent_in_mid_selector_error
3090
3404
  assert_raise_message(Sass::SyntaxError, <<MESSAGE.rstrip) {render <<SCSS}
3091
- Invalid CSS after " .foo": expected "{", was "&.bar {a: b}"
3405
+ Invalid CSS after ".foo": expected "{", was "&.bar"
3092
3406
 
3093
3407
  "&.bar" may only be used at the beginning of a compound selector.
3094
3408
  MESSAGE
@@ -3100,7 +3414,7 @@ SCSS
3100
3414
 
3101
3415
  def test_parent_after_selector_error
3102
3416
  assert_raise_message(Sass::SyntaxError, <<MESSAGE.rstrip) {render <<SCSS}
3103
- Invalid CSS after " .foo.bar": expected "{", was "& {a: b}"
3417
+ Invalid CSS after ".foo.bar": expected "{", was "&"
3104
3418
 
3105
3419
  "&" may only be used at the beginning of a compound selector.
3106
3420
  MESSAGE
@@ -3112,7 +3426,7 @@ SCSS
3112
3426
 
3113
3427
  def test_double_parent_selector_error
3114
3428
  assert_raise_message(Sass::SyntaxError, <<MESSAGE.rstrip) {render <<SCSS}
3115
- Invalid CSS after " &": expected "{", was "& {a: b}"
3429
+ Invalid CSS after "&": expected "{", was "&"
3116
3430
 
3117
3431
  "&" may only be used at the beginning of a compound selector.
3118
3432
  MESSAGE
@@ -3182,6 +3496,36 @@ MESSAGE
3182
3496
  SCSS
3183
3497
  end
3184
3498
 
3499
+ def test_newline_in_property_value
3500
+ assert_equal(<<CSS, render(<<SCSS))
3501
+ .foo {
3502
+ bar: "bazbang"; }
3503
+ CSS
3504
+ .foo {
3505
+ $var: "baz\\
3506
+ bang";
3507
+ bar: $var;
3508
+ }
3509
+ SCSS
3510
+ end
3511
+
3512
+ def test_raw_newline_warning
3513
+ assert_warning(<<MESSAGE.rstrip) {assert_equal(<<CSS, render(<<SCSS))}
3514
+ DEPRECATION WARNING on line 2, column 9:
3515
+ Unescaped multiline strings are deprecated and will be removed in a future version of Sass.
3516
+ To include a newline in a string, use "\\a" or "\\a " as in CSS.
3517
+ MESSAGE
3518
+ .foo {
3519
+ bar: "baz\\a bang"; }
3520
+ CSS
3521
+ .foo {
3522
+ $var: "baz
3523
+ bang";
3524
+ bar: $var;
3525
+ }
3526
+ SCSS
3527
+ end
3528
+
3185
3529
  # Regression
3186
3530
 
3187
3531
  def test_top_level_unknown_directive_in_at_root