sass 3.4.25 → 3.5.0

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 (135) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/Rakefile +2 -117
  4. data/VERSION +1 -1
  5. data/VERSION_DATE +1 -1
  6. data/VERSION_NAME +1 -1
  7. data/lib/sass/cache_stores/filesystem.rb +1 -1
  8. data/lib/sass/css.rb +1 -2
  9. data/lib/sass/engine.rb +38 -20
  10. data/lib/sass/environment.rb +26 -5
  11. data/lib/sass/error.rb +2 -2
  12. data/lib/sass/exec/base.rb +2 -11
  13. data/lib/sass/features.rb +1 -0
  14. data/lib/sass/importers/filesystem.rb +2 -2
  15. data/lib/sass/plugin/compiler.rb +20 -50
  16. data/lib/sass/plugin/configuration.rb +2 -2
  17. data/lib/sass/railtie.rb +1 -1
  18. data/lib/sass/script/functions.rb +235 -43
  19. data/lib/sass/script/lexer.rb +13 -2
  20. data/lib/sass/script/parser.rb +69 -67
  21. data/lib/sass/script/tree/funcall.rb +35 -30
  22. data/lib/sass/script/tree/list_literal.rb +23 -8
  23. data/lib/sass/script/tree/map_literal.rb +2 -2
  24. data/lib/sass/script/tree/node.rb +0 -8
  25. data/lib/sass/script/tree/operation.rb +0 -7
  26. data/lib/sass/script/value/arg_list.rb +1 -1
  27. data/lib/sass/script/value/base.rb +17 -0
  28. data/lib/sass/script/value/callable.rb +25 -0
  29. data/lib/sass/script/value/color.rb +5 -0
  30. data/lib/sass/script/value/function.rb +19 -0
  31. data/lib/sass/script/value/helpers.rb +29 -9
  32. data/lib/sass/script/value/list.rb +35 -14
  33. data/lib/sass/script/value/map.rb +2 -2
  34. data/lib/sass/script/value/number.rb +1 -1
  35. data/lib/sass/script/value.rb +2 -0
  36. data/lib/sass/scss/parser.rb +99 -40
  37. data/lib/sass/scss/rx.rb +4 -10
  38. data/lib/sass/scss/static_parser.rb +5 -24
  39. data/lib/sass/selector/abstract_sequence.rb +7 -6
  40. data/lib/sass/selector/comma_sequence.rb +7 -4
  41. data/lib/sass/selector/pseudo.rb +19 -2
  42. data/lib/sass/selector/sequence.rb +35 -6
  43. data/lib/sass/selector/simple.rb +9 -2
  44. data/lib/sass/selector/simple_sequence.rb +8 -4
  45. data/lib/sass/selector.rb +4 -0
  46. data/lib/sass/source/map.rb +2 -2
  47. data/lib/sass/stack.rb +21 -1
  48. data/lib/sass/tree/charset_node.rb +1 -1
  49. data/lib/sass/tree/prop_node.rb +45 -53
  50. data/lib/sass/tree/rule_node.rb +3 -2
  51. data/lib/sass/tree/visitors/check_nesting.rb +1 -1
  52. data/lib/sass/tree/visitors/convert.rb +2 -3
  53. data/lib/sass/tree/visitors/cssize.rb +4 -15
  54. data/lib/sass/tree/visitors/deep_copy.rb +1 -1
  55. data/lib/sass/tree/visitors/extend.rb +2 -8
  56. data/lib/sass/tree/visitors/perform.rb +21 -9
  57. data/lib/sass/tree/visitors/set_options.rb +1 -1
  58. data/lib/sass/tree/visitors/to_css.rb +47 -13
  59. data/lib/sass/util/multibyte_string_scanner.rb +127 -131
  60. data/lib/sass/util/normalized_map.rb +1 -8
  61. data/lib/sass/util.rb +12 -290
  62. data/lib/sass/version.rb +0 -2
  63. data/lib/sass.rb +0 -7
  64. data/test/sass/cache_test.rb +0 -1
  65. data/test/sass/callbacks_test.rb +0 -1
  66. data/test/sass/compiler_test.rb +4 -15
  67. data/test/sass/conversion_test.rb +113 -163
  68. data/test/sass/css2sass_test.rb +16 -19
  69. data/test/sass/css_variable_test.rb +176 -71
  70. data/test/sass/encoding_test.rb +2 -33
  71. data/test/sass/engine_test.rb +71 -19
  72. data/test/sass/exec_test.rb +0 -1
  73. data/test/sass/extend_test.rb +37 -92
  74. data/test/sass/functions_test.rb +58 -14
  75. data/test/sass/importer_test.rb +2 -3
  76. data/test/sass/logger_test.rb +0 -1
  77. data/test/sass/plugin_test.rb +6 -10
  78. data/test/sass/results/script.css +1 -1
  79. data/test/sass/results/units.css +2 -2
  80. data/test/sass/script_conversion_test.rb +10 -2
  81. data/test/sass/script_test.rb +22 -24
  82. data/test/sass/scss/css_test.rb +3 -18
  83. data/test/sass/scss/rx_test.rb +0 -1
  84. data/test/sass/scss/scss_test.rb +49 -16
  85. data/test/sass/source_map_test.rb +13 -16
  86. data/test/sass/superselector_test.rb +0 -1
  87. data/test/sass/util/multibyte_string_scanner_test.rb +121 -124
  88. data/test/sass/util/normalized_map_test.rb +0 -1
  89. data/test/sass/util/subset_map_test.rb +0 -1
  90. data/test/sass/util_test.rb +4 -39
  91. data/test/sass/value_helpers_test.rb +0 -1
  92. data/test/sass-spec.yml +1 -1
  93. data/test/test_helper.rb +39 -0
  94. metadata +19 -44
  95. data/lib/sass/script/css_variable_warning.rb +0 -52
  96. data/lib/sass/util/cross_platform_random.rb +0 -19
  97. data/lib/sass/util/ordered_hash.rb +0 -192
  98. data/test/sass/results/import_charset_1_8.css +0 -5
  99. data/test/sass/templates/import_charset_1_8.sass +0 -6
  100. data/vendor/listen/CHANGELOG.md +0 -1
  101. data/vendor/listen/CONTRIBUTING.md +0 -38
  102. data/vendor/listen/Gemfile +0 -20
  103. data/vendor/listen/Guardfile +0 -8
  104. data/vendor/listen/LICENSE +0 -20
  105. data/vendor/listen/README.md +0 -349
  106. data/vendor/listen/Rakefile +0 -5
  107. data/vendor/listen/Vagrantfile +0 -96
  108. data/vendor/listen/lib/listen/adapter.rb +0 -327
  109. data/vendor/listen/lib/listen/adapters/bsd.rb +0 -75
  110. data/vendor/listen/lib/listen/adapters/darwin.rb +0 -48
  111. data/vendor/listen/lib/listen/adapters/linux.rb +0 -81
  112. data/vendor/listen/lib/listen/adapters/polling.rb +0 -58
  113. data/vendor/listen/lib/listen/adapters/windows.rb +0 -91
  114. data/vendor/listen/lib/listen/directory_record.rb +0 -406
  115. data/vendor/listen/lib/listen/listener.rb +0 -323
  116. data/vendor/listen/lib/listen/turnstile.rb +0 -32
  117. data/vendor/listen/lib/listen/version.rb +0 -3
  118. data/vendor/listen/lib/listen.rb +0 -54
  119. data/vendor/listen/listen.gemspec +0 -28
  120. data/vendor/listen/spec/listen/adapter_spec.rb +0 -149
  121. data/vendor/listen/spec/listen/adapters/bsd_spec.rb +0 -36
  122. data/vendor/listen/spec/listen/adapters/darwin_spec.rb +0 -37
  123. data/vendor/listen/spec/listen/adapters/linux_spec.rb +0 -47
  124. data/vendor/listen/spec/listen/adapters/polling_spec.rb +0 -68
  125. data/vendor/listen/spec/listen/adapters/windows_spec.rb +0 -30
  126. data/vendor/listen/spec/listen/directory_record_spec.rb +0 -1250
  127. data/vendor/listen/spec/listen/listener_spec.rb +0 -258
  128. data/vendor/listen/spec/listen/turnstile_spec.rb +0 -56
  129. data/vendor/listen/spec/listen_spec.rb +0 -67
  130. data/vendor/listen/spec/spec_helper.rb +0 -25
  131. data/vendor/listen/spec/support/adapter_helper.rb +0 -666
  132. data/vendor/listen/spec/support/directory_record_helper.rb +0 -57
  133. data/vendor/listen/spec/support/fixtures_helper.rb +0 -29
  134. data/vendor/listen/spec/support/listeners_helper.rb +0 -179
  135. data/vendor/listen/spec/support/platform_helper.rb +0 -15
