sass 3.4.0 → 3.4.25

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 (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