sass 3.4.0 → 3.4.25

Sign up to get free protection for your applications and to get access to all the features.
Files changed (142) hide show
  1. checksums.yaml +4 -4
  2. data/.yardopts +3 -1
  3. data/CODE_OF_CONDUCT.md +10 -0
  4. data/CONTRIBUTING.md +148 -0
  5. data/MIT-LICENSE +1 -1
  6. data/README.md +26 -20
  7. data/Rakefile +103 -20
  8. data/VERSION +1 -1
  9. data/VERSION_DATE +1 -1
  10. data/extra/sass-spec-ref.sh +32 -0
  11. data/extra/update_watch.rb +1 -1
  12. data/lib/sass/cache_stores/filesystem.rb +7 -7
  13. data/lib/sass/cache_stores/memory.rb +4 -5
  14. data/lib/sass/callbacks.rb +2 -2
  15. data/lib/sass/css.rb +11 -10
  16. data/lib/sass/deprecation.rb +55 -0
  17. data/lib/sass/engine.rb +83 -38
  18. data/lib/sass/environment.rb +26 -2
  19. data/lib/sass/error.rb +12 -12
  20. data/lib/sass/exec/base.rb +15 -3
  21. data/lib/sass/exec/sass_convert.rb +34 -15
  22. data/lib/sass/exec/sass_scss.rb +23 -7
  23. data/lib/sass/features.rb +2 -2
  24. data/lib/sass/importers/base.rb +1 -1
  25. data/lib/sass/importers/deprecated_path.rb +51 -0
  26. data/lib/sass/importers/filesystem.rb +24 -16
  27. data/lib/sass/importers.rb +1 -0
  28. data/lib/sass/logger/base.rb +8 -2
  29. data/lib/sass/logger/delayed.rb +50 -0
  30. data/lib/sass/logger.rb +8 -3
  31. data/lib/sass/plugin/compiler.rb +42 -25
  32. data/lib/sass/plugin/configuration.rb +38 -22
  33. data/lib/sass/plugin/merb.rb +2 -2
  34. data/lib/sass/plugin/rack.rb +3 -3
  35. data/lib/sass/plugin/rails.rb +1 -1
  36. data/lib/sass/plugin/staleness_checker.rb +3 -3
  37. data/lib/sass/plugin.rb +3 -2
  38. data/lib/sass/script/css_parser.rb +2 -3
  39. data/lib/sass/script/css_variable_warning.rb +52 -0
  40. data/lib/sass/script/functions.rb +140 -73
  41. data/lib/sass/script/lexer.rb +37 -22
  42. data/lib/sass/script/parser.rb +235 -40
  43. data/lib/sass/script/tree/funcall.rb +12 -5
  44. data/lib/sass/script/tree/interpolation.rb +109 -4
  45. data/lib/sass/script/tree/list_literal.rb +31 -4
  46. data/lib/sass/script/tree/literal.rb +4 -0
  47. data/lib/sass/script/tree/node.rb +21 -3
  48. data/lib/sass/script/tree/operation.rb +54 -1
  49. data/lib/sass/script/tree/string_interpolation.rb +58 -37
  50. data/lib/sass/script/tree/variable.rb +1 -1
  51. data/lib/sass/script/value/base.rb +10 -9
  52. data/lib/sass/script/value/color.rb +42 -24
  53. data/lib/sass/script/value/helpers.rb +16 -6
  54. data/lib/sass/script/value/map.rb +1 -1
  55. data/lib/sass/script/value/number.rb +52 -19
  56. data/lib/sass/script/value/string.rb +46 -5
  57. data/lib/sass/script.rb +3 -3
  58. data/lib/sass/scss/css_parser.rb +16 -2
  59. data/lib/sass/scss/parser.rb +120 -75
  60. data/lib/sass/scss/rx.rb +9 -10
  61. data/lib/sass/scss/static_parser.rb +19 -14
  62. data/lib/sass/scss.rb +0 -2
  63. data/lib/sass/selector/abstract_sequence.rb +8 -6
  64. data/lib/sass/selector/comma_sequence.rb +25 -9
  65. data/lib/sass/selector/pseudo.rb +45 -35
  66. data/lib/sass/selector/sequence.rb +54 -18
  67. data/lib/sass/selector/simple.rb +11 -11
  68. data/lib/sass/selector/simple_sequence.rb +34 -15
  69. data/lib/sass/selector.rb +7 -10
  70. data/lib/sass/shared.rb +1 -1
  71. data/lib/sass/source/map.rb +7 -4
  72. data/lib/sass/source/position.rb +4 -4
  73. data/lib/sass/stack.rb +2 -2
  74. data/lib/sass/supports.rb +8 -10
  75. data/lib/sass/tree/comment_node.rb +1 -1
  76. data/lib/sass/tree/css_import_node.rb +9 -1
  77. data/lib/sass/tree/function_node.rb +8 -3
  78. data/lib/sass/tree/import_node.rb +6 -5
  79. data/lib/sass/tree/node.rb +5 -3
  80. data/lib/sass/tree/prop_node.rb +5 -6
  81. data/lib/sass/tree/rule_node.rb +14 -4
  82. data/lib/sass/tree/visitors/check_nesting.rb +18 -22
  83. data/lib/sass/tree/visitors/convert.rb +43 -26
  84. data/lib/sass/tree/visitors/cssize.rb +5 -1
  85. data/lib/sass/tree/visitors/deep_copy.rb +1 -1
  86. data/lib/sass/tree/visitors/extend.rb +15 -13
  87. data/lib/sass/tree/visitors/perform.rb +42 -17
  88. data/lib/sass/tree/visitors/set_options.rb +1 -1
  89. data/lib/sass/tree/visitors/to_css.rb +58 -30
  90. data/lib/sass/util/multibyte_string_scanner.rb +0 -2
  91. data/lib/sass/util/normalized_map.rb +0 -1
  92. data/lib/sass/util/subset_map.rb +1 -2
  93. data/lib/sass/util.rb +125 -68
  94. data/lib/sass/version.rb +2 -2
  95. data/lib/sass.rb +10 -3
  96. data/test/sass/compiler_test.rb +6 -2
  97. data/test/sass/conversion_test.rb +187 -53
  98. data/test/sass/css2sass_test.rb +50 -1
  99. data/test/sass/css_variable_test.rb +132 -0
  100. data/test/sass/engine_test.rb +207 -61
  101. data/test/sass/exec_test.rb +10 -0
  102. data/test/sass/extend_test.rb +101 -29
  103. data/test/sass/functions_test.rb +60 -9
  104. data/test/sass/importer_test.rb +9 -0
  105. data/test/sass/more_templates/more1.sass +10 -10
  106. data/test/sass/more_templates/more_import.sass +2 -2
  107. data/test/sass/plugin_test.rb +10 -8
  108. data/test/sass/results/script.css +3 -3
  109. data/test/sass/script_conversion_test.rb +58 -29
  110. data/test/sass/script_test.rb +430 -53
  111. data/test/sass/scss/css_test.rb +73 -7
  112. data/test/sass/scss/rx_test.rb +4 -0
  113. data/test/sass/scss/scss_test.rb +309 -4
  114. data/test/sass/source_map_test.rb +152 -74
  115. data/test/sass/superselector_test.rb +19 -0
  116. data/test/sass/templates/_partial.sass +1 -1
  117. data/test/sass/templates/basic.sass +10 -10
  118. data/test/sass/templates/bork1.sass +1 -1
  119. data/test/sass/templates/bork5.sass +1 -1
  120. data/test/sass/templates/compact.sass +10 -10
  121. data/test/sass/templates/complex.sass +187 -187
  122. data/test/sass/templates/compressed.sass +10 -10
  123. data/test/sass/templates/expanded.sass +10 -10
  124. data/test/sass/templates/import.sass +2 -2
  125. data/test/sass/templates/importee.sass +3 -3
  126. data/test/sass/templates/mixins.sass +22 -22
  127. data/test/sass/templates/multiline.sass +4 -4
  128. data/test/sass/templates/nested.sass +13 -13
  129. data/test/sass/templates/parent_ref.sass +12 -12
  130. data/test/sass/templates/script.sass +70 -70
  131. data/test/sass/templates/subdir/nested_subdir/_nested_partial.sass +1 -1
  132. data/test/sass/templates/subdir/nested_subdir/nested_subdir.sass +2 -2
  133. data/test/sass/templates/subdir/subdir.sass +3 -3
  134. data/test/sass/templates/units.sass +10 -10
  135. data/test/sass/util/multibyte_string_scanner_test.rb +10 -2
  136. data/test/sass/util_test.rb +15 -44
  137. data/test/sass-spec.yml +3 -0
  138. data/test/test_helper.rb +5 -4
  139. metadata +302 -295
  140. data/CONTRIBUTING +0 -3
  141. data/lib/sass/scss/script_lexer.rb +0 -15
  142. data/lib/sass/scss/script_parser.rb +0 -25