@@ -77,7 +77,7 @@ module Sass::Script
77
77
  # \{#complement complement($color)}
78
78
  # : Returns the complement of a color.
79
79
  #
80
- # \{#invert invert($color)}
80
+ # \{#invert invert($color, \[$weight\])}
81
81
  # : Returns the inverse of a color.
82
82
  #
83
83
  # ## Opacity Functions
@@ -176,7 +176,7 @@ module Sass::Script
176
176
  # \{#set-nth set-nth($list, $n, $value)}
177
177
  # : Replaces the nth item in a list.
178
178
  #
179
- # \{#join join($list1, $list2, \[$separator\])}
179
+ # \{#join join($list1, $list2, \[$separator, $bracketed\])}
180
180
  # : Joins together two lists into one.
181
181
  #
182
182
  # \{#append append($list1, $val, \[$separator\])}
@@ -191,6 +191,9 @@ module Sass::Script
191
191
  # \{#list_separator list-separator($list)}
192
192
  # : Returns the separator of a list.
193
193
  #
194
+ # \{#is_bracketed is-bracketed($list)}
195
+ # : Returns whether a list has square brackets.
196
+ #
194
197
  # ## Map Functions {#map-functions}
195
198
  #
196
199
  # Maps in Sass are immutable; all map functions return a new map rather than
