sass4 4.0.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 (147) hide show
  1. checksums.yaml +7 -0
  2. data/.yardopts +13 -0
  3. data/AGENTS.md +534 -0
  4. data/CODE_OF_CONDUCT.md +10 -0
  5. data/CONTRIBUTING.md +148 -0
  6. data/MIT-LICENSE +20 -0
  7. data/README.md +242 -0
  8. data/VERSION +1 -0
  9. data/VERSION_NAME +1 -0
  10. data/bin/sass +13 -0
  11. data/bin/sass-convert +12 -0
  12. data/bin/scss +13 -0
  13. data/extra/sass-spec-ref.sh +40 -0
  14. data/extra/update_watch.rb +13 -0
  15. data/init.rb +18 -0
  16. data/lib/sass/cache_stores/base.rb +88 -0
  17. data/lib/sass/cache_stores/chain.rb +34 -0
  18. data/lib/sass/cache_stores/filesystem.rb +60 -0
  19. data/lib/sass/cache_stores/memory.rb +46 -0
  20. data/lib/sass/cache_stores/null.rb +25 -0
  21. data/lib/sass/cache_stores.rb +15 -0
  22. data/lib/sass/callbacks.rb +67 -0
  23. data/lib/sass/css.rb +407 -0
  24. data/lib/sass/deprecation.rb +55 -0
  25. data/lib/sass/engine.rb +1236 -0
  26. data/lib/sass/environment.rb +236 -0
  27. data/lib/sass/error.rb +198 -0
  28. data/lib/sass/exec/base.rb +188 -0
  29. data/lib/sass/exec/sass_convert.rb +283 -0
  30. data/lib/sass/exec/sass_scss.rb +436 -0
  31. data/lib/sass/exec.rb +9 -0
  32. data/lib/sass/features.rb +48 -0
  33. data/lib/sass/importers/base.rb +182 -0
  34. data/lib/sass/importers/deprecated_path.rb +51 -0
  35. data/lib/sass/importers/filesystem.rb +221 -0
  36. data/lib/sass/importers.rb +23 -0
  37. data/lib/sass/logger/base.rb +47 -0
  38. data/lib/sass/logger/delayed.rb +50 -0
  39. data/lib/sass/logger/log_level.rb +45 -0
  40. data/lib/sass/logger.rb +17 -0
  41. data/lib/sass/media.rb +210 -0
  42. data/lib/sass/plugin/compiler.rb +552 -0
  43. data/lib/sass/plugin/configuration.rb +134 -0
  44. data/lib/sass/plugin/generic.rb +15 -0
  45. data/lib/sass/plugin/merb.rb +48 -0
  46. data/lib/sass/plugin/rack.rb +60 -0
  47. data/lib/sass/plugin/rails.rb +47 -0
  48. data/lib/sass/plugin/staleness_checker.rb +199 -0
  49. data/lib/sass/plugin.rb +134 -0
  50. data/lib/sass/railtie.rb +10 -0
  51. data/lib/sass/repl.rb +57 -0
  52. data/lib/sass/root.rb +7 -0
  53. data/lib/sass/script/css_lexer.rb +33 -0
  54. data/lib/sass/script/css_parser.rb +36 -0
  55. data/lib/sass/script/functions.rb +3103 -0
  56. data/lib/sass/script/lexer.rb +518 -0
  57. data/lib/sass/script/parser.rb +1164 -0
  58. data/lib/sass/script/tree/funcall.rb +314 -0
  59. data/lib/sass/script/tree/interpolation.rb +220 -0
  60. data/lib/sass/script/tree/list_literal.rb +119 -0
  61. data/lib/sass/script/tree/literal.rb +49 -0
  62. data/lib/sass/script/tree/map_literal.rb +64 -0
  63. data/lib/sass/script/tree/node.rb +119 -0
  64. data/lib/sass/script/tree/operation.rb +149 -0
  65. data/lib/sass/script/tree/selector.rb +26 -0
  66. data/lib/sass/script/tree/string_interpolation.rb +125 -0
  67. data/lib/sass/script/tree/unary_operation.rb +69 -0
  68. data/lib/sass/script/tree/variable.rb +57 -0
  69. data/lib/sass/script/tree.rb +16 -0
  70. data/lib/sass/script/value/arg_list.rb +36 -0
  71. data/lib/sass/script/value/base.rb +258 -0
  72. data/lib/sass/script/value/bool.rb +35 -0
  73. data/lib/sass/script/value/callable.rb +25 -0
  74. data/lib/sass/script/value/color.rb +704 -0
  75. data/lib/sass/script/value/function.rb +19 -0
  76. data/lib/sass/script/value/helpers.rb +298 -0
  77. data/lib/sass/script/value/list.rb +135 -0
  78. data/lib/sass/script/value/map.rb +70 -0
  79. data/lib/sass/script/value/null.rb +44 -0
  80. data/lib/sass/script/value/number.rb +564 -0
  81. data/lib/sass/script/value/string.rb +138 -0
  82. data/lib/sass/script/value.rb +13 -0
  83. data/lib/sass/script.rb +66 -0
  84. data/lib/sass/scss/css_parser.rb +61 -0
  85. data/lib/sass/scss/parser.rb +1343 -0
  86. data/lib/sass/scss/rx.rb +134 -0
  87. data/lib/sass/scss/static_parser.rb +351 -0
  88. data/lib/sass/scss.rb +14 -0
  89. data/lib/sass/selector/abstract_sequence.rb +112 -0
  90. data/lib/sass/selector/comma_sequence.rb +195 -0
  91. data/lib/sass/selector/pseudo.rb +291 -0
  92. data/lib/sass/selector/sequence.rb +661 -0
  93. data/lib/sass/selector/simple.rb +124 -0
  94. data/lib/sass/selector/simple_sequence.rb +348 -0
  95. data/lib/sass/selector.rb +327 -0
  96. data/lib/sass/shared.rb +76 -0
  97. data/lib/sass/source/map.rb +209 -0
  98. data/lib/sass/source/position.rb +39 -0
  99. data/lib/sass/source/range.rb +41 -0
  100. data/lib/sass/stack.rb +140 -0
  101. data/lib/sass/supports.rb +225 -0
  102. data/lib/sass/tree/at_root_node.rb +83 -0
  103. data/lib/sass/tree/charset_node.rb +22 -0
  104. data/lib/sass/tree/comment_node.rb +82 -0
  105. data/lib/sass/tree/content_node.rb +9 -0
  106. data/lib/sass/tree/css_import_node.rb +68 -0
  107. data/lib/sass/tree/debug_node.rb +18 -0
  108. data/lib/sass/tree/directive_node.rb +59 -0
  109. data/lib/sass/tree/each_node.rb +24 -0
  110. data/lib/sass/tree/error_node.rb +18 -0
  111. data/lib/sass/tree/extend_node.rb +43 -0
  112. data/lib/sass/tree/for_node.rb +36 -0
  113. data/lib/sass/tree/function_node.rb +44 -0
  114. data/lib/sass/tree/if_node.rb +52 -0
  115. data/lib/sass/tree/import_node.rb +75 -0
  116. data/lib/sass/tree/keyframe_rule_node.rb +15 -0
  117. data/lib/sass/tree/media_node.rb +48 -0
  118. data/lib/sass/tree/mixin_def_node.rb +38 -0
  119. data/lib/sass/tree/mixin_node.rb +52 -0
  120. data/lib/sass/tree/node.rb +240 -0
  121. data/lib/sass/tree/prop_node.rb +162 -0
  122. data/lib/sass/tree/return_node.rb +19 -0
  123. data/lib/sass/tree/root_node.rb +44 -0
  124. data/lib/sass/tree/rule_node.rb +153 -0
  125. data/lib/sass/tree/supports_node.rb +38 -0
  126. data/lib/sass/tree/trace_node.rb +33 -0
  127. data/lib/sass/tree/variable_node.rb +36 -0
  128. data/lib/sass/tree/visitors/base.rb +72 -0
  129. data/lib/sass/tree/visitors/check_nesting.rb +173 -0
  130. data/lib/sass/tree/visitors/convert.rb +350 -0
  131. data/lib/sass/tree/visitors/cssize.rb +362 -0
  132. data/lib/sass/tree/visitors/deep_copy.rb +107 -0
  133. data/lib/sass/tree/visitors/extend.rb +64 -0
  134. data/lib/sass/tree/visitors/perform.rb +572 -0
  135. data/lib/sass/tree/visitors/set_options.rb +139 -0
  136. data/lib/sass/tree/visitors/to_css.rb +440 -0
  137. data/lib/sass/tree/warn_node.rb +18 -0
  138. data/lib/sass/tree/while_node.rb +18 -0
  139. data/lib/sass/util/multibyte_string_scanner.rb +151 -0
  140. data/lib/sass/util/normalized_map.rb +122 -0
  141. data/lib/sass/util/subset_map.rb +109 -0
  142. data/lib/sass/util/test.rb +9 -0
  143. data/lib/sass/util.rb +1137 -0
  144. data/lib/sass/version.rb +120 -0
  145. data/lib/sass.rb +102 -0
  146. data/rails/init.rb +1 -0
  147. metadata +283 -0