@@ -123,7 +123,7 @@ module Sass::Script
123
123
  # : Inserts `$insert` into `$string` at `$index`.
124
124
  #
125
125
  # \{#str_index str-index($string, $substring)}
126
- # : Returns the index of the first occurance of `$substring` in `$string`.
126
+ # : Returns the index of the first occurrence of `$substring` in `$string`.
127
127
  #
128
128
  # \{#str_slice str-slice($string, $start-at, [$end-at])}
129
129
  # : Extracts a substring from `$string`.
@@ -162,6 +162,9 @@ module Sass::Script
162
162
  #
163
163
  # ## List Functions {#list-functions}
164
164
  #
165
+ # Lists in Sass are immutable; all list functions return a new list rather
166
+ # than updating the existing list in-place.
167
+ #
165
168
  # All list functions work for maps as well, treating them as lists of pairs.
166
169
  #
167
170
  # \{#length length($list)}
@@ -170,6 +173,9 @@ module Sass::Script
170
173
  # \{#nth nth($list, $n)}
171
174
  # : Returns a specific item in a list.
172
175
  #
176
+ # \{#set-nth set-nth($list, $n, $value)}
177
+ # : Replaces the nth item in a list.
178
+ #
173
179
  # \{#join join($list1, $list2, \[$separator\])}