@@ -276,6 +279,9 @@ module Sass::Script
276
279
  # \{#mixin_exists mixin-exists($name)}
277
280
  # : Returns whether a mixin with the given name exists.
278
281
  #
282
+ # \{#content_exists content-exists()}
283
+ # : Returns whether the current mixin was passed a content block.
284
+ #
279
285
  # \{#inspect inspect($value)}
280
286
  # : Returns the string representation of a value as it would be represented in Sass.
281
287
  #
@@ -291,8 +297,12 @@ module Sass::Script
291
297
  # \{#comparable comparable($number1, $number2)}
292
298
  # : Returns whether two numbers can be added, subtracted, or compared.
293
299
  #
294
- # \{#call call($name, $args...)}
295
- # : Dynamically calls a Sass function.
300
+ # \{#call call($function, $args...)}
301
+ # : Dynamically calls a Sass function reference returned by `get-function`.
302
+ #
303
+ # \{#get_function get-function($name, $css: false)}
304
+ # : Looks up a function with the given name in the current lexical scope
305
+ # and returns a reference to it.
296
306
  #
297
307
  # ## Miscellaneous Functions
298
308
  #
@@ -471,14 +481,14 @@ module Sass::Script
471
481
  # @param seed [Integer]
472
482
  # @return [Integer] The same seed.
473
483
  def self.random_seed=(seed)
474
- @random_number_generator = Sass::Util::CrossPlatformRandom.new(seed)
484
+ @random_number_generator = Random.new(seed)
475
485
  end
476
486
 
477
487
  # Get Sass's internal random number generator.
478
488
  #
479
489
  # @return [Random]
480
490
  def self.random_number_generator
481
- @random_number_generator ||= Sass::Util::CrossPlatformRandom.new
491
+ @random_number_generator ||= Random.new
482
492
  end
483
493
 
484
494
  # The context in which methods in {Script::Functions} are evaluated.
@@ -522,18 +532,27 @@ module Sass::Script
522
532
  # assert_type value, :String
523
533
  # assert_type value, :Number
524
534
  # @param value [Sass::Script::Value::Base] A SassScript value
525
- # @param type [Symbol] The name of the type the value is expected to be
535
+ # @param type [Symbol, Array<Symbol>] The name(s) of the type the value is expected to be
526
536
  # @param name [String, Symbol, nil] The name of the argument.
527
537
  # @raise [ArgumentError] if value is not of the correct type.
528
538
  def assert_type(value, type, name = nil)
