sass-embedded 0.14.0 → 0.16.2
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/lib/sass/compile_error.rb +1 -10
- data/lib/sass/compile_result.rb +1 -5
- data/lib/sass/embedded/channel.rb +2 -2
- data/lib/sass/embedded/compile_context/function_registry.rb +85 -0
- data/lib/sass/embedded/compile_context/importer_registry.rb +99 -0
- data/lib/sass/embedded/compile_context/logger_registry.rb +45 -0
- data/lib/sass/embedded/compile_context/value_protofier.rb +237 -0
- data/lib/sass/embedded/compile_context.rb +31 -238
- data/lib/sass/embedded/compiler/requirements.rb +1 -1
- data/lib/sass/embedded/compiler.rb +10 -43
- data/lib/sass/embedded/{render.rb → legacy.rb} +79 -3
- data/lib/sass/embedded/observer.rb +2 -0
- data/lib/sass/embedded/protofier.rb +91 -0
- data/lib/sass/embedded/structifier.rb +30 -0
- data/lib/sass/embedded/varint.rb +33 -0
- data/lib/sass/embedded/version.rb +1 -1
- data/lib/sass/embedded/version_context.rb +2 -3
- data/lib/sass/embedded.rb +39 -54
- data/lib/sass/embedded_protocol.rb +0 -6
- data/lib/sass/logger/source_location.rb +3 -9
- data/lib/sass/logger/source_span.rb +1 -13
- data/lib/sass/logger.rb +3 -3
- data/lib/sass/script_error.rb +5 -0
- data/lib/sass/value/argument_list.rb +24 -0
- data/lib/sass/value/boolean.rb +42 -0
- data/lib/sass/value/color.rb +213 -0
- data/lib/sass/value/function.rb +35 -0
- data/lib/sass/value/fuzzy_math.rb +81 -0
- data/lib/sass/value/list.rb +60 -0
- data/lib/sass/value/map.rb +57 -0
- data/lib/sass/value/null.rb +39 -0
- data/lib/sass/value/number/unit.rb +186 -0
- data/lib/sass/value/number.rb +272 -0
- data/lib/sass/value/string.rb +43 -0
- data/lib/sass/value.rb +92 -0
- data/lib/sass.rb +51 -48
- metadata +30 -56
- data/lib/sass/embedded/url.rb +0 -35
- data/lib/sass/file_importer.rb +0 -10
- data/lib/sass/importer.rb +0 -14
- data/lib/sass/importer_result.rb +0 -14
@@ -1,8 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative '../embedded_protocol'
|
4
|
-
require_relative 'observer'
|
5
|
-
|
6
3
|
module Sass
|
7
4
|
class Embedded
|
8
5
|
# The {Observer} for {Embedded#info}.
|
@@ -32,5 +29,7 @@ module Sass
|
|
32
29
|
end
|
33
30
|
end
|
34
31
|
end
|
32
|
+
|
33
|
+
private_constant :VersionContext
|
35
34
|
end
|
36
35
|
end
|
data/lib/sass/embedded.rb
CHANGED
@@ -1,19 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative 'compile_error'
|
4
|
-
require_relative 'compile_result'
|
5
|
-
require_relative 'embedded/channel'
|
6
|
-
require_relative 'embedded/compile_context'
|
7
|
-
require_relative 'embedded/render'
|
8
|
-
require_relative 'embedded/url'
|
9
|
-
require_relative 'embedded/version'
|
10
|
-
require_relative 'embedded/version_context'
|
11
|
-
require_relative 'importer_result'
|
12
|
-
require_relative 'logger'
|
13
|
-
|
14
3
|
module Sass
|
15
4
|
# The {Embedded} host for using dart-sass-embedded. Each instance creates
|
16
|
-
# its own {Channel}.
|
5
|
+
# its own communication {Channel} with a dedicated compiler process.
|
17
6
|
#
|
18
7
|
# @example
|
19
8
|
# embedded = Sass::Embedded.new
|
@@ -48,27 +37,25 @@ module Sass
|
|
48
37
|
|
49
38
|
raise ArgumentError, 'path must be set' if path.nil?
|
50
39
|
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
CompileResult.from_proto(message.success)
|
40
|
+
Protofier.from_proto_compile_response(
|
41
|
+
CompileContext.new(@channel,
|
42
|
+
path: path,
|
43
|
+
source: nil,
|
44
|
+
importer: nil,
|
45
|
+
load_paths: load_paths,
|
46
|
+
syntax: nil,
|
47
|
+
url: nil,
|
48
|
+
source_map: source_map,
|
49
|
+
source_map_include_sources: source_map_include_sources,
|
50
|
+
style: style,
|
51
|
+
functions: functions,
|
52
|
+
importers: importers,
|
53
|
+
alert_color: alert_color,
|
54
|
+
alert_ascii: alert_ascii,
|
55
|
+
logger: logger,
|
56
|
+
quiet_deps: quiet_deps,
|
57
|
+
verbose: verbose).receive_message
|
58
|
+
)
|
72
59
|
end
|
73
60
|
|
74
61
|
# The {Embedded#compile_string} method.
|
@@ -96,27 +83,25 @@ module Sass
|
|
96
83
|
verbose: false)
|
97
84
|
raise ArgumentError, 'source must be set' if source.nil?
|
98
85
|
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
CompileResult.from_proto(message.success)
|
86
|
+
Protofier.from_proto_compile_response(
|
87
|
+
CompileContext.new(@channel,
|
88
|
+
path: nil,
|
89
|
+
source: source,
|
90
|
+
importer: importer,
|
91
|
+
load_paths: load_paths,
|
92
|
+
syntax: syntax,
|
93
|
+
url: url,
|
94
|
+
source_map: source_map,
|
95
|
+
source_map_include_sources: source_map_include_sources,
|
96
|
+
style: style,
|
97
|
+
functions: functions,
|
98
|
+
importers: importers,
|
99
|
+
alert_color: alert_color,
|
100
|
+
alert_ascii: alert_ascii,
|
101
|
+
logger: logger,
|
102
|
+
quiet_deps: quiet_deps,
|
103
|
+
verbose: verbose).receive_message
|
104
|
+
)
|
120
105
|
end
|
121
106
|
|
122
107
|
# The {Embedded#info} method.
|
@@ -2,7 +2,9 @@
|
|
2
2
|
|
3
3
|
module Sass
|
4
4
|
module Logger
|
5
|
-
#
|
5
|
+
# A specific location within a source file.
|
6
|
+
#
|
7
|
+
# This is always associated with a {SourceSpan} which indicates which file it refers to.
|
6
8
|
class SourceLocation
|
7
9
|
attr_reader :offset, :line, :column
|
8
10
|
|
@@ -11,14 +13,6 @@ module Sass
|
|
11
13
|
@line = line
|
12
14
|
@column = column
|
13
15
|
end
|
14
|
-
|
15
|
-
def self.from_proto(source_location)
|
16
|
-
return nil if source_location.nil?
|
17
|
-
|
18
|
-
SourceLocation.new(source_location.offset,
|
19
|
-
source_location.line,
|
20
|
-
source_location.column)
|
21
|
-
end
|
22
16
|
end
|
23
17
|
end
|
24
18
|
end
|
@@ -1,10 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative 'source_location'
|
4
|
-
|
5
3
|
module Sass
|
6
4
|
module Logger
|
7
|
-
#
|
5
|
+
# A span of text within a source file.
|
8
6
|
class SourceSpan
|
9
7
|
attr_reader :start, :end, :text, :url, :context
|
10
8
|
|
@@ -15,16 +13,6 @@ module Sass
|
|
15
13
|
@url = url == '' ? nil : url
|
16
14
|
@context = context == '' ? nil : context
|
17
15
|
end
|
18
|
-
|
19
|
-
def self.from_proto(source_span)
|
20
|
-
return nil if source_span.nil?
|
21
|
-
|
22
|
-
SourceSpan.new(SourceLocation.from_proto(source_span.start),
|
23
|
-
SourceLocation.from_proto(source_span.end),
|
24
|
-
source_span.text,
|
25
|
-
source_span.url,
|
26
|
-
source_span.context)
|
27
|
-
end
|
28
16
|
end
|
29
17
|
end
|
30
18
|
end
|
data/lib/sass/logger.rb
CHANGED
@@ -1,16 +1,16 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module Sass
|
4
|
-
#
|
4
|
+
# A namespace for built-in Loggers.
|
5
5
|
module Logger
|
6
6
|
module_function
|
7
7
|
|
8
|
-
#
|
8
|
+
# A Logger that silently ignores all warnings and debug messages.
|
9
9
|
def silent
|
10
10
|
Silent
|
11
11
|
end
|
12
12
|
|
13
|
-
#
|
13
|
+
# A Logger that silently ignores all warnings and debug messages.
|
14
14
|
module Silent
|
15
15
|
module_function
|
16
16
|
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Sass
|
4
|
+
class Value
|
5
|
+
# Sass's argument list type.
|
6
|
+
#
|
7
|
+
# An argument list comes from a rest argument. It's distinct from a normal {List} in that it may contain a keyword
|
8
|
+
# map as well as the positional arguments.
|
9
|
+
class ArgumentList < Sass::Value::List
|
10
|
+
def initialize(contents = [], keywords = {}, separator = ',')
|
11
|
+
super(contents, separator: separator)
|
12
|
+
|
13
|
+
@id = 0
|
14
|
+
@keywords_accessed = false
|
15
|
+
@keywords = keywords.transform_keys(&:to_s).freeze
|
16
|
+
end
|
17
|
+
|
18
|
+
def keywords
|
19
|
+
@keywords_accessed = true
|
20
|
+
@keywords
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Sass
|
4
|
+
class Value
|
5
|
+
# Sass's boolean type.
|
6
|
+
class Boolean < Sass::Value
|
7
|
+
def initialize(value) # rubocop:disable Lint/MissingSuper
|
8
|
+
@value = value
|
9
|
+
end
|
10
|
+
|
11
|
+
attr_reader :value
|
12
|
+
|
13
|
+
alias to_bool value
|
14
|
+
|
15
|
+
def assert_boolean(_name = nil)
|
16
|
+
self
|
17
|
+
end
|
18
|
+
|
19
|
+
def ==(other)
|
20
|
+
other.is_a?(Sass::Value::Boolean) && other.value == value
|
21
|
+
end
|
22
|
+
|
23
|
+
def hash
|
24
|
+
@hash ||= value.hash
|
25
|
+
end
|
26
|
+
|
27
|
+
def !
|
28
|
+
value ? Boolean::FALSE : Boolean::TRUE
|
29
|
+
end
|
30
|
+
|
31
|
+
# Sass's true value.
|
32
|
+
TRUE = Boolean.new(true)
|
33
|
+
|
34
|
+
# Sass's false value.
|
35
|
+
FALSE = Boolean.new(false)
|
36
|
+
|
37
|
+
def self.new(value)
|
38
|
+
value ? Boolean::TRUE : Boolean::FALSE
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,213 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Sass
|
4
|
+
class Value
|
5
|
+
# Sass's color type.
|
6
|
+
#
|
7
|
+
# No matter what representation was originally used to create this color, all of its channels are accessible.
|
8
|
+
class Color < Sass::Value
|
9
|
+
def initialize(red: nil, green: nil, blue: nil, # rubocop:disable Lint/MissingSuper
|
10
|
+
hue: nil, saturation: nil, lightness: nil,
|
11
|
+
whiteness: nil, blackness: nil,
|
12
|
+
alpha: nil)
|
13
|
+
@alpha = alpha.nil? ? 1 : FuzzyMath.assert_between(alpha, 0, 1, 'alpha')
|
14
|
+
if red && green && blue
|
15
|
+
@red = FuzzyMath.assert_between(FuzzyMath.round(red), 0, 255, 'red')
|
16
|
+
@green = FuzzyMath.assert_between(FuzzyMath.round(green), 0, 255, 'green')
|
17
|
+
@blue = FuzzyMath.assert_between(FuzzyMath.round(blue), 0, 255, 'blue')
|
18
|
+
elsif hue && saturation && lightness
|
19
|
+
@hue = hue % 360
|
20
|
+
@saturation = FuzzyMath.assert_between(saturation, 0, 100, 'saturation')
|
21
|
+
@lightness = FuzzyMath.assert_between(lightness, 0, 100, 'lightness')
|
22
|
+
elsif hue && whiteness && blackness
|
23
|
+
@hue = hue % 360
|
24
|
+
@whiteness = FuzzyMath.assert_between(whiteness, 0, 100, 'whiteness')
|
25
|
+
@blackness = FuzzyMath.assert_between(blackness, 0, 100, 'blackness')
|
26
|
+
hwb_to_rgb
|
27
|
+
@whiteness = @blackness = nil
|
28
|
+
else
|
29
|
+
raise error 'Invalid Color'
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def change(red: nil,
|
34
|
+
green: nil,
|
35
|
+
blue: nil,
|
36
|
+
hue: nil,
|
37
|
+
saturation: nil,
|
38
|
+
lightness: nil,
|
39
|
+
whiteness: nil,
|
40
|
+
blackness: nil,
|
41
|
+
alpha: nil)
|
42
|
+
if whiteness || blackness
|
43
|
+
Sass::Value::Color.new(hue: hue || self.hue,
|
44
|
+
whiteness: whiteness || self.whiteness,
|
45
|
+
blackness: blackness || self.blackness,
|
46
|
+
alpha: alpha || self.alpha)
|
47
|
+
elsif hue || saturation || lightness
|
48
|
+
Sass::Value::Color.new(hue: hue || self.hue,
|
49
|
+
saturation: saturation || self.saturation,
|
50
|
+
lightness: lightness || self.lightness,
|
51
|
+
alpha: alpha || self.alpha)
|
52
|
+
elsif red || green || blue
|
53
|
+
Sass::Value::Color.new(red: red ? FuzzyMath.round(red) : self.red,
|
54
|
+
green: green ? FuzzyMath.round(green) : self.green,
|
55
|
+
blue: blue ? FuzzyMath.round(blue) : self.blue,
|
56
|
+
alpha: alpha || self.alpha)
|
57
|
+
else
|
58
|
+
dup.instance_eval do
|
59
|
+
@alpha = FuzzyMath.assert_between(alpha, 0, 1, 'alpha')
|
60
|
+
self
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def red
|
66
|
+
hsl_to_rgb if @red.nil?
|
67
|
+
|
68
|
+
@red
|
69
|
+
end
|
70
|
+
|
71
|
+
def green
|
72
|
+
hsl_to_rgb if @green.nil?
|
73
|
+
|
74
|
+
@green
|
75
|
+
end
|
76
|
+
|
77
|
+
def blue
|
78
|
+
hsl_to_rgb if @blue.nil?
|
79
|
+
|
80
|
+
@blue
|
81
|
+
end
|
82
|
+
|
83
|
+
def hue
|
84
|
+
rgb_to_hsl if @hue.nil?
|
85
|
+
|
86
|
+
@hue
|
87
|
+
end
|
88
|
+
|
89
|
+
def saturation
|
90
|
+
rgb_to_hsl if @saturation.nil?
|
91
|
+
|
92
|
+
@saturation
|
93
|
+
end
|
94
|
+
|
95
|
+
def lightness
|
96
|
+
rgb_to_hsl if @lightness.nil?
|
97
|
+
|
98
|
+
@lightness
|
99
|
+
end
|
100
|
+
|
101
|
+
def whiteness
|
102
|
+
@whiteness ||= Rational([red, green, blue].min, 255) * 100
|
103
|
+
end
|
104
|
+
|
105
|
+
def blackness
|
106
|
+
@blackness ||= 100 - (Rational([red, green, blue].max, 255) * 100)
|
107
|
+
end
|
108
|
+
|
109
|
+
attr_reader :alpha
|
110
|
+
|
111
|
+
def assert_color(_name = nil)
|
112
|
+
self
|
113
|
+
end
|
114
|
+
|
115
|
+
def ==(other)
|
116
|
+
other.is_a?(Sass::Value::Color) &&
|
117
|
+
other.red == red &&
|
118
|
+
other.green == green &&
|
119
|
+
other.blue == blue &&
|
120
|
+
other.alpha == alpha
|
121
|
+
end
|
122
|
+
|
123
|
+
def hash
|
124
|
+
@hash ||= red.hash ^ green.hash ^ blue.hash ^ alpha.hash
|
125
|
+
end
|
126
|
+
|
127
|
+
private
|
128
|
+
|
129
|
+
def rgb_to_hsl
|
130
|
+
scaled_red = Rational(red, 255)
|
131
|
+
scaled_green = Rational(green, 255)
|
132
|
+
scaled_blue = Rational(blue, 255)
|
133
|
+
|
134
|
+
max = [scaled_red, scaled_green, scaled_blue].max
|
135
|
+
min = [scaled_red, scaled_green, scaled_blue].min
|
136
|
+
delta = max - min
|
137
|
+
|
138
|
+
if max == min
|
139
|
+
@hue = 0
|
140
|
+
elsif max == scaled_red
|
141
|
+
@hue = (60 * (scaled_green - scaled_blue) / delta) % 360
|
142
|
+
elsif max == scaled_green
|
143
|
+
@hue = (120 + (60 * (scaled_blue - scaled_red) / delta)) % 360
|
144
|
+
elsif max == scaled_blue
|
145
|
+
@hue = (240 + (60 * (scaled_red - scaled_green) / delta)) % 360
|
146
|
+
end
|
147
|
+
|
148
|
+
lightness = @lightness = 50 * (max + min)
|
149
|
+
|
150
|
+
@saturation = if max == min
|
151
|
+
0
|
152
|
+
elsif lightness < 50
|
153
|
+
100 * delta / (max + min)
|
154
|
+
else
|
155
|
+
100 * delta / (2 - max - min)
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
def hsl_to_rgb
|
160
|
+
scaled_hue = Rational(hue, 360)
|
161
|
+
scaled_saturation = Rational(saturation, 100)
|
162
|
+
scaled_lightness = Rational(lightness, 100)
|
163
|
+
|
164
|
+
tmp2 = if scaled_lightness <= 0.5
|
165
|
+
scaled_lightness * (scaled_saturation + 1)
|
166
|
+
else
|
167
|
+
scaled_lightness + scaled_saturation - (scaled_lightness * scaled_saturation)
|
168
|
+
end
|
169
|
+
tmp1 = (scaled_lightness * 2) - tmp2
|
170
|
+
@red = FuzzyMath.round(hsl_hue_to_rgb(tmp1, tmp2, scaled_hue + Rational(1, 3)) * 255)
|
171
|
+
@green = FuzzyMath.round(hsl_hue_to_rgb(tmp1, tmp2, scaled_hue) * 255)
|
172
|
+
@blue = FuzzyMath.round(hsl_hue_to_rgb(tmp1, tmp2, scaled_hue - Rational(1, 3)) * 255)
|
173
|
+
end
|
174
|
+
|
175
|
+
def hsl_hue_to_rgb(tmp1, tmp2, hue)
|
176
|
+
hue += 1 if hue.negative?
|
177
|
+
hue -= 1 if hue > 1
|
178
|
+
|
179
|
+
if hue < Rational(1, 6)
|
180
|
+
tmp1 + ((tmp2 - tmp1) * hue * 6)
|
181
|
+
elsif hue < Rational(1, 2)
|
182
|
+
tmp2
|
183
|
+
elsif hue < Rational(2, 3)
|
184
|
+
tmp1 + ((tmp2 - tmp1) * (Rational(2, 3) - hue) * 6)
|
185
|
+
else
|
186
|
+
tmp1
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
def hwb_to_rgb
|
191
|
+
scaled_hue = Rational(hue, 360)
|
192
|
+
scaled_whiteness = Rational(whiteness, 100)
|
193
|
+
scaled_blackness = Rational(blackness, 100)
|
194
|
+
|
195
|
+
sum = scaled_whiteness + scaled_blackness
|
196
|
+
if sum > 1
|
197
|
+
scaled_whiteness /= sum
|
198
|
+
scaled_blackness /= sum
|
199
|
+
end
|
200
|
+
|
201
|
+
factor = 1 - scaled_whiteness - scaled_blackness
|
202
|
+
@red = hwb_hue_to_rgb(factor, scaled_whiteness, scaled_hue + Rational(1, 3))
|
203
|
+
@green = hwb_hue_to_rgb(factor, scaled_whiteness, scaled_hue)
|
204
|
+
@blue = hwb_hue_to_rgb(factor, scaled_whiteness, scaled_hue - Rational(1, 3))
|
205
|
+
end
|
206
|
+
|
207
|
+
def hwb_hue_to_rgb(factor, scaled_whiteness, scaled_hue)
|
208
|
+
channel = (hsl_hue_to_rgb(0, 1, scaled_hue) * factor) + scaled_whiteness
|
209
|
+
FuzzyMath.round(channel * 255)
|
210
|
+
end
|
211
|
+
end
|
212
|
+
end
|
213
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Sass
|
4
|
+
class Value
|
5
|
+
# Sass's function type.
|
6
|
+
class Function < Sass::Value
|
7
|
+
def initialize(id_or_signature, callback = nil) # rubocop:disable Lint/MissingSuper
|
8
|
+
if id_or_signature.is_a? Numeric
|
9
|
+
@id = id_or_signature
|
10
|
+
else
|
11
|
+
@signature = id_or_signature
|
12
|
+
@callback = callback
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
attr_reader :id, :signature, :callback
|
17
|
+
|
18
|
+
def assert_function(_name = nil)
|
19
|
+
self
|
20
|
+
end
|
21
|
+
|
22
|
+
def ==(other)
|
23
|
+
if id.nil?
|
24
|
+
other.equal? self
|
25
|
+
else
|
26
|
+
other.is_a?(Sass::Value::Function) && other.id == id
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def hash
|
31
|
+
id.nil? ? signature.hash : id.hash
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Sass
|
4
|
+
class Value
|
5
|
+
# Sass's {FuzzyMath} module.
|
6
|
+
module FuzzyMath
|
7
|
+
PRECISION = 10
|
8
|
+
|
9
|
+
EPSILON = 10.pow(-PRECISION - 1)
|
10
|
+
|
11
|
+
INVERSE_EPSILON = 1 / EPSILON
|
12
|
+
|
13
|
+
module_function
|
14
|
+
|
15
|
+
def equals(number1, number2)
|
16
|
+
(number1 - number2).abs < EPSILON
|
17
|
+
end
|
18
|
+
|
19
|
+
def less_than(number1, number2)
|
20
|
+
number1 < number2 && !equals(number1, number2)
|
21
|
+
end
|
22
|
+
|
23
|
+
def less_than_or_equals(number1, number2)
|
24
|
+
number1 < number2 || equals(number1, number2)
|
25
|
+
end
|
26
|
+
|
27
|
+
def greater_than(number1, number2)
|
28
|
+
number1 > number2 && !equals(number1, number2)
|
29
|
+
end
|
30
|
+
|
31
|
+
def greater_than_or_equals(number1, number2)
|
32
|
+
number1 > number2 || equals(number1, number2)
|
33
|
+
end
|
34
|
+
|
35
|
+
def integer?(number)
|
36
|
+
return false unless number.finite?
|
37
|
+
return true if number.integer?
|
38
|
+
|
39
|
+
equals((number - 0.5).abs % 1, 0.5)
|
40
|
+
end
|
41
|
+
|
42
|
+
def to_i(number)
|
43
|
+
integer?(number) ? number.round : nil
|
44
|
+
end
|
45
|
+
|
46
|
+
def round(number)
|
47
|
+
if number.positive?
|
48
|
+
less_than(number % 1, 0.5) ? number.floor : number.ceil
|
49
|
+
else
|
50
|
+
less_than_or_equals(number % 1, 0.5) ? number.floor : number.ceil
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def between(number, min, max)
|
55
|
+
return min if equals(number, min)
|
56
|
+
return max if equals(number, max)
|
57
|
+
return number if number > min && number < max
|
58
|
+
|
59
|
+
nil
|
60
|
+
end
|
61
|
+
|
62
|
+
def assert_between(number, min, max, name)
|
63
|
+
result = between(number, min, max)
|
64
|
+
return result unless result.nil?
|
65
|
+
|
66
|
+
message = "#{number} must be between #{min} and #{max}."
|
67
|
+
raise Sass::ScriptError, name.nil? ? message : "$#{name}: #{message}"
|
68
|
+
end
|
69
|
+
|
70
|
+
def hash(number)
|
71
|
+
@hash ||= if number.finite?
|
72
|
+
(number * INVERSE_EPSILON).round.hash
|
73
|
+
else
|
74
|
+
number.hash
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
private_constant :FuzzyMath
|
80
|
+
end
|
81
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Sass
|
4
|
+
class Value
|
5
|
+
# Sass's list type.
|
6
|
+
class List < Sass::Value
|
7
|
+
def initialize(contents = [], separator: ',', bracketed: false) # rubocop:disable Lint/MissingSuper
|
8
|
+
if separator.nil? && contents.length > 1
|
9
|
+
raise error 'A list with more than one element must have an explicit separator'
|
10
|
+
end
|
11
|
+
|
12
|
+
@contents = contents.freeze
|
13
|
+
@separator = separator.freeze
|
14
|
+
@bracketed = bracketed.freeze
|
15
|
+
end
|
16
|
+
|
17
|
+
attr_reader :contents, :separator
|
18
|
+
|
19
|
+
alias to_a contents
|
20
|
+
|
21
|
+
def bracketed?
|
22
|
+
@bracketed
|
23
|
+
end
|
24
|
+
|
25
|
+
def assert_map(name = nil)
|
26
|
+
to_a.empty? ? Sass::Value::Map.new({}) : super.assert_map(name)
|
27
|
+
end
|
28
|
+
|
29
|
+
def to_map
|
30
|
+
to_a.empty? ? Sass::Value::Map.new({}) : nil
|
31
|
+
end
|
32
|
+
|
33
|
+
def at(index)
|
34
|
+
index = index.floor
|
35
|
+
index = to_a.length + index if index.negative?
|
36
|
+
return nil if index.negative? || index >= to_a.length
|
37
|
+
|
38
|
+
to_a[index]
|
39
|
+
end
|
40
|
+
|
41
|
+
def ==(other)
|
42
|
+
(other.is_a?(Sass::Value::List) &&
|
43
|
+
other.contents == contents &&
|
44
|
+
other.separator == separator &&
|
45
|
+
other.bracketed? == bracketed?) ||
|
46
|
+
(to_a.empty? && other.is_a?(Sass::Value::Map) && other.to_a.empty?)
|
47
|
+
end
|
48
|
+
|
49
|
+
def hash
|
50
|
+
@hash ||= contents.hash
|
51
|
+
end
|
52
|
+
|
53
|
+
private
|
54
|
+
|
55
|
+
def to_a_length
|
56
|
+
to_a.length
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|