174
180
  # : Joins together two lists into one.
175
181
  #
@@ -182,11 +188,14 @@ module Sass::Script
182
188
  # \{#index index($list, $value)}
183
189
  # : Returns the position of a value within a list.
184
190
  #
185
- # \{#list_separator list-separator(#list)}
191
+ # \{#list_separator list-separator($list)}
186
192
  # : Returns the separator of a list.
187
193
  #
188
194
  # ## Map Functions {#map-functions}
189
195
  #
196
+ # Maps in Sass are immutable; all map functions return a new map rather than
197
+ # updating the existing map in-place.
198
+ #
190
199
  # \{#map_get map-get($map, $key)}
191
200
  # : Returns the value in a map associated with a given key.
192
201
  #
@@ -214,7 +223,7 @@ module Sass::Script
214
223
  # for selector arguments. They can take a plain string, a list of
215
224
  # lists as returned by `&` or anything in between:
216
225
  #
217
- # * A plain sring, such as `".foo .bar, .baz .bang"`.
226
+ # * A plain string, such as `".foo .bar, .baz .bang"`.
218
227
  # * A space-separated list of strings such as `(".foo" ".bar")`.
219
228
  # * A comma-separated list of strings such as `(".foo .bar", ".baz .bang")`.
220
229
  # * A comma-separated list of space-separated lists of strings such
@@ -347,6 +356,7 @@ module Sass::Script
347
356
  #
348
357
  # @comment
349
358
  # rubocop:enable LineLength
359
+ # rubocop:disable ModuleLength
350
360
  module Functions
351
361
  @signatures = {}
352
362
 
@@ -421,8 +431,8 @@ module Sass::Script
421
431
  # If no signatures match, the first signature is returned for error messaging.
422
432
  #
423
433
  # @param method_name [Symbol] The name of the Ruby function to be called.
424
- # @param arg_arity [Fixnum] The number of unnamed arguments the function was passed.
425
- # @param kwarg_arity [Fixnum] The number of keyword arguments the function was passed.
434
+ # @param arg_arity [Integer] The number of unnamed arguments the function was passed.
435
+ # @param kwarg_arity [Integer] The number of keyword arguments the function was passed.
426
436
  #
427
437
  # @return [{Symbol => Object}, nil]
428
438
  # The signature options for the matching signature,
@@ -445,8 +455,8 @@ module Sass::Script
445
455
  t_arg_arity = sig_arity
446
456
  end
447
457
 
448
- if (t_arg_arity == sig_arity || t_arg_arity > sig_arity && signature.var_args) &&
449
- (t_kwarg_arity == 0 || t_kwarg_arity > 0 && signature.var_kwargs)
458
+ if (t_arg_arity == sig_arity || t_arg_arity > sig_arity && signature.var_args) &&
459
+ (t_kwarg_arity == 0 || t_kwarg_arity > 0 && signature.var_kwargs)
450
460
  return signature
451
461
  end
452
462
  end
@@ -479,8 +489,7 @@ module Sass::Script
479
489
  include Value::Helpers
480
490
 
481
491
  # The human-readable names for [Sass::Script::Value::Base]. The default is
482
- # just the downcased name of the type. The default is the downcased type
483
- # name.
492
+ # just the downcased name of the type.
484
493
  TYPE_NAMES = {:ArgList => 'variable argument list'}
485
494
 
486
495
  # The environment for this function. This environment's
@@ -518,10 +527,14 @@ module Sass::Script
518
527
  # @raise [ArgumentError] if value is not of the correct type.
519
528
  def assert_type(value, type, name = nil)
520
529
  klass = Sass::Script::Value.const_get(type)
521
- return if value.is_a?(klass)
530
+ if value.is_a?(klass)
531
+ value.check_deprecated_interp if type == :String
532
+ return
533
+ end
534
+
522
535
  return if value.is_a?(Sass::Script::Value::List) && type == :Map && value.value.empty?
523
536
  err = "#{value.inspect} is not a #{TYPE_NAMES[type] || type.to_s.downcase}"
524
- err = "$#{name.to_s.gsub('_', '-')}: " + err if name
537
+ err = "$#{name.to_s.tr('_', '-')}: " + err if name
525
538
  raise ArgumentError.new(err)
526
539
  end
527
540
 
@@ -622,11 +635,14 @@ module Sass::Script
622
635
  # @return [Sass::Script::Value::Color]
623
636
  # @raise [ArgumentError] if any parameter is the wrong type or out of bounds
624
637
  def rgb(red, green, blue)
