sass 3.2.7 → 3.3.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 (184) hide show
  1. data/MIT-LICENSE +2 -2
  2. data/README.md +14 -2
  3. data/Rakefile +25 -1
  4. data/VERSION +1 -1
  5. data/VERSION_DATE +1 -1
  6. data/VERSION_NAME +1 -1
  7. data/lib/sass/cache_stores/base.rb +4 -2
  8. data/lib/sass/cache_stores/chain.rb +2 -1
  9. data/lib/sass/cache_stores/filesystem.rb +2 -6
  10. data/lib/sass/cache_stores/memory.rb +1 -1
  11. data/lib/sass/cache_stores/null.rb +2 -2
  12. data/lib/sass/callbacks.rb +1 -0
  13. data/lib/sass/css.rb +10 -10
  14. data/lib/sass/engine.rb +403 -150
  15. data/lib/sass/environment.rb +136 -57
  16. data/lib/sass/error.rb +7 -7
  17. data/lib/sass/exec.rb +123 -39
  18. data/lib/sass/features.rb +41 -0
  19. data/lib/sass/importers/base.rb +33 -2
  20. data/lib/sass/importers/deprecated_path.rb +45 -0
  21. data/lib/sass/importers/filesystem.rb +25 -14
  22. data/lib/sass/importers.rb +1 -0
  23. data/lib/sass/logger/base.rb +3 -3
  24. data/lib/sass/logger/log_level.rb +4 -6
  25. data/lib/sass/media.rb +19 -19
  26. data/lib/sass/plugin/compiler.rb +141 -101
  27. data/lib/sass/plugin/configuration.rb +18 -22
  28. data/lib/sass/plugin/merb.rb +1 -1
  29. data/lib/sass/plugin/staleness_checker.rb +24 -8
  30. data/lib/sass/plugin.rb +4 -2
  31. data/lib/sass/repl.rb +3 -3
  32. data/lib/sass/script/css_lexer.rb +9 -4
  33. data/lib/sass/script/css_parser.rb +6 -2
  34. data/lib/sass/script/functions.rb +1343 -590
  35. data/lib/sass/script/lexer.rb +84 -52
  36. data/lib/sass/script/parser.rb +217 -97
  37. data/lib/sass/script/tree/funcall.rb +290 -0
  38. data/lib/sass/script/{interpolation.rb → tree/interpolation.rb} +34 -13
  39. data/lib/sass/script/tree/list_literal.rb +80 -0
  40. data/lib/sass/script/tree/literal.rb +47 -0
  41. data/lib/sass/script/tree/map_literal.rb +64 -0
  42. data/lib/sass/script/{node.rb → tree/node.rb} +22 -12
  43. data/lib/sass/script/{operation.rb → tree/operation.rb} +17 -25
  44. data/lib/sass/script/tree/selector.rb +30 -0
  45. data/lib/sass/script/{string_interpolation.rb → tree/string_interpolation.rb} +5 -4
  46. data/lib/sass/script/{unary_operation.rb → tree/unary_operation.rb} +14 -9
  47. data/lib/sass/script/tree/variable.rb +57 -0
  48. data/lib/sass/script/tree.rb +16 -0
  49. data/lib/sass/script/{arg_list.rb → value/arg_list.rb} +4 -24
  50. data/lib/sass/script/value/base.rb +248 -0
  51. data/lib/sass/script/value/bool.rb +36 -0
  52. data/lib/sass/script/{color.rb → value/color.rb} +239 -195
  53. data/lib/sass/script/value/helpers.rb +155 -0
  54. data/lib/sass/script/value/list.rb +119 -0
  55. data/lib/sass/script/value/map.rb +70 -0
  56. data/lib/sass/script/value/null.rb +45 -0
  57. data/lib/sass/script/{number.rb → value/number.rb} +91 -65
  58. data/lib/sass/script/{string.rb → value/string.rb} +9 -11
  59. data/lib/sass/script/value.rb +11 -0
  60. data/lib/sass/script.rb +35 -8
  61. data/lib/sass/scss/css_parser.rb +2 -1
  62. data/lib/sass/scss/parser.rb +338 -170
  63. data/lib/sass/scss/rx.rb +5 -6
  64. data/lib/sass/scss/script_lexer.rb +1 -0
  65. data/lib/sass/scss/script_parser.rb +1 -0
  66. data/lib/sass/scss/static_parser.rb +23 -6
  67. data/lib/sass/selector/abstract_sequence.rb +2 -2
  68. data/lib/sass/selector/comma_sequence.rb +21 -16
  69. data/lib/sass/selector/sequence.rb +60 -34
  70. data/lib/sass/selector/simple.rb +11 -12
  71. data/lib/sass/selector/simple_sequence.rb +55 -33
  72. data/lib/sass/selector.rb +52 -48
  73. data/lib/sass/source/map.rb +211 -0
  74. data/lib/sass/source/position.rb +39 -0
  75. data/lib/sass/source/range.rb +41 -0
  76. data/lib/sass/stack.rb +120 -0
  77. data/lib/sass/supports.rb +12 -13
  78. data/lib/sass/tree/at_root_node.rb +82 -0
  79. data/lib/sass/tree/comment_node.rb +3 -3
  80. data/lib/sass/tree/css_import_node.rb +11 -11
  81. data/lib/sass/tree/debug_node.rb +2 -2
  82. data/lib/sass/tree/directive_node.rb +13 -2
  83. data/lib/sass/tree/each_node.rb +8 -8
  84. data/lib/sass/tree/extend_node.rb +13 -6
  85. data/lib/sass/tree/for_node.rb +4 -4
  86. data/lib/sass/tree/function_node.rb +5 -4
  87. data/lib/sass/tree/if_node.rb +1 -1
  88. data/lib/sass/tree/import_node.rb +4 -5
  89. data/lib/sass/tree/media_node.rb +4 -14
  90. data/lib/sass/tree/mixin_def_node.rb +4 -4
  91. data/lib/sass/tree/mixin_node.rb +21 -8
  92. data/lib/sass/tree/node.rb +29 -12
  93. data/lib/sass/tree/prop_node.rb +38 -18
  94. data/lib/sass/tree/return_node.rb +3 -2
  95. data/lib/sass/tree/root_node.rb +19 -3
  96. data/lib/sass/tree/rule_node.rb +25 -17
  97. data/lib/sass/tree/supports_node.rb +0 -13
  98. data/lib/sass/tree/trace_node.rb +2 -1
  99. data/lib/sass/tree/variable_node.rb +9 -3
  100. data/lib/sass/tree/visitors/base.rb +6 -6
  101. data/lib/sass/tree/visitors/check_nesting.rb +12 -9
  102. data/lib/sass/tree/visitors/convert.rb +63 -38
  103. data/lib/sass/tree/visitors/cssize.rb +63 -23
  104. data/lib/sass/tree/visitors/deep_copy.rb +6 -5
  105. data/lib/sass/tree/visitors/extend.rb +7 -7
  106. data/lib/sass/tree/visitors/perform.rb +256 -151
  107. data/lib/sass/tree/visitors/set_options.rb +6 -6
  108. data/lib/sass/tree/visitors/to_css.rb +231 -81
  109. data/lib/sass/tree/warn_node.rb +2 -2
  110. data/lib/sass/tree/while_node.rb +2 -2
  111. data/lib/sass/util/multibyte_string_scanner.rb +2 -0
  112. data/lib/sass/util/normalized_map.rb +65 -0
  113. data/lib/sass/util/ordered_hash.rb +188 -0
  114. data/lib/sass/util/subset_map.rb +3 -2
  115. data/lib/sass/util/test.rb +9 -0
  116. data/lib/sass/util.rb +220 -34
  117. data/lib/sass/version.rb +9 -9
  118. data/lib/sass.rb +14 -7
  119. data/test/sass/compiler_test.rb +213 -0
  120. data/test/sass/conversion_test.rb +235 -9
  121. data/test/sass/engine_test.rb +230 -60
  122. data/test/sass/exec_test.rb +86 -0
  123. data/test/sass/extend_test.rb +215 -147
  124. data/test/sass/functions_test.rb +584 -99
  125. data/test/sass/importer_test.rb +165 -17
  126. data/test/sass/plugin_test.rb +19 -13
  127. data/test/sass/script_conversion_test.rb +40 -0
  128. data/test/sass/script_test.rb +231 -21
  129. data/test/sass/scss/css_test.rb +14 -5
  130. data/test/sass/scss/scss_test.rb +1266 -66
  131. data/test/sass/source_map_test.rb +879 -0
  132. data/test/sass/templates/bork5.sass +3 -0
  133. data/test/sass/util/normalized_map_test.rb +30 -0
  134. data/test/sass/util_test.rb +90 -0
  135. data/test/sass/value_helpers_test.rb +181 -0
  136. data/test/test_helper.rb +7 -2
  137. metadata +316 -291
  138. data/lib/sass/script/bool.rb +0 -18
  139. data/lib/sass/script/funcall.rb +0 -231
  140. data/lib/sass/script/list.rb +0 -84
  141. data/lib/sass/script/literal.rb +0 -239
  142. data/lib/sass/script/null.rb +0 -34
  143. data/lib/sass/script/variable.rb +0 -58
  144. data/test/Gemfile +0 -3
  145. data/vendor/listen/CHANGELOG.md +0 -221
  146. data/vendor/listen/CONTRIBUTING.md +0 -38
  147. data/vendor/listen/Gemfile +0 -30
  148. data/vendor/listen/Guardfile +0 -8
  149. data/vendor/listen/LICENSE +0 -20
  150. data/vendor/listen/README.md +0 -315
  151. data/vendor/listen/Rakefile +0 -47
  152. data/vendor/listen/Vagrantfile +0 -96
  153. data/vendor/listen/lib/listen/adapter.rb +0 -214
  154. data/vendor/listen/lib/listen/adapters/bsd.rb +0 -112
  155. data/vendor/listen/lib/listen/adapters/darwin.rb +0 -85
  156. data/vendor/listen/lib/listen/adapters/linux.rb +0 -113
  157. data/vendor/listen/lib/listen/adapters/polling.rb +0 -67
  158. data/vendor/listen/lib/listen/adapters/windows.rb +0 -87
  159. data/vendor/listen/lib/listen/dependency_manager.rb +0 -126
  160. data/vendor/listen/lib/listen/directory_record.rb +0 -371
  161. data/vendor/listen/lib/listen/listener.rb +0 -225
  162. data/vendor/listen/lib/listen/multi_listener.rb +0 -143
  163. data/vendor/listen/lib/listen/turnstile.rb +0 -28
  164. data/vendor/listen/lib/listen/version.rb +0 -3
  165. data/vendor/listen/lib/listen.rb +0 -40
  166. data/vendor/listen/listen.gemspec +0 -22
  167. data/vendor/listen/spec/listen/adapter_spec.rb +0 -183
  168. data/vendor/listen/spec/listen/adapters/bsd_spec.rb +0 -36
  169. data/vendor/listen/spec/listen/adapters/darwin_spec.rb +0 -37
  170. data/vendor/listen/spec/listen/adapters/linux_spec.rb +0 -47
  171. data/vendor/listen/spec/listen/adapters/polling_spec.rb +0 -68
  172. data/vendor/listen/spec/listen/adapters/windows_spec.rb +0 -30
  173. data/vendor/listen/spec/listen/dependency_manager_spec.rb +0 -107
  174. data/vendor/listen/spec/listen/directory_record_spec.rb +0 -1225
  175. data/vendor/listen/spec/listen/listener_spec.rb +0 -169
  176. data/vendor/listen/spec/listen/multi_listener_spec.rb +0 -174
  177. data/vendor/listen/spec/listen/turnstile_spec.rb +0 -56
  178. data/vendor/listen/spec/listen_spec.rb +0 -73
  179. data/vendor/listen/spec/spec_helper.rb +0 -21
  180. data/vendor/listen/spec/support/adapter_helper.rb +0 -629
  181. data/vendor/listen/spec/support/directory_record_helper.rb +0 -55
  182. data/vendor/listen/spec/support/fixtures_helper.rb +0 -29
  183. data/vendor/listen/spec/support/listeners_helper.rb +0 -156
  184. data/vendor/listen/spec/support/platform_helper.rb +0 -15