@@ -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
@@ -0,0 +1,298 @@
1
+ module Sass::Script::Value
2
+ # Provides helper functions for creating sass values from within ruby methods.
3
+ # @since `3.3.0`
4
+ module Helpers
5
+ # Construct a Sass Boolean.
6
+ #
7
+ # @param value [Object] A ruby object that will be tested for truthiness.
8
+ # @return [Sass::Script::Value::Bool] whether the ruby value is truthy.
9
+ def bool(value)
10
+ Bool.new(value)
11
+ end
12
+
13
+ # Construct a Sass Color from a hex color string.
14
+ #
15
+ # @param value [::String] A string representing a hex color.
16
+ # The leading hash ("#") is optional.
17
+ # @param alpha [::Number] The alpha channel. A number between 0 and 1.
18
+ # @return [Sass::Script::Value::Color] the color object
19
+ def hex_color(value, alpha = nil)
20
+ Color.from_hex(value, alpha)
21
+ end
22
+
23
+ # Construct a Sass Color from hsl values.
24
+ #
25
+ # @param hue [::Number] The hue of the color in degrees.
26
+ # A non-negative number, usually less than 360.
27
+ # @param saturation [::Number] The saturation of the color.
28
+ # Must be between 0 and 100 inclusive.
29
+ # @param lightness [::Number] The lightness of the color.
30
+ # Must be between 0 and 100 inclusive.
31
+ # @param alpha [::Number] The alpha channel. A number between 0 and 1.
32
+ #
33
+ # @return [Sass::Script::Value::Color] the color object
34
+ def hsl_color(hue, saturation, lightness, alpha = nil)
35
+ attrs = {:hue => hue, :saturation => saturation, :lightness => lightness}
36
+ attrs[:alpha] = alpha if alpha
37
+ Color.new(attrs)
38
+ end
39
+
40
+ # Construct a Sass Color from rgb values.
41
+ #
42
+ # @param red [::Number] The red component. Must be between 0 and 255 inclusive.
43
+ # @param green [::Number] The green component. Must be between 0 and 255 inclusive.
44
+ # @param blue [::Number] The blue component. Must be between 0 and 255 inclusive.
45
+ # @param alpha [::Number] The alpha channel. A number between 0 and 1.
46
+ #
47
+ # @return [Sass::Script::Value::Color] the color object
48
+ def rgb_color(red, green, blue, alpha = nil)
49
+ attrs = {:red => red, :green => green, :blue => blue}
50
+ attrs[:alpha] = alpha if alpha
51
+ Color.new(attrs)
52
+ end
53
+
54
+ # Construct a Sass Number from a ruby number.
55
+ #
56
+ # @param number [::Number] A numeric value.
57
+ # @param unit_string [::String] A unit string of the form
58
+ # `numeral_unit1 * numeral_unit2 ... / denominator_unit1 * denominator_unit2 ...`
59
+ # this is the same format that is returned by
60
+ # {Sass::Script::Value::Number#unit_str the `unit_str` method}
61
+ #
62
+ # @see Sass::Script::Value::Number#unit_str
63
+ #
64
+ # @return [Sass::Script::Value::Number] The sass number representing the given ruby number.
65
+ def number(number, unit_string = nil)
66
+ Number.new(number, *parse_unit_string(unit_string))
67
+ end
68
+
69
+ # @overload list(*elements, separator:, bracketed: false)
70
+ # Create a space-separated list from the arguments given.
71
+ # @param elements [Array<Sass::Script::Value::Base>] Each argument will be a list element.
72
+ # @param separator [Symbol] Either :space or :comma.
73
+ # @param bracketed [Boolean] Whether the list uses square brackets.
74
+ # @return [Sass::Script::Value::List] The space separated list.
75
+ #
76
+ # @overload list(array, separator:, bracketed: false)
77
+ # Create a space-separated list from the array given.
78
+ # @param array [Array<Sass::Script::Value::Base>] A ruby array of Sass values
79
+ # to make into a list.
80
+ # @param separator [Symbol] Either :space or :comma.
81
+ # @param bracketed [Boolean] Whether the list uses square brackets.
82
+ # @return [Sass::Script::Value::List] The space separated list.
83
+ def list(*elements, separator: nil, bracketed: false)
84
+ # Support passing separator as the last value in elements for
85
+ # backwards-compatibility.
86
+ if separator.nil?
87
+ if elements.last.is_a?(Symbol)
88
+ separator = elements.pop
89
+ else
90
+ raise ArgumentError.new("A separator of :space or :comma must be specified.")
91
+ end
92
+ end
93
+
94
+ if elements.size == 1 && elements.first.is_a?(Array)
95
+ elements = elements.first
96
+ end
97
+ Sass::Script::Value::List.new(elements, separator: separator, bracketed: bracketed)
98
+ end
99
+
100
+ # Construct a Sass map.
101
+ #
102
+ # @param hash [Hash<Sass::Script::Value::Base,
103
+ # Sass::Script::Value::Base>] A Ruby map to convert to a Sass map.
104
+ # @return [Sass::Script::Value::Map] The map.
105
+ def map(hash)
106
+ Map.new(hash)
107
+ end
108
+
109
+ # Create a sass null value.
110
+ #
111
+ # @return [Sass::Script::Value::Null]
112
+ def null
113
+ Sass::Script::Value::Null.new
114
+ end
115
+
116
+ # Create a quoted string.
117
+ #
118
+ # @param str [::String] A ruby string.
119
+ # @return [Sass::Script::Value::String] A quoted string.
120
+ def quoted_string(str)
121
+ Sass::Script::String.new(str, :string)
122
+ end
123
+
124
+ # Create an unquoted string.
125
+ #
126
+ # @param str [::String] A ruby string.
127
+ # @return [Sass::Script::Value::String] An unquoted string.
128
+ def unquoted_string(str)
129
+ Sass::Script::String.new(str, :identifier)
130
+ end
131
+ alias_method :identifier, :unquoted_string
132
+
133
+ # Parses a user-provided selector.
134
+ #
135
+ # @param value [Sass::Script::Value::String, Sass::Script::Value::List]
136
+ # The selector to parse. This can be either a string, a list of
137
+ # strings, or a list of lists of strings as returned by `&`.
138
+ # @param name [Symbol, nil]
139
+ # If provided, the name of the selector argument. This is used
140
+ # for error reporting.
141
+ # @param allow_parent_ref [Boolean]
142
+ # Whether the parsed selector should allow parent references.
143
+ # @return [Sass::Selector::CommaSequence] The parsed selector.
144
+ # @throw [ArgumentError] if the parse failed for any reason.
145
+ def parse_selector(value, name = nil, allow_parent_ref = false)
146
+ str = normalize_selector(value, name)
147
+ begin
148
+ Sass::SCSS::StaticParser.new(str, nil, nil, 1, 1, allow_parent_ref).parse_selector
149
+ rescue Sass::SyntaxError => e
150
+ err = "#{value.inspect} is not a valid selector: #{e}"
151
+ err = "$#{name.to_s.tr('_', '-')}: #{err}" if name
152
+ raise ArgumentError.new(err)
153
+ end
154
+ end
155
+
156
+ # Parses a user-provided complex selector.
157
+ #
158
+ # A complex selector can contain combinators but cannot contain commas.
159
+ #
160
+ # @param value [Sass::Script::Value::String, Sass::Script::Value::List]
161
+ # The selector to parse. This can be either a string or a list of
162
+ # strings.
163
+ # @param name [Symbol, nil]
164
+ # If provided, the name of the selector argument. This is used
165
+ # for error reporting.
166
+ # @param allow_parent_ref [Boolean]
167
+ # Whether the parsed selector should allow parent references.
168
+ # @return [Sass::Selector::Sequence] The parsed selector.
169
+ # @throw [ArgumentError] if the parse failed for any reason.
170
+ def parse_complex_selector(value, name = nil, allow_parent_ref = false)
171
+ selector = parse_selector(value, name, allow_parent_ref)
172
+ return seq if selector.members.length == 1
173
+
174
+ err = "#{value.inspect} is not a complex selector"
175
+ err = "$#{name.to_s.tr('_', '-')}: #{err}" if name
176
+ raise ArgumentError.new(err)
177
+ end
178
+
179
+ # Parses a user-provided compound selector.
180
+ #
181
+ # A compound selector cannot contain combinators or commas.
182
+ #
183
+ # @param value [Sass::Script::Value::String] The selector to parse.
184
+ # @param name [Symbol, nil]
185
+ # If provided, the name of the selector argument. This is used
186
+ # for error reporting.
187
+ # @param allow_parent_ref [Boolean]
188
+ # Whether the parsed selector should allow parent references.
189
+ # @return [Sass::Selector::SimpleSequence] The parsed selector.
190
+ # @throw [ArgumentError] if the parse failed for any reason.
191
+ def parse_compound_selector(value, name = nil, allow_parent_ref = false)
192
+ assert_type value, :String, name
193
+ selector = parse_selector(value, name, allow_parent_ref)
194
+ seq = selector.members.first
195
+ sseq = seq.members.first
196
+ if selector.members.length == 1 && seq.members.length == 1 &&
197
+ sseq.is_a?(Sass::Selector::SimpleSequence)
198
+ return sseq
199
+ end
200
+
201
+ err = "#{value.inspect} is not a compound selector"
202
+ err = "$#{name.to_s.tr('_', '-')}: #{err}" if name
203
+ raise ArgumentError.new(err)
204
+ end
205
+
206
+ # Returns true when the literal is a string containing a calc().
207
+ #
208
+ # Use \{#special_number?} in preference to this.
209
+ #
210
+ # @param literal [Sass::Script::Value::Base] The value to check
211
+ # @return Boolean
212
+ def calc?(literal)
213
+ literal.is_a?(Sass::Script::Value::String) && literal.value =~ /calc\(/
214
+ end
215
+
216
+ # Returns true when the literal is a string containing a var().
217
+ #
218
+ # @param literal [Sass::Script::Value::Base] The value to check
219
+ # @return Boolean
220
+ def var?(literal)
221
+ literal.is_a?(Sass::Script::Value::String) && literal.value =~ /var\(/
222
+ end
223
+
224
+ # Returns whether the literal is a special CSS value that may evaluate to a
225
+ # number, such as `calc()` or `var()`.
226
+ #
227
+ # @param literal [Sass::Script::Value::Base] The value to check
228
+ # @return Boolean
229
+ def special_number?(literal)
230
+ literal.is_a?(Sass::Script::Value::String) && literal.value =~ /(calc|var)\(/
231
+ end
232
+
233
+ private
234
+
235
+ # Converts a user-provided selector into string form or throws an
236
+ # ArgumentError if it's in an invalid format.
237
+ def normalize_selector(value, name)
238
+ if (str = selector_to_str(value))
239
+ return str
240
+ end
241
+
242
+ err = "#{value.inspect} is not a valid selector: it must be a string,\n" +
243
+ "a list of strings, or a list of lists of strings"
244
+ err = "$#{name.to_s.tr('_', '-')}: #{err}" if name
245
+ raise ArgumentError.new(err)
246
+ end
247
+
248
+ # Converts a user-provided selector into string form or returns
249
+ # `nil` if it's in an invalid format.
250
+ def selector_to_str(value)
251
+ return value.value if value.is_a?(Sass::Script::String)
252
+ return unless value.is_a?(Sass::Script::List)
253
+
254
+ if value.separator == :comma
255
+ return value.to_a.map do |complex|
256
+ next complex.value if complex.is_a?(Sass::Script::String)
257
+ return unless complex.is_a?(Sass::Script::List) && complex.separator == :space
258
+ return unless (str = selector_to_str(complex))
259
+ str
260
+ end.join(', ')
261
+ end
262
+
263
+ value.to_a.map do |compound|
264
+ return unless compound.is_a?(Sass::Script::String)
265
+ compound.value
266
+ end.join(' ')
267
+ end
268
+
269
+ # @private
270
+ VALID_UNIT = /#{Sass::SCSS::RX::NMSTART}#{Sass::SCSS::RX::NMCHAR}|%*/
271
+
272
+ # @example
273
+ # parse_unit_string("em*px/in*%") # => [["em", "px], ["in", "%"]]
274
+ #
275
+ # @param unit_string [String] A string adhering to the output of a number with complex
276
+ # units. E.g. "em*px/in*%"
277
+ # @return [Array<Array<String>>] A list of numerator units and a list of denominator units.
278
+ def parse_unit_string(unit_string)
279
+ denominator_units = numerator_units = Sass::Script::Value::Number::NO_UNITS
280
+ return numerator_units, denominator_units unless unit_string && unit_string.length > 0
281
+ num_over_denominator = unit_string.split(%r{ */ *})
282
+ unless (1..2).include?(num_over_denominator.size)
283
+ raise ArgumentError.new("Malformed unit string: #{unit_string}")
284
+ end
285
+ numerator_units = num_over_denominator[0].split(/ *\* */)
286
+ denominator_units = (num_over_denominator[1] || "").split(/ *\* */)
287
+ [[numerator_units, "numerator"], [denominator_units, "denominator"]].each do |units, name|
288
+ if unit_string =~ %r{/} && units.size == 0
289
+ raise ArgumentError.new("Malformed unit string: #{unit_string}")
290
+ end
291
+ if units.any? {|unit| unit !~ VALID_UNIT}
292
+ raise ArgumentError.new("Malformed #{name} in unit string: #{unit_string}")
293
+ end
294
+ end
295
+ [numerator_units, denominator_units]
296
+ end
297
+ end
298
+ end
@@ -0,0 +1,135 @@
1
+ module Sass::Script::Value
2
+ # A SassScript object representing a CSS list.
3
+ # This includes both comma-separated lists and space-separated lists.
4
+ class List < Base
5
+ # The Ruby array containing the contents of the list.
6
+ #
7
+ # @return [Array<Value>]
8
+ attr_reader :value
9
+ alias_method :to_a, :value
10
+
11
+ # The operator separating the values of the list.
12
+ # Either `:comma`, `:space`, or `:slash`.
13
+ #
14
+ # @return [Symbol]
15
+ attr_reader :separator
16
+
17
+ # Whether the list is surrounded by square brackets.
18
+ #
19
+ # @return [Boolean]
20
+ attr_reader :bracketed
21
+
22
+ # Creates a new list.
23
+ #
24
+ # @param value [Array<Value>] See \{#value}
25
+ # @param separator [Symbol] See \{#separator}
26
+ # @param bracketed [Boolean] See \{#bracketed}
27
+ def initialize(value, separator: nil, bracketed: false)
28
+ super(value)
29
+ @separator = separator
30
+ @bracketed = bracketed
31
+ end
32
+
33
+ # @see Value#options=
34
+ def options=(options)
35
+ super
36
+ value.each {|v| v.options = options}
37
+ end
38
+
39
+ # @see Value#eq
40
+ def eq(other)
41
+ Sass::Script::Value::Bool.new(
42
+ other.is_a?(List) && value == other.value &&
43
+ separator == other.separator && bracketed == other.bracketed)
44
+ end
45
+
46
+ def hash
47
+ @hash ||= [value, separator, bracketed].hash
48
+ end
49
+
50
+ # @see Value#to_s
51
+ def to_s(opts = {})
52
+ if !bracketed && value.empty?
53
+ raise Sass::SyntaxError.new("#{inspect} isn't a valid CSS value.")
54
+ end
55
+
56
+ members = value.
57
+ reject {|e| e.is_a?(Null) || e.is_a?(List) && e.value.empty?}.
58
+ map {|e| e.to_s(opts)}
59
+
60
+ contents = members.join(sep_str)
61
+ bracketed ? "[#{contents}]" : contents
62
+ end
63
+
64
+ # @see Value#to_sass
65
+ def to_sass(opts = {})
66
+ return bracketed ? "[]" : "()" if value.empty?
67
+ members = value.map do |v|
68
+ if element_needs_parens?(v)
69
+ "(#{v.to_sass(opts)})"
70
+ else
71
+ v.to_sass(opts)
72
+ end
73
+ end
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
81
+ end
82
+
83
+ # @see Value#to_h
84
+ def to_h
85
+ return {} if value.empty?
86
+ super
87
+ end
88
+
89
+ # @see Value#inspect
90
+ def inspect
91
+ (bracketed ? '[' : '(') +
92
+ value.map {|e| e.inspect}.join(sep_str(nil)) +
93
+ (bracketed ? ']' : ')')
94
+ end
95
+
96
+ # Asserts an index is within the list.
97
+ #
98
+ # @private
99
+ #
100
+ # @param list [Sass::Script::Value::List] The list for which the index should be checked.
101
+ # @param n [Sass::Script::Value::Number] The index being checked.
102
+ def self.assert_valid_index(list, n)
103
+ if !n.int? || n.to_i == 0
104
+ raise ArgumentError.new("List index #{n} must be a non-zero integer")
105
+ elsif list.to_a.size == 0
106
+ raise ArgumentError.new("List index is #{n} but list has no items")
107
+ elsif n.to_i.abs > (size = list.to_a.size)
108
+ raise ArgumentError.new(
109
+ "List index is #{n} but list is only #{size} item#{'s' if size != 1} long")
110
+ end
111
+ end
112
+
113
+ private
114
+
115
+ def element_needs_parens?(element)
116
+ if element.is_a?(List)
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
121
+ end
122
+
123
+ return false unless separator == :space
124
+ return false unless element.is_a?(Sass::Script::Tree::UnaryOperation)
125
+ element.operator == :minus || element.operator == :plus
126
+ end
127
+
128
+ def sep_str(opts = options)
129
+ return ' ' if separator == :space
130
+ return ' / ' if separator == :slash
131
+ return ',' if opts && opts[:style] == :compressed
132
+ ', '
133
+ end
134
+ end
135
+ end
@@ -0,0 +1,70 @@
1
+ module Sass::Script::Value
2
+ # A SassScript object representing a map from keys to values. Both keys and
3
+ # values can be any SassScript object.
4
+ class Map < Base
5
+ # The Ruby hash containing the contents of this map.
6
+ #
7
+ # @return [Hash<Node, Node>]
8
+ attr_reader :value
9
+ alias_method :to_h, :value
10
+
11
+ # Creates a new map.
12
+ #
13
+ # @param hash [Hash<Node, Node>]
14
+ def initialize(hash)
15
+ super(hash)
16
+ end
17
+
18
+ # @see Value#options=
19
+ def options=(options)
20
+ super
21
+ value.each do |k, v|
22
+ k.options = options
23
+ v.options = options
24
+ end
25
+ end
26
+
27
+ # @see Value#separator
28
+ def separator
29
+ :comma unless value.empty?
30
+ end
31
+
32
+ # @see Value#to_a
33
+ def to_a
34
+ value.map do |k, v|
35
+ list = List.new([k, v], separator: :space)
36
+ list.options = options
37
+ list
38
+ end
39
+ end
40
+
41
+ # @see Value#eq
42
+ def eq(other)
43
+ Bool.new(other.is_a?(Map) && value == other.value)
44
+ end
45
+
46
+ def hash
47
+ @hash ||= value.hash
48
+ end
49
+
50
+ # @see Value#to_s
51
+ def to_s(opts = {})
52
+ raise Sass::SyntaxError.new("#{inspect} isn't a valid CSS value.")
53
+ end
54
+
55
+ def to_sass(opts = {})
56
+ return "()" if value.empty?
57
+
58
+ to_sass = lambda do |value|
59
+ if value.is_a?(List) && value.separator == :comma
60
+ "(#{value.to_sass(opts)})"
61
+ else
62
+ value.to_sass(opts)
63
+ end
64
+ end
65
+
66
+ "(#{value.map {|(k, v)| "#{to_sass[k]}: #{to_sass[v]}"}.join(', ')})"
67
+ end
68
+ alias_method :inspect, :to_sass
69
+ end
70
+ end
@@ -0,0 +1,44 @@
1
+ module Sass::Script::Value
2
+ # A SassScript object representing a null value.
3
+ class Null < Base
4
+ # The null value in SassScript.
5
+ #
6
+ # This is assigned before new is overridden below so that we use the default implementation.
7
+ NULL = new(nil)
8
+
9
+ # We override object creation so that users of the core API
10
+ # will not need to know that null is a specific constant.
11
+ #
12
+ # @private
13
+ # @return [Null] the {NULL} constant.
14
+ def self.new
15
+ NULL
16
+ end
17
+
18
+ # @return [Boolean] `false` (the Ruby boolean value)
19
+ def to_bool
20
+ false
21
+ end
22
+
23
+ # @return [Boolean] `true`
24
+ def null?
25
+ true
26
+ end
27
+
28
+ # @return [String] '' (An empty string)
29
+ def to_s(opts = {})
30
+ ''
31
+ end
32
+
33
+ def to_sass(opts = {})
34
+ 'null'
35
+ end
36
+
37
+ # Returns a string representing a null value.
38
+ #
39
+ # @return [String]
40
+ def inspect
41
+ 'null'
42
+ end
43
+ end
44
+ end