638
+ if calc?(red) || calc?(green) || calc?(blue)
639
+ return unquoted_string("rgb(#{red}, #{green}, #{blue})")
640
+ end
625
641
  assert_type red, :Number, :red
626
642
  assert_type green, :Number, :green
627
643
  assert_type blue, :Number, :blue
628
644
 
629
- color_attrs = [[red, :red], [green, :green], [blue, :blue]].map do |(c, name)|
645
+ color_attrs = [red, green, blue].map do |c|
630
646
  if c.is_unit?("%")
631
647
  c.value * 255 / 100.0
632
648
  elsif c.unitless?
@@ -649,11 +665,11 @@ module Sass::Script
649
665
  #
650
666
  # @overload rgba($red, $green, $blue, $alpha)
651
667
  # @param $red [Sass::Script::Value::Number] The amount of red in the
652
- # color. Must be between 0 and 255 inclusive
668
+ # color. Must be between 0 and 255 inclusive or 0% and 100% inclusive
653
669
  # @param $green [Sass::Script::Value::Number] The amount of green in the
654
- # color. Must be between 0 and 255 inclusive
670
+ # color. Must be between 0 and 255 inclusive or 0% and 100% inclusive
655
671
  # @param $blue [Sass::Script::Value::Number] The amount of blue in the
656
- # color. Must be between 0 and 255 inclusive
672
+ # color. Must be between 0 and 255 inclusive or 0% and 100% inclusive
657
673
  # @param $alpha [Sass::Script::Value::Number] The opacity of the color.
658
674
  # Must be between 0 and 1 inclusive
659
675
  # @return [Sass::Script::Value::Color]
@@ -680,12 +696,20 @@ module Sass::Script
680
696
  color, alpha = args
681
697
 
682
698
  assert_type color, :Color, :color
683
- assert_type alpha, :Number, :alpha
684
-
685
- color.with(:alpha => alpha.value)
699
+ if calc?(alpha)
700
+ unquoted_string("rgba(#{color.red}, #{color.green}, #{color.blue}, #{alpha})")
701
+ else
702
+ assert_type alpha, :Number, :alpha
703
+ check_alpha_unit alpha, 'rgba'
704
+ color.with(:alpha => alpha.value)
705
+ end
686
706
  when 4
687
707
  red, green, blue, alpha = args
688
- rgba(rgb(red, green, blue), alpha)
708
+ if calc?(red) || calc?(green) || calc?(blue) || calc?(alpha)
709
+ unquoted_string("rgba(#{red}, #{green}, #{blue}, #{alpha})")
710
+ else
711
+ rgba(rgb(red, green, blue), alpha)
712
+ end
689
713
  else
690
714
  raise ArgumentError.new("wrong number of arguments (#{args.size} for 4)")
691
715
  end
@@ -710,7 +734,11 @@ module Sass::Script
710
734
  # @raise [ArgumentError] if `$saturation` or `$lightness` are out of bounds
711
735
  # or any parameter is the wrong type
712
736
  def hsl(hue, saturation, lightness)
713
- hsla(hue, saturation, lightness, number(1))
737
+ if calc?(hue) || calc?(saturation) || calc?(lightness)
738
+ unquoted_string("hsl(#{hue}, #{saturation}, #{lightness})")
739
+ else
740
+ hsla(hue, saturation, lightness, number(1))
741
+ end
714
742
  end
715
743
  declare :hsl, [:hue, :saturation, :lightness]
716
744
 
@@ -734,10 +762,14 @@ module Sass::Script
734
762
  # @raise [ArgumentError] if `$saturation`, `$lightness`, or `$alpha` are out
735
763
  # of bounds or any parameter is the wrong type
736
764
  def hsla(hue, saturation, lightness, alpha)
765
+ if calc?(hue) || calc?(saturation) || calc?(lightness) || calc?(alpha)
766
+ return unquoted_string("hsla(#{hue}, #{saturation}, #{lightness}, #{alpha})")
767
+ end
737
768
  assert_type hue, :Number, :hue
738
769
  assert_type saturation, :Number, :saturation
739
770
  assert_type lightness, :Number, :lightness
740
771
  assert_type alpha, :Number, :alpha
772
+ check_alpha_unit alpha, 'hsla'
741
773
 
742
774
  h = hue.value
743
775
  s = saturation.value
@@ -869,7 +901,7 @@ module Sass::Script
869
901
  a.value =~ /^[a-zA-Z]+\s*=/
870
902
  end
871
903
  # Support the proprietary MS alpha() function
872
- return identifier("alpha(#{args.map {|a| a.to_s}.join(", ")})")
904
+ return identifier("alpha(#{args.map {|a| a.to_s}.join(', ')})")
873
905
  end
874
906
 
875
907
  raise ArgumentError.new("wrong number of arguments (#{args.size} for 1)") if args.size != 1
@@ -1053,7 +1085,7 @@ module Sass::Script
1053
1085
  # @raise [ArgumentError] if `$color` isn't a color
1054
1086
  def ie_hex_str(color)
