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
@@ -1,5 +1,4 @@
1
1
  require 'sass/script/lexer'
2
- require 'sass/script/css_variable_warning'
3
2
 
4
3
  module Sass
5
4
  module Script
@@ -35,7 +34,6 @@ module Sass
35
34
  @allow_extra_text = options.delete(:allow_extra_text)
36
35
  @lexer = lexer_class.new(str, line, offset, options)
37
36
  @stop_at = nil
38
- @css_variable_warning = nil
39
37
  end
40
38
 
41
39
  # Parses a SassScript expression within an interpolated segment (`#{}`).
@@ -64,23 +62,13 @@ module Sass
64
62
 
65
63
  # Parses a SassScript expression.
66
64
  #
67
- # @param css_variable [Boolean] Whether this is the value of a CSS variable.
68
65
  # @return [Script::Tree::Node] The root node of the parse tree
69
66
  # @raise [Sass::SyntaxError] if the expression isn't valid SassScript
70
- def parse(css_variable = false)
71
- if css_variable
72
- @css_variable_warning = CssVariableWarning.new
73
- end
74
-
67
+ def parse
75
68
  expr = assert_expr :expr
76
69
  assert_done
77
70
  expr.options = @options
78
71
  check_for_interpolation expr
79
-
80
- if css_variable
81
- @css_variable_warning.value = expr
82
- end
83
-
84
72
  expr
85
73
  rescue Sass::SyntaxError => e
86
74
  e.modify_backtrace :line => @lexer.line, :filename => @options[:filename]
@@ -127,7 +115,7 @@ module Sass
127
115
  a.options = @options
128
116
  end
129
117
 
130
- keywords.each do |_k, v|
118
+ keywords.each do |_, v|
131
119
  check_for_interpolation v
132
120
  v.options = @options
133
121
  end
@@ -232,12 +220,12 @@ module Sass
232
220
 
233
221
  # Parses a SassScript expression.
234
222
  #
223
+ # @overload parse(str, line, offset, filename = nil)
235
224
  # @return [Script::Tree::Node] The root node of the parse tree
236
225
  # @see Parser#initialize
237
226
  # @see Parser#parse
238
- def self.parse(value, line, offset, options = {})
239
- css_variable = options.delete :css_variable
240
- new(value, line, offset, options).parse(css_variable)
227
+ def self.parse(*args)
228
+ new(*args).parse
241
229
  end
242
230
 
