sass 3.4.0 → 3.4.25
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.yardopts +3 -1
- data/CODE_OF_CONDUCT.md +10 -0
- data/CONTRIBUTING.md +148 -0
- data/MIT-LICENSE +1 -1
- data/README.md +26 -20
- data/Rakefile +103 -20
- data/VERSION +1 -1
- data/VERSION_DATE +1 -1
- data/extra/sass-spec-ref.sh +32 -0
- data/extra/update_watch.rb +1 -1
- data/lib/sass/cache_stores/filesystem.rb +7 -7
- data/lib/sass/cache_stores/memory.rb +4 -5
- data/lib/sass/callbacks.rb +2 -2
- data/lib/sass/css.rb +11 -10
- data/lib/sass/deprecation.rb +55 -0
- data/lib/sass/engine.rb +83 -38
- data/lib/sass/environment.rb +26 -2
- data/lib/sass/error.rb +12 -12
- data/lib/sass/exec/base.rb +15 -3
- data/lib/sass/exec/sass_convert.rb +34 -15
- data/lib/sass/exec/sass_scss.rb +23 -7
- data/lib/sass/features.rb +2 -2
- data/lib/sass/importers/base.rb +1 -1
- data/lib/sass/importers/deprecated_path.rb +51 -0
- data/lib/sass/importers/filesystem.rb +24 -16
- data/lib/sass/importers.rb +1 -0
- data/lib/sass/logger/base.rb +8 -2
- data/lib/sass/logger/delayed.rb +50 -0
- data/lib/sass/logger.rb +8 -3
- data/lib/sass/plugin/compiler.rb +42 -25
- data/lib/sass/plugin/configuration.rb +38 -22
- data/lib/sass/plugin/merb.rb +2 -2
- data/lib/sass/plugin/rack.rb +3 -3
- data/lib/sass/plugin/rails.rb +1 -1
- data/lib/sass/plugin/staleness_checker.rb +3 -3
- data/lib/sass/plugin.rb +3 -2
- data/lib/sass/script/css_parser.rb +2 -3
- data/lib/sass/script/css_variable_warning.rb +52 -0
- data/lib/sass/script/functions.rb +140 -73
- data/lib/sass/script/lexer.rb +37 -22
- data/lib/sass/script/parser.rb +235 -40
- data/lib/sass/script/tree/funcall.rb +12 -5
- data/lib/sass/script/tree/interpolation.rb +109 -4
- data/lib/sass/script/tree/list_literal.rb +31 -4
- data/lib/sass/script/tree/literal.rb +4 -0
- data/lib/sass/script/tree/node.rb +21 -3
- data/lib/sass/script/tree/operation.rb +54 -1
- data/lib/sass/script/tree/string_interpolation.rb +58 -37
- data/lib/sass/script/tree/variable.rb +1 -1
- data/lib/sass/script/value/base.rb +10 -9
- data/lib/sass/script/value/color.rb +42 -24
- data/lib/sass/script/value/helpers.rb +16 -6
- data/lib/sass/script/value/map.rb +1 -1
- data/lib/sass/script/value/number.rb +52 -19
- data/lib/sass/script/value/string.rb +46 -5
- data/lib/sass/script.rb +3 -3
- data/lib/sass/scss/css_parser.rb +16 -2
- data/lib/sass/scss/parser.rb +120 -75
- data/lib/sass/scss/rx.rb +9 -10
- data/lib/sass/scss/static_parser.rb +19 -14
- data/lib/sass/scss.rb +0 -2
- data/lib/sass/selector/abstract_sequence.rb +8 -6
- data/lib/sass/selector/comma_sequence.rb +25 -9
- data/lib/sass/selector/pseudo.rb +45 -35
- data/lib/sass/selector/sequence.rb +54 -18
- data/lib/sass/selector/simple.rb +11 -11
- data/lib/sass/selector/simple_sequence.rb +34 -15
- data/lib/sass/selector.rb +7 -10
- data/lib/sass/shared.rb +1 -1
- data/lib/sass/source/map.rb +7 -4
- data/lib/sass/source/position.rb +4 -4
- data/lib/sass/stack.rb +2 -2
- data/lib/sass/supports.rb +8 -10
- data/lib/sass/tree/comment_node.rb +1 -1
- data/lib/sass/tree/css_import_node.rb +9 -1
- data/lib/sass/tree/function_node.rb +8 -3
- data/lib/sass/tree/import_node.rb +6 -5
- data/lib/sass/tree/node.rb +5 -3
- data/lib/sass/tree/prop_node.rb +5 -6
- data/lib/sass/tree/rule_node.rb +14 -4
- data/lib/sass/tree/visitors/check_nesting.rb +18 -22
- data/lib/sass/tree/visitors/convert.rb +43 -26
- data/lib/sass/tree/visitors/cssize.rb +5 -1
- data/lib/sass/tree/visitors/deep_copy.rb +1 -1
- data/lib/sass/tree/visitors/extend.rb +15 -13
- data/lib/sass/tree/visitors/perform.rb +42 -17
- data/lib/sass/tree/visitors/set_options.rb +1 -1
- data/lib/sass/tree/visitors/to_css.rb +58 -30
- data/lib/sass/util/multibyte_string_scanner.rb +0 -2
- data/lib/sass/util/normalized_map.rb +0 -1
- data/lib/sass/util/subset_map.rb +1 -2
- data/lib/sass/util.rb +125 -68
- data/lib/sass/version.rb +2 -2
- data/lib/sass.rb +10 -3
- data/test/sass/compiler_test.rb +6 -2
- data/test/sass/conversion_test.rb +187 -53
- data/test/sass/css2sass_test.rb +50 -1
- data/test/sass/css_variable_test.rb +132 -0
- data/test/sass/engine_test.rb +207 -61
- data/test/sass/exec_test.rb +10 -0
- data/test/sass/extend_test.rb +101 -29
- data/test/sass/functions_test.rb +60 -9
- data/test/sass/importer_test.rb +9 -0
- data/test/sass/more_templates/more1.sass +10 -10
- data/test/sass/more_templates/more_import.sass +2 -2
- data/test/sass/plugin_test.rb +10 -8
- data/test/sass/results/script.css +3 -3
- data/test/sass/script_conversion_test.rb +58 -29
- data/test/sass/script_test.rb +430 -53
- data/test/sass/scss/css_test.rb +73 -7
- data/test/sass/scss/rx_test.rb +4 -0
- data/test/sass/scss/scss_test.rb +309 -4
- data/test/sass/source_map_test.rb +152 -74
- data/test/sass/superselector_test.rb +19 -0
- data/test/sass/templates/_partial.sass +1 -1
- data/test/sass/templates/basic.sass +10 -10
- data/test/sass/templates/bork1.sass +1 -1
- data/test/sass/templates/bork5.sass +1 -1
- data/test/sass/templates/compact.sass +10 -10
- data/test/sass/templates/complex.sass +187 -187
- data/test/sass/templates/compressed.sass +10 -10
- data/test/sass/templates/expanded.sass +10 -10
- data/test/sass/templates/import.sass +2 -2
- data/test/sass/templates/importee.sass +3 -3
- data/test/sass/templates/mixins.sass +22 -22
- data/test/sass/templates/multiline.sass +4 -4
- data/test/sass/templates/nested.sass +13 -13
- data/test/sass/templates/parent_ref.sass +12 -12
- data/test/sass/templates/script.sass +70 -70
- data/test/sass/templates/subdir/nested_subdir/_nested_partial.sass +1 -1
- data/test/sass/templates/subdir/nested_subdir/nested_subdir.sass +2 -2
- data/test/sass/templates/subdir/subdir.sass +3 -3
- data/test/sass/templates/units.sass +10 -10
- data/test/sass/util/multibyte_string_scanner_test.rb +10 -2
- data/test/sass/util_test.rb +15 -44
- data/test/sass-spec.yml +3 -0
- data/test/test_helper.rb +5 -4
- metadata +302 -295
- data/CONTRIBUTING +0 -3
- data/lib/sass/scss/script_lexer.rb +0 -15
- data/lib/sass/scss/script_parser.rb +0 -25
@@ -17,15 +17,16 @@ module Sass::Script::Value
|
|
17
17
|
# @private
|
18
18
|
#
|
19
19
|
# Convert a ruby integer to a rgba components
|
20
|
-
# @param color [
|
21
|
-
# @return [Array<
|
20
|
+
# @param color [Integer]
|
21
|
+
# @return [Array<Integer>] Array of 4 numbers representing r,g,b and alpha
|
22
22
|
def self.int_to_rgba(color)
|
23
23
|
rgba = (0..3).map {|n| color >> (n << 3) & 0xff}.reverse
|
24
24
|
rgba[-1] = rgba[-1] / 255.0
|
25
25
|
rgba
|
26
26
|
end
|
27
27
|
|
28
|
-
ALTERNATE_COLOR_NAMES = Sass::Util.map_vals(
|
28
|
+
ALTERNATE_COLOR_NAMES = Sass::Util.map_vals(
|
29
|
+
{
|
29
30
|
'aqua' => 0x00FFFFFF,
|
30
31
|
'darkgrey' => 0xA9A9A9FF,
|
31
32
|
'darkslategrey' => 0x2F4F4FFF,
|
@@ -35,10 +36,11 @@ module Sass::Script::Value
|
|
35
36
|
'lightgrey' => 0xD3D3D3FF,
|
36
37
|
'lightslategrey' => 0x778899FF,
|
37
38
|
'slategrey' => 0x708090FF,
|
38
|
-
|
39
|
+
}, &method(:int_to_rgba))
|
39
40
|
|
40
41
|
# A hash from color names to `[red, green, blue]` value arrays.
|
41
|
-
COLOR_NAMES = Sass::Util.map_vals(
|
42
|
+
COLOR_NAMES = Sass::Util.map_vals(
|
43
|
+
{
|
42
44
|
'aliceblue' => 0xF0F8FFFF,
|
43
45
|
'antiquewhite' => 0xFAEBD7FF,
|
44
46
|
'aquamarine' => 0x7FFFD4FF,
|
@@ -179,7 +181,7 @@ module Sass::Script::Value
|
|
179
181
|
'whitesmoke' => 0xF5F5F5FF,
|
180
182
|
'yellow' => 0xFFFF00FF,
|
181
183
|
'yellowgreen' => 0x9ACD32FF
|
182
|
-
|
184
|
+
}, &method(:int_to_rgba))
|
183
185
|
|
184
186
|
# A hash from `[red, green, blue, alpha]` value arrays to color names.
|
185
187
|
COLOR_NAMES_REVERSE = COLOR_NAMES.invert.freeze
|
@@ -204,7 +206,7 @@ module Sass::Script::Value
|
|
204
206
|
#
|
205
207
|
# @overload initialize(attrs)
|
206
208
|
# The attributes are specified as a hash. This hash must contain either
|
207
|
-
# `:hue`, `:saturation`, and `:
|
209
|
+
# `:hue`, `:saturation`, and `:lightness` keys, or `:red`, `:green`, and
|
208
210
|
# `:blue` keys. It cannot contain both HSL and RGB keys. It may also
|
209
211
|
# optionally contain an `:alpha` key, and a `:representation` key
|
210
212
|
# indicating the original representation of the color that the user wrote
|
@@ -232,12 +234,12 @@ module Sass::Script::Value
|
|
232
234
|
raise ArgumentError.new("Color.new(array) expects a three- or four-element array")
|
233
235
|
end
|
234
236
|
|
235
|
-
red, green, blue = attrs[0...3].map {|c| c
|
237
|
+
red, green, blue = attrs[0...3].map {|c| Sass::Util.round(c)}
|
236
238
|
@attrs = {:red => red, :green => green, :blue => blue}
|
237
239
|
@attrs[:alpha] = attrs[3] ? attrs[3].to_f : 1
|
238
240
|
@representation = representation
|
239
241
|
else
|
240
|
-
attrs = attrs.reject {|
|
242
|
+
attrs = attrs.reject {|_k, v| v.nil?}
|
241
243
|
hsl = [:hue, :saturation, :lightness] & attrs.keys
|
242
244
|
rgb = [:red, :green, :blue] & attrs.keys
|
243
245
|
if !allow_both_rgb_and_hsl && !hsl.empty? && !rgb.empty?
|
@@ -258,7 +260,7 @@ module Sass::Script::Value
|
|
258
260
|
|
259
261
|
[:red, :green, :blue].each do |k|
|
260
262
|
next if @attrs[k].nil?
|
261
|
-
@attrs[k] = Sass::Util.restrict(@attrs[k]
|
263
|
+
@attrs[k] = Sass::Util.restrict(Sass::Util.round(@attrs[k]), 0..255)
|
262
264
|
end
|
263
265
|
|
264
266
|
[:saturation, :lightness].each do |k|
|
@@ -283,7 +285,7 @@ module Sass::Script::Value
|
|
283
285
|
green = $2.ljust(2, $2).to_i(16)
|
284
286
|
blue = $3.ljust(2, $3).to_i(16)
|
285
287
|
|
286
|
-
hex_string =
|
288
|
+
hex_string = "##{hex_string}" unless hex_string[0] == ?#
|
287
289
|
attrs = {:red => red, :green => green, :blue => blue, :representation => hex_string}
|
288
290
|
attrs[:alpha] = alpha if alpha
|
289
291
|
new(attrs)
|
@@ -291,7 +293,7 @@ module Sass::Script::Value
|
|
291
293
|
|
292
294
|
# The red component of the color.
|
293
295
|
#
|
294
|
-
# @return [
|
296
|
+
# @return [Integer]
|
295
297
|
def red
|
296
298
|
hsl_to_rgb!
|
297
299
|
@attrs[:red]
|
@@ -299,7 +301,7 @@ module Sass::Script::Value
|
|
299
301
|
|
300
302
|
# The green component of the color.
|
301
303
|
#
|
302
|
-
# @return [
|
304
|
+
# @return [Integer]
|
303
305
|
def green
|
304
306
|
hsl_to_rgb!
|
305
307
|
@attrs[:green]
|
@@ -307,7 +309,7 @@ module Sass::Script::Value
|
|
307
309
|
|
308
310
|
# The blue component of the color.
|
309
311
|
#
|
310
|
-
# @return [
|
312
|
+
# @return [Integer]
|
311
313
|
def blue
|
312
314
|
hsl_to_rgb!
|
313
315
|
@attrs[:blue]
|
@@ -340,7 +342,7 @@ module Sass::Script::Value
|
|
340
342
|
# The alpha channel (opacity) of the color.
|
341
343
|
# This is 1 unless otherwise defined.
|
342
344
|
#
|
343
|
-
# @return [
|
345
|
+
# @return [Integer]
|
344
346
|
def alpha
|
345
347
|
@attrs[:alpha].to_f
|
346
348
|
end
|
@@ -355,7 +357,7 @@ module Sass::Script::Value
|
|
355
357
|
|
356
358
|
# Returns the red, green, and blue components of the color.
|
357
359
|
#
|
358
|
-
# @return [Array<
|
360
|
+
# @return [Array<Integer>] A frozen three-element array of the red, green, and blue
|
359
361
|
# values (respectively) of the color
|
360
362
|
def rgb
|
361
363
|
[red, green, blue].freeze
|
@@ -363,7 +365,7 @@ module Sass::Script::Value
|
|
363
365
|
|
364
366
|
# Returns the red, green, blue, and alpha components of the color.
|
365
367
|
#
|
366
|
-
# @return [Array<
|
368
|
+
# @return [Array<Integer>] A frozen four-element array of the red, green,
|
367
369
|
# blue, and alpha values (respectively) of the color
|
368
370
|
def rgba
|
369
371
|
[red, green, blue, alpha].freeze
|
@@ -371,7 +373,7 @@ module Sass::Script::Value
|
|
371
373
|
|
372
374
|
# Returns the hue, saturation, and lightness components of the color.
|
373
375
|
#
|
374
|
-
# @return [Array<
|
376
|
+
# @return [Array<Integer>] A frozen three-element array of the
|
375
377
|
# hue, saturation, and lightness values (respectively) of the color
|
376
378
|
def hsl
|
377
379
|
[hue, saturation, lightness].freeze
|
@@ -379,10 +381,10 @@ module Sass::Script::Value
|
|
379
381
|
|
380
382
|
# Returns the hue, saturation, lightness, and alpha components of the color.
|
381
383
|
#
|
382
|
-
# @return [Array<
|
384
|
+
# @return [Array<Integer>] A frozen four-element array of the hue,
|
383
385
|
# saturation, lightness, and alpha values (respectively) of the color
|
384
386
|
def hsla
|
385
|
-
[hue, saturation, lightness].freeze
|
387
|
+
[hue, saturation, lightness, alpha].freeze
|
386
388
|
end
|
387
389
|
|
388
390
|
# The SassScript `==` operation.
|
@@ -421,7 +423,7 @@ module Sass::Script::Value
|
|
421
423
|
# @return [Color] The new Color object
|
422
424
|
# @raise [ArgumentError] if both RGB and HSL keys are specified
|
423
425
|
def with(attrs)
|
424
|
-
attrs = attrs.reject {|
|
426
|
+
attrs = attrs.reject {|_k, v| v.nil?}
|
425
427
|
hsl = !([:hue, :saturation, :lightness] & attrs.keys).empty?
|
426
428
|
rgb = !([:red, :green, :blue] & attrs.keys).empty?
|
427
429
|
if hsl && rgb
|
@@ -598,16 +600,32 @@ module Sass::Script::Value
|
|
598
600
|
"##{red}#{green}#{blue}"
|
599
601
|
end
|
600
602
|
|
603
|
+
def operation_name(operation)
|
604
|
+
case operation
|
605
|
+
when :+
|
606
|
+
"add"
|
607
|
+
when :-
|
608
|
+
"subtract"
|
609
|
+
when :*
|
610
|
+
"multiply"
|
611
|
+
when :/
|
612
|
+
"divide"
|
613
|
+
when :%
|
614
|
+
"modulo"
|
615
|
+
end
|
616
|
+
end
|
617
|
+
|
601
618
|
def piecewise(other, operation)
|
602
619
|
other_num = other.is_a? Number
|
603
620
|
if other_num && !other.unitless?
|
604
621
|
raise Sass::SyntaxError.new(
|
605
|
-
"Cannot
|
622
|
+
"Cannot #{operation_name(operation)} a number with units (#{other}) to a color (#{self})."
|
623
|
+
)
|
606
624
|
end
|
607
625
|
|
608
626
|
result = []
|
609
627
|
(0...3).each do |i|
|
610
|
-
res = rgb[i].send(operation, other_num ? other.value : other.rgb[i])
|
628
|
+
res = rgb[i].to_f.send(operation, other_num ? other.value : other.rgb[i])
|
611
629
|
result[i] = [[res, 255].min, 0].max
|
612
630
|
end
|
613
631
|
|
@@ -632,7 +650,7 @@ module Sass::Script::Value
|
|
632
650
|
hue_to_rgb(m1, m2, h + 1.0 / 3),
|
633
651
|
hue_to_rgb(m1, m2, h),
|
634
652
|
hue_to_rgb(m1, m2, h - 1.0 / 3)
|
635
|
-
].map {|c| (c * 0xff)
|
653
|
+
].map {|c| Sass::Util.round(c * 0xff)}
|
636
654
|
end
|
637
655
|
|
638
656
|
def hue_to_rgb(m1, m2, h)
|
@@ -1,6 +1,8 @@
|
|
1
1
|
module Sass::Script::Value
|
2
2
|
# Provides helper functions for creating sass values from within ruby methods.
|
3
3
|
# @since `3.3.0`
|
4
|
+
# @comment
|
5
|
+
# rubocop:disable ModuleLength
|
4
6
|
module Helpers
|
5
7
|
# Construct a Sass Boolean.
|
6
8
|
#
|
@@ -139,7 +141,7 @@ module Sass::Script::Value
|
|
139
141
|
Sass::SCSS::StaticParser.new(str, nil, nil, 1, 1, allow_parent_ref).parse_selector
|
140
142
|
rescue Sass::SyntaxError => e
|
141
143
|
err = "#{value.inspect} is not a valid selector: #{e}"
|
142
|
-
err = "$#{name.to_s.
|
144
|
+
err = "$#{name.to_s.tr('_', '-')}: #{err}" if name
|
143
145
|
raise ArgumentError.new(err)
|
144
146
|
end
|
145
147
|
end
|
@@ -163,7 +165,7 @@ module Sass::Script::Value
|
|
163
165
|
return seq if selector.members.length == 1
|
164
166
|
|
165
167
|
err = "#{value.inspect} is not a complex selector"
|
166
|
-
err = "$#{name.to_s.
|
168
|
+
err = "$#{name.to_s.tr('_', '-')}: #{err}" if name
|
167
169
|
raise ArgumentError.new(err)
|
168
170
|
end
|
169
171
|
|
@@ -190,10 +192,18 @@ module Sass::Script::Value
|
|
190
192
|
end
|
191
193
|
|
192
194
|
err = "#{value.inspect} is not a compound selector"
|
193
|
-
err = "$#{name.to_s.
|
195
|
+
err = "$#{name.to_s.tr('_', '-')}: #{err}" if name
|
194
196
|
raise ArgumentError.new(err)
|
195
197
|
end
|
196
198
|
|
199
|
+
# Returns true when the literal is a string containing a calc()
|
200
|
+
#
|
201
|
+
# @param literal [Sass::Script::Value::Base] The value to check
|
202
|
+
# @return boolean
|
203
|
+
def calc?(literal)
|
204
|
+
literal.is_a?(Sass::Script::Value::String) && literal.value =~ /calc\(/
|
205
|
+
end
|
206
|
+
|
197
207
|
private
|
198
208
|
|
199
209
|
# Converts a user-provided selector into string form or throws an
|
@@ -205,7 +215,7 @@ module Sass::Script::Value
|
|
205
215
|
|
206
216
|
err = "#{value.inspect} is not a valid selector: it must be a string,\n" +
|
207
217
|
"a list of strings, or a list of lists of strings"
|
208
|
-
err = "$#{name.to_s.
|
218
|
+
err = "$#{name.to_s.tr('_', '-')}: #{err}" if name
|
209
219
|
raise ArgumentError.new(err)
|
210
220
|
end
|
211
221
|
|
@@ -242,14 +252,14 @@ module Sass::Script::Value
|
|
242
252
|
def parse_unit_string(unit_string)
|
243
253
|
denominator_units = numerator_units = Sass::Script::Value::Number::NO_UNITS
|
244
254
|
return numerator_units, denominator_units unless unit_string && unit_string.length > 0
|
245
|
-
num_over_denominator = unit_string.split(
|
255
|
+
num_over_denominator = unit_string.split(%r{ */ *})
|
246
256
|
unless (1..2).include?(num_over_denominator.size)
|
247
257
|
raise ArgumentError.new("Malformed unit string: #{unit_string}")
|
248
258
|
end
|
249
259
|
numerator_units = num_over_denominator[0].split(/ *\* */)
|
250
260
|
denominator_units = (num_over_denominator[1] || "").split(/ *\* */)
|
251
261
|
[[numerator_units, "numerator"], [denominator_units, "denominator"]].each do |units, name|
|
252
|
-
if unit_string =~
|
262
|
+
if unit_string =~ %r{/} && units.size == 0
|
253
263
|
raise ArgumentError.new("Malformed unit string: #{unit_string}")
|
254
264
|
end
|
255
265
|
if units.any? {|unit| unit !~ VALID_UNIT}
|
@@ -56,7 +56,7 @@ module Sass::Script::Value
|
|
56
56
|
return "()" if value.empty?
|
57
57
|
|
58
58
|
to_sass = lambda do |value|
|
59
|
-
if value.is_a?(
|
59
|
+
if value.is_a?(List) && value.separator == :comma
|
60
60
|
"(#{value.to_sass(opts)})"
|
61
61
|
else
|
62
62
|
value.to_sass(opts)
|
@@ -34,25 +34,35 @@ module Sass::Script::Value
|
|
34
34
|
attr_accessor :original
|
35
35
|
|
36
36
|
def self.precision
|
37
|
-
|
37
|
+
Thread.current[:sass_numeric_precision] || Thread.main[:sass_numeric_precision] || 5
|
38
38
|
end
|
39
39
|
|
40
40
|
# Sets the number of digits of precision
|
41
41
|
# For example, if this is `3`,
|
42
42
|
# `3.1415926` will be printed as `3.142`.
|
43
|
+
# The numeric precision is stored as a thread local for thread safety reasons.
|
44
|
+
# To set for all threads, be sure to set the precision on the main thread.
|
43
45
|
def self.precision=(digits)
|
44
|
-
|
45
|
-
|
46
|
+
Thread.current[:sass_numeric_precision] = digits.round
|
47
|
+
Thread.current[:sass_numeric_precision_factor] = nil
|
48
|
+
Thread.current[:sass_numeric_epsilon] = nil
|
46
49
|
end
|
47
50
|
|
48
51
|
# the precision factor used in numeric output
|
49
52
|
# it is derived from the `precision` method.
|
50
53
|
def self.precision_factor
|
51
|
-
|
54
|
+
Thread.current[:sass_numeric_precision_factor] ||= 10.0**precision
|
55
|
+
end
|
56
|
+
|
57
|
+
# Used in checking equality of floating point numbers. Any
|
58
|
+
# numbers within an `epsilon` of each other are considered functionally equal.
|
59
|
+
# The value for epsilon is one tenth of the current numeric precision.
|
60
|
+
def self.epsilon
|
61
|
+
Thread.current[:sass_numeric_epsilon] ||= 1 / (precision_factor * 10)
|
52
62
|
end
|
53
63
|
|
54
64
|
# Used so we don't allocate two new arrays for each new number.
|
55
|
-
NO_UNITS
|
65
|
+
NO_UNITS = []
|
56
66
|
|
57
67
|
# @param value [Numeric] The value of the number
|
58
68
|
# @param numerator_units [::String, Array<::String>] See \{#numerator\_units}
|
@@ -63,6 +73,7 @@ module Sass::Script::Value
|
|
63
73
|
super(value)
|
64
74
|
@numerator_units = numerator_units
|
65
75
|
@denominator_units = denominator_units
|
76
|
+
@options = nil
|
66
77
|
normalize!
|
67
78
|
end
|
68
79
|
|
@@ -200,7 +211,7 @@ module Sass::Script::Value
|
|
200
211
|
rescue Sass::UnitConversionError
|
201
212
|
return Bool::FALSE
|
202
213
|
end
|
203
|
-
Bool.new(this.value
|
214
|
+
Bool.new(basically_equal?(this.value, other.value))
|
204
215
|
end
|
205
216
|
|
206
217
|
def hash
|
@@ -211,7 +222,7 @@ module Sass::Script::Value
|
|
211
222
|
# Hash-equality must be transitive, so it just compares the exact value,
|
212
223
|
# numerator units, and denominator units.
|
213
224
|
def eql?(other)
|
214
|
-
value
|
225
|
+
basically_equal?(value, other.value) && numerator_units == other.numerator_units &&
|
215
226
|
denominator_units == other.denominator_units
|
216
227
|
end
|
217
228
|
|
@@ -281,20 +292,30 @@ module Sass::Script::Value
|
|
281
292
|
# and confusing.
|
282
293
|
str = ("%0.#{self.class.precision}f" % value).gsub(/0*$/, '') if str.include?('e')
|
283
294
|
|
295
|
+
# Sometimes numeric formatting will result in a decimal number with a trailing zero (x.0)
|
296
|
+
if str =~ /(.*)\.0$/
|
297
|
+
str = $1
|
298
|
+
end
|
299
|
+
|
300
|
+
# We omit a leading zero before the decimal point in compressed mode.
|
301
|
+
if @options && options[:style] == :compressed
|
302
|
+
str.sub!(/^(-)?0\./, '\1.')
|
303
|
+
end
|
304
|
+
|
284
305
|
unitless? ? str : "#{str}#{unit_str}"
|
285
306
|
end
|
286
307
|
alias_method :to_sass, :inspect
|
287
308
|
|
288
|
-
# @return [
|
309
|
+
# @return [Integer] The integer value of the number
|
289
310
|
# @raise [Sass::SyntaxError] if the number isn't an integer
|
290
311
|
def to_i
|
291
312
|
super unless int?
|
292
|
-
value
|
313
|
+
value.to_i
|
293
314
|
end
|
294
315
|
|
295
316
|
# @return [Boolean] Whether or not this number is an integer.
|
296
317
|
def int?
|
297
|
-
value % 1
|
318
|
+
basically_equal?(value % 1, 0.0)
|
298
319
|
end
|
299
320
|
|
300
321
|
# @return [Boolean] Whether or not this number has no units.
|
@@ -375,12 +396,24 @@ module Sass::Script::Value
|
|
375
396
|
|
376
397
|
private
|
377
398
|
|
399
|
+
# @private
|
400
|
+
# @see Sass::Script::Number.basically_equal?
|
401
|
+
def basically_equal?(num1, num2)
|
402
|
+
self.class.basically_equal?(num1, num2)
|
403
|
+
end
|
404
|
+
|
405
|
+
# Checks whether two numbers are within an epsilon of each other.
|
406
|
+
# @return [Boolean]
|
407
|
+
def self.basically_equal?(num1, num2)
|
408
|
+
(num1 - num2).abs < epsilon
|
409
|
+
end
|
410
|
+
|
378
411
|
# @private
|
379
412
|
def self.round(num)
|
380
413
|
if num.is_a?(Float) && (num.infinite? || num.nan?)
|
381
414
|
num
|
382
|
-
elsif num % 1
|
383
|
-
num.
|
415
|
+
elsif basically_equal?(num % 1, 0.0)
|
416
|
+
num.round
|
384
417
|
else
|
385
418
|
((num * precision_factor).round / precision_factor).to_f
|
386
419
|
end
|
@@ -439,11 +472,10 @@ module Sass::Script::Value
|
|
439
472
|
sans_common_units(@numerator_units, @denominator_units)
|
440
473
|
|
441
474
|
@denominator_units.each_with_index do |d, i|
|
442
|
-
|
443
|
-
|
444
|
-
|
445
|
-
|
446
|
-
end
|
475
|
+
next unless convertable?(d) && (u = @numerator_units.find(&method(:convertable?)))
|
476
|
+
@value /= conversion_factor(d, u)
|
477
|
+
@denominator_units.delete_at(i)
|
478
|
+
@numerator_units.delete_at(@numerator_units.index(u))
|
447
479
|
end
|
448
480
|
end
|
449
481
|
|
@@ -458,6 +490,7 @@ module Sass::Script::Value
|
|
458
490
|
'cm' => Rational(1, 2.54),
|
459
491
|
'pc' => Rational(1, 6),
|
460
492
|
'mm' => Rational(1, 25.4),
|
493
|
+
'q' => Rational(1, 101.6),
|
461
494
|
'pt' => Rational(1, 72),
|
462
495
|
'px' => Rational(1, 96)
|
463
496
|
},
|
@@ -477,8 +510,8 @@ module Sass::Script::Value
|
|
477
510
|
},
|
478
511
|
{
|
479
512
|
'dpi' => Rational(1),
|
480
|
-
'dpcm' => Rational(
|
481
|
-
'dppx' => Rational(
|
513
|
+
'dpcm' => Rational(254, 100),
|
514
|
+
'dppx' => Rational(96)
|
482
515
|
}
|
483
516
|
]
|
484
517
|
|
@@ -2,6 +2,8 @@
|
|
2
2
|
module Sass::Script::Value
|
3
3
|
# A SassScript object representing a CSS string *or* a CSS identifier.
|
4
4
|
class String < Base
|
5
|
+
@@interpolation_deprecation = Sass::Deprecation.new
|
6
|
+
|
5
7
|
# The Ruby value of the string.
|
6
8
|
#
|
7
9
|
# @return [String]
|
@@ -28,9 +30,18 @@ module Sass::Script::Value
|
|
28
30
|
end
|
29
31
|
end
|
30
32
|
|
31
|
-
|
33
|
+
# Returns the quoted string representation of `contents`.
|
34
|
+
#
|
35
|
+
# @options opts :quote [String]
|
36
|
+
# The preferred quote style for quoted strings. If `:none`, strings are
|
37
|
+
# always emitted unquoted. If `nil`, quoting is determined automatically.
|
38
|
+
# @options opts :sass [String]
|
39
|
+
# Whether to quote strings for Sass source, as opposed to CSS. Defaults to `false`.
|
40
|
+
def self.quote(contents, opts = {})
|
41
|
+
quote = opts[:quote]
|
42
|
+
|
32
43
|
# Short-circuit if there are no characters that need quoting.
|
33
|
-
unless contents =~ /[\n\\"']/
|
44
|
+
unless contents =~ /[\n\\"']|\#\{/
|
34
45
|
quote ||= '"'
|
35
46
|
return "#{quote}#{contents}#{quote}"
|
36
47
|
end
|
@@ -50,6 +61,9 @@ module Sass::Script::Value
|
|
50
61
|
# Replace single backslashes with multiples.
|
51
62
|
contents = contents.gsub("\\", "\\\\\\\\")
|
52
63
|
|
64
|
+
# Escape interpolation.
|
65
|
+
contents = contents.gsub('#{', "\\\#{") if opts[:sass]
|
66
|
+
|
53
67
|
if quote == '"'
|
54
68
|
contents = contents.gsub('"', "\\\"")
|
55
69
|
else
|
@@ -64,9 +78,13 @@ module Sass::Script::Value
|
|
64
78
|
#
|
65
79
|
# @param value [String] See \{#value}
|
66
80
|
# @param type [Symbol] See \{#type}
|
67
|
-
|
81
|
+
# @param deprecated_interp_equivalent [String?]
|
82
|
+
# If this was created via a potentially-deprecated string interpolation,
|
83
|
+
# this is the replacement expression that should be suggested to the user.
|
84
|
+
def initialize(value, type = :identifier, deprecated_interp_equivalent = nil)
|
68
85
|
super(value)
|
69
86
|
@type = type
|
87
|
+
@deprecated_interp_equivalent = deprecated_interp_equivalent
|
70
88
|
end
|
71
89
|
|
72
90
|
# @see Value#plus
|
@@ -82,12 +100,35 @@ module Sass::Script::Value
|
|
82
100
|
# @see Value#to_s
|
83
101
|
def to_s(opts = {})
|
84
102
|
return @value.gsub(/\n\s*/, ' ') if opts[:quote] == :none || @type == :identifier
|
85
|
-
|
103
|
+
String.quote(value, opts)
|
86
104
|
end
|
87
105
|
|
88
106
|
# @see Value#to_sass
|
89
107
|
def to_sass(opts = {})
|
90
|
-
to_s
|
108
|
+
to_s(opts.merge(:sass => true))
|
109
|
+
end
|
110
|
+
|
111
|
+
def separator
|
112
|
+
check_deprecated_interp
|
113
|
+
super
|
114
|
+
end
|
115
|
+
|
116
|
+
def to_a
|
117
|
+
check_deprecated_interp
|
118
|
+
super
|
119
|
+
end
|
120
|
+
|
121
|
+
# Prints a warning if this string was created using potentially-deprecated
|
122
|
+
# interpolation.
|
123
|
+
def check_deprecated_interp
|
124
|
+
return unless @deprecated_interp_equivalent
|
125
|
+
|
126
|
+
@@interpolation_deprecation.warn(source_range.file, source_range.start_pos.line, <<WARNING)
|
127
|
+
\#{} interpolation near operators will be simplified in a future version of Sass.
|
128
|
+
To preserve the current behavior, use quotes:
|
129
|
+
|
130
|
+
#{@deprecated_interp_equivalent}
|
131
|
+
WARNING
|
91
132
|
end
|
92
133
|
|
93
134
|
def inspect
|
data/lib/sass/script.rb
CHANGED
@@ -16,12 +16,12 @@ module Sass
|
|
16
16
|
# Parses a string of SassScript
|
17
17
|
#
|
18
18
|
# @param value [String] The SassScript
|
19
|
-
# @param line [
|
19
|
+
# @param line [Integer] The number of the line on which the SassScript appeared.
|
20
20
|
# Used for error reporting
|
21
|
-
# @param offset [
|
21
|
+
# @param offset [Integer] The number of characters in on `line` that the SassScript started.
|
22
22
|
# Used for error reporting
|
23
23
|
# @param options [{Symbol => Object}] An options hash;
|
24
|
-
# see {file:SASS_REFERENCE.md#
|
24
|
+
# see {file:SASS_REFERENCE.md#Options the Sass options documentation}
|
25
25
|
# @return [Script::Tree::Node] The root node of the parse tree
|
26
26
|
def self.parse(value, line, offset, options = {})
|
27
27
|
Parser.parse(value, line, offset, options)
|
data/lib/sass/scss/css_parser.rb
CHANGED
@@ -14,6 +14,13 @@ module Sass
|
|
14
14
|
def interpolation(warn_for_color = false); nil; end
|
15
15
|
def use_css_import?; true; end
|
16
16
|
|
17
|
+
def block_contents(node, context)
|
18
|
+
if node.is_a?(Sass::Tree::DirectiveNode) && node.normalized_name == '@keyframes'
|
19
|
+
context = :keyframes
|
20
|
+
end
|
21
|
+
super(node, context)
|
22
|
+
end
|
23
|
+
|
17
24
|
def block_child(context)
|
18
25
|
case context
|
19
26
|
when :ruleset
|
@@ -22,6 +29,8 @@ module Sass
|
|
22
29
|
directive || ruleset
|
23
30
|
when :directive
|
24
31
|
directive || declaration_or_ruleset
|
32
|
+
when :keyframes
|
33
|
+
keyframes_ruleset
|
25
34
|
end
|
26
35
|
end
|
27
36
|
|
@@ -35,8 +44,13 @@ module Sass
|
|
35
44
|
block(node(Sass::Tree::RuleNode.new(selector, range(start_pos)), start_pos), :ruleset)
|
36
45
|
end
|
37
46
|
|
38
|
-
|
39
|
-
|
47
|
+
def keyframes_ruleset
|
48
|
+
start_pos = source_position
|
49
|
+
return unless (selector = keyframes_selector)
|
50
|
+
block(node(Sass::Tree::KeyframeRuleNode.new(selector.strip), start_pos), :ruleset)
|
51
|
+
end
|
52
|
+
|
53
|
+
@sass_script_parser = Sass::Script::CssParser
|
40
54
|
end
|
41
55
|
end
|
42
56
|
end
|