sass-embedded 1.6.2 → 1.83.1

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 (85) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +9 -3
  3. data/exe/sass +13 -0
  4. data/ext/sass/Rakefile +352 -76
  5. data/ext/sass/embedded_sass_pb.rb +61 -0
  6. data/ext/sass/expand-archive.ps1 +1 -0
  7. data/ext/sass/package.json +1 -1
  8. data/lib/sass/calculation_value/calculation_operation.rb +49 -0
  9. data/lib/sass/calculation_value.rb +22 -0
  10. data/lib/sass/canonicalize_context.rb +25 -0
  11. data/lib/sass/compile_result.rb +3 -2
  12. data/lib/sass/compiler/channel.rb +68 -0
  13. data/lib/sass/compiler/connection.rb +89 -0
  14. data/lib/sass/compiler/dispatcher.rb +116 -0
  15. data/lib/sass/{embedded → compiler}/host/function_registry.rb +31 -34
  16. data/lib/sass/compiler/host/importer_registry.rb +141 -0
  17. data/lib/sass/compiler/host/logger_registry.rb +80 -0
  18. data/lib/sass/compiler/host/protofier.rb +360 -0
  19. data/lib/sass/compiler/host/structifier.rb +37 -0
  20. data/lib/sass/compiler/host.rb +226 -0
  21. data/lib/sass/{embedded → compiler}/varint.rb +9 -5
  22. data/lib/sass/compiler.rb +212 -0
  23. data/lib/sass/elf.rb +222 -0
  24. data/lib/sass/embedded/version.rb +2 -2
  25. data/lib/sass/embedded.rb +76 -204
  26. data/lib/sass/embedded_protocol.rb +10 -0
  27. data/lib/sass/exception.rb +74 -0
  28. data/lib/sass/fork_tracker.rb +51 -0
  29. data/lib/sass/logger/silent.rb +5 -3
  30. data/lib/sass/logger/source_location.rb +6 -5
  31. data/lib/sass/logger/source_span.rb +8 -7
  32. data/lib/sass/node_package_importer.rb +17 -0
  33. data/lib/sass/serializer.rb +30 -0
  34. data/lib/sass/value/argument_list.rb +13 -6
  35. data/lib/sass/value/boolean.rb +1 -1
  36. data/lib/sass/value/calculation.rb +90 -0
  37. data/lib/sass/value/color/channel.rb +79 -0
  38. data/lib/sass/value/color/conversions.rb +473 -0
  39. data/lib/sass/value/color/gamut_map_method/clip.rb +45 -0
  40. data/lib/sass/value/color/gamut_map_method/local_minde.rb +94 -0
  41. data/lib/sass/value/color/gamut_map_method.rb +45 -0
  42. data/lib/sass/value/color/interpolation_method.rb +51 -0
  43. data/lib/sass/value/color/space/a98_rgb.rb +57 -0
  44. data/lib/sass/value/color/space/display_p3.rb +57 -0
  45. data/lib/sass/value/color/space/hsl.rb +65 -0
  46. data/lib/sass/value/color/space/hwb.rb +70 -0
  47. data/lib/sass/value/color/space/lab.rb +77 -0
  48. data/lib/sass/value/color/space/lch.rb +53 -0
  49. data/lib/sass/value/color/space/lms.rb +129 -0
  50. data/lib/sass/value/color/space/oklab.rb +66 -0
  51. data/lib/sass/value/color/space/oklch.rb +54 -0
  52. data/lib/sass/value/color/space/prophoto_rgb.rb +59 -0
  53. data/lib/sass/value/color/space/rec2020.rb +69 -0
  54. data/lib/sass/value/color/space/rgb.rb +52 -0
  55. data/lib/sass/value/color/space/srgb.rb +140 -0
  56. data/lib/sass/value/color/space/srgb_linear.rb +72 -0
  57. data/lib/sass/value/color/space/utils.rb +86 -0
  58. data/lib/sass/value/color/space/xyz_d50.rb +100 -0
  59. data/lib/sass/value/color/space/xyz_d65.rb +57 -0
  60. data/lib/sass/value/color/space.rb +198 -0
  61. data/lib/sass/value/color.rb +538 -163
  62. data/lib/sass/value/function.rb +11 -16
  63. data/lib/sass/value/fuzzy_math.rb +24 -21
  64. data/lib/sass/value/list.rb +7 -7
  65. data/lib/sass/value/map.rb +6 -6
  66. data/lib/sass/value/mixin.rb +34 -0
  67. data/lib/sass/value/null.rb +1 -1
  68. data/lib/sass/value/number/unit.rb +7 -6
  69. data/lib/sass/value/number.rb +34 -26
  70. data/lib/sass/value/string.rb +9 -3
  71. data/lib/sass/value.rb +20 -16
  72. metadata +67 -103
  73. data/ext/sass/unzip.vbs +0 -13
  74. data/lib/sass/compile_error.rb +0 -28
  75. data/lib/sass/embedded/async.rb +0 -65
  76. data/lib/sass/embedded/channel.rb +0 -61
  77. data/lib/sass/embedded/compiler.rb +0 -60
  78. data/lib/sass/embedded/dispatcher.rb +0 -90
  79. data/lib/sass/embedded/host/importer_registry.rb +0 -107
  80. data/lib/sass/embedded/host/logger_registry.rb +0 -50
  81. data/lib/sass/embedded/host/value_protofier.rb +0 -241
  82. data/lib/sass/embedded/host.rb +0 -139
  83. data/lib/sass/embedded/protofier.rb +0 -78
  84. data/lib/sass/embedded/structifier.rb +0 -36
  85. data/lib/sass/script_error.rb +0 -6
