sass-embedded 1.58.0-x86_64-linux-musl

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 (43) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +20 -0
  3. data/README.md +42 -0
  4. data/ext/sass/embedded.rb +12 -0
  5. data/ext/sass/embedded_sass_pb.rb +349 -0
  6. data/ext/sass/sass_embedded/dart-sass-embedded +20 -0
  7. data/ext/sass/sass_embedded/src/LICENSE +1434 -0
  8. data/ext/sass/sass_embedded/src/dart +0 -0
  9. data/ext/sass/sass_embedded/src/dart-sass-embedded.snapshot +0 -0
  10. data/lib/sass/compile_error.rb +28 -0
  11. data/lib/sass/compile_result.rb +23 -0
  12. data/lib/sass/embedded/async.rb +58 -0
  13. data/lib/sass/embedded/channel.rb +61 -0
  14. data/lib/sass/embedded/compiler.rb +60 -0
  15. data/lib/sass/embedded/dispatcher.rb +98 -0
  16. data/lib/sass/embedded/host/function_registry.rb +89 -0
  17. data/lib/sass/embedded/host/importer_registry.rb +104 -0
  18. data/lib/sass/embedded/host/logger_registry.rb +50 -0
  19. data/lib/sass/embedded/host/value_protofier.rb +241 -0
  20. data/lib/sass/embedded/host.rb +141 -0
  21. data/lib/sass/embedded/protofier.rb +78 -0
  22. data/lib/sass/embedded/structifier.rb +39 -0
  23. data/lib/sass/embedded/varint.rb +35 -0
  24. data/lib/sass/embedded/version.rb +7 -0
  25. data/lib/sass/embedded.rb +251 -0
  26. data/lib/sass/logger/silent.rb +26 -0
  27. data/lib/sass/logger/source_location.rb +21 -0
  28. data/lib/sass/logger/source_span.rb +27 -0
  29. data/lib/sass/script_error.rb +10 -0
  30. data/lib/sass/value/argument_list.rb +37 -0
  31. data/lib/sass/value/boolean.rb +52 -0
  32. data/lib/sass/value/color.rb +253 -0
  33. data/lib/sass/value/function.rb +54 -0
  34. data/lib/sass/value/fuzzy_math.rb +80 -0
  35. data/lib/sass/value/list.rb +79 -0
  36. data/lib/sass/value/map.rb +71 -0
  37. data/lib/sass/value/null.rb +48 -0
  38. data/lib/sass/value/number/unit.rb +186 -0
  39. data/lib/sass/value/number.rb +365 -0
  40. data/lib/sass/value/string.rb +55 -0
  41. data/lib/sass/value.rb +128 -0
  42. data/lib/sass-embedded.rb +4 -0
  43. metadata +186 -0