1055
1087
  assert_type color, :Color, :color
1056
- alpha = (color.alpha * 255).round.to_s(16).rjust(2, '0')
1088
+ alpha = Sass::Util.round(color.alpha * 255).to_s(16).rjust(2, '0')
1057
1089
  identifier("##{alpha}#{color.send(:hex_str)[1..-1]}".upcase)
1058
1090
  end
1059
1091
  declare :ie_hex_str, [:color]
@@ -1071,11 +1103,7 @@ module Sass::Script
1071
1103
  # adjust-color(#102030, $blue: 5) => #102035
1072
1104
  # adjust-color(#102030, $red: -5, $blue: 5) => #0b2035
1073
1105
  # adjust-color(hsl(25, 100%, 80%), $lightness: -30%, $alpha: -0.4) => hsla(25, 100%, 50%, 0.6)
1074
- # @comment
1075
- # rubocop:disable LineLength
1076
1106
  # @overload adjust_color($color, [$red], [$green], [$blue], [$hue], [$saturation], [$lightness], [$alpha])
1077
- # @comment
1078
- # rubocop:disable LineLength
1079
1107
  # @param $color [Sass::Script::Value::Color]
1080
1108
  # @param $red [Sass::Script::Value::Number] The adjustment to make on the
1081
1109
  # red component, between -255 and 255 inclusive
@@ -1098,15 +1126,14 @@ module Sass::Script
1098
1126
  def adjust_color(color, kwargs)
1099
1127
  assert_type color, :Color, :color
1100
1128
  with = Sass::Util.map_hash(
1101
- "red" => [-255..255, ""],
1102
- "green" => [-255..255, ""],
1103
- "blue" => [-255..255, ""],
1104
- "hue" => nil,
1105
- "saturation" => [-100..100, "%"],
1106
- "lightness" => [-100..100, "%"],
1107
- "alpha" => [-1..1, ""]
1108
- ) do |name, (range, units)|
1109
-
1129
+ "red" => [-255..255, ""],
1130
+ "green" => [-255..255, ""],
1131
+ "blue" => [-255..255, ""],
1132
+ "hue" => nil,
1133
+ "saturation" => [-100..100, "%"],
1134
+ "lightness" => [-100..100, "%"],
1135
+ "alpha" => [-1..1, ""]
1136
+ ) do |name, (range, units)|
1110
1137
  val = kwargs.delete(name)
1111
1138
  next unless val
1112
1139
  assert_type val, :Number, name
@@ -1152,11 +1179,7 @@ module Sass::Script
1152
1179
  # scale-color(hsl(120, 70%, 80%), $lightness: 50%) => hsl(120, 70%, 90%)
1153
1180
  # scale-color(rgb(200, 150%, 170%), $green: -40%, $blue: 70%) => rgb(200, 90, 229)
1154
1181
  # scale-color(hsl(200, 70%, 80%), $saturation: -90%, $alpha: -30%) => hsla(200, 7%, 80%, 0.7)
1155
- # @comment
1156
- # rubocop:disable LineLength
1157
1182
  # @overload scale_color($color, [$red], [$green], [$blue], [$saturation], [$lightness], [$alpha])
1158
- # @comment
1159
- # rubocop:disable LineLength
1160
1183
  # @param $color [Sass::Script::Value::Color]
1161
1184
  # @param $red [Sass::Script::Value::Number]
1162
1185
  # @param $green [Sass::Script::Value::Number]
@@ -1171,14 +1194,13 @@ module Sass::Script
1171
1194
  def scale_color(color, kwargs)
1172
1195
  assert_type color, :Color, :color
1173
1196
  with = Sass::Util.map_hash(
1174
- "red" => 255,
1175
- "green" => 255,
1176
- "blue" => 255,
1177
- "saturation" => 100,
1178
- "lightness" => 100,
1179
- "alpha" => 1
1180
- ) do |name, max|
1181
-
1197
+ "red" => 255,
1198
+ "green" => 255,
1199
+ "blue" => 255,
1200
+ "saturation" => 100,
1201
+ "lightness" => 100,
1202
+ "alpha" => 1
1203
+ ) do |name, max|
1182
1204
  val = kwargs.delete(name)
1183
1205
  next unless val
1184
1206
  assert_type val, :Number, name
@@ -1213,11 +1235,7 @@ module Sass::Script
1213
1235
  # change-color(#102030, $blue: 5) => #102005
1214
1236
  # change-color(#102030, $red: 120, $blue: 5) => #782005
1215
1237
  # change-color(hsl(25, 100%, 80%), $lightness: 40%, $alpha: 0.8) => hsla(25, 100%, 40%, 0.8)
1216
- # @comment
1217
- # rubocop:disable LineLength
1218
1238
  # @overload change_color($color, [$red], [$green], [$blue], [$hue], [$saturation], [$lightness], [$alpha])
1219
- # @comment
1220
- # rubocop:disable LineLength
1221
1239
  # @param $color [Sass::Script::Value::Color]