@@ -0,0 +1,141 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Sass
4
+ class Compiler
5
+ class Host
6
+ # The {ImporterRegistry} class.
7
+ #
8
+ # It stores importers and handles import requests.
9
+ class ImporterRegistry
10
+ attr_reader :importers
11
+
12
+ def initialize(importers, load_paths, alert_color:)
13
+ @id = 0
14
+ @importers_by_id = {}.compare_by_identity
15
+ @importers = importers
16
+ .map { |importer| register(importer) }
17
+ .concat(
18
+ load_paths.map do |load_path|
19
+ EmbeddedProtocol::InboundMessage::CompileRequest::Importer.new(
20
+ path: File.absolute_path(load_path)
21
+ )
22
+ end
23
+ )
24
+
25
+ @highlight = alert_color
26
+ end
27
+
28
+ def register(importer)
29
+ if importer.is_a?(Sass::NodePackageImporter)
30
+ EmbeddedProtocol::InboundMessage::CompileRequest::Importer.new(
31
+ node_package_importer: EmbeddedProtocol::NodePackageImporter.new(
32
+ entry_point_directory: importer.instance_eval { @entry_point_directory }
33
+ )
34
+ )
35
+ else
36
+ importer = Structifier.to_struct(importer, :canonicalize, :load, :non_canonical_scheme, :find_file_url)
37
+
38
+ is_importer = importer.respond_to?(:canonicalize) && importer.respond_to?(:load)
39
+ is_file_importer = importer.respond_to?(:find_file_url)
40
+
41
+ raise ArgumentError, 'importer must be an Importer or a FileImporter' if is_importer == is_file_importer
42
+
43
+ id = @id
44
+ @id = id.next
45
+
46
+ @importers_by_id[id] = importer
47
+ if is_importer
48
+ EmbeddedProtocol::InboundMessage::CompileRequest::Importer.new(
49
+ importer_id: id,
50
+ non_canonical_scheme: if importer.respond_to?(:non_canonical_scheme)
51
+ non_canonical_scheme = importer.non_canonical_scheme
52
+ if non_canonical_scheme.is_a?(String)
53
+ [non_canonical_scheme]
54
+ else
55
+ non_canonical_scheme || []
56
+ end
57
+ else
58
+ []
59
+ end
60
+ )
61
+ else
62
+ EmbeddedProtocol::InboundMessage::CompileRequest::Importer.new(
63
+ file_importer_id: id
64
+ )
65
+ end
66
+ end
67
+ end
68
+
69
+ def canonicalize(canonicalize_request)
70
+ importer = @importers_by_id[canonicalize_request.importer_id]
71
+ canonicalize_context = CanonicalizeContext.new(canonicalize_request)
72
+ url = importer.canonicalize(canonicalize_request.url,
73
+ canonicalize_context)&.to_s
74
+
75
+ EmbeddedProtocol::InboundMessage::CanonicalizeResponse.new(
76
+ id: canonicalize_request.id,
77
+ url:,
78
+ containing_url_unused: canonicalize_context.instance_eval { @containing_url_unused }
79
+ )
80
+ rescue StandardError => e
81
+ EmbeddedProtocol::InboundMessage::CanonicalizeResponse.new(
82
+ id: canonicalize_request.id,
83
+ error: e.full_message(highlight: @highlight, order: :top)
84
+ )
85
+ end
86
+
87
+ def import(import_request)
88
+ importer = @importers_by_id[import_request.importer_id]
89
+ importer_result = Structifier.to_struct importer.load(import_request.url), :contents, :syntax, :source_map_url
90
+
91
+ EmbeddedProtocol::InboundMessage::ImportResponse.new(
92
+ id: import_request.id,
93
+ success: EmbeddedProtocol::InboundMessage::ImportResponse::ImportSuccess.new(
94
+ contents: importer_result.contents.to_str,
95
+ syntax: syntax_to_proto(importer_result.syntax),
96
+ source_map_url: (importer_result.source_map_url&.to_s if importer_result.respond_to?(:source_map_url))
97
+ )
98
+ )
99
+ rescue StandardError => e
100
+ EmbeddedProtocol::InboundMessage::ImportResponse.new(
101
+ id: import_request.id,
102
+ error: e.full_message(highlight: @highlight, order: :top)
103
+ )
104
+ end
105
+
106
+ def file_import(file_import_request)
107
+ importer = @importers_by_id[file_import_request.importer_id]
108
+ canonicalize_context = CanonicalizeContext.new(file_import_request)
109
+ file_url = importer.find_file_url(file_import_request.url,
110
+ canonicalize_context)&.to_s
111
+
112
+ EmbeddedProtocol::InboundMessage::FileImportResponse.new(
113
+ id: file_import_request.id,
114
+ file_url:,
115
+ containing_url_unused: canonicalize_context.instance_eval { @containing_url_unused }
116
+ )
117
+ rescue StandardError => e
118
+ EmbeddedProtocol::InboundMessage::FileImportResponse.new(
119
+ id: file_import_request.id,
120
+ error: e.full_message(highlight: @highlight, order: :top)
121
+ )
122
+ end
123
+
124
+ def syntax_to_proto(syntax)
125
+ case syntax&.to_sym
126
+ when :scss
127
+ EmbeddedProtocol::Syntax::SCSS
128
+ when :indented
129
+ EmbeddedProtocol::Syntax::INDENTED
130
+ when :css
131
+ EmbeddedProtocol::Syntax::CSS
132
+ else
133
+ raise ArgumentError, 'syntax must be one of :scss, :indented, :css'
134
+ end
135
+ end
136
+ end
137
+
138
+ private_constant :ImporterRegistry
139
+ end
140
+ end
141
+ end
@@ -0,0 +1,80 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Sass
4
+ class Compiler
5
+ class Host
6
+ # The {LoggerRegistry} class.
7
+ #
8
+ # It stores logger and handles log events.
9
+ class LoggerRegistry
10
+ def initialize(logger)
11
+ logger = Structifier.to_struct(logger, :debug, :warn)
12
+
13
+ { debug: DebugContext, warn: WarnContext }.each do |symbol, context_class|
14
+ next unless logger.respond_to?(symbol)
15
+
16
+ define_singleton_method(symbol) do |event|
17
+ logger.public_send(symbol, event.message, context_class.new(event))
18
+ end
19
+ end
20
+ end
21
+
22
+ def log(event)
23
+ case event.type
24
+ when :DEBUG
25
+ debug(event)
26
+ when :DEPRECATION_WARNING, :WARNING
27
+ warn(event)
28
+ else
29
+ raise ArgumentError, "Unknown LogEvent.type #{event.type}"
30
+ end
31
+ end
32
+
33
+ private
34
+
35
+ def debug(event)
36
+ Kernel.warn(event.formatted)
37
+ end
38
+
39
+ def warn(event)
40
+ Kernel.warn(event.formatted)
41
+ end
42
+
43
+ # Contextual information passed to `debug`.
44
+ class DebugContext
45
+ # @return [Logger::SourceSpan, nil]
46
+ attr_reader :span
47
+
48
+ def initialize(event)
49
+ @span = event.span.nil? ? nil : Logger::SourceSpan.new(event.span)
50
+ end
51
+ end
52
+
53
+ private_constant :DebugContext
54
+
55
+ # Contextual information passed to `warn`.
56
+ class WarnContext < DebugContext
57
+ # @return [Boolean]
58
+ attr_reader :deprecation
59
+
60
+ # @return [String, nil]
61
+ attr_reader :deprecation_type
62
+
63
+ # @return [String]
64
+ attr_reader :stack
65
+
66
+ def initialize(event)
67
+ super
68
+ @deprecation = event.type == :DEPRECATION_WARNING
69
+ @deprecation_type = (event.deprecation_type if @deprecation)
70
+ @stack = event.stack_trace
71
+ end
72
+ end
73
+
74
+ private_constant :WarnContext
75
+ end
76
+
77
+ private_constant :LoggerRegistry
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,360 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Sass
4
+ class Compiler
5
+ class Host
6
+ # The {Protofier} class.
7
+ #
8
+ # It converts Pure Ruby types and Protobuf Ruby types.
9
+ class Protofier
10
+ def initialize(function_registry)
11
+ @function_registry = function_registry
12
+ end
13
+
14
+ def to_proto(obj)
15
+ case obj
16
+ when Sass::Value::String
17
+ EmbeddedProtocol::Value.new(
18
+ string: EmbeddedProtocol::Value::String.new(
19
+ text: obj.text.to_str,
20
+ quoted: obj.quoted?
21
+ )
22
+ )
23
+ when Sass::Value::Number
24
+ EmbeddedProtocol::Value.new(
25
+ number: Number.to_proto(obj)
26
+ )
27
+ when Sass::Value::Color
28
+ EmbeddedProtocol::Value.new(
29
+ color: EmbeddedProtocol::Value::Color.new(
30
+ channel1: obj.send(:channel0_or_nil),
31
+ channel2: obj.send(:channel1_or_nil),
32
+ channel3: obj.send(:channel2_or_nil),
33
+ alpha: obj.send(:alpha_or_nil),
34
+ space: obj.space
35
+ )
36
+ )
37
+ when Sass::Value::ArgumentList
38
+ EmbeddedProtocol::Value.new(
39
+ argument_list: EmbeddedProtocol::Value::ArgumentList.new(
40
+ id: obj.instance_eval { @id },
41
+ contents: obj.to_a.map { |element| to_proto(element) },
42
+ keywords: obj.keywords.each_with_object({}) { |(key, value), hash| hash[key.to_s] = to_proto(value) },
43
+ separator: ListSeparator.to_proto(obj.separator)
44
+ )
45
+ )
46
+ when Sass::Value::List
47
+ EmbeddedProtocol::Value.new(
48
+ list: EmbeddedProtocol::Value::List.new(
49
+ contents: obj.to_a.map { |element| to_proto(element) },
50
+ separator: ListSeparator.to_proto(obj.separator),
51
+ has_brackets: obj.bracketed?
52
+ )
53
+ )
54
+ when Sass::Value::Map
55
+ EmbeddedProtocol::Value.new(
56
+ map: EmbeddedProtocol::Value::Map.new(
57
+ entries: obj.contents.map do |key, value|
58
+ EmbeddedProtocol::Value::Map::Entry.new(
59
+ key: to_proto(key),
60
+ value: to_proto(value)
61
+ )
62
+ end
63
+ )
64
+ )
65
+ when Sass::Value::Function
66
+ if obj.instance_eval { @id }
67
+ EmbeddedProtocol::Value.new(
68
+ compiler_function: EmbeddedProtocol::Value::CompilerFunction.new(
69
+ id: obj.instance_eval { @id }
70
+ )
71
+ )
72
+ else
73
+ EmbeddedProtocol::Value.new(
74
+ host_function: EmbeddedProtocol::Value::HostFunction.new(
75
+ id: @function_registry.register(obj.callback),
76
+ signature: obj.signature
77
+ )
78
+ )
79
+ end
80
+ when Sass::Value::Mixin
81
+ EmbeddedProtocol::Value.new(
82
+ compiler_mixin: EmbeddedProtocol::Value::CompilerMixin.new(
83
+ id: obj.instance_eval { @id }
84
+ )
85
+ )
86
+ when Sass::Value::Calculation
87
+ EmbeddedProtocol::Value.new(
88
+ calculation: Calculation.to_proto(obj)
89
+ )
90
+ when Sass::Value::Boolean
91
+ EmbeddedProtocol::Value.new(
92
+ singleton: obj.value ? :TRUE : :FALSE
93
+ )
94
+ when Sass::Value::Null
95
+ EmbeddedProtocol::Value.new(
96
+ singleton: :NULL
97
+ )
98
+ else
99
+ raise Sass::ScriptError, "Unknown Sass::Value #{obj}"
100
+ end
101
+ end
102
+
103
+ def from_proto(proto)
104
+ oneof = proto.value
105
+ obj = proto.public_send(oneof)
106
+ case oneof
107
+ when :string
108
+ Sass::Value::String.new(
109
+ obj.text,
110
+ quoted: obj.quoted
111
+ )
112
+ when :number
113
+ Number.from_proto(obj)
114
+ when :color
115
+ obj.to_s if RUBY_ENGINE == 'jruby' # TODO: https://github.com/protocolbuffers/protobuf/issues/18807
116
+ Sass::Value::Color.send(
117
+ :for_space,
118
+ obj.space,
119
+ obj.has_channel1? ? obj.channel1 : nil,
120
+ obj.has_channel2? ? obj.channel2 : nil,
121
+ obj.has_channel3? ? obj.channel3 : nil,
122
+ obj.has_alpha? ? obj.alpha : nil
123
+ )
124
+ when :argument_list
125
+ Sass::Value::ArgumentList.new(
126
+ obj.contents.map do |element|
127
+ from_proto(element)
128
+ end,
129
+ obj.keywords.to_enum.with_object({}) do |(key, value), hash|
130
+ hash[key.to_sym] = from_proto(value)
131
+ end,
132
+ ListSeparator.from_proto(obj.separator)
133
+ ).instance_eval do
134
+ @id = obj.id
135
+ self
136
+ end
137
+ when :list
138
+ Sass::Value::List.new(
139
+ obj.contents.map do |element|
140
+ from_proto(element)
141
+ end,
142
+ separator: ListSeparator.from_proto(obj.separator),
143
+ bracketed: obj.has_brackets
144
+ )
145
+ when :map
146
+ Sass::Value::Map.new(
147
+ obj.entries.to_enum.with_object({}) do |entry, hash|
148
+ hash[from_proto(entry.key)] = from_proto(entry.value)
149
+ end
150
+ )
151
+ when :compiler_function
152
+ Sass::Value::Function.new(nil).instance_eval do
153
+ @id = obj.id
154
+ self
155
+ end
156
+ when :host_function
157
+ raise Sass::ScriptError, 'The compiler may not send Value.host_function to host'
158
+ when :compiler_mixin
159
+ Sass::Value::Mixin.send(:new).instance_eval do
160
+ @id = obj.id
161
+ self
162
+ end
163
+ when :calculation
164
+ Calculation.from_proto(obj)
165
+ when :singleton
166
+ case obj
167
+ when :TRUE
168
+ Sass::Value::Boolean::TRUE
169
+ when :FALSE
170
+ Sass::Value::Boolean::FALSE
171
+ when :NULL
172
+ Sass::Value::Null::NULL
173
+ else
174
+ raise Sass::ScriptError, "Unknown Value.singleton #{obj}"
175
+ end
176
+ else
177
+ raise Sass::ScriptError, "Unknown Value.value #{obj}"
178
+ end
179
+ end
180
+
181
+ # The {Number} Protofier.
182
+ module Number
183
+ module_function
184
+
185
+ def to_proto(obj)
186
+ EmbeddedProtocol::Value::Number.new(
187
+ value: obj.value.to_f,
188
+ numerators: obj.numerator_units,
189
+ denominators: obj.denominator_units
190
+ )
191
+ end
192
+
193
+ def from_proto(obj)
194
+ Sass::Value::Number.new(
195
+ obj.value, {
196
+ numerator_units: obj.numerators.to_a,
197
+ denominator_units: obj.denominators.to_a
198
+ }
199
+ )
200
+ end
201
+ end
202
+
203
+ private_constant :Number
204
+
205
+ # The {Calculation} Protofier.
206
+ module Calculation
207
+ module_function
208
+
209
+ def to_proto(obj)
210
+ EmbeddedProtocol::Value::Calculation.new(
211
+ name: obj.name,
212
+ arguments: obj.arguments.map { |argument| CalculationValue.to_proto(argument) }
213
+ )
214
+ end
215
+
216
+ def from_proto(obj)
217
+ Sass::Value::Calculation.send(
218
+ :new,
219
+ obj.name,
220
+ obj.arguments.map { |argument| CalculationValue.from_proto(argument) }
221
+ )
222
+ end
223
+ end
224
+
225
+ private_constant :Calculation
226
+
227
+ # The {CalculationValue} Protofier.
228
+ module CalculationValue
229
+ module_function
230
+
231
+ def to_proto(value)
232
+ case value
233
+ when Sass::Value::Number
234
+ EmbeddedProtocol::Value::Calculation::CalculationValue.new(
235
+ number: Number.to_proto(value)
236
+ )
237
+ when Sass::Value::Calculation
238
+ EmbeddedProtocol::Value::Calculation::CalculationValue.new(
239
+ calculation: Calculation.to_proto(value)
240
+ )
241
+ when Sass::Value::String
242
+ EmbeddedProtocol::Value::Calculation::CalculationValue.new(
243
+ string: value.text
244
+ )
245
+ when Sass::CalculationValue::CalculationOperation
246
+ EmbeddedProtocol::Value::Calculation::CalculationValue.new(
247
+ operation: EmbeddedProtocol::Value::Calculation::CalculationOperation.new(
248
+ operator: CalculationOperator.to_proto(value.operator),
249
+ left: to_proto(value.left),
250
+ right: to_proto(value.right)
251
+ )
252
+ )
253
+ else
254
+ raise Sass::ScriptError, "Unknown CalculationValue #{value}"
255
+ end
256
+ end
257
+
258
+ def from_proto(value)
259
+ oneof = value.value
260
+ obj = value.public_send(oneof)
261
+ case oneof
262
+ when :number
263
+ Number.from_proto(obj)
264
+ when :calculation
265
+ Calculation.from_proto(obj)
266
+ when :string
267
+ Sass::Value::String.new(obj, quoted: false)
268
+ when :operation
269
+ Sass::CalculationValue::CalculationOperation.new(
270
+ CalculationOperator.from_proto(obj.operator),
271
+ from_proto(obj.left),
272
+ from_proto(obj.right)
273
+ )
274
+ else
275
+ raise Sass::ScriptError, "Unknown CalculationValue #{value}"
276
+ end
277
+ end
278
+ end
279
+
280
+ private_constant :CalculationValue
281
+
282
+ # The {CalculationOperator} Protofier.
283
+ module CalculationOperator
284
+ module_function
285
+
286
+ def to_proto(operator)
287
+ case operator
288
+ when '+'
289
+ :PLUS
290
+ when '-'
291
+ :MINUS
292
+ when '*'
293
+ :TIMES
294
+ when '/'
295
+ :DIVIDE
296
+ else
297
+ raise Sass::ScriptError, "Unknown CalculationOperator #{separator}"
298
+ end
299
+ end
300
+
301
+ def from_proto(operator)
302
+ case operator
303
+ when :PLUS
304
+ '+'
305
+ when :MINUS
306
+ '-'
307
+ when :TIMES
308
+ '*'
309
+ when :DIVIDE
310
+ '/'
311
+ else
312
+ raise Sass::ScriptError, "Unknown CalculationOperator #{separator}"
313
+ end
314
+ end
315
+ end
316
+
317
+ private_constant :CalculationOperator
318
+
319
+ # The {ListSeparator} Protofier.
320
+ module ListSeparator
321
+ module_function
322
+
323
+ def to_proto(separator)
324
+ case separator
325
+ when ','
326
+ :COMMA
327
+ when ' '
328
+ :SPACE
329
+ when '/'
330
+ :SLASH
331
+ when nil
332
+ :UNDECIDED
333
+ else
334
+ raise Sass::ScriptError, "Unknown ListSeparator #{separator}"
335
+ end
336
+ end
337
+
338
+ def from_proto(separator)
339
+ case separator
340
+ when :COMMA
341
+ ','
342
+ when :SPACE
343
+ ' '
344
+ when :SLASH
345
+ '/'
346
+ when :UNDECIDED
347
+ nil
348
+ else
349
+ raise Sass::ScriptError, "Unknown ListSeparator #{separator}"
350
+ end
351
+ end
352
+ end
353
+
354
+ private_constant :ListSeparator
355
+ end
356
+
357
+ private_constant :Protofier
358
+ end
359
+ end
360
+ end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Sass
4
+ class Compiler
5
+ class Host
6
+ # The {Structifier} module.
7
+ #
8
+ # It converts {::Hash} to {Struct}-like objects.
9
+ module Structifier
10
+ module_function
11
+
12
+ def to_struct(obj, *symbols)
13
+ return obj unless obj.is_a?(Hash)
14
+
15
+ struct = Object.new
16
+ symbols.each do |key|
17
+ next unless obj.key?(key)
18
+
19
+ value = obj[key]
20
+ if value.respond_to?(:call)
21
+ struct.define_singleton_method key do |*args, **kwargs|
22
+ value.call(*args, **kwargs)
23
+ end
24
+ else
25
+ struct.define_singleton_method key do
26
+ value
27
+ end
28
+ end
29
+ end
30
+ struct
31
+ end
32
+ end
33
+
34
+ private_constant :Structifier
35
+ end
36
+ end
37
+ end