243
231
  PRECEDENCE = [
@@ -250,8 +238,6 @@ module Sass
250
238
 
251
239
  ASSOCIATIVE = [:plus, :times]
252
240
 
253
- VALID_CSS_OPS = [:comma, :single_eq, :space, :div]
254
-
255
241
  class << self
256
242
  # Returns an integer representing the precedence
257
243
  # of the given operator.
@@ -291,10 +277,6 @@ module Sass
291
277
  return other_interp
292
278
  end
293
279
 
294
- if @css_variable_warning && !VALID_CSS_OPS.include?(tok.type)
295
- @css_variable_warning.warn!
296
- end
297
-
298
280
  e = node(Tree::Operation.new(e, assert_expr(#{sub.inspect}), tok.type),
299
281
  e.source_range.start_pos)
300
282
  end
@@ -310,8 +292,6 @@ RUBY
310
292
  interp = try_op_before_interp(tok)
311
293
  return interp if interp
312
294
  start_pos = source_position
313
-
314
- @css_variable_warning.warn! if @css_variable_warning
315
295
  node(Tree::UnaryOperation.new(assert_expr(:unary_#{op}), :#{op}), start_pos)
316
296
  end
317
297
  RUBY
@@ -338,7 +318,6 @@ RUBY
338
318
  return list e, start_pos unless @lexer.peek && @lexer.peek.type == :colon
339
319
 
340
320
  pair = map_pair(e)
341
- @css_variable_warning.warn! if @css_variable_warning
342
321
  map = node(Sass::Script::Tree::MapLiteral.new([pair]), start_pos)
343
322
  while try_tok(:comma)
344
323
  pair = map_pair
@@ -364,7 +343,7 @@ RUBY
364
343
  def list(first, start_pos)
365
344
  return first unless @lexer.peek && @lexer.peek.type == :comma
366
345
 
367
- list = node(Sass::Script::Tree::ListLiteral.new([first], :comma), start_pos)
346
+ list = node(Sass::Script::Tree::ListLiteral.new([first], separator: :comma), start_pos)
368
347
  while (tok = try_tok(:comma))
369
348
  element_before_interp = list.elements.length == 1 ? list.elements.first : list
370
349
  if (interp = try_op_before_interp(tok, element_before_interp))
@@ -401,7 +380,7 @@ RUBY
401
380
  Script::Tree::Interpolation.new(
402
381
  prev, str, nil, wb, false, :originally_text => true, :deprecation => deprecation),
403
382
  (prev || str).source_range.start_pos)
404
- interpolation(interp)
383
+ interpolation(first: interp)
405
384
  end
406
385
 
407
386
  def try_ops_after_interp(ops, name, prev = nil)
@@ -431,17 +410,17 @@ RUBY
431
410
  interp
432
411
  end
433
412
 
434
- def interpolation(first = space)
435
- e = first
413
+ def interpolation(first: nil, inner: :space)
414
+ e = first || send(inner)
436
415
  while (interp = try_tok(:begin_interpolation))
437
416
  wb = @lexer.whitespace?(interp)
438
417
  char_before = @lexer.char(interp.pos - 1)
439
- mid = without_css_variable_warning {assert_expr :expr}
418
+ mid = assert_expr :expr
440
419
  assert_tok :end_interpolation
441
420
  wa = @lexer.whitespace?
442
421
  char_after = @lexer.char
443
422
 
444
- after = space
423
+ after = send(inner)
445
424
  before_deprecation = e.is_a?(Script::Tree::Interpolation) ? e.deprecation : :none
446
425
  after_deprecation = after.is_a?(Script::Tree::Interpolation) ? after.deprecation : :none
447
426
 
@@ -500,7 +479,7 @@ RUBY
500
479
  if arr.size == 1
501
480
  arr.first
502
481
  else
503
- node(Sass::Script::Tree::ListLiteral.new(arr, :space), start_pos)
482
+ node(Sass::Script::Tree::ListLiteral.new(arr, separator: :space), start_pos)
504
483
  end
505
484
  end
506
485
 
@@ -549,12 +528,12 @@ RUBY
549
528
  else
550
529
  return [], nil unless try_tok(:lparen)
551
530
  end
552
- return [], nil if try_tok(:rparen)
553
531
 
554
532
  res = []
555
533
  splat = nil
556
534
  must_have_default = false
557
535
  loop do
536
+ break if peek_tok(:rparen)
558
537
  c = assert_tok(:const)
559
538
  var = node(Script::Tree::Variable.new(c.value), c.source_range)
560
539
  if try_tok(:colon)
@@ -585,12 +564,8 @@ RUBY
585
564
  def arglist(subexpr, description)
586
565
  args = []
587
566
  keywords = Sass::Util::NormalizedMap.new
588
- e = send(subexpr)
589
-
590
- return [args, keywords] unless e
591
-
592
567
  splat = nil
593
- loop do
568
+ while (e = send(subexpr))
594
569
  if @lexer.peek && @lexer.peek.type == :colon
595
570
  name = e
596
571
  @lexer.expected!("comma") unless name.is_a?(Tree::Variable)
@@ -611,13 +586,12 @@ RUBY
611
586
  elsif !keywords.empty?
612
587
  raise SyntaxError.new("Positional arguments must come before keyword arguments.")
613
588
  end
614
-
615
589
  args << e if e
616
590
  end
617
591
 
618
592
  return args, keywords, splat unless try_tok(:comma)
619
- e = assert_expr(subexpr, description)
620
593
  end
594
+ return args, keywords
621
595
  end
622
596
 
623
597
  def raw
@@ -628,10 +602,10 @@ RUBY
628
602
 
629
603
  def special_fun
630
604
  first = try_tok(:special_fun)
631
- return paren unless first
605
+ return square_list unless first
632
606
  str = literal_node(first.value, first.source_range)
633
607
  return str unless try_tok(:string_interpolation)
634
- mid = without_css_variable_warning {assert_expr :expr}
608
+ mid = assert_expr :expr
635
609
  assert_tok :end_interpolation
636
610
  last = assert_expr(:special_fun)
637
611
  node(
@@ -639,6 +613,50 @@ RUBY
639
613
  first.source_range.start_pos)
640
614
  end
641
615
 
616
+ def square_list
617
+ start_pos = source_position
618
+ return paren unless try_tok(:lsquare)
619
+
620
+ space_start_pos = source_position
621
+ e = interpolation(inner: :or_expr)
622
+ separator = nil
623
+ if e
624
+ elements = [e]
625
+ while (e = interpolation(inner: :or_expr))
626
+ elements << e
627
+ end
628
+
629
+ # If there's a comma after a space-separated list, it's actually a
630
+ # space-separated list nested in a comma-separated list.
631
+ if try_tok(:comma)
632
+ e = if elements.length == 1
633
+ elements.first
634
+ else
635
+ node(
636
+ Sass::Script::Tree::ListLiteral.new(elements, separator: :space),
637
+ space_start_pos)
638
+ end
639
+ elements = [e]
640
+
641
+ while (e = space)
642
+ elements << e
643
+ break unless try_tok(:comma)
644
+ end
645
+ separator = :comma
646
+ else
647
+ separator = :space if elements.length > 1
648
+ end
649
+ else
650
+ elements = []
651
+ end
652
+
653
+ assert_tok(:rsquare)
654
+ end_pos = source_position
655
+
656
+ node(Sass::Script::Tree::ListLiteral.new(elements, separator: separator, bracketed: true),
657
+ start_pos, end_pos)
658
+ end
659
+
642
660
  def paren
643
661
  return variable unless try_tok(:lparen)
644
662
  start_pos = source_position
@@ -646,17 +664,13 @@ RUBY
646
664
  e.force_division! if e
647
665
  end_pos = source_position
648
666
  assert_tok(:rparen)
649
-
650
- @css_variable_warning.warn! if @css_variable_warning
651
- e || node(Sass::Script::Tree::ListLiteral.new([], nil), start_pos, end_pos)
667
+ e || node(Sass::Script::Tree::ListLiteral.new([]), start_pos, end_pos)
652
668
  end
653
669
 
654
670
  def variable
655
671
  start_pos = source_position
656
672
  c = try_tok(:const)
657
673
  return string unless c
658
-
659
- @css_variable_warning.warn! if @css_variable_warning
660
674
  node(Tree::Variable.new(*c.value), start_pos)
661
675
  end
662
676
 
@@ -665,7 +679,7 @@ RUBY
665
679
  return number unless first
666
680
  str = literal_node(first.value, first.source_range)
667
681
  return str unless try_tok(:string_interpolation)
668
- mid = without_css_variable_warning {assert_expr :expr}
682
+ mid = assert_expr :expr
669
683
  assert_tok :end_interpolation
670
684
  last = assert_expr(:string)
671
685
  node(Tree::StringInterpolation.new(str, mid, last), first.source_range.start_pos)
@@ -683,7 +697,6 @@ RUBY
683
697
  def selector
684
698
  tok = try_tok(:selector)
685
699
  return literal unless tok
686
- @css_variable_warning.warn! if @css_variable_warning
687
700
  node(tok.value, tok.source_range.start_pos)
688
701
  end
689
702
 
@@ -723,10 +736,14 @@ RUBY
723
736
  @lexer.expected!(names.map {|tok| Lexer::TOKEN_NAMES[tok] || tok}.join(" or "))
724
737
  end
725
738
 
726
- def try_tok(name)
739
+ def peek_tok(name)
727
740
  # Avoids an array allocation caused by argument globbing in the try_toks method.
728
741
  peeked = @lexer.peek
729
- peeked && name == peeked.type && @lexer.next
742
+ peeked && name == peeked.type
743
+ end
744
+
745
+ def try_tok(name)
746
+ peek_tok(name) && @lexer.next
730
747
  end
731
748
 
732
749
  def try_toks(*names)
@@ -771,27 +788,12 @@ RUBY
771
788
  range(source_range_or_start_pos, end_pos)
772
789
  end
773
790
 
774
- node.css_variable_warning = @css_variable_warning
775
791
  node.line = source_range.start_pos.line
776
792
  node.source_range = source_range
777
793
  node.filename = @options[:filename]
778
794
  node
779
795
  end
780
796
 
781
- # Runs the given block without CSS variable warnings enabled.
782
- #
783
- # CSS warnings don't apply within interpolation, so this is used to
784
- # disable them.
785
- #
786
- # @yield []
787
- def without_css_variable_warning
788
- old_css_variable_warning = @css_variable_warning
789
- @css_variable_warning = nil
790
- yield
791
- ensure
792
- @css_variable_warning = old_css_variable_warning
793
- end
794
-
795
797
  # Checks a script node for any immediately-deprecated interpolations, and
796
798
  # emits warnings for them.
797
799
  #
@@ -13,6 +13,11 @@ module Sass::Script::Tree
13
13
  # @return [String]
14
14
  attr_reader :name
15
15
 
16
+ # The callable to be invoked
17
+ #
18
+ # @return [Sass::Callable] or nil if no callable is provided.
19
+ attr_reader :callable
20
+
16
21
  # The arguments to the function.
17
22
  #
18
23
  # @return [Array<Node>]
@@ -39,13 +44,19 @@ module Sass::Script::Tree
39
44
  # @return [Node?]
40
45
  attr_accessor :kwarg_splat
41
46
 
42
- # @param name [String] See \{#name}
47
+ # @param name_or_callable [String, Sass::Callable] See \{#name}
43
48
  # @param args [Array<Node>] See \{#args}
44
49
  # @param keywords [Sass::Util::NormalizedMap<Node>] See \{#keywords}
45
50
  # @param splat [Node] See \{#splat}
46
51
  # @param kwarg_splat [Node] See \{#kwarg_splat}
47
- def initialize(name, args, keywords, splat, kwarg_splat)
48
- @name = name
52
+ def initialize(name_or_callable, args, keywords, splat, kwarg_splat)
53
+ if name_or_callable.is_a?(Sass::Callable)
54
+ @callable = name_or_callable
55
+ @name = name_or_callable.name
56
+ else
57
+ @callable = nil
58
+ @name = name_or_callable
59
+ end
49
60
  @args = args
50
61
  @keywords = keywords
51
62
  @splat = splat
@@ -56,8 +67,7 @@ module Sass::Script::Tree
56
67
  # @return [String] A string representation of the function call
57
68
  def inspect
58
69
  args = @args.map {|a| a.inspect}.join(', ')
59
- keywords = Sass::Util.hash_to_a(@keywords.as_stored).
60
- map {|k, v| "$#{k}: #{v.inspect}"}.join(', ')
70
+ keywords = @keywords.as_stored.to_a.map {|k, v| "$#{k}: #{v.inspect}"}.join(', ')
61
71
  # rubocop:disable RedundantSelf
62
72
  if self.splat
63
73
  splat = args.empty? && keywords.empty? ? "" : ", "
@@ -77,8 +87,7 @@ module Sass::Script::Tree
77
87
  end
78
88
 
79
89
  args = @args.map(&arg_to_sass)
80
- keywords = Sass::Util.hash_to_a(@keywords.as_stored).
81
- map {|k, v| "$#{dasherize(k, opts)}: #{arg_to_sass[v]}"}
90
+ keywords = @keywords.as_stored.to_a.map {|k, v| "$#{dasherize(k, opts)}: #{arg_to_sass[v]}"}
82
91
 
83
92
  # rubocop:disable RedundantSelf
84
93
  if self.splat
@@ -120,27 +129,31 @@ module Sass::Script::Tree
120
129
  # @return [Sass::Script::Value] The SassScript object that is the value of the function call
121
130
  # @raise [Sass::SyntaxError] if the function call raises an ArgumentError
122
131
  def _perform(environment)
123
- args = Sass::Util.enum_with_index(@args).
132
+ args = @args.each_with_index.
124
133
  map {|a, i| perform_arg(a, environment, signature && signature.args[i])}
125
134
  keywords = Sass::Util.map_hash(@keywords) do |k, v|
126
135
  [k, perform_arg(v, environment, k.tr('-', '_'))]
127
136
  end
128
137
  splat = Sass::Tree::Visitors::Perform.perform_splat(
129
138
  @splat, keywords, @kwarg_splat, environment)
130
- if (fn = environment.function(@name))
131
- css_variable_warning.warn! if css_variable_warning
132
- return without_original(perform_sass_fn(fn, args, splat, environment))
139
+
140
+ fn = @callable || environment.function(@name)
141
+
142
+ if fn && fn.origin == :stylesheet
143
+ environment.stack.with_function(filename, line, name) do
144
+ return without_original(perform_sass_fn(fn, args, splat, environment))
145
+ end
133
146
  end
134
147
 
135
148
  args = construct_ruby_args(ruby_name, args, splat, environment)
136
149
 
137
- if Sass::Script::Functions.callable?(ruby_name)
138
- css_variable_warning.warn! if css_variable_warning
139
-
150
+ if Sass::Script::Functions.callable?(ruby_name) && (!fn || fn.origin == :builtin)
140
151
  local_environment = Sass::Environment.new(environment.global_env, environment.options)
141
152
  local_environment.caller = Sass::ReadOnlyEnvironment.new(environment, environment.options)
142
- result = opts(Sass::Script::Functions::EvaluationContext.new(
143
- local_environment).send(ruby_name, *args))
153
+ result = local_environment.stack.with_function(filename, line, name) do
154
+ opts(Sass::Script::Functions::EvaluationContext.new(
155
+ local_environment).send(ruby_name, *args))
156
+ end
144
157
  without_original(result)
145
158
  else
146
159
  opts(to_literal(args))
@@ -206,6 +219,7 @@ module Sass::Script::Tree
206
219
  raise Sass::SyntaxError.new(
207
220
  "#{args[signature.args.size].inspect} is not a keyword argument for `#{name}'")
208
221
  elsif keywords.empty?
222
+ args << {} if signature.var_kwargs
209
223
  return args
210
224
  end
211
225
 
@@ -271,30 +285,21 @@ module Sass::Script::Tree
271
285
  message = "wrong number of arguments (#{given} for #{expected})"
272
286
  end
273
287
  elsif Sass::Util.jruby?
274
- if Sass::Util.jruby1_6?
275
- should_maybe_raise = e.message =~ /^wrong number of arguments \((\d+) for (\d+)\)/ &&
276
- # The one case where JRuby does include the Ruby name of the function
277
- # is manually-thrown ArgumentErrors, which are indistinguishable from
278
- # legitimate ArgumentErrors. We treat both of these as
279
- # Sass::SyntaxErrors even though it can hide Ruby errors.
280
- e.backtrace[0] !~ /:in `(block in )?#{ruby_name}'$/
281
- else
282
- should_maybe_raise =
283
- e.message =~ /^wrong number of arguments calling `[^`]+` \((\d+) for (\d+)\)/
284
- given, expected = $1, $2
285
- end
288
+ should_maybe_raise =
289
+ e.message =~ /^wrong number of arguments calling `[^`]+` \((\d+) for (\d+)\)/
290
+ given, expected = $1, $2
286
291
 
287
292
  if should_maybe_raise
288
293
  # JRuby 1.7 includes __send__ before send and _perform.
289
294
  trace = e.backtrace.dup
290
- raise e if !Sass::Util.jruby1_6? && trace.shift !~ /:in `__send__'$/
295
+ raise e if trace.shift !~ /:in `__send__'$/
291
296
 
292
297
  # JRuby (as of 1.7.2) doesn't put the actual method
293
298
  # for which the argument error was thrown in the backtrace, so we
294
299
  # detect whether our send threw an argument error.
295
300
  if !(trace[0] =~ /:in `send'$/ && trace[1] =~ /:in `_perform'$/)
296
301
  raise e
297
- elsif !Sass::Util.jruby1_6?
302
+ else
298
303
  # JRuby 1.7 doesn't use standard formatting for its ArgumentErrors.
299
304
  message = "wrong number of arguments (#{given} for #{expected})"
300
305
  end
@@ -13,13 +13,20 @@ module Sass::Script::Tree
13
13
  # @return [Symbol]
14
14
  attr_reader :separator
15
15
 
16
+ # Whether the list is surrounded by square brackets.
17
+ #
18
+ # @return [Boolean]
19
+ attr_reader :bracketed
20
+
16
21
  # Creates a new list literal.
17
22
  #
18
23
  # @param elements [Array<Node>] See \{#elements}
19
24
  # @param separator [Symbol] See \{#separator}
20
- def initialize(elements, separator)
25
+ # @param bracketed [Boolean] See \{#bracketed}
26
+ def initialize(elements, separator: nil, bracketed: false)
21
27
  @elements = elements
22
28
  @separator = separator
29
+ @bracketed = bracketed
23
30
  end
24
31
 
25
32
  # @see Node#children
@@ -27,7 +34,7 @@ module Sass::Script::Tree
27
34
 
28
35
  # @see Value#to_sass
29
36
  def to_sass(opts = {})
30
- return "()" if elements.empty?
37
+ return bracketed ? "[]" : "()" if elements.empty?
31
38
  members = elements.map do |v|
32
39
  if element_needs_parens?(v)
33
40
  "(#{v.to_sass(opts)})"
@@ -36,9 +43,12 @@ module Sass::Script::Tree
36
43
  end
37
44
  end
38
45
 
39
- return "(#{members.first},)" if separator == :comma && members.length == 1
46
+ if separator == :comma && members.length == 1
47
+ return "#{bracketed ? '[' : '('}#{members.first},#{bracketed ? ']' : ')'}"
48
+ end
40
49
 
41
- members.join(sep_str(nil))
50
+ contents = members.join(sep_str(nil))
51
+ bracketed ? "[#{contents}]" : contents
42
52
  end
43
53
 
44
54
  # @see Node#deep_copy
@@ -49,7 +59,9 @@ module Sass::Script::Tree
49
59
  end
50
60
 
51
61
  def inspect
52
- "(#{elements.map {|e| e.inspect}.join(separator == :space ? ' ' : ', ')})"
62
+ (bracketed ? '[' : '(') +
63
+ elements.map {|e| e.inspect}.join(separator == :space ? ' ' : ', ') +
64
+ (bracketed ? ']' : ')')
53
65
  end
54
66
 
55
67
  def force_division!
@@ -61,7 +73,8 @@ module Sass::Script::Tree
61
73
  def _perform(environment)
62
74
  list = Sass::Script::Value::List.new(
63
75
  elements.map {|e| e.perform(environment)},
64
- separator)
76
+ separator: separator,
77
+ bracketed: bracketed)
65
78
  list.source_range = source_range
66
79
  list.options = options
67
80
  list
@@ -73,8 +86,10 @@ module Sass::Script::Tree
73
86
  # when serialized to Sass.
74
87
  def element_needs_parens?(element)
75
88
  if element.is_a?(ListLiteral)
76
- return Sass::Script::Parser.precedence_of(element.separator) <=
77
- Sass::Script::Parser.precedence_of(separator)
89
+ return false if element.elements.length < 2
90
+ return false if element.bracketed
91
+ return Sass::Script::Parser.precedence_of(element.separator || :space) <=
92
+ Sass::Script::Parser.precedence_of(separator || :space)
78
93
  end
79
94
 
80
95
  return false unless separator == :space
@@ -49,14 +49,14 @@ module Sass::Script::Tree
49
49
  # @see Node#_perform
50
50
  def _perform(environment)
51
51
  keys = Set.new
52
- map = Sass::Script::Value::Map.new(Sass::Util.to_hash(pairs.map do |(k, v)|
52
+ map = Sass::Script::Value::Map.new(Hash[pairs.map do |(k, v)|
53
53
  k, v = k.perform(environment), v.perform(environment)
54
54
  if keys.include?(k)
55
55
  raise Sass::SyntaxError.new("Duplicate key #{k.inspect} in map #{to_sass}.")
56
56
  end
57
57
  keys << k
58
58
  [k, v]
59
- end))
59
+ end])
60
60
  map.options = options
61
61
  map
62
62
  end
@@ -23,14 +23,6 @@ module Sass::Script::Tree
23
23
  # @return [String]
24
24
  attr_accessor :filename
25
25
 
26
- # The warning that this node should emit if it executes in a way that's not
27
- # safe for a CSS variable value.
28
- #
29
- # This is `nil` if this is not in a CSS variable value.
30
- #
31
- # @return [Sass::Script::CssVariableWarning]
32
- attr_accessor :css_variable_warning
33
-
34
26
  # Sets the options hash for this node,
35
27
  # as well as for all child nodes.
36
28
  # See {file:SASS_REFERENCE.md#Options the Sass options documentation}.
@@ -81,13 +81,6 @@ module Sass::Script::Tree
81
81
  "Invalid null operation: \"#{value1.inspect} #{@operator} #{value2.inspect}\".")
82
82
  end
83
83
 
84
- if css_variable_warning && @operator == :div &&
85
- !(value1.is_a?(Sass::Script::Value::Number) && value1.original &&
86
- value2.is_a?(Sass::Script::Value::Number) && value2.original) &&
87
- !(value1.is_a?(Sass::Script::Value::String) && value2.is_a?(Sass::Script::Value::String))
88
- css_variable_warning.warn!
89
- end
90
-
91
84
  begin
92
85
  result = opts(value1.send(@operator, value2))
93
86
  rescue NoMethodError => e
@@ -17,7 +17,7 @@ module Sass::Script::Value
17
17
  # @param keywords [Hash<String, Value>, NormalizedMap<Value>] See \{#keywords}
18
18
  # @param separator [String] See \{List#separator}.
19
19
  def initialize(value, keywords, separator)
20
- super(value, separator)
20
+ super(value, separator: separator)
21
21
  if keywords.is_a?(Sass::Util::NormalizedMap)
22
22
  @keywords = keywords
23
23
  else
@@ -192,6 +192,12 @@ MSG
192
192
  # @return [Symbol]
193
193
  def separator; nil; end
194
194
 
195
+ # Whether the value is surrounded by square brackets. For non-list values,
196
+ # this will be `false`.
197
+ #
198
+ # @return [Boolean]
199
+ def bracketed; false; end
200
+
195
201
  # Returns the value of this value as a list.
196
202
  # Single values are considered the same as single-element lists.
197
203
  #
@@ -228,6 +234,17 @@ MSG
228
234
  false
229
235
  end
230
236
 
237
+ # Creates a new list containing `contents` but with the same brackets and
238
+ # separators as this object, when interpreted as a list.
239
+ #
240
+ # @param contents [Array<Value>] The contents of the new list.
241
+ # @param separator [Symbol] The separator of the new list. Defaults to \{#separator}.
242
+ # @param bracketed [Boolean] Whether the new list is bracketed. Defaults to \{#bracketed}.
243
+ # @return [Sass::Script::Value::List]
244
+ def with_contents(contents, separator: self.separator, bracketed: self.bracketed)
245
+ Sass::Script::Value::List.new(contents, separator: separator, bracketed: bracketed)
246
+ end
247
+
231
248
  protected
232
249
 
233
250
  # Evaluates the value.
@@ -0,0 +1,25 @@
1
+ module Sass::Script::Value
2
+ # A SassScript object representing a null value.
3
+ class Callable < Base
4
+ # Constructs a Callable value for use in SassScript.
5
+ #
6
+ # @param callable [Sass::Callable] The callable to be used when the
7
+ # callable is called.
8
+ def initialize(callable)
9
+ super(callable)
10
+ end
11
+
12
+ def to_s(opts = {})
13
+ raise Sass::SyntaxError.new("#{to_sass} isn't a valid CSS value.")
14
+ end
15
+
16
+ def inspect
17
+ to_sass
18
+ end
19
+
20
+ # @abstract
21
+ def to_sass
22
+ Sass::Util.abstract(self)
23
+ end
24
+ end
25
+ end
@@ -563,6 +563,11 @@ module Sass::Script::Value
563
563
  def to_s(opts = {})
564
564
  return smallest if options[:style] == :compressed
565
565
  return representation if representation
566
+
567
+ # IE10 doesn't properly support the color name "transparent", so we emit
568
+ # generated transparent colors as rgba(0, 0, 0, 0) in favor of that. See
569
+ # #1782.
570
+ return rgba_str if Number.basically_equal?(alpha, 0)
566
571
  return name if name
567
572
  alpha? ? rgba_str : hex_str
568
573
  end