@@ -0,0 +1,251 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../../ext/sass/embedded'
4
+ require_relative '../../ext/sass/embedded_sass_pb'
5
+ require_relative 'compile_error'
6
+ require_relative 'compile_result'
7
+ require_relative 'embedded/async'
8
+ require_relative 'embedded/channel'
9
+ require_relative 'embedded/compiler'
10
+ require_relative 'embedded/dispatcher'
11
+ require_relative 'embedded/host'
12
+ require_relative 'embedded/protofier'
13
+ require_relative 'embedded/structifier'
14
+ require_relative 'embedded/varint'
15
+ require_relative 'embedded/version'
16
+ require_relative 'logger/silent'
17
+ require_relative 'logger/source_location'
18
+ require_relative 'logger/source_span'
19
+ require_relative 'value'
20
+
21
+ # The Sass module.
22
+ #
23
+ # This communicates with Embedded Dart Sass using the Embedded Sass protocol.
24
+ #
25
+ # @example
26
+ # Sass.compile('style.scss')
27
+ #
28
+ # @example
29
+ # Sass.compile_string('h1 { font-size: 40px; }')
30
+ module Sass
31
+ @instance = nil
32
+ @mutex = Mutex.new
33
+
34
+ # rubocop:disable Layout/LineLength
35
+ class << self
36
+ # Compiles the Sass file at +path+ to CSS.
37
+ # @overload compile(path, load_paths: [], charset: true, source_map: false, source_map_include_sources: false, style: :expanded, functions: {}, importers: [], alert_ascii: false, alert_color: nil, logger: nil, quiet_deps: false, verbose: false)
38
+ # @param (see Embedded#compile)
39
+ # @return (see Embedded#compile)
40
+ # @raise (see Embedded#compile)
41
+ # @see Embedded#compile
42
+ def compile(path, **kwargs)
43
+ instance.compile(path, **kwargs)
44
+ end
45
+
46
+ # Compiles a stylesheet whose contents is +source+ to CSS.
47
+ # @overload compile_string(source, importer: nil, load_paths: [], syntax: :scss, url: nil, charset: true, source_map: false, source_map_include_sources: false, style: :expanded, functions: {}, importers: [], alert_ascii: false, alert_color: nil, logger: nil, quiet_deps: false, verbose: false)
48
+ # @param (see Embedded#compile_string)
49
+ # @return (see Embedded#compile_string)
50
+ # @raise (see Embedded#compile_string)
51
+ # @see Embedded#compile_string
52
+ def compile_string(source, **kwargs)
53
+ instance.compile_string(source, **kwargs)
54
+ end
55
+
56
+ # @param (see Embedded#info)
57
+ # @return (see Embedded#info)
58
+ # @raise (see Embedded#info)
59
+ # @see Embedded#info
60
+ def info
61
+ instance.info
62
+ end
63
+
64
+ private
65
+
66
+ def instance
67
+ return @instance if @instance
68
+
69
+ @mutex.synchronize do
70
+ return @instance if @instance
71
+
72
+ @instance = Embedded.new
73
+ at_exit do
74
+ @instance.close
75
+ end
76
+ end
77
+
78
+ @instance
79
+ end
80
+ end
81
+ # rubocop:enable Layout/LineLength
82
+
83
+ # The {Embedded} host for using dart-sass-embedded. Each instance creates
84
+ # its own communication {Channel} with a dedicated compiler process.
85
+ #
86
+ # @example
87
+ # embedded = Sass::Embedded.new
88
+ # result = embedded.compile_string('h1 { font-size: 40px; }')
89
+ # result = embedded.compile('style.scss')
90
+ # embedded.close
91
+ class Embedded
92
+ def initialize
93
+ @channel = Channel.new
94
+ end
95
+
96
+ # Compiles the Sass file at +path+ to CSS.
97
+ # @param path [String]
98
+ # @param load_paths [Array<String>] Paths in which to look for stylesheets loaded by rules like
99
+ # {@use}[https://sass-lang.com/documentation/at-rules/use] and {@import}[https://sass-lang.com/documentation/at-rules/import].
100
+ # @param charset [Boolean] By default, if the CSS document contains non-ASCII characters, Sass adds a +@charset+
101
+ # declaration (in expanded output mode) or a byte-order mark (in compressed mode) to indicate its encoding to
102
+ # browsers or other consumers. If +charset+ is +false+, these annotations are omitted.
103
+ # @param source_map [Boolean] Whether or not Sass should generate a source map.
104
+ # @param source_map_include_sources [Boolean] Whether Sass should include the sources in the generated source map.
105
+ # @param style [String, Symbol] The OutputStyle of the compiled CSS.
106
+ # @param functions [Hash<String, Proc>] Additional built-in Sass functions that are available in all stylesheets.
107
+ # @param importers [Array<Object>] Custom importers that control how Sass resolves loads from rules like
108
+ # {@use}[https://sass-lang.com/documentation/at-rules/use] and {@import}[https://sass-lang.com/documentation/at-rules/import].
109
+ # @param alert_ascii [Boolean] If this is +true+, the compiler will exclusively use ASCII characters in its error
110
+ # and warning messages. Otherwise, it may use non-ASCII Unicode characters as well.
111
+ # @param alert_color [Boolean] If this is +true+, the compiler will use ANSI color escape codes in its error and
112
+ # warning messages. If it's +false+, it won't use these. If it's +nil+, the compiler will determine whether or
113
+ # not to use colors depending on whether the user is using an interactive terminal.
114
+ # @param logger [Object] An object to use to handle warnings and/or debug messages from Sass.
115
+ # @param quiet_deps [Boolean] If this option is set to +true+, Sass won’t print warnings that are caused by
116
+ # dependencies. A “dependency” is defined as any file that’s loaded through +load_paths+ or +importer+.
117
+ # Stylesheets that are imported relative to the entrypoint are not considered dependencies.
118
+ # @param verbose [Boolean] By default, Dart Sass will print only five instances of the same deprecation warning per
119
+ # compilation to avoid deluging users in console noise. If you set verbose to +true+, it will instead print every
120
+ # deprecation warning it encounters.
121
+ # @return [CompileResult]
122
+ # @raise [CompileError]
123
+ # @see https://sass-lang.com/documentation/js-api/modules#compile
124
+ def compile(path,
125
+ load_paths: [],
126
+
127
+ charset: true,
128
+ source_map: false,
129
+ source_map_include_sources: false,
130
+ style: :expanded,
131
+
132
+ functions: {},
133
+ importers: [],
134
+
135
+ alert_ascii: false,
136
+ alert_color: nil,
137
+ logger: nil,
138
+ quiet_deps: false,
139
+ verbose: false)
140
+ raise ArgumentError, 'path must be set' if path.nil?
141
+
142
+ Host.new(@channel).compile_request(
143
+ path: path,
144
+ source: nil,
145
+ importer: nil,
146
+ load_paths: load_paths,
147
+ syntax: nil,
148
+ url: nil,
149
+ charset: charset,
150
+ source_map: source_map,
151
+ source_map_include_sources: source_map_include_sources,
152
+ style: style,
153
+ functions: functions,
154
+ importers: importers,
155
+ alert_color: alert_color,
156
+ alert_ascii: alert_ascii,
157
+ logger: logger,
158
+ quiet_deps: quiet_deps,
159
+ verbose: verbose
160
+ )
161
+ end
162
+
163
+ # Compiles a stylesheet whose contents is +source+ to CSS.
164
+ # @param source [String]
165
+ # @param importer [Object] The importer to use to handle loads that are relative to the entrypoint stylesheet.
166
+ # @param load_paths [Array<String>] Paths in which to look for stylesheets loaded by rules like
167
+ # {@use}[https://sass-lang.com/documentation/at-rules/use] and {@import}[https://sass-lang.com/documentation/at-rules/import].
168
+ # @param syntax [String, Symbol] The Syntax to use to parse the entrypoint stylesheet.
169
+ # @param url [String] The canonical URL of the entrypoint stylesheet. If this is passed along with +importer+, it's
170
+ # used to resolve relative loads in the entrypoint stylesheet.
171
+ # @param charset [Boolean] By default, if the CSS document contains non-ASCII characters, Sass adds a +@charset+
172
+ # declaration (in expanded output mode) or a byte-order mark (in compressed mode) to indicate its encoding to
173
+ # browsers or other consumers. If +charset+ is +false+, these annotations are omitted.
174
+ # @param source_map [Boolean] Whether or not Sass should generate a source map.
175
+ # @param source_map_include_sources [Boolean] Whether Sass should include the sources in the generated source map.
176
+ # @param style [String, Symbol] The OutputStyle of the compiled CSS.
177
+ # @param functions [Hash<String, Proc>] Additional built-in Sass functions that are available in all stylesheets.
178
+ # @param importers [Array<Object>] Custom importers that control how Sass resolves loads from rules like
179
+ # {@use}[https://sass-lang.com/documentation/at-rules/use] and {@import}[https://sass-lang.com/documentation/at-rules/import].
180
+ # @param alert_ascii [Boolean] If this is +true+, the compiler will exclusively use ASCII characters in its error
181
+ # and warning messages. Otherwise, it may use non-ASCII Unicode characters as well.
182
+ # @param alert_color [Boolean] If this is +true+, the compiler will use ANSI color escape codes in its error and
183
+ # warning messages. If it's +false+, it won't use these. If it's +nil+, the compiler will determine whether or
184
+ # not to use colors depending on whether the user is using an interactive terminal.
185
+ # @param logger [Object] An object to use to handle warnings and/or debug messages from Sass.
186
+ # @param quiet_deps [Boolean] If this option is set to +true+, Sass won’t print warnings that are caused by
187
+ # dependencies. A “dependency” is defined as any file that’s loaded through +load_paths+ or +importer+.
188
+ # Stylesheets that are imported relative to the entrypoint are not considered dependencies.
189
+ # @param verbose [Boolean] By default, Dart Sass will print only five instances of the same deprecation warning per
190
+ # compilation to avoid deluging users in console noise. If you set verbose to +true+, it will instead print every
191
+ # deprecation warning it encounters.
192
+ # @return [CompileResult]
193
+ # @raise [CompileError]
194
+ # @see https://sass-lang.com/documentation/js-api/modules#compileString
195
+ def compile_string(source,
196
+ importer: nil,
197
+ load_paths: [],
198
+ syntax: :scss,
199
+ url: nil,
200
+
201
+ charset: true,
202
+ source_map: false,
203
+ source_map_include_sources: false,
204
+ style: :expanded,
205
+
206
+ functions: {},
207
+ importers: [],
208
+
209
+ alert_ascii: false,
210
+ alert_color: nil,
211
+ logger: nil,
212
+ quiet_deps: false,
213
+ verbose: false)
214
+ raise ArgumentError, 'source must be set' if source.nil?
215
+
216
+ Host.new(@channel).compile_request(
217
+ path: nil,
218
+ source: source,
219
+ importer: importer,
220
+ load_paths: load_paths,
221
+ syntax: syntax,
222
+ url: url,
223
+ charset: charset,
224
+ source_map: source_map,
225
+ source_map_include_sources: source_map_include_sources,
226
+ style: style,
227
+ functions: functions,
228
+ importers: importers,
229
+ alert_color: alert_color,
230
+ alert_ascii: alert_ascii,
231
+ logger: logger,
232
+ quiet_deps: quiet_deps,
233
+ verbose: verbose
234
+ )
235
+ end
236
+
237
+ # @return [String] Information about the Sass implementation.
238
+ # @see https://sass-lang.com/documentation/js-api/modules#info
239
+ def info
240
+ @info ||= Host.new(@channel).version_request
241
+ end
242
+
243
+ def close
244
+ @channel.close
245
+ end
246
+
247
+ def closed?
248
+ @channel.closed?
249
+ end
250
+ end
251
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Sass
4
+ # A namespace for built-in Loggers.
5
+ #
6
+ # @see https://sass-lang.com/documentation/js-api/modules/Logger
7
+ module Logger
8
+ module_function
9
+
10
+ # A Logger that silently ignores all warnings and debug messages.
11
+ def silent
12
+ Silent
13
+ end
14
+
15
+ # A Logger that silently ignores all warnings and debug messages.
16
+ module Silent
17
+ module_function
18
+
19
+ def warn(message, deprecation: false, span: nil, stack: nil); end
20
+
21
+ def debug(message, span: nil); end
22
+ end
23
+
24
+ private_constant :Silent
25
+ end
26
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Sass
4
+ module Logger
5
+ # A specific location within a source file.
6
+ #
7
+ # This is always associated with a {SourceSpan} which indicates which file it refers to.
8
+ #
9
+ # @see https://sass-lang.com/documentation/js-api/interfaces/SourceLocation
10
+ class SourceLocation
11
+ # @return [Integer]
12
+ attr_reader :offset, :line, :column
13
+
14
+ def initialize(offset, line, column)
15
+ @offset = offset
16
+ @line = line
17
+ @column = column
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Sass
4
+ module Logger
5
+ # A span of text within a source file.
6
+ #
7
+ # @see https://sass-lang.com/documentation/js-api/interfaces/SourceSpan
8
+ class SourceSpan
9
+ # @return [SourceLocation]
10
+ attr_reader :start, :end
11
+
12
+ # @return [String]
13
+ attr_reader :text
14
+
15
+ # @return [String, nil]
16
+ attr_reader :url, :context
17
+
18
+ def initialize(start, end_, text, url, context)
19
+ @start = start
20
+ @end = end_
21
+ @text = text
22
+ @url = url == '' ? nil : url
23
+ @context = context == '' ? nil : context
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Sass
4
+ # An exception thrown by Sass Script.
5
+ class ScriptError < StandardError
6
+ def initialize(message, name = nil)
7
+ super(name.nil? ? message : "$#{name}: #{message}")
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Sass
4
+ module 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
+ #
10
+ # @see https://sass-lang.com/documentation/js-api/classes/SassArgumentList
11
+ class ArgumentList < Value::List
12
+ # @param contents [Array<Value>]
13
+ # @param keywords [Hash<::String, Value>]
14
+ # @param separator [::String]
15
+ def initialize(contents = [], keywords = {}, separator = ',')
16
+ super(contents, separator: separator)
17
+
18
+ @id = 0
19
+ @keywords_accessed = false
20
+ @keywords = keywords.transform_keys(&:to_s).freeze
21
+ end
22
+
23
+ # @return [Hash<::String, Value>]
24
+ def keywords
25
+ @keywords_accessed = true
26
+ @keywords
27
+ end
28
+
29
+ private
30
+
31
+ def initialize_copy(orig)
32
+ super
33
+ @id = 0
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Sass
4
+ module Value
5
+ # Sass's boolean type.
6
+ #
7
+ # @see https://sass-lang.com/documentation/js-api/classes/SassBoolean
8
+ class Boolean
9
+ include Value
10
+
11
+ # @param value [::Boolean]
12
+ def initialize(value)
13
+ @value = value
14
+ end
15
+
16
+ # @return [::Boolean]
17
+ attr_reader :value
18
+
19
+ # @return [Boolean]
20
+ def !
21
+ value ? Boolean::FALSE : Boolean::TRUE
22
+ end
23
+
24
+ # @return [::Boolean]
25
+ def ==(other)
26
+ other.is_a?(Sass::Value::Boolean) && other.value == value
27
+ end
28
+
29
+ # @return [Integer]
30
+ def hash
31
+ @hash ||= value.hash
32
+ end
33
+
34
+ alias to_bool value
35
+
36
+ # @return [Boolean]
37
+ def assert_boolean(_name = nil)
38
+ self
39
+ end
40
+
41
+ # Sass's true value.
42
+ TRUE = Boolean.new(true)
43
+
44
+ # Sass's false value.
45
+ FALSE = Boolean.new(false)
46
+
47
+ def self.new(value)
48
+ value ? Boolean::TRUE : Boolean::FALSE
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,253 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Sass
4
+ module 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
+ #
9
+ # @see https://sass-lang.com/documentation/js-api/classes/SassColor
10
+ class Color
11
+ include Value
12
+
13
+ # @param red [Numeric]
14
+ # @param green [Numeric]
15
+ # @param blue [Numeric]
16
+ # @param hue [Numeric]
17
+ # @param saturation [Numeric]
18
+ # @param lightness [Numeric]
19
+ # @param whiteness [Numeric]
20
+ # @param blackness [Numeric]
21
+ # @param alpha [Numeric]
22
+ def initialize(red: nil,
23
+ green: nil,
24
+ blue: nil,
25
+ hue: nil,
26
+ saturation: nil,
27
+ lightness: nil,
28
+ whiteness: nil,
29
+ blackness: nil,
30
+ alpha: nil)
31
+ @alpha = alpha.nil? ? 1 : FuzzyMath.assert_between(alpha, 0, 1, 'alpha')
32
+ if red && green && blue
33
+ @red = FuzzyMath.assert_between(FuzzyMath.round(red), 0, 255, 'red')
34
+ @green = FuzzyMath.assert_between(FuzzyMath.round(green), 0, 255, 'green')
35
+ @blue = FuzzyMath.assert_between(FuzzyMath.round(blue), 0, 255, 'blue')
36
+ elsif hue && saturation && lightness
37
+ @hue = hue % 360
38
+ @saturation = FuzzyMath.assert_between(saturation, 0, 100, 'saturation')
39
+ @lightness = FuzzyMath.assert_between(lightness, 0, 100, 'lightness')
40
+ elsif hue && whiteness && blackness
41
+ @hue = hue % 360
42
+ @whiteness = FuzzyMath.assert_between(whiteness, 0, 100, 'whiteness')
43
+ @blackness = FuzzyMath.assert_between(blackness, 0, 100, 'blackness')
44
+ hwb_to_rgb
45
+ @whiteness = @blackness = nil
46
+ else
47
+ raise Sass::ScriptError, 'Invalid Color'
48
+ end
49
+ end
50
+
51
+ # @return [Integer]
52
+ def red
53
+ hsl_to_rgb unless defined? @red
54
+
55
+ @red
56
+ end
57
+
58
+ # @return [Integer]
59
+ def green
60
+ hsl_to_rgb unless defined? @green
61
+
62
+ @green
63
+ end
64
+
65
+ # @return [Integer]
66
+ def blue
67
+ hsl_to_rgb unless defined? @blue
68
+
69
+ @blue
70
+ end
71
+
72
+ # @return [Numeric]
73
+ def hue
74
+ rgb_to_hsl unless defined? @hue
75
+
76
+ @hue
77
+ end
78
+
79
+ # @return [Numeric]
80
+ def saturation
81
+ rgb_to_hsl unless defined? @saturation
82
+
83
+ @saturation
84
+ end
85
+
86
+ # @return [Numeric]
87
+ def lightness
88
+ rgb_to_hsl unless defined? @lightness
89
+
90
+ @lightness
91
+ end
92
+
93
+ # @return [Numeric]
94
+ def whiteness
95
+ @whiteness ||= Rational([red, green, blue].min, 255) * 100
96
+ end
97
+
98
+ # @return [Numeric]
99
+ def blackness
100
+ @blackness ||= 100 - (Rational([red, green, blue].max, 255) * 100)
101
+ end
102
+
103
+ # @return [Numeric]
104
+ attr_reader :alpha
105
+
106
+ # @param red [Numeric]
107
+ # @param green [Numeric]
108
+ # @param blue [Numeric]
109
+ # @param hue [Numeric]
110
+ # @param saturation [Numeric]
111
+ # @param lightness [Numeric]
112
+ # @param whiteness [Numeric]
113
+ # @param blackness [Numeric]
114
+ # @param alpha [Numeric]
115
+ # @return [Color]
116
+ def change(red: nil,
117
+ green: nil,
118
+ blue: nil,
119
+ hue: nil,
120
+ saturation: nil,
121
+ lightness: nil,
122
+ whiteness: nil,
123
+ blackness: nil,
124
+ alpha: nil)
125
+ if whiteness || blackness
126
+ Sass::Value::Color.new(hue: hue || self.hue,
127
+ whiteness: whiteness || self.whiteness,
128
+ blackness: blackness || self.blackness,
129
+ alpha: alpha || self.alpha)
130
+ elsif hue || saturation || lightness
131
+ Sass::Value::Color.new(hue: hue || self.hue,
132
+ saturation: saturation || self.saturation,
133
+ lightness: lightness || self.lightness,
134
+ alpha: alpha || self.alpha)
135
+ elsif red || green || blue
136
+ Sass::Value::Color.new(red: red ? FuzzyMath.round(red) : self.red,
137
+ green: green ? FuzzyMath.round(green) : self.green,
138
+ blue: blue ? FuzzyMath.round(blue) : self.blue,
139
+ alpha: alpha || self.alpha)
140
+ else
141
+ dup.instance_eval do
142
+ @alpha = FuzzyMath.assert_between(alpha, 0, 1, 'alpha')
143
+ self
144
+ end
145
+ end
146
+ end
147
+
148
+ # @return [::Boolean]
149
+ def ==(other)
150
+ other.is_a?(Sass::Value::Color) &&
151
+ other.red == red &&
152
+ other.green == green &&
153
+ other.blue == blue &&
154
+ other.alpha == alpha
155
+ end
156
+
157
+ # @return [Integer]
158
+ def hash
159
+ @hash ||= [red, green, blue, alpha].hash
160
+ end
161
+
162
+ # @return [Color]
163
+ def assert_color(_name = nil)
164
+ self
165
+ end
166
+
167
+ private
168
+
169
+ def rgb_to_hsl
170
+ scaled_red = Rational(red, 255)
171
+ scaled_green = Rational(green, 255)
172
+ scaled_blue = Rational(blue, 255)
173
+
174
+ max = [scaled_red, scaled_green, scaled_blue].max
175
+ min = [scaled_red, scaled_green, scaled_blue].min
176
+ delta = max - min
177
+
178
+ if max == min
179
+ @hue = 0
180
+ elsif max == scaled_red
181
+ @hue = ((scaled_green - scaled_blue) * 60 / delta) % 360
182
+ elsif max == scaled_green
183
+ @hue = (((scaled_blue - scaled_red) * 60 / delta) + 120) % 360
184
+ elsif max == scaled_blue
185
+ @hue = (((scaled_red - scaled_green) * 60 / delta) + 240) % 360
186
+ end
187
+
188
+ lightness = @lightness = (max + min) * 50
189
+
190
+ @saturation = if max == min
191
+ 0
192
+ elsif lightness < 50
193
+ delta * 100 / (max + min)
194
+ else
195
+ delta * 100 / (2 - max - min)
196
+ end
197
+ end
198
+
199
+ def hsl_to_rgb
200
+ scaled_hue = Rational(hue, 360)
201
+ scaled_saturation = Rational(saturation, 100)
202
+ scaled_lightness = Rational(lightness, 100)
203
+
204
+ tmp2 = if scaled_lightness <= 0.5
205
+ scaled_lightness * (scaled_saturation + 1)
206
+ else
207
+ scaled_lightness + scaled_saturation - (scaled_lightness * scaled_saturation)
208
+ end
209
+ tmp1 = (scaled_lightness * 2) - tmp2
210
+ @red = FuzzyMath.round(hsl_hue_to_rgb(tmp1, tmp2, scaled_hue + Rational(1, 3)) * 255)
211
+ @green = FuzzyMath.round(hsl_hue_to_rgb(tmp1, tmp2, scaled_hue) * 255)
212
+ @blue = FuzzyMath.round(hsl_hue_to_rgb(tmp1, tmp2, scaled_hue - Rational(1, 3)) * 255)
213
+ end
214
+
215
+ def hsl_hue_to_rgb(tmp1, tmp2, hue)
216
+ hue += 1 if hue.negative?
217
+ hue -= 1 if hue > 1
218
+
219
+ if hue < Rational(1, 6)
220
+ tmp1 + ((tmp2 - tmp1) * hue * 6)
221
+ elsif hue < Rational(1, 2)
222
+ tmp2
223
+ elsif hue < Rational(2, 3)
224
+ tmp1 + ((tmp2 - tmp1) * (Rational(2, 3) - hue) * 6)
225
+ else
226
+ tmp1
227
+ end
228
+ end
229
+
230
+ def hwb_to_rgb
231
+ scaled_hue = Rational(hue, 360)
232
+ scaled_whiteness = Rational(whiteness, 100)
233
+ scaled_blackness = Rational(blackness, 100)
234
+
235
+ sum = scaled_whiteness + scaled_blackness
236
+ if sum > 1
237
+ scaled_whiteness /= sum
238
+ scaled_blackness /= sum
239
+ end
240
+
241
+ factor = 1 - scaled_whiteness - scaled_blackness
242
+ @red = hwb_hue_to_rgb(factor, scaled_whiteness, scaled_hue + Rational(1, 3))
243
+ @green = hwb_hue_to_rgb(factor, scaled_whiteness, scaled_hue)
244
+ @blue = hwb_hue_to_rgb(factor, scaled_whiteness, scaled_hue - Rational(1, 3))
245
+ end
246
+
247
+ def hwb_hue_to_rgb(factor, scaled_whiteness, scaled_hue)
248
+ channel = (hsl_hue_to_rgb(0, 1, scaled_hue) * factor) + scaled_whiteness
249
+ FuzzyMath.round(channel * 255)
250
+ end
251
+ end
252
+ end
253
+ end