sass-embedded 1.69.1 → 1.69.7

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 (42) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/exe/sass +2 -2
  4. data/ext/sass/Rakefile +8 -24
  5. data/ext/sass/embedded_sass_pb.rb +1 -1
  6. data/ext/sass/package.json +1 -1
  7. data/lib/sass/calculation_value/calculation_operation.rb +2 -5
  8. data/lib/sass/calculation_value.rb +10 -4
  9. data/lib/sass/compiler/connection.rb +92 -0
  10. data/lib/sass/{embedded → compiler}/dispatcher.rb +54 -38
  11. data/lib/sass/compiler/dispatcher_manager.rb +44 -0
  12. data/lib/sass/{embedded → compiler}/host/function_registry.rb +3 -3
  13. data/lib/sass/{embedded → compiler}/host/importer_registry.rb +4 -4
  14. data/lib/sass/{embedded → compiler}/host/logger_registry.rb +1 -1
  15. data/lib/sass/compiler/host/protofier.rb +88 -0
  16. data/lib/sass/compiler/host/structifier.rb +37 -0
  17. data/lib/sass/{embedded → compiler}/host/value_protofier.rb +3 -3
  18. data/lib/sass/{embedded → compiler}/host.rb +26 -15
  19. data/lib/sass/{embedded → compiler}/varint.rb +3 -5
  20. data/lib/sass/compiler.rb +191 -0
  21. data/lib/sass/elf.rb +2 -2
  22. data/lib/sass/embedded/version.rb +2 -2
  23. data/lib/sass/embedded.rb +65 -208
  24. data/lib/sass/exception.rb +65 -0
  25. data/lib/sass/fork_tracker.rb +51 -0
  26. data/lib/sass/serializer.rb +41 -0
  27. data/lib/sass/value/argument_list.rb +2 -2
  28. data/lib/sass/value/calculation.rb +3 -1
  29. data/lib/sass/value/color.rb +6 -6
  30. data/lib/sass/value/function.rb +6 -4
  31. data/lib/sass/value/map.rb +1 -1
  32. data/lib/sass/value/number.rb +11 -11
  33. data/lib/sass/value/string.rb +5 -8
  34. data/lib/sass/value.rb +1 -9
  35. metadata +25 -23
  36. data/ext/sass/win32_api.rb +0 -133
  37. data/lib/sass/compile_error.rb +0 -31
  38. data/lib/sass/embedded/connection.rb +0 -71
  39. data/lib/sass/embedded/protofier.rb +0 -86
  40. data/lib/sass/embedded/resilient_dispatcher.rb +0 -44
  41. data/lib/sass/embedded/structifier.rb +0 -35
  42. data/lib/sass/script_error.rb +0 -10
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ae83f7f88503d1c7001b81342c7e101361ea96ce9cfa73b73269e9bfa37a6fd3
4
- data.tar.gz: 9c9b5115d21cc5a502da73d47f95d6d5bd9350fa0d4c70fabb1658beb3acec39
3
+ metadata.gz: 5ddf58c29aaacc85fb79d2f70cccf60ef11566a7dd961ce4d1b6753580e63be7
4
+ data.tar.gz: 3f94c4fc1435af31542aba4af84997a0e3628372ead2fe0e61a5eafd35270d76
5
5
  SHA512:
6
- metadata.gz: cfeb10f453f62ecf33d398659fd47e951fa3565803f2891ebc3c7beec65130c8caf8046a85c2b466c026ee442eeac2a2ff1ad534742b6f47b6756471f8f245c9
7
- data.tar.gz: 6249ad82375ba882dc5652a9db29d9a0c00f8edc57da07d9b3fec3f32cea715bdcc6a2e85baeeb4e08e16c83cea57cff3fef7c355e1532d072443379588e5d5f
6
+ metadata.gz: 91a8794f30f711b9e5f3c23e93aeff8e2849c194f1774a3125c69d06f71b5e0a195a8b8114701ee27089b7bd5b6ecd922aaaabcc3886577aab0e0c2668c2ddac
7
+ data.tar.gz: b51d8a8acd12db57a88293a9f8a4b6c0efebc8591e167ae7e3ce56dbf776d1cc0d2e64c980ceb78802356659afc142a9f6128e11e1e3264340074d0aef664acc
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Embedded Sass Host for Ruby
2
2
 
