sass-embedded 1.6.2 → 1.83.1

Sign up to get free protection for your applications and to get access to all the features.
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