529
- klass = Sass::Script::Value.const_get(type)
530
- if value.is_a?(klass)
531
- value.check_deprecated_interp if type == :String
539
+ valid_types = Array(type)
540
+ found_type = valid_types.find do |t|
541
+ value.is_a?(Sass::Script::Value.const_get(t)) ||
542
+ t == :Map && value.is_a?(Sass::Script::Value::List) && value.value.empty?
543
+ end
544
+
545
+ if found_type
546
+ value.check_deprecated_interp if found_type == :String
532
547
  return
533
548
  end
534
549
 
535
- return if value.is_a?(Sass::Script::Value::List) && type == :Map && value.value.empty?
536
- err = "#{value.inspect} is not a #{TYPE_NAMES[type] || type.to_s.downcase}"
550
+ err = if valid_types.size == 1
551
+ "#{value.inspect} is not a #{TYPE_NAMES[type] || type.to_s.downcase}"
552
+ else
553
+ type_names = valid_types.map {|t| TYPE_NAMES[t] || t.to_s.downcase}
554
+ "#{value.inspect} is not any of #{type_names.join(', ')}"
555
+ end
537
556
  err = "$#{name.to_s.tr('_', '-')}: " + err if name
538
557
  raise ArgumentError.new(err)
539
558
  end
@@ -635,7 +654,7 @@ module Sass::Script
635
654
  # @return [Sass::Script::Value::Color]
636
655
  # @raise [ArgumentError] if any parameter is the wrong type or out of bounds
637
656
  def rgb(red, green, blue)
638
- if calc?(red) || calc?(green) || calc?(blue)
657
+ if special_number?(red) || special_number?(green) || special_number?(blue)
639
658
  return unquoted_string("rgb(#{red}, #{green}, #{blue})")
640
659
  end
641
660
  assert_type red, :Number, :red
@@ -696,7 +715,7 @@ module Sass::Script
696
715
  color, alpha = args
697
716
 
698
717
  assert_type color, :Color, :color
699
- if calc?(alpha)
718
+ if special_number?(alpha)
700
719
  unquoted_string("rgba(#{color.red}, #{color.green}, #{color.blue}, #{alpha})")
701
720
  else
702
721
  assert_type alpha, :Number, :alpha
@@ -705,7 +724,8 @@ module Sass::Script
705
724
  end
706
725
  when 4
707
726
  red, green, blue, alpha = args
708
- if calc?(red) || calc?(green) || calc?(blue) || calc?(alpha)
727
+ if special_number?(red) || special_number?(green) ||
728
+ special_number?(blue) || special_number?(alpha)
709
729
  unquoted_string("rgba(#{red}, #{green}, #{blue}, #{alpha})")
710
730
  else
711
731
  rgba(rgb(red, green, blue), alpha)
@@ -734,7 +754,7 @@ module Sass::Script
734
754
  # @raise [ArgumentError] if `$saturation` or `$lightness` are out of bounds
735
755
  # or any parameter is the wrong type
736
756
  def hsl(hue, saturation, lightness)
737
- if calc?(hue) || calc?(saturation) || calc?(lightness)
757
+ if special_number?(hue) || special_number?(saturation) || special_number?(lightness)
738
758
  unquoted_string("hsl(#{hue}, #{saturation}, #{lightness})")
739
759
  else
740
760
  hsla(hue, saturation, lightness, number(1))
@@ -762,7 +782,8 @@ module Sass::Script
762
782
  # @raise [ArgumentError] if `$saturation`, `$lightness`, or `$alpha` are out
763
783
  # of bounds or any parameter is the wrong type
764
784
  def hsla(hue, saturation, lightness, alpha)
765
- if calc?(hue) || calc?(saturation) || calc?(lightness) || calc?(alpha)
785
+ if special_number?(hue) || special_number?(saturation) ||
786
+ special_number?(lightness) || special_number?(alpha)
766
787
  return unquoted_string("hsla(#{hue}, #{saturation}, #{lightness}, #{alpha})")
767
788
  end
768
789
  assert_type hue, :Number, :hue
@@ -1384,20 +1405,28 @@ module Sass::Script
1384
1405
  #
1385
1406
  # @overload invert($color)
1386
1407
  # @param $color [Sass::Script::Value::Color]
1408
+ # @overload invert($color, $weight: 100%)
1409
+ # @param $color [Sass::Script::Value::Color]
1410
+ # @param $weight [Sass::Script::Value::Number] The relative weight of the
1411
+ # color color's inverse
1387
1412
  # @return [Sass::Script::Value::Color]