1222
1240
  # @param $red [Sass::Script::Value::Number] The new red component for the
1223
1241
  # color, within 0 and 255 inclusive
@@ -1287,7 +1305,7 @@ module Sass::Script
1287
1305
  # @param $color1 [Sass::Script::Value::Color]
1288
1306
  # @param $color2 [Sass::Script::Value::Color]
1289
1307
  # @param $weight [Sass::Script::Value::Number] The relative weight of each
1290
- # color. Closer to `0%` gives more weight to `$color`, closer to `100%`
1308
+ # color. Closer to `100%` gives more weight to `$color1`, closer to `0%`
1291
1309
  # gives more weight to `$color2`
1292
1310
  # @return [Sass::Script::Value::Color]
1293
1311
  # @raise [ArgumentError] if `$weight` is out of bounds or any parameter is
@@ -1393,11 +1411,27 @@ module Sass::Script
1393
1411
  # @return [Sass::Script::Value::String]
1394
1412
  # @raise [ArgumentError] if `$string` isn't a string
1395
1413
  def unquote(string)
1396
- if string.is_a?(Sass::Script::Value::String) && string.type != :identifier
1397
- identifier(string.value)
1398
- else
1399
- string
1414
+ unless string.is_a?(Sass::Script::Value::String)
1415
+ # Don't warn multiple times for the same source line.
1416
+ # rubocop:disable GlobalVars
1417
+ $_sass_warned_for_unquote ||= Set.new
1418
+ frame = environment.stack.frames.last
1419
+ key = [frame.filename, frame.line] if frame
1420
+ return string if frame && $_sass_warned_for_unquote.include?(key)
1421
+ $_sass_warned_for_unquote << key if frame
1422
+ # rubocop:enable GlobalVars
1423
+
1424
+ Sass::Util.sass_warn(<<MESSAGE.strip)
1425
+ DEPRECATION WARNING: Passing #{string.to_sass}, a non-string value, to unquote()
1426
+ will be an error in future versions of Sass.
1427
+ #{environment.stack.to_s.gsub(/^/, ' ' * 8)}
1428
+ MESSAGE
1429
+ return string
1400
1430
  end
1431
+
1432
+ string.check_deprecated_interp
1433
+ return string if string.type == :identifier
1434
+ identifier(string.value)
1401
1435
  end
1402
1436
  declare :unquote, [:string]
1403
1437
 
@@ -1461,10 +1495,10 @@ module Sass::Script
1461
1495
  assert_type insert, :String, :insert
1462
1496
  assert_integer index, :index
1463
1497
  assert_unit index, nil, :index
1464
- insertion_point = if index.value > 0
1465
- [index.value - 1, original.value.size].min
1498
+ insertion_point = if index.to_i > 0
1499
+ [index.to_i - 1, original.value.size].min
1466
1500
  else
1467
- [index.value, -original.value.size - 1].max
1501
+ [index.to_i, -original.value.size - 1].max
1468
1502
  end
1469
1503
  result = original.value.dup.insert(insertion_point, insert.value)
1470
1504
  Sass::Script::Value::String.new(result, original.type)
@@ -1512,7 +1546,7 @@ module Sass::Script
1512
1546
  # @param $start-at [Sass::Script::Value::Number] The index of the first
1513
1547
  # character of the substring. If this is negative, it counts from the end
1514
1548
  # of `$string`
1515
- # @param $end-before [Sass::Script::Value::Number] The index of the last
1549
+ # @param $end-at [Sass::Script::Value::Number] The index of the last
1516
1550
  # character of the substring. If this is negative, it counts from the end
1517
1551
  # of `$string`. Defaults to -1
1518
1552
  # @return [Sass::Script::Value::String] The substring. This will be quoted
@@ -1531,7 +1565,7 @@ module Sass::Script
1531
1565
  s = string.value.length + s if s < 0
1532
1566
  s = 0 if s < 0
1533
1567
  e = string.value.length + e if e < 0
1534
- e = 0 if s < 0
1568
+ return Sass::Script::Value::String.new("", string.type) if e < 0
1535
1569
  extracted = string.value.slice(s..e)
1536
1570
  Sass::Script::Value::String.new(extracted || "", string.type)
1537
1571
  end
@@ -1549,7 +1583,7 @@ module Sass::Script
1549
1583
  # @raise [ArgumentError] if `$string` isn't a string
1550
1584
  def to_upper_case(string)
1551
1585
  assert_type string, :String, :string
1552
- Sass::Script::Value::String.new(string.value.upcase, string.type)
1586
+ Sass::Script::Value::String.new(Sass::Util.upcase(string.value), string.type)
1553
1587
  end
1554
1588
  declare :to_upper_case, [:string]
1555
1589
 
@@ -1564,7 +1598,7 @@ module Sass::Script
1564
1598
  # @raise [ArgumentError] if `$string` isn't a string
1565
1599
  def to_lower_case(string)
1566
1600
  assert_type string, :String, :string