@@ -229,7 +229,7 @@ $i: 1;
229
229
  .foo {
230
230
  @while $i != 5 {
231
231
  a: $i;
232
- $i: $i + 1;
232
+ $i: $i + 1 !global;
233
233
  }
234
234
  }
235
235
  SCSS
@@ -262,6 +262,31 @@ c {
262
262
  SCSS
263
263
  end
264
264
 
265
+ def test_destructuring_each_directive
266
+ assert_equal <<CSS, render(<<SCSS)
267
+ a {
268
+ foo: 1px;
269
+ bar: 2px;
270
+ baz: 3px; }
271
+
272
+ c {
273
+ foo: "Value is bar";
274
+ bar: "Value is baz";
275
+ bang: "Value is "; }
276
+ CSS
277
+ a {
278
+ @each $name, $number in (foo: 1px, bar: 2px, baz: 3px) {
279
+ \#{$name}: $number;
280
+ }
281
+ }
282
+ c {
283
+ @each $key, $value in (foo bar) (bar, baz) bang {
284
+ \#{$key}: "Value is \#{$value}";
285
+ }
286
+ }
287
+ SCSS
288
+ end
289
+
265
290
  def test_css_import_directive
266
291
  assert_equal "@import url(foo.css);\n", render('@import "foo.css";')
267
292
  assert_equal "@import url(foo.css);\n", render("@import 'foo.css';")
@@ -538,6 +563,20 @@ foo bar {
538
563
  SCSS
539
564
  end
540
565
 
566
+ def test_unknown_directive_bubbling
567
+ assert_equal(<<CSS, render(<<SCSS, :style => :nested))
568
+ @fblthp {
569
+ .foo .bar {
570
+ a: b; } }
571
+ CSS
572
+ .foo {
573
+ @fblthp {
574
+ .bar {a: b}
575
+ }
576
+ }
577
+ SCSS
578
+ end
579
+
541
580
  ## Namespace Properties
542
581
 
543
582
  def test_namespace_properties
@@ -929,6 +968,257 @@ CSS
929
968
  SCSS
930
969
  end
931
970
 
971
+ def test_mixin_var_keyword_args
972
+ assert_equal <<CSS, render(<<SCSS)
973
+ .foo {
974
+ a: 1;
975
+ b: 2;
976
+ c: 3; }
977
+ CSS
978
+ @mixin foo($args...) {
979
+ a: map-get(keywords($args), a);
980
+ b: map-get(keywords($args), b);
981
+ c: map-get(keywords($args), c);
982
+ }
983
+
984
+ .foo {@include foo($a: 1, $b: 2, $c: 3)}
985
+ SCSS
986
+ end
987
+
988
+ def test_mixin_empty_var_keyword_args
989
+ assert_equal <<CSS, render(<<SCSS)
990
+ .foo {
991
+ length: 0; }
992
+ CSS
993
+ @mixin foo($args...) {
994
+ length: length(keywords($args));
995
+ }
996
+
997
+ .foo {@include foo}
998
+ SCSS
999
+ end
1000
+
1001
+ def test_mixin_map_splat
1002
+ assert_equal <<CSS, render(<<SCSS)
1003
+ .foo {
1004
+ a: 1;
1005
+ b: 2;
1006
+ c: 3; }
1007
+ CSS
1008
+ @mixin foo($a, $b, $c) {
1009
+ a: $a;
1010
+ b: $b;
1011
+ c: $c;
1012
+ }
1013
+
1014
+ .foo {
1015
+ $map: (a: 1, b: 2, c: 3);
1016
+ @include foo($map...);
1017
+ }
1018
+ SCSS
1019
+ end
1020
+
1021
+ def test_mixin_map_and_list_splat
1022
+ assert_equal <<CSS, render(<<SCSS)
1023
+ .foo {
1024
+ a: x;
1025
+ b: y;
1026
+ c: z;
1027
+ d: 1;
1028
+ e: 2;
1029
+ f: 3; }
1030
+ CSS
1031
+ @mixin foo($a, $b, $c, $d, $e, $f) {
1032
+ a: $a;
1033
+ b: $b;
1034
+ c: $c;
1035
+ d: $d;
1036
+ e: $e;
1037
+ f: $f;
1038
+ }
1039
+
1040
+ .foo {
1041
+ $list: x y z;
1042
+ $map: (d: 1, e: 2, f: 3);
1043
+ @include foo($list..., $map...);
1044
+ }
1045
+ SCSS
1046
+ end
1047
+
1048
+ def test_mixin_map_splat_takes_precedence_over_pass_through
1049
+ assert_equal <<CSS, render(<<SCSS)
1050
+ .foo {
1051
+ a: 1;
1052
+ b: 2;
1053
+ c: z; }
1054
+ CSS
1055
+ @mixin foo($args...) {
1056
+ $map: (c: z);
1057
+ @include bar($args..., $map...);
1058
+ }
1059
+
1060
+ @mixin bar($a, $b, $c) {
1061
+ a: $a;
1062
+ b: $b;
1063
+ c: $c;
1064
+ }
1065
+
1066
+ .foo {
1067
+ @include foo(1, $b: 2, $c: 3);
1068
+ }
1069
+ SCSS
1070
+ end
1071
+
1072
+ def test_mixin_list_of_pairs_splat_treated_as_list
1073
+ assert_equal <<CSS, render(<<SCSS)
1074
+ .foo {
1075
+ a: a 1;
1076
+ b: b 2;
1077
+ c: c 3; }
1078
+ CSS
1079
+ @mixin foo($a, $b, $c) {
1080
+ a: $a;
1081
+ b: $b;
1082
+ c: $c;
1083
+ }
1084
+
1085
+ .foo {
1086
+ @include foo((a 1, b 2, c 3)...);
1087
+ }
1088
+ SCSS
1089
+ end
1090
+
1091
+ def test_mixin_splat_after_keyword_args
1092
+ assert_equal <<CSS, render(<<SCSS)
1093
+ .foo {
1094
+ a: 1;
1095
+ b: 2;
1096
+ c: 3; }
1097
+ CSS
1098
+ @mixin foo($a, $b, $c) {
1099
+ a: 1;
1100
+ b: 2;
1101
+ c: 3;
1102
+ }
1103
+
1104
+ .foo {
1105
+ @include foo(1, $c: 3, 2...);
1106
+ }
1107
+ SCSS
1108
+ end
1109
+
1110
+ def test_mixin_keyword_args_after_splat
1111
+ assert_equal <<CSS, render(<<SCSS)
1112
+ .foo {
1113
+ a: 1;
1114
+ b: 2;
1115
+ c: 3; }
1116
+ CSS
1117
+ @mixin foo($a, $b, $c) {
1118
+ a: 1;
1119
+ b: 2;
1120
+ c: 3;
1121
+ }
1122
+
1123
+ .foo {
1124
+ @include foo(1, 2..., $c: 3);
1125
+ }
1126
+ SCSS
1127
+ end
1128
+
1129
+ def test_mixin_keyword_splat_after_keyword_args
1130
+ assert_equal <<CSS, render(<<SCSS)
1131
+ .foo {
1132
+ a: 1;
1133
+ b: 2;
1134
+ c: 3; }
1135
+ CSS
1136
+ @mixin foo($a, $b, $c) {
1137
+ a: 1;
1138
+ b: 2;
1139
+ c: 3;
1140
+ }
1141
+
1142
+ .foo {
1143
+ @include foo(1, $b: 2, (c: 3)...);
1144
+ }
1145
+ SCSS
1146
+ end
1147
+
1148
+ def test_mixin_triple_keyword_splat_merge
1149
+ assert_equal <<CSS, render(<<SCSS)
1150
+ .foo {
1151
+ foo: 1;
1152
+ bar: 2;
1153
+ kwarg: 3;
1154
+ a: 3;
1155
+ b: 2;
1156
+ c: 3; }
1157
+ CSS
1158
+ @mixin foo($foo, $bar, $kwarg, $a, $b, $c) {
1159
+ foo: $foo;
1160
+ bar: $bar;
1161
+ kwarg: $kwarg;
1162
+ a: $a;
1163
+ b: $b;
1164
+ c: $c;
1165
+ }
1166
+
1167
+ @mixin bar($args...) {
1168
+ @include foo($args..., $bar: 2, $a: 2, $b: 2, (kwarg: 3, a: 3, c: 3)...);
1169
+ }
1170
+
1171
+ .foo {
1172
+ @include bar($foo: 1, $a: 1, $b: 1, $c: 1);
1173
+ }
1174
+ SCSS
1175
+ end
1176
+
1177
+ def test_mixin_conflicting_splat_after_keyword_args
1178
+ assert_raise_message(Sass::SyntaxError, <<MESSAGE.rstrip) {render(<<SCSS)}
1179
+ Mixin foo was passed argument $b both by position and by name.
1180
+ MESSAGE
1181
+ @mixin foo($a, $b, $c) {
1182
+ a: 1;
1183
+ b: 2;
1184
+ c: 3;
1185
+ }
1186
+
1187
+ .foo {
1188
+ @include foo(1, $b: 2, 3...);
1189
+ }
1190
+ SCSS
1191
+ end
1192
+
1193
+ def test_mixin_keyword_splat_must_have_string_keys
1194
+ assert_raise_message(Sass::SyntaxError, <<MESSAGE.rstrip) {render <<SCSS}
1195
+ Variable keyword argument map must have string keys.
1196
+ 12 is not a string in (12: 1).
1197
+ MESSAGE
1198
+ @mixin foo($a) {
1199
+ a: $a;
1200
+ }
1201
+
1202
+ .foo {@include foo((12: 1)...)}
1203
+ SCSS
1204
+ end
1205
+
1206
+ def test_mixin_positional_arg_after_splat
1207
+ assert_raise_message(Sass::SyntaxError, <<MESSAGE.rstrip) {render(<<SCSS)}
1208
+ Only keyword arguments may follow variable arguments (...).
1209
+ MESSAGE
1210
+ @mixin foo($a, $b, $c) {
1211
+ a: 1;
1212
+ b: 2;
1213
+ c: 3;
1214
+ }
1215
+
1216
+ .foo {
1217
+ @include foo(1, 2..., 3);
1218
+ }
1219
+ SCSS
1220
+ end
1221
+
932
1222
  def test_mixin_var_args_with_keyword
933
1223
  assert_raise_message(Sass::SyntaxError, "Positional arguments must come before keyword arguments.") {render <<SCSS}
934
1224
  @mixin foo($a, $b...) {
@@ -962,6 +1252,46 @@ SCSS
962
1252
  SCSS
963
1253
  end
964
1254
 
1255
+ def test_mixin_map_splat_before_list_splat
1256
+ assert_raise_message(Sass::SyntaxError, "Variable keyword arguments must be a map (was (2 3)).") {render <<SCSS}
1257
+ @mixin foo($a, $b, $c) {
1258
+ a: $a;
1259
+ b: $b;
1260
+ c: $c;
1261
+ }
1262
+
1263
+ .foo {
1264
+ @include foo((a: 1)..., (2 3)...);
1265
+ }
1266
+ SCSS
1267
+ end
1268
+
1269
+ def test_mixin_map_splat_with_unknown_keyword
1270
+ assert_raise_message(Sass::SyntaxError, "Mixin foo doesn't have an argument named $c.") {render <<SCSS}
1271
+ @mixin foo($a, $b) {
1272
+ a: $a;
1273
+ b: $b;
1274
+ }
1275
+
1276
+ .foo {
1277
+ @include foo(1, 2, (c: 1)...);
1278
+ }
1279
+ SCSS
1280
+ end
1281
+
1282
+ def test_mixin_map_splat_with_wrong_type
1283
+ assert_raise_message(Sass::SyntaxError, "Variable keyword arguments must be a map (was 12).") {render <<SCSS}
1284
+ @mixin foo($a, $b) {
1285
+ a: $a;
1286
+ b: $b;
1287
+ }
1288
+
1289
+ .foo {
1290
+ @include foo((1, 2)..., 12...);
1291
+ }
1292
+ SCSS
1293
+ end
1294
+
965
1295
  def test_function_var_args
966
1296
  assert_equal <<CSS, render(<<SCSS)
967
1297
  .foo {
@@ -1087,46 +1417,299 @@ CSS
1087
1417
  SCSS
1088
1418
  end
1089
1419
 
1090
- def test_function_var_args_with_keyword
1091
- assert_raise_message(Sass::SyntaxError, "Positional arguments must come before keyword arguments.") {render <<SCSS}
1092
- @function foo($a, $b...) {
1093
- @return "a: \#{$a}, b: $b";
1420
+ def test_function_var_keyword_args
1421
+ assert_equal <<CSS, render(<<SCSS)
1422
+ .foo {
1423
+ val: "a: 1, b: 2, c: 3"; }
1424
+ CSS
1425
+ @function foo($args...) {
1426
+ @return "a: \#{map-get(keywords($args), a)}, " +
1427
+ "b: \#{map-get(keywords($args), b)}, " +
1428
+ "c: \#{map-get(keywords($args), c)}";
1094
1429
  }
1095
1430
 
1096
- .foo {val: foo($a: 1, 2, 3, 4)}
1431
+ .foo {val: foo($a: 1, $b: 2, $c: 3)}
1097
1432
  SCSS
1098
1433
  end
1099
1434
 
1100
- def test_function_keyword_for_var_arg
1101
- assert_raise_message(Sass::SyntaxError, "Argument $b of function foo cannot be used as a named argument.") {render <<SCSS}
1102
- @function foo($a, $b...) {
1103
- @return "a: \#{$a}, b: \#{$b}";
1435
+ def test_function_empty_var_keyword_args
1436
+ assert_equal <<CSS, render(<<SCSS)
1437
+ .foo {
1438
+ length: 0; }
1439
+ CSS
1440
+ @function foo($args...) {
1441
+ @return length(keywords($args));
1104
1442
  }
1105
1443
 
1106
- .foo {val: foo(1, $b: 2 3 4)}
1444
+ .foo {length: foo()}
1107
1445
  SCSS
1108
1446
  end
1109
1447
 
1110
- def test_function_keyword_for_unknown_arg_with_var_args
1111
- assert_raise_message(Sass::SyntaxError, "Function foo doesn't have an argument named $c.") {render <<SCSS}
1112
- @function foo($a, $b...) {
1113
- @return "a: \#{$a}, b: \#{$b}";
1448
+ def test_function_map_splat
1449
+ assert_equal <<CSS, render(<<SCSS)
1450
+ .foo {
1451
+ val: "a: 1, b: 2, c: 3"; }
1452
+ CSS
1453
+ @function foo($a, $b, $c) {
1454
+ @return "a: \#{$a}, b: \#{$b}, c: \#{$c}";
1114
1455
  }
1115
1456
 
1116
- .foo {val: foo(1, $c: 2 3 4)}
1457
+ .foo {
1458
+ $map: (a: 1, b: 2, c: 3);
1459
+ val: foo($map...);
1460
+ }
1117
1461
  SCSS
1118
1462
  end
1119
1463
 
1120
- def test_function_var_args_passed_to_native
1464
+ def test_function_map_and_list_splat
1121
1465
  assert_equal <<CSS, render(<<SCSS)
1122
1466
  .foo {
1123
- val: #102035; }
1467
+ val: "a: x, b: y, c: z, d: 1, e: 2, f: 3"; }
1124
1468
  CSS
1125
- @function foo($args...) {
1126
- @return adjust-color($args...);
1469
+ @function foo($a, $b, $c, $d, $e, $f) {
1470
+ @return "a: \#{$a}, b: \#{$b}, c: \#{$c}, d: \#{$d}, e: \#{$e}, f: \#{$f}";
1127
1471
  }
1128
1472
 
1129
- .foo {val: foo(#102030, $blue: 5)}
1473
+ .foo {
1474
+ $list: x y z;
1475
+ $map: (d: 1, e: 2, f: 3);
1476
+ val: foo($list..., $map...);
1477
+ }
1478
+ SCSS
1479
+ end
1480
+
1481
+ def test_function_map_splat_takes_precedence_over_pass_through
1482
+ assert_equal <<CSS, render(<<SCSS)
1483
+ .foo {
1484
+ val: "a: 1, b: 2, c: z"; }
1485
+ CSS
1486
+ @function foo($args...) {
1487
+ $map: (c: z);
1488
+ @return bar($args..., $map...);
1489
+ }
1490
+
1491
+ @function bar($a, $b, $c) {
1492
+ @return "a: \#{$a}, b: \#{$b}, c: \#{$c}";
1493
+ }
1494
+
1495
+ .foo {
1496
+ val: foo(1, $b: 2, $c: 3);
1497
+ }
1498
+ SCSS
1499
+ end
1500
+
1501
+ def test_ruby_function_map_splat_takes_precedence_over_pass_through
1502
+ assert_equal <<CSS, render(<<SCSS)
1503
+ .foo {
1504
+ val: 1 2 3 z; }
1505
+ CSS
1506
+ @function foo($args...) {
1507
+ $map: (val: z);
1508
+ @return append($args..., $map...);
1509
+ }
1510
+
1511
+ .foo {
1512
+ val: foo(1 2 3, $val: 4)
1513
+ }
1514
+ SCSS
1515
+ end
1516
+
1517
+ def test_function_list_of_pairs_splat_treated_as_list
1518
+ assert_equal <<CSS, render(<<SCSS)
1519
+ .foo {
1520
+ val: "a: a 1, b: b 2, c: c 3"; }
1521
+ CSS
1522
+ @function foo($a, $b, $c) {
1523
+ @return "a: \#{$a}, b: \#{$b}, c: \#{$c}";
1524
+ }
1525
+
1526
+ .foo {
1527
+ val: foo((a 1, b 2, c 3)...);
1528
+ }
1529
+ SCSS
1530
+ end
1531
+
1532
+ def test_function_splat_after_keyword_args
1533
+ assert_equal <<CSS, render(<<SCSS)
1534
+ .foo {
1535
+ val: "a: 1, b: 2, c: 3"; }
1536
+ CSS
1537
+ @function foo($a, $b, $c) {
1538
+ @return "a: \#{$a}, b: \#{$b}, c: \#{$c}";
1539
+ }
1540
+
1541
+ .foo {
1542
+ val: foo(1, $c: 3, 2...);
1543
+ }
1544
+ SCSS
1545
+ end
1546
+
1547
+ def test_function_keyword_args_after_splat
1548
+ assert_equal <<CSS, render(<<SCSS)
1549
+ .foo {
1550
+ val: "a: 1, b: 2, c: 3"; }
1551
+ CSS
1552
+ @function foo($a, $b, $c) {
1553
+ @return "a: \#{$a}, b: \#{$b}, c: \#{$c}";
1554
+ }
1555
+
1556
+ .foo {
1557
+ val: foo(1, 2..., $c: 3);
1558
+ }
1559
+ SCSS
1560
+ end
1561
+
1562
+ def test_function_keyword_splat_after_keyword_args
1563
+ assert_equal <<CSS, render(<<SCSS)
1564
+ .foo {
1565
+ val: "a: 1, b: 2, c: 3"; }
1566
+ CSS
1567
+ @function foo($a, $b, $c) {
1568
+ @return "a: \#{$a}, b: \#{$b}, c: \#{$c}";
1569
+ }
1570
+
1571
+ .foo {
1572
+ val: foo(1, $b: 2, (c: 3)...);
1573
+ }
1574
+ SCSS
1575
+ end
1576
+
1577
+ def test_function_triple_keyword_splat_merge
1578
+ assert_equal <<CSS, render(<<SCSS)
1579
+ .foo {
1580
+ val: "foo: 1, bar: 2, kwarg: 3, a: 3, b: 2, c: 3"; }
1581
+ CSS
1582
+ @function foo($foo, $bar, $kwarg, $a, $b, $c) {
1583
+ @return "foo: \#{$foo}, bar: \#{$bar}, kwarg: \#{$kwarg}, a: \#{$a}, b: \#{$b}, c: \#{$c}";
1584
+ }
1585
+
1586
+ @function bar($args...) {
1587
+ @return foo($args..., $bar: 2, $a: 2, $b: 2, (kwarg: 3, a: 3, c: 3)...);
1588
+ }
1589
+
1590
+ .foo {
1591
+ val: bar($foo: 1, $a: 1, $b: 1, $c: 1);
1592
+ }
1593
+ SCSS
1594
+ end
1595
+
1596
+ def test_function_conflicting_splat_after_keyword_args
1597
+ assert_raise_message(Sass::SyntaxError, <<MESSAGE.rstrip) {render(<<SCSS)}
1598
+ Function foo was passed argument $b both by position and by name.
1599
+ MESSAGE
1600
+ @function foo($a, $b, $c) {
1601
+ @return "a: \#{$a}, b: \#{$b}, c: \#{$c}";
1602
+ }
1603
+
1604
+ .foo {
1605
+ val: foo(1, $b: 2, 3...);
1606
+ }
1607
+ SCSS
1608
+ end
1609
+
1610
+ def test_function_positional_arg_after_splat
1611
+ assert_raise_message(Sass::SyntaxError, <<MESSAGE.rstrip) {render(<<SCSS)}
1612
+ Only keyword arguments may follow variable arguments (...).
1613
+ MESSAGE
1614
+ @function foo($a, $b, $c) {
1615
+ @return "a: \#{$a}, b: \#{$b}, c: \#{$c}";
1616
+ }
1617
+
1618
+ .foo {
1619
+ val: foo(1, 2..., 3);
1620
+ }
1621
+ SCSS
1622
+ end
1623
+
1624
+ def test_function_var_args_with_keyword
1625
+ assert_raise_message(Sass::SyntaxError, "Positional arguments must come before keyword arguments.") {render <<SCSS}
1626
+ @function foo($a, $b...) {
1627
+ @return "a: \#{$a}, b: \#{$b}";
1628
+ }
1629
+
1630
+ .foo {val: foo($a: 1, 2, 3, 4)}
1631
+ SCSS
1632
+ end
1633
+
1634
+ def test_function_keyword_for_var_arg
1635
+ assert_raise_message(Sass::SyntaxError, "Argument $b of function foo cannot be used as a named argument.") {render <<SCSS}
1636
+ @function foo($a, $b...) {
1637
+ @return "a: \#{$a}, b: \#{$b}";
1638
+ }
1639
+
1640
+ .foo {val: foo(1, $b: 2 3 4)}
1641
+ SCSS
1642
+ end
1643
+
1644
+ def test_function_keyword_for_unknown_arg_with_var_args
1645
+ assert_raise_message(Sass::SyntaxError, "Function foo doesn't have an argument named $c.") {render <<SCSS}
1646
+ @function foo($a, $b...) {
1647
+ @return "a: \#{$a}, b: \#{length($b)}";
1648
+ }
1649
+
1650
+ .foo {val: foo(1, $c: 2 3 4)}
1651
+ SCSS
1652
+ end
1653
+
1654
+ def test_function_var_args_passed_to_native
1655
+ assert_equal <<CSS, render(<<SCSS)
1656
+ .foo {
1657
+ val: #102035; }
1658
+ CSS
1659
+ @function foo($args...) {
1660
+ @return adjust-color($args...);
1661
+ }
1662
+
1663
+ .foo {val: foo(#102030, $blue: 5)}
1664
+ SCSS
1665
+ end
1666
+
1667
+ def test_function_map_splat_before_list_splat
1668
+ assert_raise_message(Sass::SyntaxError, "Variable keyword arguments must be a map (was (2 3)).") {render <<SCSS}
1669
+ @function foo($a, $b, $c) {
1670
+ @return "a: \#{$a}, b: \#{$b}, c: \#{$c}";
1671
+ }
1672
+
1673
+ .foo {
1674
+ val: foo((a: 1)..., (2 3)...);
1675
+ }
1676
+ SCSS
1677
+ end
1678
+
1679
+ def test_function_map_splat_with_unknown_keyword
1680
+ assert_raise_message(Sass::SyntaxError, "Function foo doesn't have an argument named $c.") {render <<SCSS}
1681
+ @function foo($a, $b) {
1682
+ @return "a: \#{$a}, b: \#{$b}";
1683
+ }
1684
+
1685
+ .foo {
1686
+ val: foo(1, 2, (c: 1)...);
1687
+ }
1688
+ SCSS
1689
+ end
1690
+
1691
+ def test_function_map_splat_with_wrong_type
1692
+ assert_raise_message(Sass::SyntaxError, "Variable keyword arguments must be a map (was 12).") {render <<SCSS}
1693
+ @function foo($a, $b) {
1694
+ @return "a: \#{$a}, b: \#{$b}";
1695
+ }
1696
+
1697
+ .foo {
1698
+ val: foo((1, 2)..., 12...);
1699
+ }
1700
+ SCSS
1701
+ end
1702
+
1703
+ def test_function_keyword_splat_must_have_string_keys
1704
+ assert_raise_message(Sass::SyntaxError, <<MESSAGE.rstrip) {render <<SCSS}
1705
+ Variable keyword argument map must have string keys.
1706
+ 12 is not a string in (12: 1).
1707
+ MESSAGE
1708
+ @function foo($a) {
1709
+ @return $a;
1710
+ }
1711
+
1712
+ .foo {val: foo((12: 1)...)}
1130
1713
  SCSS
1131
1714
  end
1132
1715
 
@@ -1501,64 +2084,673 @@ baz {b: foo()}
1501
2084
  SCSS
1502
2085
  end
1503
2086
 
1504
- ## Errors
2087
+ ## @at-root
1505
2088
 
1506
- def test_nested_mixin_def_is_scoped
1507
- render <<SCSS
1508
- foo {
1509
- @mixin bar {a: b}}
1510
- bar {@include bar}
2089
+ def test_simple_at_root
2090
+ assert_equal <<CSS, render(<<SCSS)
2091
+ .bar {
2092
+ a: b; }
2093
+ CSS
2094
+ .foo {
2095
+ @at-root {
2096
+ .bar {a: b}
2097
+ }
2098
+ }
1511
2099
  SCSS
1512
- assert(false, "Expected syntax error")
1513
- rescue Sass::SyntaxError => e
1514
- assert_equal "Undefined mixin 'bar'.", e.message
1515
- assert_equal 3, e.sass_line
1516
2100
  end
1517
2101
 
1518
- def test_rules_beneath_properties
1519
- render <<SCSS
1520
- foo {
1521
- bar: {
1522
- baz {
1523
- bang: bop }}}
2102
+ def test_at_root_with_selector
2103
+ assert_equal <<CSS, render(<<SCSS)
2104
+ .bar {
2105
+ a: b; }
2106
+ CSS
2107
+ .foo {
2108
+ @at-root .bar {a: b}
2109
+ }
1524
2110
  SCSS
1525
- assert(false, "Expected syntax error")
1526
- rescue Sass::SyntaxError => e
1527
- assert_equal 'Illegal nesting: Only properties may be nested beneath properties.', e.message
1528
- assert_equal 3, e.sass_line
1529
2111
  end
1530
2112
 
1531
- def test_uses_property_exception_with_star_hack
1532
- render <<SCSS
1533
- foo {
1534
- *bar:baz [fail]; }
2113
+ def test_at_root_in_mixin
2114
+ assert_equal <<CSS, render(<<SCSS)
2115
+ .bar {
2116
+ a: b; }
2117
+ CSS
2118
+ @mixin bar {
2119
+ @at-root .bar {a: b}
2120
+ }
2121
+
2122
+ .foo {
2123
+ @include bar;
2124
+ }
1535
2125
  SCSS
1536
- assert(false, "Expected syntax error")
1537
- rescue Sass::SyntaxError => e
1538
- assert_equal 'Invalid CSS after " *bar:baz ": expected ";", was "[fail]; }"', e.message
1539
- assert_equal 2, e.sass_line
1540
2126
  end
1541
2127
 
1542
- def test_uses_property_exception_with_colon_hack
1543
- render <<SCSS
1544
- foo {
1545
- :bar:baz [fail]; }
2128
+ def test_at_root_in_media
2129
+ assert_equal <<CSS, render(<<SCSS)
2130
+ @media screen {
2131
+ .bar {
2132
+ a: b; } }
2133
+ CSS
2134
+ @media screen {
2135
+ .foo {
2136
+ @at-root .bar {a: b}
2137
+ }
2138
+ }
1546
2139
  SCSS
1547
- assert(false, "Expected syntax error")
1548
- rescue Sass::SyntaxError => e
1549
- assert_equal 'Invalid CSS after " :bar:baz ": expected ";", was "[fail]; }"', e.message
1550
- assert_equal 2, e.sass_line
1551
2140
  end
1552
2141
 
1553
- def test_uses_rule_exception_with_dot_hack
1554
- render <<SCSS
1555
- foo {
1556
- .bar:baz <fail>; }
2142
+ def test_at_root_in_bubbled_media
2143
+ assert_equal <<CSS, render(<<SCSS)
2144
+ @media screen {
2145
+ .bar {
2146
+ a: b; } }
2147
+ CSS
2148
+ .foo {
2149
+ @media screen {
2150
+ @at-root .bar {a: b}
2151
+ }
2152
+ }
1557
2153
  SCSS
1558
- assert(false, "Expected syntax error")
1559
- rescue Sass::SyntaxError => e
1560
- assert_equal 'Invalid CSS after " .bar:baz ": expected "{", was "<fail>; }"', e.message
1561
- assert_equal 2, e.sass_line
2154
+ end
2155
+
2156
+ def test_at_root_in_unknown_directive
2157
+ assert_equal <<CSS, render(<<SCSS)
2158
+ @fblthp {
2159
+ .bar {
2160
+ a: b; } }
2161
+ CSS
2162
+ @fblthp {
2163
+ .foo {
2164
+ @at-root .bar {a: b}
2165
+ }
2166
+ }
2167
+ SCSS
2168
+ end
2169
+
2170
+ def test_at_root_with_parent_ref
2171
+ assert_equal <<CSS, render(<<SCSS)
2172
+ .foo {
2173
+ a: b; }
2174
+ CSS
2175
+ .foo {
2176
+ @at-root & {
2177
+ a: b;
2178
+ }
2179
+ }
2180
+ SCSS
2181
+ end
2182
+
2183
+ def test_multi_level_at_root_with_parent_ref
2184
+ assert_equal <<CSS, render(<<SCSS)
2185
+ .foo .bar {
2186
+ a: b; }
2187
+ CSS
2188
+ .foo {
2189
+ @at-root & {
2190
+ .bar {
2191
+ @at-root & {
2192
+ a: b;
2193
+ }
2194
+ }
2195
+ }
2196
+ }
2197
+ SCSS
2198
+ end
2199
+
2200
+ def test_multi_level_at_root_with_inner_parent_ref
2201
+ assert_equal <<CSS, render(<<SCSS)
2202
+ .bar {
2203
+ a: b; }
2204
+ CSS
2205
+ .foo {
2206
+ @at-root .bar {
2207
+ @at-root & {
2208
+ a: b;
2209
+ }
2210
+ }
2211
+ }
2212
+ SCSS
2213
+ end
2214
+
2215
+ ## @at-root (...)
2216
+
2217
+ def test_at_root_without_media
2218
+ assert_equal <<CSS, render(<<SCSS)
2219
+ .foo .bar {
2220
+ a: b; }
2221
+ CSS
2222
+ .foo {
2223
+ @media screen {
2224
+ @at-root (without: media) {
2225
+ .bar {
2226
+ a: b;
2227
+ }
2228
+ }
2229
+ }
2230
+ }
2231
+ SCSS
2232
+ end
2233
+
2234
+ def test_at_root_without_supports
2235
+ assert_equal <<CSS, render(<<SCSS)
2236
+ .foo .bar {
2237
+ a: b; }
2238
+ CSS
2239
+ .foo {
2240
+ @supports (foo: bar) {
2241
+ @at-root (without: supports) {
2242
+ .bar {
2243
+ a: b;
2244
+ }
2245
+ }
2246
+ }
2247
+ }
2248
+ SCSS
2249
+ end
2250
+
2251
+ def test_at_root_without_rule
2252
+ assert_equal <<CSS, render(<<SCSS)
2253
+ @media screen {
2254
+ .bar {
2255
+ a: b; } }
2256
+ CSS
2257
+ .foo {
2258
+ @media screen {
2259
+ @at-root (without: rule) {
2260
+ .bar {
2261
+ a: b;
2262
+ }
2263
+ }
2264
+ }
2265
+ }
2266
+ SCSS
2267
+ end
2268
+
2269
+ def test_at_root_without_unknown_directive
2270
+ assert_equal <<CSS, render(<<SCSS)
2271
+ .foo .bar {
2272
+ a: b; }
2273
+ CSS
2274
+ .foo {
2275
+ @fblthp {
2276
+ @at-root (without: fblthp) {
2277
+ .bar {
2278
+ a: b;
2279
+ }
2280
+ }
2281
+ }
2282
+ }
2283
+ SCSS
2284
+ end
2285
+
2286
+ def test_at_root_without_multiple
2287
+ assert_equal <<CSS, render(<<SCSS)
2288
+ @supports (foo: bar) {
2289
+ .bar {
2290
+ a: b; } }
2291
+ CSS
2292
+ .foo {
2293
+ @media screen {
2294
+ @supports (foo: bar) {
2295
+ @at-root (without: media rule) {
2296
+ .bar {
2297
+ a: b;
2298
+ }
2299
+ }
2300
+ }
2301
+ }
2302
+ }
2303
+ SCSS
2304
+ end
2305
+
2306
+ def test_at_root_without_all
2307
+ assert_equal <<CSS, render(<<SCSS)
2308
+ .bar {
2309
+ a: b; }
2310
+ CSS
2311
+ .foo {
2312
+ @supports (foo: bar) {
2313
+ @fblthp {
2314
+ @at-root (without: all) {
2315
+ .bar {
2316
+ a: b;
2317
+ }
2318
+ }
2319
+ }
2320
+ }
2321
+ }
2322
+ SCSS
2323
+ end
2324
+
2325
+ def test_at_root_with_media
2326
+ assert_equal <<CSS, render(<<SCSS)
2327
+ @media screen {
2328
+ .bar {
2329
+ a: b; } }
2330
+ CSS
2331
+ .foo {
2332
+ @media screen {
2333
+ @fblthp {
2334
+ @supports (foo: bar) {
2335
+ @at-root (with: media) {
2336
+ .bar {
2337
+ a: b;
2338
+ }
2339
+ }
2340
+ }
2341
+ }
2342
+ }
2343
+ }
2344
+ SCSS
2345
+ end
2346
+
2347
+ def test_at_root_with_rule
2348
+ assert_equal <<CSS, render(<<SCSS)
2349
+ .foo .bar {
2350
+ a: b; }
2351
+ CSS
2352
+ .foo {
2353
+ @media screen {
2354
+ @fblthp {
2355
+ @supports (foo: bar) {
2356
+ @at-root (with: rule) {
2357
+ .bar {
2358
+ a: b;
2359
+ }
2360
+ }
2361
+ }
2362
+ }
2363
+ }
2364
+ }
2365
+ SCSS
2366
+ end
2367
+
2368
+ def test_at_root_with_supports
2369
+ assert_equal <<CSS, render(<<SCSS)
2370
+ @supports (foo: bar) {
2371
+ .bar {
2372
+ a: b; } }
2373
+ CSS
2374
+ .foo {
2375
+ @media screen {
2376
+ @fblthp {
2377
+ @supports (foo: bar) {
2378
+ @at-root (with: supports) {
2379
+ .bar {
2380
+ a: b;
2381
+ }
2382
+ }
2383
+ }
2384
+ }
2385
+ }
2386
+ }
2387
+ SCSS
2388
+ end
2389
+
2390
+ def test_at_root_with_unknown_directive
2391
+ assert_equal <<CSS, render(<<SCSS)
2392
+ @fblthp {
2393
+ .bar {
2394
+ a: b; } }
2395
+ CSS
2396
+ .foo {
2397
+ @media screen {
2398
+ @fblthp {
2399
+ @supports (foo: bar) {
2400
+ @at-root (with: fblthp) {
2401
+ .bar {
2402
+ a: b;
2403
+ }
2404
+ }
2405
+ }
2406
+ }
2407
+ }
2408
+ }
2409
+ SCSS
2410
+ end
2411
+
2412
+ def test_at_root_with_multiple
2413
+ assert_equal <<CSS, render(<<SCSS)
2414
+ @media screen {
2415
+ .foo .bar {
2416
+ a: b; } }
2417
+ CSS
2418
+ .foo {
2419
+ @media screen {
2420
+ @fblthp {
2421
+ @supports (foo: bar) {
2422
+ @at-root (with: media rule) {
2423
+ .bar {
2424
+ a: b;
2425
+ }
2426
+ }
2427
+ }
2428
+ }
2429
+ }
2430
+ }
2431
+ SCSS
2432
+ end
2433
+
2434
+ def test_at_root_with_all
2435
+ assert_equal <<CSS, render(<<SCSS)
2436
+ @media screen {
2437
+ @fblthp {
2438
+ @supports (foo: bar) {
2439
+ .foo .bar {
2440
+ a: b; } } } }
2441
+ CSS
2442
+ .foo {
2443
+ @media screen {
2444
+ @fblthp {
2445
+ @supports (foo: bar) {
2446
+ @at-root (with: all) {
2447
+ .bar {
2448
+ a: b;
2449
+ }
2450
+ }
2451
+ }
2452
+ }
2453
+ }
2454
+ }
2455
+ SCSS
2456
+ end
2457
+
2458
+ def test_at_root_dynamic_values
2459
+ assert_equal <<CSS, render(<<SCSS)
2460
+ @media screen {
2461
+ .bar {
2462
+ a: b; } }
2463
+ CSS
2464
+ $key: with;
2465
+ $value: media;
2466
+ .foo {
2467
+ @media screen {
2468
+ @at-root ($key: $value) {
2469
+ .bar {
2470
+ a: b;
2471
+ }
2472
+ }
2473
+ }
2474
+ }
2475
+ SCSS
2476
+ end
2477
+
2478
+ def test_at_root_interpolated_query
2479
+ assert_equal <<CSS, render(<<SCSS)
2480
+ @media screen {
2481
+ .bar {
2482
+ a: b; } }
2483
+ CSS
2484
+ .foo {
2485
+ @media screen {
2486
+ @at-root (\#{"with: media"}) {
2487
+ .bar {
2488
+ a: b;
2489
+ }
2490
+ }
2491
+ }
2492
+ }
2493
+ SCSS
2494
+ end
2495
+
2496
+ def test_at_root_plus_extend
2497
+ assert_equal <<CSS, render(<<SCSS)
2498
+ .foo .bar {
2499
+ a: b; }
2500
+ CSS
2501
+ %base {
2502
+ a: b;
2503
+ }
2504
+
2505
+ .foo {
2506
+ @media screen {
2507
+ @at-root (without: media) {
2508
+ .bar {
2509
+ @extend %base;
2510
+ }
2511
+ }
2512
+ }
2513
+ }
2514
+ SCSS
2515
+ end
2516
+
2517
+ ## Selector Script
2518
+
2519
+ def test_selector_script
2520
+ assert_equal(<<CSS, render(<<SCSS))
2521
+ .foo .bar {
2522
+ content: ".foo .bar"; }
2523
+ CSS
2524
+ .foo .bar {
2525
+ content: "\#{&}";
2526
+ }
2527
+ SCSS
2528
+ end
2529
+
2530
+ def test_nested_selector_script
2531
+ assert_equal(<<CSS, render(<<SCSS))
2532
+ .foo .bar {
2533
+ content: ".foo .bar"; }
2534
+ CSS
2535
+ .foo {
2536
+ .bar {
2537
+ content: "\#{&}";
2538
+ }
2539
+ }
2540
+ SCSS
2541
+ end
2542
+
2543
+ def test_nested_selector_script_with_outer_comma_selector
2544
+ assert_equal(<<CSS, render(<<SCSS))
2545
+ .foo .baz, .bar .baz {
2546
+ content: ".foo .baz, .bar .baz"; }
2547
+ CSS
2548
+ .foo, .bar {
2549
+ .baz {
2550
+ content: "\#{&}";
2551
+ }
2552
+ }
2553
+ SCSS
2554
+ end
2555
+
2556
+ def test_nested_selector_script_with_inner_comma_selector
2557
+ assert_equal(<<CSS, render(<<SCSS))
2558
+ .foo .bar, .foo .baz {
2559
+ content: ".foo .bar, .foo .baz"; }
2560
+ CSS
2561
+ .foo {
2562
+ .bar, .baz {
2563
+ content: "\#{&}";
2564
+ }
2565
+ }
2566
+ SCSS
2567
+ end
2568
+
2569
+ def test_selector_script_through_mixin
2570
+ assert_equal(<<CSS, render(<<SCSS))
2571
+ .foo {
2572
+ content: ".foo"; }
2573
+ CSS
2574
+ @mixin mixin {
2575
+ content: "\#{&}";
2576
+ }
2577
+
2578
+ .foo {
2579
+ @include mixin;
2580
+ }
2581
+ SCSS
2582
+ end
2583
+
2584
+ def test_selector_script_through_content
2585
+ assert_equal(<<CSS, render(<<SCSS))
2586
+ .foo {
2587
+ content: ".foo"; }
2588
+ CSS
2589
+ @mixin mixin {
2590
+ @content;
2591
+ }
2592
+
2593
+ .foo {
2594
+ @include mixin {
2595
+ content: "\#{&}";
2596
+ }
2597
+ }
2598
+ SCSS
2599
+ end
2600
+
2601
+ def test_selector_script_through_function
2602
+ assert_equal(<<CSS, render(<<SCSS))
2603
+ .foo {
2604
+ content: ".foo"; }
2605
+ CSS
2606
+ @function fn() {
2607
+ @return "\#{&}";
2608
+ }
2609
+
2610
+ .foo {
2611
+ content: fn();
2612
+ }
2613
+ SCSS
2614
+ end
2615
+
2616
+ def test_selector_script_through_media
2617
+ assert_equal(<<CSS, render(<<SCSS))
2618
+ .foo {
2619
+ content: "outer"; }
2620
+ @media screen {
2621
+ .foo .bar {
2622
+ content: ".foo .bar"; } }
2623
+ CSS
2624
+ .foo {
2625
+ content: "outer";
2626
+ @media screen {
2627
+ .bar {
2628
+ content: "\#{&}";
2629
+ }
2630
+ }
2631
+ }
2632
+ SCSS
2633
+ end
2634
+
2635
+ def test_selector_script_save_and_reuse
2636
+ assert_equal(<<CSS, render(<<SCSS))
2637
+ .bar {
2638
+ content: ".foo"; }
2639
+ CSS
2640
+ $var: null;
2641
+ .foo {
2642
+ $var: & !global;
2643
+ }
2644
+
2645
+ .bar {
2646
+ content: "\#{$var}";
2647
+ }
2648
+ SCSS
2649
+ end
2650
+
2651
+ def test_selector_script_with_at_root
2652
+ assert_equal(<<CSS, render(<<SCSS))
2653
+ .foo-bar {
2654
+ a: b; }
2655
+ CSS
2656
+ .foo {
2657
+ @at-root \#{&}-bar {
2658
+ a: b;
2659
+ }
2660
+ }
2661
+ SCSS
2662
+ end
2663
+
2664
+ def test_multi_level_at_root_with_inner_selector_script
2665
+ assert_equal <<CSS, render(<<SCSS)
2666
+ .bar {
2667
+ a: b; }
2668
+ CSS
2669
+ .foo {
2670
+ @at-root .bar {
2671
+ @at-root \#{&} {
2672
+ a: b;
2673
+ }
2674
+ }
2675
+ }
2676
+ SCSS
2677
+ end
2678
+
2679
+ def test_at_root_with_at_root_through_mixin
2680
+ assert_equal(<<CSS, render(<<SCSS))
2681
+ .bar-baz {
2682
+ a: b; }
2683
+ CSS
2684
+ @mixin foo {
2685
+ .bar {
2686
+ @at-root \#{&}-baz {
2687
+ a: b;
2688
+ }
2689
+ }
2690
+ }
2691
+
2692
+ @include foo;
2693
+ SCSS
2694
+ end
2695
+
2696
+ ## Errors
2697
+
2698
+ def test_nested_mixin_def_is_scoped
2699
+ render <<SCSS
2700
+ foo {
2701
+ @mixin bar {a: b}}
2702
+ bar {@include bar}
2703
+ SCSS
2704
+ assert(false, "Expected syntax error")
2705
+ rescue Sass::SyntaxError => e
2706
+ assert_equal "Undefined mixin 'bar'.", e.message
2707
+ assert_equal 3, e.sass_line
2708
+ end
2709
+
2710
+ def test_rules_beneath_properties
2711
+ render <<SCSS
2712
+ foo {
2713
+ bar: {
2714
+ baz {
2715
+ bang: bop }}}
2716
+ SCSS
2717
+ assert(false, "Expected syntax error")
2718
+ rescue Sass::SyntaxError => e
2719
+ assert_equal 'Illegal nesting: Only properties may be nested beneath properties.', e.message
2720
+ assert_equal 3, e.sass_line
2721
+ end
2722
+
2723
+ def test_uses_property_exception_with_star_hack
2724
+ render <<SCSS
2725
+ foo {
2726
+ *bar:baz [fail]; }
2727
+ SCSS
2728
+ assert(false, "Expected syntax error")
2729
+ rescue Sass::SyntaxError => e
2730
+ assert_equal 'Invalid CSS after " *bar:baz ": expected ";", was "[fail]; }"', e.message
2731
+ assert_equal 2, e.sass_line
2732
+ end
2733
+
2734
+ def test_uses_property_exception_with_colon_hack
2735
+ render <<SCSS
2736
+ foo {
2737
+ :bar:baz [fail]; }
2738
+ SCSS
2739
+ assert(false, "Expected syntax error")
2740
+ rescue Sass::SyntaxError => e
2741
+ assert_equal 'Invalid CSS after " :bar:baz ": expected ";", was "[fail]; }"', e.message
2742
+ assert_equal 2, e.sass_line
2743
+ end
2744
+
2745
+ def test_uses_rule_exception_with_dot_hack
2746
+ render <<SCSS
2747
+ foo {
2748
+ .bar:baz <fail>; }
2749
+ SCSS
2750
+ assert(false, "Expected syntax error")
2751
+ rescue Sass::SyntaxError => e
2752
+ assert_equal 'Invalid CSS after " .bar:baz ": expected "{", was "<fail>; }"', e.message
2753
+ assert_equal 2, e.sass_line
1562
2754
  end
1563
2755
 
1564
2756
  def test_uses_property_exception_with_space_after_name
@@ -1711,6 +2903,14 @@ SCSS
1711
2903
 
1712
2904
  # Regression
1713
2905
 
2906
+ def test_loud_comment_in_compressed_mode
2907
+ assert_equal(<<CSS, render(<<SCSS))
2908
+ /*! foo */
2909
+ CSS
2910
+ /*! foo */
2911
+ SCSS
2912
+ end
2913
+
1714
2914
  def test_parsing_decimals_followed_by_comments_doesnt_take_forever
1715
2915
  assert_equal(<<CSS, render(<<SCSS))
1716
2916
  .foo {
@@ -2010,7 +3210,7 @@ SCSS
2010
3210
  @extend .bbb;
2011
3211
  }
2012
3212
  SCSS
2013
- Sass::SCSS::Parser.new(template, "test.scss").parse
3213
+ Sass::SCSS::Parser.new(template, "test.scss", nil).parse
2014
3214
  end
2015
3215
 
2016
3216
  def test_extend_in_media_in_rule