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
@@ -0,0 +1,19 @@
1
+ module Sass::Script::Value
2
+ # A SassScript object representing a function.
3
+ class Function < Callable
4
+ # Constructs a Function value for use in SassScript.
5
+ #
6
+ # @param function [Sass::Callable] The callable to be used when the
7
+ # function is invoked.
8
+ def initialize(function)
9
+ unless function.type == "function"
10
+ raise ArgumentError.new("A callable of type function was expected.")
11
+ end
12
+ super
13
+ end
14
+
15
+ def to_sass
16
+ %{get-function("#{value.name}")}
17
+ end
18
+ end
19
+ end
@@ -68,26 +68,35 @@ module Sass::Script::Value
68
68
  Number.new(number, *parse_unit_string(unit_string))
69
69
  end
70
70
 
71
- # @overload list(*elements, separator)
71
+ # @overload list(*elements, separator:, bracketed: false)
72
72
  # Create a space-separated list from the arguments given.
73
73
  # @param elements [Array<Sass::Script::Value::Base>] Each argument will be a list element.
74
74
  # @param separator [Symbol] Either :space or :comma.
75
+ # @param bracketed [Boolean] Whether the list uses square brackets.
75
76
  # @return [Sass::Script::Value::List] The space separated list.
76
77
  #
77
- # @overload list(array, separator)
78
+ # @overload list(array, separator:, bracketed: false)
78
79
  # Create a space-separated list from the array given.
79
80
  # @param array [Array<Sass::Script::Value::Base>] A ruby array of Sass values
80
81
  # to make into a list.
82
+ # @param separator [Symbol] Either :space or :comma.
83
+ # @param bracketed [Boolean] Whether the list uses square brackets.
81
84
  # @return [Sass::Script::Value::List] The space separated list.
82
- def list(*elements)
83
- unless elements.last.is_a?(Symbol)
84
- raise ArgumentError.new("A list type of :space or :comma must be specified.")
85
+ def list(*elements, separator: nil, bracketed: false)
86
+ # Support passing separator as the last value in elements for
87
+ # backwards-compatibility.
88
+ if separator.nil?
89
+ if elements.last.is_a?(Symbol)
90
+ separator = elements.pop
91
+ else
92
+ raise ArgumentError.new("A separator of :space or :comma must be specified.")
93
+ end
85
94
  end
86
- separator = elements.pop
95
+
87
96
  if elements.size == 1 && elements.first.is_a?(Array)
88
97
  elements = elements.first
89
98
  end
90
- Sass::Script::Value::List.new(elements, separator)
99
+ Sass::Script::Value::List.new(elements, separator: separator, bracketed: bracketed)
91
100
  end
92
101
 
93
102
  # Construct a Sass map.
@@ -196,14 +205,25 @@ module Sass::Script::Value
196
205
  raise ArgumentError.new(err)
197
206
  end
198
207
 
199
- # Returns true when the literal is a string containing a calc()
208
+ # Returns true when the literal is a string containing a calc().
209
+ #
210
+ # Use \{#special_number?} in preference to this.
200
211
  #
201
212
  # @param literal [Sass::Script::Value::Base] The value to check
202
- # @return boolean
213
+ # @return Boolean
203
214
  def calc?(literal)