1567
- Sass::Script::Value::String.new(string.value.downcase, string.type)
1601
+ Sass::Script::Value::String.new(Sass::Util.downcase(string.value), string.type)
1568
1602
  end
1569
1603
  declare :to_lower_case, [:string]
1570
1604
 
@@ -1577,11 +1611,13 @@ module Sass::Script
1577
1611
  # type-of(true) => bool
1578
1612
  # type-of(#fff) => color
1579
1613
  # type-of(blue) => color
1614
+ # type-of(null) => null
1580
1615
  # @overload type_of($value)
1581
1616
  # @param $value [Sass::Script::Value::Base] The value to inspect
1582
1617
  # @return [Sass::Script::Value::String] The unquoted string name of the
1583
1618
  # value's type
1584
1619
  def type_of(value)
1620
+ value.check_deprecated_interp if value.is_a?(Sass::Script::Value::String)
1585
1621
  identifier(value.class.name.gsub(/Sass::Script::Value::/, '').downcase)
1586
1622
  end
1587
1623
  declare :type_of, [:value]
@@ -1697,7 +1733,7 @@ module Sass::Script
1697
1733
  # @return [Sass::Script::Value::Number]
1698
1734
  # @raise [ArgumentError] if `$number` isn't a number
1699
1735
  def round(number)
1700
- numeric_transformation(number) {|n| n.round}
1736
+ numeric_transformation(number) {|n| Sass::Util.round(n)}
1701
1737
  end
1702
1738
  declare :round, [:number]
1703
1739
 
@@ -1860,6 +1896,9 @@ module Sass::Script
1860
1896
  # list. If both lists have fewer than two items, spaces are used for the
1861
1897
  # resulting list.
1862
1898
  #
1899
+ # Like all list functions, `join()` returns a new list rather than modifying
1900
+ # its arguments in place.
1901
+ #
1863
1902
  # @example
1864
1903
  # join(10px 20px, 30px 40px) => 10px 20px 30px 40px
1865
1904
  # join((blue, red), (#abc, #def)) => blue, red, #abc, #def
@@ -1875,7 +1914,7 @@ module Sass::Script
1875
1914
  # @return [Sass::Script::Value::List]
1876
1915
  def join(list1, list2, separator = identifier("auto"))
1877
1916
  assert_type separator, :String, :separator
1878
- unless %w[auto space comma].include?(separator.value)
1917
+ unless %w(auto space comma).include?(separator.value)
1879
1918
  raise ArgumentError.new("Separator name must be space, comma, or auto")
1880
1919
  end
1881
1920
  sep = if separator.value == 'auto'
@@ -1893,6 +1932,9 @@ module Sass::Script
1893
1932
  # Unless the `$separator` argument is passed, if the list had only one item,
1894
1933
  # the resulting list will be space-separated.
1895
1934
  #
1935
+ # Like all list functions, `append()` returns a new list rather than
1936
+ # modifying its argument in place.
1937
+ #
1896
1938
  # @example
1897
1939
  # append(10px 20px, 30px) => 10px 20px 30px
1898
1940
  # append((blue, red), green) => blue, red, green
@@ -1908,7 +1950,7 @@ module Sass::Script
1908
1950
  # @return [Sass::Script::Value::List]
1909
1951
  def append(list, val, separator = identifier("auto"))
1910
1952
  assert_type separator, :String, :separator
1911
- unless %w[auto space comma].include?(separator.value)
1953
+ unless %w(auto space comma).include?(separator.value)
1912
1954
  raise ArgumentError.new("Separator name must be space, comma, or auto")
1913
1955
  end
1914
1956
  sep = if separator.value == 'auto'
@@ -2016,6 +2058,9 @@ module Sass::Script
2016
2058
  # same order as in `$map1`. New keys from `$map2` will be placed at the end
2017
2059
  # of the map.
2018
2060
  #
2061
+ # Like all map functions, `map-merge()` returns a new map rather than
2062
+ # modifying its arguments in place.
2063
+ #
2019
2064
  # @example
2020
2065
  # map-merge(("foo": 1), ("bar": 2)) => ("foo": 1, "bar": 2)
2021
2066
  # map-merge(("foo": 1, "bar": 2), ("bar": 3)) => ("foo": 1, "bar": 3)
@@ -2033,6 +2078,9 @@ module Sass::Script
2033
2078
 
2034
2079
  # Returns a new map with keys removed.
2035
2080
  #
2081
+ # Like all map functions, `map-merge()` returns a new map rather than
2082
+ # modifying its arguments in place.
2083
+ #
2036
2084
  # @example
2037
2085
  # map-remove(("foo": 1, "bar": 2), "bar") => ("foo": 1)
2038
2086
  # map-remove(("foo": 1, "bar": 2, "baz": 3), "bar", "baz") => ("foo": 1)
@@ -2216,6 +2264,7 @@ module Sass::Script
2216
2264
  # @example
2217
2265
  # $a-false-value: false;