3
- [![build](https://github.com/ntkme/sass-embedded-host-ruby/actions/workflows/build.yml/badge.svg)](https://github.com/ntkme/sass-embedded-host-ruby/actions/workflows/build.yml)
3
+ [![build](https://github.com/sass-contrib/sass-embedded-host-ruby/actions/workflows/build.yml/badge.svg)](https://github.com/sass-contrib/sass-embedded-host-ruby/actions/workflows/build.yml)
4
4
  [![gem](https://badge.fury.io/rb/sass-embedded.svg)](https://rubygems.org/gems/sass-embedded)
5
5
 
6
6
  This is a Ruby library that implements the host side of the [Embedded Sass protocol](https://github.com/sass/sass/blob/HEAD/spec/embedded-protocol.md).
data/exe/sass CHANGED
@@ -7,13 +7,13 @@ module Sass
7
7
  # The `sass` command line interface
8
8
  class CLI
9
9
  begin
10
- exec(*COMMAND, *ARGV)
10
+ Kernel.exec(*COMMAND, *ARGV)
11
11
  rescue Errno::ENOENT
12
12
  require_relative '../lib/sass/elf'
13
13
 
14
14
  raise if ELF::INTERPRETER.nil?
15
15
 
16
- exec(ELF::INTERPRETER, *COMMAND, *ARGV)
16
+ Kernel.exec(ELF::INTERPRETER, *COMMAND, *ARGV)
17
17
  end
18
18
  end
19
19
 
data/ext/sass/Rakefile CHANGED
@@ -41,12 +41,12 @@ file 'cli.rb' => %w[dart-sass] do |t|
41
41
 
42
42
  command = if File.exist?(runtime) && File.exist?(snapshot)
43
43
  "
44
- File.absolute_path('#{runtime}', __dir__),
45
- File.absolute_path('#{snapshot}', __dir__)
44
+ File.absolute_path('#{runtime}', __dir__).freeze,
45
+ File.absolute_path('#{snapshot}', __dir__).freeze
46
46
  "
47
47
  else
48
48
  "
49
- File.absolute_path('#{exe}', __dir__)
49
+ File.absolute_path('#{exe}', __dir__).freeze
50
50
  "
51
51
  end
52
52
 
@@ -164,7 +164,7 @@ module FileUtils
164
164
  cp source_path, dest_path
165
165
  else
166
166
  fetcher = Gem::RemoteFetcher.fetcher
167
- symbol = "fetch_#{scheme}".to_sym
167
+ symbol = :"fetch_#{scheme}"
168
168
  raise ArgumentError, "Unsupported URI scheme #{scheme}" unless fetcher.respond_to?(symbol)
169
169
 
170
170
  if Rake::FileUtilsExt.verbose_flag
@@ -207,10 +207,10 @@ module FileUtils
207
207
  raise if spec.nil? || source.nil?
208
208
 
209
209
  if Rake::FileUtilsExt.nowrite_flag
210
- installer = Gem::Installer.for_spec(spec, { force: true, install_dir: install_dir })
210
+ installer = Gem::Installer.for_spec(spec, { force: true, install_dir: })
211
211
  else
212
212
  path = source.download(spec, install_dir)
213
- installer = Gem::Installer.at(path, { force: true, install_dir: install_dir })
213
+ installer = Gem::Installer.at(path, { force: true, install_dir: })
214
214
  installer.install
215
215
  end
216
216
 
@@ -251,27 +251,13 @@ module SassConfig
251
251
  'arm'
252
252
  when /ppc64le|powerpc64le/
253
253
  'powerpc64le'
254
- when /s390x/
255
- 's390x'
256
254
  else
257
255
  RbConfig::CONFIG['host_cpu']
258
256
  end
259
257
 
260
258
  ARCH = "#{CPU}-#{OS}".freeze
261
259
 
262
- EMULATION = if ARCH == 'aarch64-windows'
263
- begin
264
- require_relative 'win32_api'
265
-
266
- if Win32API.x64?
267
- 'x86_64'
268
- elsif Win32API.x86?
269
- 'i386'
270
- end
271
- rescue LoadError
272
- 'i386'
273
- end
274
- end
260
+ EMULATION = ('x86_64' if ARCH == 'aarch64-windows')
275
261
  end
276
262
 
277
263
  private_constant :Platform
@@ -299,11 +285,9 @@ module SassConfig
299
285
  when 'linux'
300
286
  'linux'
301
287
  when 'linux-android'
302
- repo = 'https://github.com/dart-android/dart-sass'
303
288
  'android'
304
289
  when 'linux-musl'
305
- repo = 'https://github.com/dart-musl/dart-sass'
306
- 'linux'
290
+ 'linux-musl'
307
291
  when 'windows'
308
292
  'windows'
309
293
  else
@@ -11,7 +11,7 @@ pool = Google::Protobuf::DescriptorPool.generated_pool
11
11
 
12
12
  begin
13
13
  pool.add_serialized_file(descriptor_data)
14
- rescue TypeError => e
14
+ rescue TypeError
15
15
  # Compatibility code: will be removed in the next major version.
16
16
  require 'google/protobuf/descriptor_pb'
17
17
  parsed = Google::Protobuf::FileDescriptorProto.decode(descriptor_data)
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "dependencies": {
3
- "sass": "1.69.1"
3
+ "sass": "1.69.7"
4
4
  }
5
5
  }
@@ -18,12 +18,9 @@ module Sass
18
18
  def initialize(operator, left, right)
19
19
  raise Sass::ScriptError, "Invalid operator: #{operator}" unless OPERATORS.include?(operator)
20
20
 
21
- left.assert_calculation_value
22
- right.assert_calculation_value
23
-
24
21
  @operator = operator.freeze
25
- @left = left.freeze
26
- @right = right.freeze
22
+ @left = assert_calculation_value(left, 'left')
23
+ @right = assert_calculation_value(right, 'right')
27
24
  end
28
25
 
29
26
  # @return [::String]
@@ -5,10 +5,16 @@ module Sass
5
5
  #
6
6
  # @see https://sass-lang.com/documentation/js-api/types/calculationvalue/
7
7
  module CalculationValue
8
- # @return [CalculationValue]
9
- # @raise [ScriptError]
10
- def assert_calculation_value(_name = nil)
11
- self
8
+ private
9
+
10
+ def assert_calculation_value(value, name = nil)
11
+ if !value.is_a?(Sass::CalculationValue) || (value.is_a?(Sass::Value::String) && value.quoted?)
12
+ raise Sass::ScriptError.new(
13
+ "#{value} must be one of SassNumber, unquoted SassString, SassCalculation, CalculationOperation", name
14
+ )
15
+ end
16
+
17
+ value
12
18
  end
13
19
  end
14
20
  end
@@ -0,0 +1,92 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'open3'
4
+
5
+ require_relative '../../../ext/sass/cli'
6
+
7
+ module Sass
8
+ class Compiler
9
+ # The stdio based {Connection} between the {Dispatcher} and the compiler.
10
+ #
11
+ # It runs the `sass --embedded` command.
12
+ class Connection
13
+ def initialize(dispatcher)
14
+ @mutex = Mutex.new
15
+ @stdin, @stdout, @stderr, @wait_thread = begin
16
+ Open3.popen3(*CLI::COMMAND, '--embedded', chdir: __dir__)
17
+ rescue Errno::ENOENT
18
+ require_relative '../elf'
19
+
20
+ raise if ELF::INTERPRETER.nil?
21
+
22
+ Open3.popen3(ELF::INTERPRETER, *CLI::COMMAND, '--embedded', chdir: __dir__)
23
+ end
24
+
25
+ @stdin.binmode
26
+
27
+ Thread.new do
28
+ Thread.current.name = "sass-embedded-process-stdout-poller-#{@wait_thread.pid}"
29
+
30
+ # # https://dart.dev/tools/dart-devtools
31
+ # if 'dart' == File.basename(CLI::COMMAND.first, '.exe') && CLI::COMMAND.include?('--observe')
32
+ # Kernel.warn(@stdout.readline, uplevel: 0)
33
+ # Kernel.warn(@stdout.readline, uplevel: 0)
34
+ # end
35
+
36
+ @stdout.binmode
37
+
38
+ loop do
39
+ length = Varint.read(@stdout)
40
+ id = Varint.read(@stdout)
41
+ proto = @stdout.read(length - Varint.length(id))
42
+ dispatcher.receive_proto(id, proto)
43
+ end
44
+ rescue IOError, Errno::EBADF, Errno::EPROTO => e
45
+ dispatcher.error(e)
46
+ @mutex.synchronize do
47
+ @stdout.close
48
+ end
49
+ end
50
+
51
+ Thread.new do
52
+ Thread.current.name = "sass-embedded-process-stderr-poller-#{@wait_thread.pid}"
53
+ loop do
54
+ Kernel.warn(@stderr.readline, uplevel: 0)
55
+ end
56
+ rescue IOError, Errno::EBADF
57
+ @mutex.synchronize do
58
+ @stderr.close
59
+ end
60
+ end
61
+
62
+ @wait_thread.name = "sass-embedded-process-waiter-#{@wait_thread.pid}"
63
+ end
64
+
65
+ def close
66
+ @mutex.synchronize do
67
+ @stdin.close
68
+ @wait_thread.join
69
+ @stdout.close
70
+ @stderr.close
71
+ end
72
+ end
73
+
74
+ def closed?
75
+ @mutex.synchronize do
76
+ @stdin.closed? && !@wait_thread.alive?
77
+ end
78
+ end
79
+
80
+ def write(id, proto)
81
+ buffer = []
82
+ Varint.write(buffer, Varint.length(id) + proto.length)
83
+ Varint.write(buffer, id)
84
+ @mutex.synchronize do
85
+ @stdin.write(buffer.pack('C*'), proto)
86
+ end
87
+ end
88
+ end
89
+
90
+ private_constant :Connection
91
+ end
92
+ end
@@ -1,38 +1,22 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Sass
4
- class Embedded
4
+ class Compiler
5
5
  # The {Dispatcher} class.
6
6
  #
7
7
  # It dispatches messages between mutliple instances of {Host} and a single {Connection} to the compiler.
8
8
  class Dispatcher
9
- UINT_MAX = 0xffffffff
10
-
11
9
  def initialize
12
- @connection = Connection.new
13
- @observers = {}
14
10
  @id = 1
11
+ @observers = {}
15
12
  @mutex = Mutex.new
16
-
17
- Thread.new do
18
- loop do
19
- receive_proto
20
- rescue IOError, Errno::EBADF, Errno::EPROTO => e
21
- values = @mutex.synchronize do
22
- @id = UINT_MAX
23
- @observers.values
24
- end
25
- values.each do |observer|
26
- observer.error(e)
27
- end
28
- break
29
- end
30
- end
13
+ @connection = Connection.new(self)
14
+ ForkTracker.add(self)
31
15
  end
32
16
 
33
17
  def subscribe(observer)
34
18
  @mutex.synchronize do
35
- raise Errno::EBUSY if @id == UINT_MAX
19
+ raise Errno::EBUSY if _closed?
36
20
 
37
21
  id = @id
38
22
  @id = id.next
@@ -47,12 +31,12 @@ module Sass
47
31
 
48
32
  return unless @observers.empty?
49
33
 
50
- if @id == UINT_MAX
34
+ if _closed?
51
35
  Thread.new do
52
36
  close
53
37
  end
54
38
  else
55
- @id = 1
39
+ _idle
56
40
  end
57
41
  end
58
42
  end
@@ -62,36 +46,42 @@ module Sass
62
46
  end
63
47
 
64
48
  def close
49
+ @mutex.synchronize do
50
+ _close
51
+ end
65
52
  @connection.close
53
+ ForkTracker.delete(self)
66
54
  end
67
55
 
68
56
  def closed?
69
57
  @connection.closed?
70
58
  end
71
59
 
72
- def error
73
- @mutex.synchronize do
74
- @id = UINT_MAX
60
+ def error(error)
61
+ observers = @mutex.synchronize do
62
+ _close
63
+ @observers.values
75
64
  end
76
- end
77
65
 
78
- def send_proto(...)
79
- @connection.write(...)
66
+ if observers.empty?
67
+ close
68
+ else
69
+ observers.each do |observer|
70
+ observer.error(error)
71
+ end
72
+ end
80
73
  end
81
74
 
82
- private
83
-
84
- def receive_proto
85
- id, proto = @connection.read
75
+ def receive_proto(id, proto)
86
76
  case id
87
- when 1...UINT_MAX
88
- @mutex.synchronize { @observers[id] }.receive_proto(proto)
77
+ when 1...0xffffffff
78
+ @mutex.synchronize { @observers[id] }&.receive_proto(proto)
89
79
  when 0
90
80
  outbound_message = EmbeddedProtocol::OutboundMessage.decode(proto)
91
81
  oneof = outbound_message.message
92
82
  message = outbound_message.public_send(oneof)
93
- @mutex.synchronize { @observers[message.id] }.public_send(oneof, message)
94
- when UINT_MAX
83
+ @mutex.synchronize { @observers[message.id] }&.public_send(oneof, message)
84
+ when 0xffffffff
95
85
  outbound_message = EmbeddedProtocol::OutboundMessage.decode(proto)
96
86
  oneof = outbound_message.message
97
87
  message = outbound_message.public_send(oneof)
@@ -101,6 +91,28 @@ module Sass
101
91
  end
102
92
  end
103
93
 
94
+ def send_proto(...)
95
+ @connection.write(...)
96
+ end
97
+
98
+ private
99
+
100
+ def _close
101
+ @id = 0xffffffff
102
+ end
103
+
104
+ def _closed?
105
+ @id == 0xffffffff
106
+ end
107
+
108
+ def _idle
109
+ @id = 1
110
+ end
111
+
112
+ def _idle?
113
+ @id == 1
114
+ end
115
+
104
116
  # The {Channel} between {Dispatcher} and {Host}.
105
117
  class Channel
106
118
  attr_reader :id
@@ -111,7 +123,11 @@ module Sass
111
123
  end
112
124
 
113
125
  def disconnect
114
- @dispatcher.unsubscribe(id)
126
+ @dispatcher.unsubscribe(@id)
127
+ end
128
+
129
+ def error(...)
130
+ @dispatcher.error(...)
115
131
  end
116
132
 
117
133
  def send_proto(...)
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Sass
4
+ class Compiler
5
+ # The {DispatcherManager} class.
6
+ #
7
+ # It manages the lifecycle of {Dispatcher}.
8
+ class DispatcherManager
9
+ def initialize(dispatcher_class)
10
+ @dispatcher_class = dispatcher_class
11
+ @dispatcher = @dispatcher_class.new
12
+ @mutex = Mutex.new
13
+ end
14
+
15
+ def close
16
+ @mutex.synchronize do
17
+ unless @dispatcher.nil?
18
+ @dispatcher.close
19
+ @dispatcher = nil
20
+ end
21
+ end
22
+ end
23
+
24
+ def closed?
25
+ @mutex.synchronize do
26
+ @dispatcher.nil?
27
+ end
28
+ end
29
+
30
+ def connect(...)
31
+ @mutex.synchronize do
32
+ raise IOError, 'closed compiler' if @dispatcher.nil?
33
+
34
+ @dispatcher.connect(...)
35
+ rescue Errno::EBUSY
36
+ @dispatcher = @dispatcher_class.new
37
+ @dispatcher.connect(...)
38
+ end
39
+ end
40
+ end
41
+
42
+ private_constant :DispatcherManager
43
+ end
44
+ end
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Sass
4
- class Embedded
4
+ class Compiler
5
5
  class Host
6
6
  # The {FunctionRegistry} class.
7
7
  #
@@ -55,8 +55,8 @@ module Sass
55
55
 
56
56
  EmbeddedProtocol::InboundMessage::FunctionCallResponse.new(
57
57
  id: function_call_request.id,
58
- success: success,
59
- accessed_argument_lists: accessed_argument_lists
58
+ success:,
59
+ accessed_argument_lists:
60
60
  )
61
61
  rescue StandardError => e
62
62
  EmbeddedProtocol::InboundMessage::FunctionCallResponse.new(
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Sass
4
- class Embedded
4
+ class Compiler
5
5
  class Host
6
6
  # The {ImporterRegistry} class.
7
7
  #
@@ -65,7 +65,7 @@ module Sass
65
65
 
66
66
  EmbeddedProtocol::InboundMessage::CanonicalizeResponse.new(
67
67
  id: canonicalize_request.id,
68
- url: url
68
+ url:
69
69
  )
70
70
  rescue StandardError => e
71
71
  EmbeddedProtocol::InboundMessage::CanonicalizeResponse.new(
@@ -81,7 +81,7 @@ module Sass
81
81
  EmbeddedProtocol::InboundMessage::ImportResponse.new(
82
82
  id: import_request.id,
83
83
  success: EmbeddedProtocol::InboundMessage::ImportResponse::ImportSuccess.new(
84
- contents: importer_result.contents,
84
+ contents: importer_result.contents.to_str,
85
85
  syntax: Protofier.to_proto_syntax(importer_result.syntax),
86
86
  source_map_url: (importer_result.source_map_url&.to_s if importer_result.respond_to?(:source_map_url))
87
87
  )
@@ -100,7 +100,7 @@ module Sass
100
100
 
101
101
  EmbeddedProtocol::InboundMessage::FileImportResponse.new(
102
102
  id: file_import_request.id,
103
- file_url: file_url
103
+ file_url:
104
104
  )
105
105
  rescue StandardError => e
106
106
  EmbeddedProtocol::InboundMessage::FileImportResponse.new(
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Sass
4
- class Embedded
4
+ class Compiler
5
5
  class Host
6
6
  # The {LoggerRegistry} class.
7
7
  #
@@ -0,0 +1,88 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Sass
4
+ class Compiler
5
+ class Host
6
+ # The {Protofier} module.
7
+ #
8
+ # It converts Pure Ruby types and Protobuf Ruby types.
9
+ module Protofier
10
+ module_function
11
+
12
+ def from_proto_canonicalize_context(canonicalize_request)
13
+ CanonicalizeContext.new(
14
+ canonicalize_request.containing_url == '' ? nil : canonicalize_request.containing_url,
15
+ canonicalize_request.from_import
16
+ )
17
+ end
18
+
19
+ def from_proto_compile_response(compile_response)
20
+ oneof = compile_response.result
21
+ result = compile_response.public_send(oneof)
22
+ case oneof
23
+ when :failure
24
+ raise CompileError.new(
25
+ result.message,
26
+ result.formatted == '' ? nil : result.formatted,
27
+ result.stack_trace == '' ? nil : result.stack_trace,
28
+ from_proto_source_span(result.span),
29
+ compile_response.loaded_urls
30
+ )
31
+ when :success
32
+ CompileResult.new(
33
+ result.css,
34
+ result.source_map == '' ? nil : result.source_map,
35
+ compile_response.loaded_urls
36
+ )
37
+ else
38
+ raise ArgumentError, "Unknown CompileResponse.result #{result}"
39
+ end
40
+ end
41
+
42
+ def from_proto_source_span(source_span)
43
+ return if source_span.nil?
44
+
45
+ Logger::SourceSpan.new(from_proto_source_location(source_span.start),
46
+ from_proto_source_location(source_span.end),
47
+ source_span.text,
48
+ source_span.url == '' ? nil : source_span.url,
49
+ source_span.context == '' ? nil : source_span.context)
50
+ end
51
+
52
+ def from_proto_source_location(source_location)
53
+ return if source_location.nil?
54
+
55
+ Logger::SourceLocation.new(source_location.offset,
56
+ source_location.line,
57
+ source_location.column)
58
+ end
59
+
60
+ def to_proto_syntax(syntax)
61
+ case syntax&.to_sym
62
+ when :scss
63
+ EmbeddedProtocol::Syntax::SCSS
64
+ when :indented
65
+ EmbeddedProtocol::Syntax::INDENTED
66
+ when :css
67
+ EmbeddedProtocol::Syntax::CSS
68
+ else
69
+ raise ArgumentError, 'syntax must be one of :scss, :indented, :css'
70
+ end
71
+ end
72
+
73
+ def to_proto_output_style(style)
74
+ case style&.to_sym
75
+ when :expanded
76
+ EmbeddedProtocol::OutputStyle::EXPANDED
77
+ when :compressed
78
+ EmbeddedProtocol::OutputStyle::COMPRESSED
79
+ else
80
+ raise ArgumentError, 'style must be one of :expanded, :compressed'
81
+ end
82
+ end
83
+ end
84
+
85
+ private_constant :Protofier
86
+ end
87
+ end
88
+ 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
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Sass
4
- class Embedded
4
+ class Compiler
5
5
  class Host
6
6
  # The {ValueProtofier} class.
7
7
  #
@@ -16,7 +16,7 @@ module Sass
16
16
  when Sass::Value::String
17
17
  EmbeddedProtocol::Value.new(
18
18
  string: EmbeddedProtocol::Value::String.new(
19
- text: obj.text,
19
+ text: obj.text.to_str,
20
20
  quoted: obj.quoted?
21
21
  )
22
22
  )
@@ -179,7 +179,7 @@ module Sass
179
179
  end
180
180
  )
181
181
  when :compiler_function
182
- Sass::Value::Function.new(nil, nil).instance_eval do
182
+ Sass::Value::Function.new(nil).instance_eval do
183
183
  @id = obj.id
184
184
  self
185
185
  end