204
215
  literal.is_a?(Sass::Script::Value::String) && literal.value =~ /calc\(/
205
216
  end
206
217
 
218
+ # Returns whether the literal is a special CSS value that may evaluate to a
219
+ # number, such as `calc()` or `var()`.
220
+ #
221
+ # @param literal [Sass::Script::Value::Base] The value to check
222
+ # @return Boolean
223
+ def special_number?(literal)
224
+ literal.is_a?(Sass::Script::Value::String) && literal.value =~ /(calc|var)\(/
225
+ end
226
+
207
227
  private
208
228
 
209
229
  # Converts a user-provided selector into string form or throws an
@@ -14,13 +14,20 @@ module Sass::Script::Value
14
14
  # @return [Symbol]
15
15
  attr_reader :separator
16
16
 
17
+ # Whether the list is surrounded by square brackets.
18
+ #
19
+ # @return [Boolean]
20
+ attr_reader :bracketed
21
+
17
22
  # Creates a new list.
18
23
  #
19
24
  # @param value [Array<Value>] See \{#value}
20
25
  # @param separator [Symbol] See \{#separator}
21
- def initialize(value, separator)
26
+ # @param bracketed [Boolean] See \{#bracketed}
27
+ def initialize(value, separator: nil, bracketed: false)
22
28
  super(value)
23
29
  @separator = separator
30
+ @bracketed = bracketed
24
31
  end
25
32
 
26
33
  # @see Value#options=
@@ -33,24 +40,30 @@ module Sass::Script::Value
33
40
  def eq(other)
34
41
  Sass::Script::Value::Bool.new(
35
42
  other.is_a?(List) && value == other.value &&
36
- separator == other.separator)
43
+ separator == other.separator && bracketed == other.bracketed)
37
44
  end
38
45
 
39
46
  def hash
40
- @hash ||= [value, separator].hash
47
+ @hash ||= [value, separator, bracketed].hash
41
48
  end
42
49
 
43
50
  # @see Value#to_s
44
51
  def to_s(opts = {})
45
- raise Sass::SyntaxError.new("() isn't a valid CSS value.") if value.empty?
46
- value.
52
+ if !bracketed && value.empty?
53
+ raise Sass::SyntaxError.new("#{inspect} isn't a valid CSS value.")
54
+ end
55
+
56
+ members = value.
47
57
  reject {|e| e.is_a?(Null) || e.is_a?(List) && e.value.empty?}.
48
- map {|e| e.to_s(opts)}.join(sep_str)
58
+ map {|e| e.to_s(opts)}
59
+
60
+ contents = members.join(sep_str)
61
+ bracketed ? "[#{contents}]" : contents
49
62
  end
50
63
 
51
64
  # @see Value#to_sass
52
65
  def to_sass(opts = {})
53
- return "()" if value.empty?
66
+ return bracketed ? "[]" : "()" if value.empty?
54
67
  members = value.map do |v|
55
68
  if element_needs_parens?(v)
56
69
  "(#{v.to_sass(opts)})"
@@ -58,19 +71,26 @@ module Sass::Script::Value
58
71
  v.to_sass(opts)
59
72
  end
60
73
  end
61
- return "(#{members.first},)" if members.length == 1 && separator == :comma
62
- members.join(sep_str(nil))
74
+
75
+ if separator == :comma && members.length == 1
76
+ return "#{bracketed ? '[' : '('}#{members.first},#{bracketed ? ']' : ')'}"
77
+ end
78
+
79
+ contents = members.join(sep_str(nil))
80
+ bracketed ? "[#{contents}]" : contents
63
81
  end
64
82
 
65
83
  # @see Value#to_h
66
84
  def to_h
67
- return Sass::Util.ordered_hash if value.empty?
85
+ return {} if value.empty?
68
86
  super
69
87
  end
70
88
 
71
89
  # @see Value#inspect
72
90
  def inspect
73
- "(#{value.map {|e| e.inspect}.join(sep_str(nil))})"
91
+ (bracketed ? '[' : '(') +
92
+ value.map {|e| e.inspect}.join(sep_str(nil)) +
93
+ (bracketed ? ']' : ')')
74
94
  end
75
95
 
76
96
  # Asserts an index is within the list.
@@ -94,9 +114,10 @@ module Sass::Script::Value
94
114
 
95
115
  def element_needs_parens?(element)
96
116
  if element.is_a?(List)
97
- return false if element.value.empty?
98
- precedence = Sass::Script::Parser.precedence_of(separator)
99
- return Sass::Script::Parser.precedence_of(element.separator) <= precedence
117
+ return false if element.value.length < 2
118
+ return false if element.bracketed
119
+ precedence = Sass::Script::Parser.precedence_of(separator || :space)
120
+ return Sass::Script::Parser.precedence_of(element.separator || :space) <= precedence
100
121
  end
101
122
 
102
123
  return false unless separator == :space
@@ -12,7 +12,7 @@ module Sass::Script::Value
12
12
  #
13
13
  # @param hash [Hash<Node, Node>]
14
14
  def initialize(hash)
15
- super(Sass::Util.ordered_hash(hash))
15
+ super(hash)
16
16
  end
17
17
 
18
18
  # @see Value#options=
@@ -32,7 +32,7 @@ module Sass::Script::Value
32
32
  # @see Value#to_a
33
33
  def to_a
34
34
  value.map do |k, v|
35
- list = List.new([k, v], :space)
35
+ list = List.new([k, v], separator: :space)
36
36
  list.options = options
37
37
  list
38
38
  end
@@ -34,7 +34,7 @@ module Sass::Script::Value
34
34
  attr_accessor :original
35
35
 
36
36
  def self.precision
37
- Thread.current[:sass_numeric_precision] || Thread.main[:sass_numeric_precision] || 5
37
+ Thread.current[:sass_numeric_precision] || Thread.main[:sass_numeric_precision] || 10
38
38
  end
39
39
 
40
40
  # Sets the number of digits of precision
@@ -9,3 +9,5 @@ require 'sass/script/value/null'
9
9
  require 'sass/script/value/list'
10
10
  require 'sass/script/value/arg_list'
11
11
  require 'sass/script/value/map'
12
+ require 'sass/script/value/callable'
13
+ require 'sass/script/value/function'
@@ -99,6 +99,18 @@ module Sass
99
99
  condition
100
100
  end
101
101
 
102
+ # Parses a custom property value.
103
+ #
104
+ # @return [Array<String, Sass::Script;:Tree::Node>] The interpolated value.
105
+ # @raise [Sass::SyntaxError] if there's a syntax error in the value,
106
+ # or if it doesn't take up the entire input string.
107
+ def parse_declaration_value
108
+ init_scanner!
109
+ value = declaration_value
110
+ expected('"}"') unless value && @scanner.eos?
111
+ value
112
+ end
113
+
102
114
  private
103
115
 
104
116
  include Sass::SCSS::RX
@@ -767,6 +779,12 @@ module Sass
767
779
  mid = [str {ss}]
768
780
  return name + mid unless tok(/:/)
769
781
  mid << ':'
782
+
783
+ # If this is a CSS variable, parse it as a property no matter what.
784
+ if name.first.is_a?(String) && name.first.start_with?("--")
785
+ return css_variable_declaration(name, name_start_pos, name_end_pos)
786
+ end
787
+
770
788
  return name + mid + [':'] if tok(/:/)
771
789
  mid << str {ss}
772
790
  post_colon_whitespace = !mid.last.empty?
@@ -775,7 +793,7 @@ module Sass
775
793
  value_start_pos = source_position
776
794
  value = nil
777
795
  error = catch_error do
778
- value = value!(name.first.is_a?(String) && name.first.start_with?("--"))
796
+ value = value!
779
797
  if tok?(/\{/)
780
798
  # Properties that are ambiguous with selectors can't have additional
781
799
  # properties nested beneath them.
@@ -802,7 +820,7 @@ module Sass
802
820
  ss
803
821
  require_block = tok?(/\{/)
804
822
 
805
- node = node(Sass::Tree::PropNode.new(name.flatten.compact, value, :new),
823
+ node = node(Sass::Tree::PropNode.new(name.flatten.compact, [value], :new),
806
824
  name_start_pos, value_end_pos)
807
825
  node.name_source_range = range(name_start_pos, name_end_pos)
808
826
  node.value_source_range = range(value_start_pos, value_end_pos)
@@ -811,13 +829,21 @@ module Sass
811
829
  nested_properties! node
812
830
  end
813
831
 
814
- # This production is similar to the CSS [`<any-value>`][any-value]
815
- # production, but as the name implies, not quite the same. It's meant to
816
- # consume values that could be a selector, an expression, or a combination
817
- # of both. It respects strings and comments and supports interpolation. It
818
- # will consume up to "{", "}", ";", or "!".
819
- #
820
- # [any-value]: http://dev.w3.org/csswg/css-variables/#typedef-any-value
832
+ def css_variable_declaration(name, name_start_pos, name_end_pos)
833
+ value_start_pos = source_position
834
+ value = declaration_value
835
+ value_end_pos = source_position
836
+
837
+ node = node(Sass::Tree::PropNode.new(name.flatten.compact, value, :new),
838
+ name_start_pos, value_end_pos)
839
+ node.name_source_range = range(name_start_pos, name_end_pos)
840
+ node.value_source_range = range(value_start_pos, value_end_pos)
841
+ node
842
+ end
843
+
844
+ # This production consumes values that could be a selector, an expression,
845
+ # or a combination of both. It respects strings and comments and supports
846
+ # interpolation. It will consume up to "{", "}", ";", or "!".
821
847
  #
822
848
  # Values consumed by this production will usually be parsed more
823
849
  # thoroughly once interpolation has been resolved.
@@ -851,6 +877,60 @@ module Sass
851
877
  interpolation(:warn_for_color)
852
878
  end
853
879
 
880
+ def declaration_value(top_level: true)
881
+ return unless (tok = declaration_value_token(top_level))
882
+ value = [tok]
883
+ while (tok = declaration_value_token(top_level))
884
+ value << tok
885
+ end
886
+ merge(value)
887
+ end
888
+
889
+ def declaration_value_token(top_level)
890
+ # This comes, more or less, from the [token consumption algorithm][].
891
+ # However, since we don't have to worry about the token semantics, we
892
+ # just consume everything until we come across a token with special
893
+ # semantics.
894
+ #
895
+ # [token consumption algorithm]: https://drafts.csswg.org/css-syntax-3/#consume-token.
896
+ result = tok(%r{
897
+ (
898
+ (?!
899
+ url\(
900
+ )
901
+ [^()\[\]{}"'#/ \t\r\n\f#{top_level ? ";!" : ""}]
902
+ |
903
+ \#(?!\{)
904
+ |
905
+ /(?!\*)
906
+ )+
907
+ }xi) || interp_string || interp_uri || interpolation || tok(COMMENT)
908
+ return result if result
909
+
910
+ # Fold together multiple characters of whitespace that don't include
911
+ # newlines. The value only cares about the tokenization, so this is safe
912
+ # as long as we don't delete whitespace entirely. It's important that we
913
+ # fold here rather than post-processing, since we aren't allowed to fold
914
+ # whitespace within strings and we lose that context later on.
915
+ if (ws = tok(S))
916
+ return ws.include?("\n") ? ws.gsub(/\A[^\n]*/, '') : ' '
917
+ end
918
+
919
+ if tok(/\(/)
920
+ value = declaration_value(top_level: false)
921
+ tok!(/\)/)
922
+ ['(', *value, ')']
923
+ elsif tok(/\[/)
924
+ value = declaration_value(top_level: false)
925
+ tok!(/\]/)
926
+ ['[', *value, ']']
927
+ elsif tok(/\{/)
928
+ value = declaration_value(top_level: false)
929
+ tok!(/\}/)
930
+ ['{', *value, '}']
931
+ end
932
+ end
933
+
854
934
  def declaration
855
935
  # This allows the "*prop: val", ":prop: val", "#prop: val", and ".prop:
856
936
  # val" hacks.
@@ -871,12 +951,12 @@ module Sass
871
951
  tok!(/:/)
872
952
  ss
873
953
  value_start_pos = source_position
874
- value = value!(name.first.is_a?(String) && name.first.start_with?("--"))
954
+ value = value!
875
955
  value_end_pos = source_position
876
956
  ss
877
957
  require_block = tok?(/\{/)
878
958
 
879
- node = node(Sass::Tree::PropNode.new(name.flatten.compact, value, :new),
959
+ node = node(Sass::Tree::PropNode.new(name.flatten.compact, [value], :new),
880
960
  name_start_pos, value_end_pos)
881
961
  node.name_source_range = range(name_start_pos, name_end_pos)
882
962
  node.value_source_range = range(value_start_pos, value_end_pos)
@@ -885,7 +965,7 @@ module Sass
885
965
  nested_properties! node
886
966
  end
887
967
 
888
- def value!(css_variable = false)
968
+ def value!
889
969
  if tok?(/\{/)
890
970
  str = Sass::Script::Tree::Literal.new(Sass::Script::Value::String.new(""))
891
971
  str.line = source_position.line
@@ -899,25 +979,16 @@ module Sass
899
979
  # we don't parse it at all, and instead return a plain old string
900
980
  # containing the value.
901
981
  # This results in a dramatic speed increase.
902
- if (val = tok(STATIC_VALUE, true))
982
+ if (val = tok(STATIC_VALUE))
903
983
  str = Sass::Script::Tree::Literal.new(Sass::Script::Value::String.new(val.strip))
904
984
  str.line = start_pos.line
905
985
  str.source_range = range(start_pos)
906
986
  return str
907
987
  end
908
-
909
- sass_script(:parse, css_variable)
988
+ sass_script(:parse)
910
989
  end
911
990
 
912
991
  def nested_properties!(node)
913
- if node.name.first.is_a?(String) && node.name.first.start_with?("--")
914
- Sass::Util.sass_warn(<<WARNING)
915
- DEPRECATION WARNING on line #{@line}#{" of #{@filename}" if @filename}:
916
- Sass 3.6 will change the way CSS variables are parsed. Instead of being parsed as
917
- normal properties, they will not allow any Sass-specific behavior other than \#{}.
918
- WARNING
919
- end
920
-
921
992
  @expected = 'expression (e.g. 1px, bold) or "{"'
922
993
  block(node, :property)
923
994
  end
@@ -1005,7 +1076,7 @@ WARNING
1005
1076
  end
1006
1077
 
1007
1078
  def interp_ident(start = IDENT)
1008
- val = tok(start) || interpolation(:warn_for_color) || tok(IDENT_HYPHEN_INTERP, true)
1079
+ val = tok(start) || interpolation(:warn_for_color) || tok(IDENT_HYPHEN_INTERP)
1009
1080
  return unless val
1010
1081
  res = [val]
1011
1082
  while (val = tok(NAME) || interpolation(:warn_for_color))
@@ -1084,7 +1155,7 @@ WARNING
1084
1155
  :media_expr => "media expression (e.g. (min-device-width: 800px))",
1085
1156
  :at_root_query => "@at-root query (e.g. (without: media))",
1086
1157
  :at_root_directive_list => '* or identifier',
1087
- :pseudo_args => "expression (e.g. fr, 2n+1)",
1158
+ :declaration_value => "expression (e.g. fr, 2n+1)",
1088
1159
  :interp_ident => "identifier",
1089
1160
  :qualified_name => "identifier",
1090
1161
  :expr => "expression (e.g. 1px, bold)",
@@ -1099,9 +1170,9 @@ WARNING
1099
1170
  :keyframes_selector => "keyframes selector (e.g. 10%)"
1100
1171
  }
1101
1172
 
1102
- TOK_NAMES = Sass::Util.to_hash(Sass::SCSS::RX.constants.map do |c|
1173
+ TOK_NAMES = Hash[Sass::SCSS::RX.constants.map do |c|
1103
1174
  [Sass::SCSS::RX.const_get(c), c.downcase]
1104
- end).merge(
1175
+ end].merge(
1105
1176
  IDENT => "identifier",
1106
1177
  /[;{}]/ => '";"',
1107
1178
  /\b(without|with)\b/ => '"with" or "without"'
@@ -1213,23 +1284,11 @@ WARNING
1213
1284
  # This is important because `#tok` is called all the time.
1214
1285
  NEWLINE = "\n"
1215
1286
 
1216
- def tok(rx, last_group_lookahead = false)
1287
+ def tok(rx)
1217
1288
  res = @scanner.scan(rx)
1218
1289
 
1219
1290
  return unless res
1220
1291
 
1221
- # This fixes https://github.com/nex3/sass/issues/104, which affects
1222
- # Ruby 1.8.7 and REE. This fix is to replace the ?= zero-width
1223
- # positive lookahead operator in the Regexp (which matches without
1224
- # consuming the matched group), with a match that does consume the
1225
- # group, but then rewinds the scanner and removes the group from the
1226
- # end of the matched string. This fix makes the assumption that the
1227
- # matched group will always occur at the end of the match.
1228
- if last_group_lookahead && @scanner[-1]
1229
- @scanner.pos -= @scanner[-1].length
1230
- res.slice!(-@scanner[-1].length..-1)
1231
- end
1232
-
1233
1292
  newline_count = res.count(NEWLINE)
1234
1293
  if newline_count > 0
1235
1294
  @line += newline_count
data/lib/sass/scss/rx.rb CHANGED
@@ -32,7 +32,7 @@ module Sass
32
32
  # @return [String] The escaped character
33
33
  # @private
34
34
  def self.escape_char(c)
35
- return "\\%06x" % (Sass::Util.ord(c)) unless c =~ %r{[ -/:-~]}
35
+ return "\\%06x" % c.ord unless c =~ %r{[ -/:-~]}
36
36
  "\\#{c}"
37
37
  end
38
38
 
@@ -50,13 +50,7 @@ module Sass
50
50
  H = /[0-9a-fA-F]/
51
51
  NL = /\n|\r\n|\r|\f/
52
52
  UNICODE = /\\#{H}{1,6}[ \t\r\n\f]?/
53
- s = if Sass::Util.ruby1_8?
54
- '\200-\377'
55
- elsif Sass::Util.macruby?
56
- '\u0080-\uD7FF\uE000-\uFFFD\U00010000-\U0010FFFF'
57
- else
58
- '\u{80}-\u{D7FF}\u{E000}-\u{FFFD}\u{10000}-\u{10FFFF}'
59
- end
53
+ s = '\u{80}-\u{D7FF}\u{E000}-\u{FFFD}\u{10000}-\u{10FFFF}'
60
54
  NONASCII = /[#{s}]/
61
55
  ESCAPE = /#{UNICODE}|\\[ -~#{s}]/
62
56
  NMSTART = /[_a-zA-Z]|#{NONASCII}|#{ESCAPE}/
@@ -127,13 +121,13 @@ module Sass
127
121
  OPTIONAL = /!#{W}optional/i
128
122
  IDENT_START = /-|#{NMSTART}/
129
123
 
130
- IDENT_HYPHEN_INTERP = /-(#\{)/
124
+ IDENT_HYPHEN_INTERP = /-(?=#\{)/
131
125
  STRING1_NOINTERP = /\"((?:[^\n\r\f\\"#]|#(?!\{)|#{ESCAPE})*)\"/
132
126
  STRING2_NOINTERP = /\'((?:[^\n\r\f\\'#]|#(?!\{)|#{ESCAPE})*)\'/
133
127
  STRING_NOINTERP = /#{STRING1_NOINTERP}|#{STRING2_NOINTERP}/
134
128
 
135
129
  STATIC_COMPONENT = /#{IDENT}|#{STRING_NOINTERP}|#{HEXCOLOR}|[+-]?#{NUMBER}|\!important/i
136
- STATIC_VALUE = %r(#{STATIC_COMPONENT}(\s*[\s,/]\s*#{STATIC_COMPONENT})*([;}]))i
130
+ STATIC_VALUE = %r(#{STATIC_COMPONENT}(\s*[\s,\/]\s*#{STATIC_COMPONENT})*(?=[;}]))i
137
131
  STATIC_SELECTOR = /(#{NMCHAR}|[ \t]|[,>+*]|[:#.]#{NMSTART}){1,50}([{])/i
138
132
  end
139
133
  end
@@ -276,6 +276,8 @@ MESSAGE
276
276
 
277
277
  PREFIXED_SELECTOR_PSEUDO_CLASSES = %w(nth-child nth-last-child).to_set
278
278
 
279
+ SELECTOR_PSEUDO_ELEMENTS = %w(slotted).to_set
280
+
279
281
  def pseudo
280
282
  s = tok(/::?/)
281
283
  return unless s
@@ -288,8 +290,10 @@ MESSAGE
288
290
  sel = selector_comma_sequence
289
291
  elsif s == ':' && PREFIXED_SELECTOR_PSEUDO_CLASSES.include?(deprefixed)
290
292
  arg, sel = prefixed_selector_pseudo
293
+ elsif s == '::' && SELECTOR_PSEUDO_ELEMENTS.include?(deprefixed)
294
+ sel = selector_comma_sequence
291
295
  else
292
- arg = expr!(:pseudo_args)
296
+ arg = expr!(:declaration_value).join
293
297
  end
294
298
 
295
299
  tok!(/\)/)
@@ -297,29 +301,6 @@ MESSAGE
297
301
  Selector::Pseudo.new(s == ':' ? :class : :element, name, arg, sel)
298
302
  end
299
303
 
300
- def pseudo_args
301
- arg = expr!(:pseudo_expr)
302
- while tok(/,/)
303
- arg << ',' << str {ss}
304
- arg.concat expr!(:pseudo_expr)
305
- end
306
- arg
307
- end
308
-
309
- def pseudo_expr
310
- res = pseudo_expr_token
311
- return unless res
312
- res << str {ss}
313
- while (e = pseudo_expr_token)
314
- res << e << str {ss}
315
- end
316
- res
317
- end
318
-
319
- def pseudo_expr_token
320
- tok(PLUS) || tok(/[-*]/) || tok(NUMBER) || tok(STRING) || tok(IDENT)
321
- end
322
-
323
304
  def prefixed_selector_pseudo
324
305
  prefix = str do
325
306
  expr = str {expr!(:a_n_plus_b)}
@@ -59,12 +59,11 @@ module Sass
59
59
  end
60
60
  alias_method :==, :eql?
61
61
 
62
- # Whether or not this selector sequence contains a placeholder selector.
63
- # Checks recursively.
64
- def has_placeholder?
65
- @has_placeholder ||= members.any? do |m|
66
- next m.has_placeholder? if m.is_a?(AbstractSequence)
67
- next m.selector && m.selector.has_placeholder? if m.is_a?(Pseudo)
62
+ # Whether or not this selector should be hidden due to containing a
63
+ # placeholder.
64
+ def invisible?
65
+ @invisible ||= members.any? do |m|
66
+ next m.invisible? if m.is_a?(AbstractSequence) || m.is_a?(Pseudo)
68
67
  m.is_a?(Placeholder)
69
68
  end
70
69
  end
@@ -73,6 +72,8 @@ module Sass
73
72
  #
74
73
  # @param opts [Hash] rendering options.
75
74
  # @option opts [Symbol] :style The css rendering style.
75
+ # @option placeholders [Boolean] :placeholders
76
+ # Whether to include placeholder selectors. Defaults to `true`.
76
77
  # @return [String]
77
78
  def to_s(opts = {})
78
79
  Sass::Util.abstract(self)
@@ -129,7 +129,7 @@ WARNING
129
129
  end
130
130
 
131
131
  extends[sel] = Sass::Tree::Visitors::Cssize::Extend.new(
132
- member, sel, extend_node, parent_directives, :not_found)
132
+ member, sel, extend_node, parent_directives, false)
133
133
  end
134
134
  end
135
135
  end
@@ -158,8 +158,8 @@ WARNING
158
158
  Sass::Script::Value::List.new(seq.members.map do |component|
159
159
  next if component == "\n"
160
160
  Sass::Script::Value::String.new(component.to_s)
161
- end.compact, :space)
162
- end, :comma)
161
+ end.compact, separator: :space)
162
+ end, separator: :comma)
163
163
  end
164
164
 
165
165
  # Returns a string representation of the sequence.
@@ -172,7 +172,10 @@ WARNING
172
172
 
173
173
  # @see AbstractSequence#to_s
174
174
  def to_s(opts = {})
175
- @members.map {|m| m.to_s(opts)}.
175
+ @members.map do |m|
176
+ next if opts[:placeholder] == false && m.invisible?
177
+ m.to_s(opts)
178
+ end.compact.
176
179
  join(opts[:style] == :compressed ? "," : ", ").
177
180
  gsub(", \n", ",\n")
178
181
  end
@@ -1,3 +1,4 @@
1
+ # coding: utf-8
1
2
  module Sass
2
3
  module Selector
3
4
  # A pseudoclass (e.g. `:visited`) or pseudoelement (e.g. `::first-line`)
@@ -48,6 +49,18 @@ module Sass
48
49
  @selector = selector
49
50
  end
50
51
 
52
+ def unique?
53
+ type == :class && normalized_name == 'root'
54
+ end
55
+
56
+ # Whether or not this selector should be hidden due to containing a
57
+ # placeholder.
58
+ def invisible?
59
+ # :not() is a special case—if you eliminate all the placeholders from
60
+ # it, it should match anything.
61
+ name != 'not' && @selector && @selector.members.all? {|s| s.invisible?}
62
+ end
63
+
51
64
  # Returns a copy of this with \{#selector} set to \{#new\_selector}.
52
65
  #
53
66
  # @param new_selector [CommaSequence]
@@ -77,7 +90,7 @@ module Sass
77
90
  # more complex cases that likely aren't worth the pain.
78
91
  next [] unless sel.name == name && sel.arg == arg
79
92
  sel.selector.members
80
- when 'has', 'host', 'host-context'
93
+ when 'has', 'host', 'host-context', 'slotted'
81
94
  # We can't expand nested selectors here, because each layer adds an
82
95
  # additional layer of semantics. For example, `:has(:has(img))`
83
96
  # doesn't match `<div><img></div>` but `:has(img)` does.
@@ -114,6 +127,10 @@ module Sass
114
127
 
115
128
  # @see Selector#to_s
116
129
  def to_s(opts = {})
130
+ # :not() is a special case, because :not(<nothing>) should match
131
+ # everything.
132
+ return '' if name == 'not' && @selector && @selector.members.all? {|m| m.invisible?}
133
+
117
134
  res = (syntactic_type == :class ? ":" : "::") + @name
118
135
  if @arg || @selector
119
136
  res << "("
@@ -161,7 +178,7 @@ module Sass
161
178
  their_seq = Sequence.new(parents + [their_sseq])
162
179
  our_seq.superselector?(their_seq)
163
180
  end
164
- when 'has', 'host', 'host-context'
181
+ when 'has', 'host', 'host-context', 'slotted'
165
182
  # Like :matches, :has (et al) can be a superselector of another
166
183
  # selector if its constituent selectors are a superset of those of
167
184
  # another :has in the other selector. However, the :matches other case