2218
2266
  # variable-exists(a-false-value) => true
2267
+ # variable-exists(a-null-value) => true
2219
2268
  #
2220
2269
  # variable-exists(nonexistent) => false
2221
2270
  #
@@ -2236,6 +2285,7 @@ module Sass::Script
2236
2285
  # @example
2237
2286
  # $a-false-value: false;
2238
2287
  # global-variable-exists(a-false-value) => true
2288
+ # global-variable-exists(a-null-value) => true
2239
2289
  #
2240
2290
  # .foo {
2241
2291
  # $some-var: false;
@@ -2298,6 +2348,7 @@ module Sass::Script
2298
2348
  # @return [Sass::Script::Value::String] A representation of the value as
2299
2349
  # it would be written in Sass.
2300
2350
  def inspect(value)
2351
+ value.check_deprecated_interp if value.is_a?(Sass::Script::Value::String)
2301
2352
  unquoted_string(value.to_sass)
2302
2353
  end
2303
2354
  declare :inspect, [:value]
@@ -2306,7 +2357,7 @@ module Sass::Script
2306
2357
  # Return a decimal between 0 and 1, inclusive of 0 but not 1.
2307
2358
  # @return [Sass::Script::Value::Number] A decimal value.
2308
2359
  # @overload random($limit)
2309
- # Return an integer between 1 and `$limit`, inclusive of 1 but not `$limit`.
2360
+ # Return an integer between 1 and `$limit`, inclusive of both 1 and `$limit`.
2310
2361
  # @param $limit [Sass::Script::Value::Number] The maximum of the random integer to be
2311
2362
  # returned, a positive integer.
2312
2363
  # @return [Sass::Script::Value::Number] An integer.
@@ -2315,10 +2366,10 @@ module Sass::Script
2315
2366
  generator = Sass::Script::Functions.random_number_generator
2316
2367
  if limit
2317
2368
  assert_integer limit, "limit"
2318
- if limit.value < 1
2369
+ if limit.to_i < 1
2319
2370
  raise ArgumentError.new("$limit #{limit} must be greater than or equal to 1")
2320
2371
  end
2321
- number(1 + generator.rand(limit.value))
2372
+ number(1 + generator.rand(limit.to_i))
2322
2373
  else
2323
2374
  number(generator.rand)
2324
2375
  end
@@ -2371,7 +2422,7 @@ module Sass::Script
2371
2422
  end
2372
2423
 
2373
2424
  parsed = [parse_selector(selectors.first, :selectors)]
2374
- parsed += selectors[1..-1].map {|sel| parse_selector(sel, :selectors, !!:parse_parent_ref)}
2425
+ parsed += selectors[1..-1].map {|sel| parse_selector(sel, :selectors, true)}
2375
2426
  parsed.inject {|result, child| child.resolve_parent_refs(result)}.to_sass_script
2376
2427
  end
2377
2428
  declare :selector_nest, [], :var_args => true
@@ -2459,7 +2510,7 @@ module Sass::Script
2459
2510
 
2460
2511
  extends = Sass::Util::SubsetMap.new
2461
2512
  begin
2462
- extender.populate_extends(extends, extendee)
2513
+ extender.populate_extends(extends, extendee, nil, [], true)
2463
2514
  selector.do_extend(extends).to_sass_script
2464
2515
  rescue Sass::SyntaxError => e
2465
2516
  raise ArgumentError.new(e.to_s)
@@ -2502,8 +2553,8 @@ module Sass::Script
2502
2553
 
2503
2554
  extends = Sass::Util::SubsetMap.new
2504
2555
  begin
2505
- replacement.populate_extends(extends, original)
2506
- selector.do_extend(extends, [], !!:replace).to_sass_script
2556
+ replacement.populate_extends(extends, original, nil, [], true)
2557
+ selector.do_extend(extends, [], true).to_sass_script
2507
2558
  rescue Sass::SyntaxError => e
2508
2559
  raise ArgumentError.new(e.to_s)
2509
2560
  end
@@ -2622,5 +2673,21 @@ module Sass::Script
2622
2673
 
2623
2674
  color.with(attr => color.send(attr).send(op, amount.value))
2624
2675
  end
2676
+
2677
+ def check_alpha_unit(alpha, function)
2678
+ return if alpha.unitless?
2679
+
2680
+ if alpha.is_unit?("%")
2681
+ Sass::Util.sass_warn(<<WARNING)
2682
+ DEPRECATION WARNING: Passing a percentage as the alpha value to #{function}() will be
2683
+ interpreted differently in future versions of Sass. For now, use #{alpha.value} instead.
2684
+ WARNING
2685
+ else
2686
+ Sass::Util.sass_warn(<<WARNING)
2687
+ DEPRECATION WARNING: Passing a number with units as the alpha value to #{function}() is
2688
+ deprecated and will be an error in future versions of Sass. Use #{alpha.value} instead.
2689
+ WARNING
2690
+ end
2691
+ end
2625
2692
  end
2626
2693
  end