1388
- # @raise [ArgumentError] if `$color` isn't a color
1389
- def invert(color)
1413
+ # @raise [ArgumentError] if `$color` isn't a color or `$weight`
1414
+ # isn't a percentage between 0% and 100%
1415
+ def invert(color, weight = number(100))
1390
1416
  if color.is_a?(Sass::Script::Value::Number)
1391
1417
  return identifier("invert(#{color})")
1392
1418
  end
1393
1419
 
1394
1420
  assert_type color, :Color, :color
1395
- color.with(
1421
+ inv = color.with(
1396
1422
  :red => (255 - color.red),
1397
1423
  :green => (255 - color.green),
1398
1424
  :blue => (255 - color.blue))
1425
+
1426
+ mix(inv, color, weight)
1399
1427
  end
1400
1428
  declare :invert, [:color]
1429
+ declare :invert, [:color, :weight]
1401
1430
 
1402
1431
  # Removes quotes from a string. If the string is already unquoted, this will
1403
1432
  # return it unmodified.
@@ -1612,6 +1641,10 @@ MESSAGE
1612
1641
  # type-of(#fff) => color
1613
1642
  # type-of(blue) => color
1614
1643
  # type-of(null) => null
1644
+ # type-of(a b c) => list
1645
+ # type-of((a: 1, b: 2)) => map
1646
+ # type-of(get-function("foo")) => function
1647
+ #
1615
1648
  # @overload type_of($value)
1616
1649
  # @param $value [Sass::Script::Value::Base] The value to inspect
1617
1650
  # @return [Sass::Script::Value::String] The unquoted string name of the
@@ -1639,6 +1672,12 @@ MESSAGE
1639
1672
  #
1640
1673
  # * `at-error` indicates that the Sass `@error` directive is supported.
1641
1674
  #
1675
+ # * `custom-property` indicates that the [Custom Properties Level 1][] spec
1676
+ # is supported. This means that custom properties are parsed statically,
1677
+ # with only interpolation treated as SassScript.
1678
+ #
1679
+ # [Custom Properties Level 1]: https://www.w3.org/TR/css-variables-1/
1680
+ #
1642
1681
  # @example
1643
1682
  # feature-exists(some-feature-that-exists) => true
1644
1683
  # feature-exists(what-is-this-i-dont-know) => false
@@ -1653,6 +1692,55 @@ MESSAGE
1653
1692
  end
1654
1693
  declare :feature_exists, [:feature]
1655
1694
 
1695
+ # Returns a reference to a function for later invocation with the `call()` function.
1696
+ #
1697
+ # If `$css` is `false`, the function reference may refer to a function
1698
+ # defined in your stylesheet or built-in to the host environment. If it's
1699
+ # `true` it will refer to a plain-CSS function.
1700
+ #
1701
+ # @example
1702
+ # get-function("rgb")
1703
+ #
1704
+ # @function myfunc { @return "something"; }
1705
+ # get-function("myfunc")
1706
+ #
1707
+ # @overload get_function($name, $css: false)
1708
+ # @param name [Sass::Script::Value::String] The name of the function being referenced.
1709
+ # @param css [Sass::Script::Value::Bool] Whether to get a plain CSS function.
1710
+ #
1711
+ # @return [Sass::Script::Value::Function] A function reference.
1712
+ def get_function(name, kwargs = {})
1713
+ assert_type name, :String, :name
1714
+
1715
+ css = if kwargs.has_key?("css")
1716
+ v = kwargs.delete("css")
1717
+ assert_type v, :Bool, :css
1718
+ v.value
1719
+ else
1720
+ false
1721
+ end
1722
+
1723
+ if kwargs.any?
1724
+ raise ArgumentError.new("Illegal keyword argument '#{kwargs.keys.first}'")
1725
+ end
1726
+
1727
+ if css
1728
+ return Sass::Script::Value::Function.new(
1729
+ Sass::Callable.new(name.value, nil, nil, nil, nil, nil, "function", :css))
1730
+ end
1731
+
1732
+ callable = environment.caller.function(name.value) ||
1733
+ (Sass::Script::Functions.callable?(name.value.tr("-", "_")) &&
1734
+ Sass::Callable.new(name.value, nil, nil, nil, nil, nil, "function", :builtin))
1735
+
1736
+ if callable
1737
+ Sass::Script::Value::Function.new(callable)
1738
+ else
1739
+ raise Sass::SyntaxError.new("Function not found: #{name}")
1740
+ end
1741
+ end
1742
+ declare :get_function, [:name], :var_kwargs => true
1743
+
1656
1744
  # Returns the unit(s) associated with a number. Complex units are sorted in
1657
1745
  # alphabetical order by numerator and denominator.
1658
1746
  #
@@ -1855,7 +1943,7 @@ MESSAGE
1855
1943
  index = n.to_i > 0 ? n.to_i - 1 : n.to_i
1856
1944
  new_list = list.to_a.dup
1857
1945
  new_list[index] = value
1858
- Sass::Script::Value::List.new(new_list, list.separator)
1946
+ list.with_contents(new_list)
1859
1947
  end
1860
1948
  declare :set_nth, [:list, :n, :value]
1861
1949
 
@@ -1896,6 +1984,9 @@ MESSAGE
1896
1984
  # list. If both lists have fewer than two items, spaces are used for the
1897
1985
  # resulting list.
1898
1986
  #
1987
+ # Unless `$bracketed` is passed, the resulting list is bracketed if the
1988
+ # first parameter is.
1989
+ #
1899
1990
  # Like all list functions, `join()` returns a new list rather than modifying
1900
1991
  # its arguments in place.
1901
1992
  #
@@ -1905,27 +1996,73 @@ MESSAGE
1905
1996
  # join(10px, 20px) => 10px 20px
1906
1997
  # join(10px, 20px, comma) => 10px, 20px
1907
1998
  # join((blue, red), (#abc, #def), space) => blue red #abc #def
1908
- # @overload join($list1, $list2, $separator: auto)
1999
+ # join([10px], 20px) => [10px 20px]
2000
+ # @overload join($list1, $list2, $separator: auto, $bracketed: auto)
1909
2001
  # @param $list1 [Sass::Script::Value::Base]
1910
2002
  # @param $list2 [Sass::Script::Value::Base]
1911
2003
  # @param $separator [Sass::Script::Value::String] The list separator to use.
1912
2004
  # If this is `comma` or `space`, that separator will be used. If this is
1913
2005
  # `auto` (the default), the separator is determined as explained above.
2006
+ # @param $bracketed [Sass::Script::Value::Base] Whether the resulting list
2007
+ # will be bracketed. If this is `auto` (the default), the separator is
2008
+ # determined as explained above.
1914
2009
  # @return [Sass::Script::Value::List]
1915
- def join(list1, list2, separator = identifier("auto"))
2010
+ # @comment
2011
+ # rubocop:disable ParameterLists
2012
+ def join(list1, list2,
2013
+ separator = identifier("auto"), bracketed = identifier("auto"),
2014
+ kwargs = nil, *rest)
2015
+ # rubocop:enable ParameterLists
2016
+ if separator.is_a?(Hash)
2017
+ kwargs = separator
2018
+ separator = identifier("auto")
2019
+ elsif bracketed.is_a?(Hash)
2020
+ kwargs = bracketed
2021
+ bracketed = identifier("auto")
2022
+ elsif rest.last.is_a?(Hash)
2023
+ rest.unshift kwargs
2024
+ kwargs = rest.pop
2025
+ end
2026
+
2027
+ unless rest.empty?
2028
+ # Add 4 to rest.length because we don't want to count the kwargs hash,
2029
+ # which is always passed.
2030
+ raise ArgumentError.new("wrong number of arguments (#{rest.length + 4} for 2..4)")
2031
+ end
2032
+
2033
+ if kwargs
2034
+ separator = kwargs.delete("separator") || separator
2035
+ bracketed = kwargs.delete("bracketed") || bracketed
2036
+
2037
+ unless kwargs.empty?
2038
+ name, val = kwargs.to_a.first
2039
+ raise ArgumentError.new("Unknown argument $#{name} (#{val})")
2040
+ end
2041
+ end
2042
+
1916
2043
  assert_type separator, :String, :separator
1917
2044
  unless %w(auto space comma).include?(separator.value)
1918
2045
  raise ArgumentError.new("Separator name must be space, comma, or auto")
1919
2046
  end
1920
- sep = if separator.value == 'auto'
1921
- list1.separator || list2.separator || :space
1922
- else
1923
- separator.value.to_sym
1924
- end
1925
- list(list1.to_a + list2.to_a, sep)
2047
+
2048
+ list(list1.to_a + list2.to_a,
2049
+ separator:
2050
+ if separator.value == 'auto'
2051
+ list1.separator || list2.separator || :space
2052
+ else
2053
+ separator.value.to_sym
2054
+ end,
2055
+ bracketed:
2056
+ if bracketed.is_a?(Sass::Script::Value::String) && bracketed.value == 'auto'
2057
+ list1.bracketed
2058
+ else
2059
+ bracketed.to_bool
2060
+ end)
1926
2061
  end
1927
- declare :join, [:list1, :list2]
1928
- declare :join, [:list1, :list2, :separator]
2062
+ # We don't actually take variable arguments or keyword arguments, but this
2063
+ # is the best way to take either `$separator` or `$bracketed` as keywords
2064
+ # without complaining about the other missing.
2065
+ declare :join, [:list1, :list2], :var_args => true, :var_kwargs => true
1929
2066
 
1930
2067
  # Appends a single value onto the end of a list.
1931
2068
  #
@@ -1953,12 +2090,13 @@ MESSAGE
1953
2090
  unless %w(auto space comma).include?(separator.value)
1954
2091
  raise ArgumentError.new("Separator name must be space, comma, or auto")
1955
2092
  end
1956
- sep = if separator.value == 'auto'
1957
- list.separator || :space
1958
- else
1959
- separator.value.to_sym
1960
- end
1961
- list(list.to_a + [val], sep)
2093
+ list.with_contents(list.to_a + [val],
2094
+ separator:
2095
+ if separator.value == 'auto'
2096
+ list.separator || :space
2097
+ else
2098
+ separator.value.to_sym
2099
+ end)
1962
2100
  end
1963
2101
  declare :append, [:list, :val]
1964
2102
  declare :append, [:list, :val, :separator]
@@ -2028,7 +2166,20 @@ MESSAGE
2028
2166
  def list_separator(list)
2029
2167
  identifier((list.separator || :space).to_s)
2030
2168
  end
2031
- declare :separator, [:list]
2169
+ declare :list_separator, [:list]
2170
+
2171
+ # Returns whether a list uses square brackets.
2172
+ #
2173
+ # @example
2174
+ # is-bracketed(1px 2px 3px) => false
2175
+ # is-bracketed([1px, 2px, 3px]) => true
2176
+ # @overload is_bracketed($list)
2177
+ # @param $list [Sass::Script::Value::Base]
2178
+ # @return [Sass::Script::Value::Bool]
2179
+ def is_bracketed(list)
2180
+ bool(list.bracketed)
2181
+ end
2182
+ declare :is_bracketed, [:list]
2032
2183
 
2033
2184
  # Returns the value in a map associated with the given key. If the map
2034
2185
  # doesn't have such a key, returns `null`.
@@ -2214,10 +2365,24 @@ MESSAGE
2214
2365
  # $fn: nth;
2215
2366
  # call($fn, (a b c), 2) => b
2216
2367
  #
2217
- # @overload call($name, $args...)
2218
- # @param $name [String] The name of the function to call.
2368
+ # @overload call($function, $args...)
2369
+ # @param $function [Sass::Script::Value::Function] The function to call.
2219
2370
  def call(name, *args)
2220
- assert_type name, :String, :name
2371
+ unless name.is_a?(Sass::Script::Value::String) ||
2372
+ name.is_a?(Sass::Script::Value::Function)
2373
+ assert_type name, :Function, :function
2374
+ end
2375
+ if name.is_a?(Sass::Script::Value::String)
2376
+ name = if function_exists(name).to_bool
2377
+ get_function(name)
2378
+ else
2379
+ get_function(name, "css" => bool(true))
2380
+ end
2381
+ Sass::Util.sass_warn(<<WARNING)
2382
+ DEPRECATION WARNING: Passing a string to call() is deprecated and will be illegal
2383
+ in Sass 4.0. Use call(#{name.to_sass}) instead.
2384
+ WARNING
2385
+ end
2221
2386
  kwargs = args.last.is_a?(Hash) ? args.pop : {}
2222
2387
  funcall = Sass::Script::Tree::Funcall.new(
2223
2388
  name.value,
@@ -2225,6 +2390,8 @@ MESSAGE
2225
2390
  Sass::Util.map_vals(kwargs) {|v| Sass::Script::Tree::Literal.new(v)},
2226
2391
  nil,
2227
2392
  nil)
2393
+ funcall.line = environment.stack.frames.last.line
2394
+ funcall.filename = environment.stack.frames.last.filename
2228
2395
  funcall.options = options
2229
2396
  perform(funcall)
2230
2397
  end
@@ -2313,12 +2480,12 @@ MESSAGE
2313
2480
  #
2314
2481
  # @overload function_exists($name)
2315
2482
  # @param name [Sass::Script::Value::String] The name of the function to
2316
- # check.
2483
+ # check or a function reference.
2317
2484
  # @return [Sass::Script::Value::Bool] Whether the function is defined.
2318
2485
  def function_exists(name)
2319
2486
  assert_type name, :String, :name
2320
2487
  exists = Sass::Script::Functions.callable?(name.value.tr("-", "_"))
2321
- exists ||= environment.function(name.value)
2488
+ exists ||= environment.caller.function(name.value)
2322
2489
  bool(exists)
2323
2490
  end
2324
2491
  declare :function_exists, [:name]
@@ -2341,6 +2508,31 @@ MESSAGE
2341
2508
  end
2342
2509
  declare :mixin_exists, [:name]
2343
2510
 
2511
+ # Check whether a mixin was passed a content block.
2512
+ #
2513
+ # Unless `content-exists()` is called directly from a mixin, an error will be raised.
2514
+ #
2515
+ # @example
2516
+ # @mixin needs-content {
2517
+ # @if not content-exists() {
2518
+ # @error "You must pass a content block!"
2519
+ # }
2520
+ # @content;
2521
+ # }
2522
+ #
2523
+ # @overload content_exists()
2524
+ # @return [Sass::Script::Value::Bool] Whether a content block was passed to the mixin.
2525
+ def content_exists
2526
+ # frames.last is the stack frame for this function,
2527
+ # so we use frames[-2] to get the frame before that.
2528
+ mixin_frame = environment.stack.frames[-2]
2529
+ unless mixin_frame && mixin_frame.type == :mixin
2530
+ raise Sass::SyntaxError.new("Cannot call content-exists() except within a mixin.")
2531
+ end
2532
+ bool(!environment.caller.content.nil?)
2533
+ end
2534
+ declare :content_exists, []
2535
+
2344
2536
  # Return a string containing the value as its Sass representation.
2345
2537
  #
2346
2538
  # @overload inspect($value)
@@ -51,6 +51,8 @@ module Sass
51
51
  ':' => :colon,
52
52
  '(' => :lparen,
53
53
  ')' => :rparen,
54
+ '[' => :lsquare,
55
+ ']' => :rsquare,
54
56
  ',' => :comma,
55
57
  'and' => :and,
56
58
  'or' => :or,
@@ -366,8 +368,17 @@ MESSAGE
366
368
  # IDs in properties are used in the Basic User Interface Module
367
369
  # (http://www.w3.org/TR/css3-ui/).
368
370
  return unless scan(REGULAR_EXPRESSIONS[:id])
369
- if @scanner[0] =~ /^\#[0-9a-fA-F]+$/ && (@scanner[0].length == 4 || @scanner[0].length == 7)
370
- return [:color, Script::Value::Color.from_hex(@scanner[0])]
371
+ if @scanner[0] =~ /^\#[0-9a-fA-F]+$/
372
+ if @scanner[0].length == 4 || @scanner[0].length == 7
373
+ return [:color, Script::Value::Color.from_hex(@scanner[0])]
374
+ elsif @scanner[0].length == 5 || @scanner[0].length == 9
375
+ filename = @options[:filename]
376
+ Sass::Util.sass_warn <<MESSAGE
377
+ DEPRECATION WARNING on line #{line}, column #{offset}#{" of #{filename}" if filename}:
378
+ The value "#{@scanner[0]}" is currently parsed as a string, but it will be parsed as a color in
379
+ future versions of Sass. Use "unquote('#{@scanner[0]}')" to continue parsing it as a string.
380
+ MESSAGE
381
+ end
371
382
  end
372
383
  [:ident, @scanner[0]]
373
384
  end