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
Binary file
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Sass
4
+ # An exception thrown because a Sass compilation failed.
5
+ class CompileError < StandardError
6
+ # @return [String, nil]
7
+ attr_accessor :sass_stack
8
+
9
+ # @return [Logger::SourceSpan, nil]
10
+ attr_accessor :span
11
+
12
+ def initialize(message, full_message, sass_stack, span)
13
+ super(message)
14
+ @full_message = full_message == '' ? nil : full_message.dup
15
+ @sass_stack = sass_stack == '' ? nil : sass_stack
16
+ @span = span
17
+ end
18
+
19
+ # @return [String]
20
+ def full_message(*args, **kwargs)
21
+ if @full_message.nil?
22
+ super(*args, **kwargs)
23
+ else
24
+ @full_message
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Sass
4
+ # The result of compiling Sass to CSS. Returned by {Sass.compile} and {Sass.compile_string}.
5
+ #
6
+ # @see https://sass-lang.com/documentation/js-api/interfaces/CompileResult
7
+ class CompileResult
8
+ # @return [String]
9
+ attr_reader :css
10
+
11
+ # @return [String, nil]
12
+ attr_reader :source_map
13
+
14
+ # @return [Array<String>]
15
+ attr_reader :loaded_urls
16
+
17
+ def initialize(css, source_map, loaded_urls)
18
+ @css = css
19
+ @source_map = source_map == '' ? nil : source_map
20
+ @loaded_urls = loaded_urls
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,58 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Sass
4
+ class Embedded
5
+ # The {Async} class.
6
+ #
7
+ # It awaits until the promise is resolved or rejected.
8
+ class Async
9
+ module State
10
+ PENDING = 0
11
+ FULFILLED = 1
12
+ REJECTED = 2
13
+ end
14
+
15
+ private_constant :State
16
+
17
+ def initialize
18
+ @result = nil
19
+ @state = State::PENDING
20
+
21
+ @condition_variable = ConditionVariable.new
22
+ @mutex = Mutex.new
23
+ end
24
+
25
+ def resolve(value)
26
+ @mutex.synchronize do
27
+ return unless @state == State::PENDING
28
+
29
+ @result = value
30
+ @state = State::FULFILLED
31
+ @condition_variable.broadcast
32
+ end
33
+ end
34
+
35
+ def reject(reason)
36
+ @mutex.synchronize do
37
+ return unless @state == State::PENDING
38
+
39
+ @result = reason
40
+ @state = State::REJECTED
41
+ @condition_variable.broadcast
42
+ end
43
+ end
44
+
45
+ def await
46
+ @mutex.synchronize do
47
+ @condition_variable.wait(@mutex) if @state == State::PENDING
48
+
49
+ raise @result if @state == State::REJECTED
50
+
51
+ @result
52
+ end
53
+ end
54
+ end
55
+
56
+ private_constant :Async
57
+ end
58
+ end
@@ -0,0 +1,61 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Sass
4
+ class Embedded
5
+ # The {Channel} class.
6
+ #
7
+ # It establishes connection between {Host} and {Dispatcher}.
8
+ class Channel
9
+ def initialize
10
+ @dispatcher = Dispatcher.new
11
+ @mutex = Mutex.new
12
+ end
13
+
14
+ def close
15
+ @mutex.synchronize do
16
+ @dispatcher.close
17
+ end
18
+ end
19
+
20
+ def closed?
21
+ @mutex.synchronize do
22
+ @dispatcher.closed?
23
+ end
24
+ end
25
+
26
+ def connect(observer)
27
+ @mutex.synchronize do
28
+ begin
29
+ id = @dispatcher.subscribe(observer)
30
+ rescue EOFError
31
+ @dispatcher = Dispatcher.new
32
+ id = @dispatcher.subscribe(observer)
33
+ end
34
+ Connection.new(@dispatcher, id)
35
+ end
36
+ end
37
+
38
+ # The {Connection} between {Host} to {Dispatcher}.
39
+ class Connection
40
+ attr_reader :id
41
+
42
+ def initialize(dispatcher, id)
43
+ @dispatcher = dispatcher
44
+ @id = id
45
+ end
46
+
47
+ def disconnect
48
+ @dispatcher.unsubscribe(id)
49
+ end
50
+
51
+ def send_message(**kwargs)
52
+ @dispatcher.send_message(**kwargs)
53
+ end
54
+ end
55
+
56
+ private_constant :Connection
57
+ end
58
+
59
+ private_constant :Channel
60
+ end
61
+ end
@@ -0,0 +1,60 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'open3'
4
+
5
+ module Sass
6
+ class Embedded
7
+ # The {Compiler} class.
8
+ #
9
+ # It runs the `dart-sass-embedded` process.
10
+ class Compiler
11
+ def initialize
12
+ @stdin, @stdout, @stderr, @wait_thread = Open3.popen3(*COMMAND, chdir: __dir__)
13
+ @stdin.binmode
14
+ @stdout.binmode
15
+ @stdin_mutex = Mutex.new
16
+ @stdout_mutex = Mutex.new
17
+
18
+ Thread.new do
19
+ loop do
20
+ warn(@stderr.readline, uplevel: 1)
21
+ rescue IOError, Errno::EBADF
22
+ break
23
+ end
24
+ end
25
+ end
26
+
27
+ def close
28
+ @stdin_mutex.synchronize do
29
+ @stdin.close unless @stdin.closed?
30
+ @stdout.close unless @stdout.closed?
31
+ @stderr.close unless @stderr.closed?
32
+ end
33
+
34
+ @wait_thread.value
35
+ end
36
+
37
+ def closed?
38
+ @stdin_mutex.synchronize do
39
+ @stdin.closed?
40
+ end
41
+ end
42
+
43
+ def write(payload)
44
+ @stdin_mutex.synchronize do
45
+ Varint.write(@stdin, payload.length)
46
+ @stdin.write(payload)
47
+ end
48
+ end
49
+
50
+ def read
51
+ @stdout_mutex.synchronize do
52
+ length = Varint.read(@stdout)
53
+ @stdout.read(length)
54
+ end
55
+ end
56
+ end
57
+
58
+ private_constant :Compiler
59
+ end
60
+ end
@@ -0,0 +1,98 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Sass
4
+ class Embedded
5
+ # The {Dispatcher} class.
6
+ #
7
+ # It dispatches messages between mutliple instances of {Host} and a single {Compiler}.
8
+ class Dispatcher
9
+ PROTOCOL_ERROR_ID = 0xffffffff
10
+
11
+ def initialize
12
+ @compiler = Compiler.new
13
+ @observers = {}
14
+ @id = 0
15
+ @mutex = Mutex.new
16
+
17
+ Thread.new do
18
+ loop do
19
+ receive_message
20
+ rescue IOError, Errno::EBADF => e
21
+ @mutex.synchronize do
22
+ @id = PROTOCOL_ERROR_ID
23
+ @observers.values
24
+ end.each do |observer|
25
+ observer.error e
26
+ end
27
+ break
28
+ end
29
+ end
30
+ end
31
+
32
+ def subscribe(observer)
33
+ @mutex.synchronize do
34
+ raise EOFError if @id == PROTOCOL_ERROR_ID
35
+
36
+ id = @id
37
+ @id = id.next
38
+ @observers[id] = observer
39
+ id
40
+ end
41
+ end
42
+
43
+ def unsubscribe(id)
44
+ @mutex.synchronize do
45
+ @observers.delete(id)
46
+
47
+ return unless @observers.empty?
48
+
49
+ if @id == PROTOCOL_ERROR_ID
50
+ close
51
+ else
52
+ @id = 0
53
+ end
54
+ end
55
+ end
56
+
57
+ def close
58
+ @compiler.close
59
+ end
60
+
61
+ def closed?
62
+ @compiler.closed?
63
+ end
64
+
65
+ def send_message(**kwargs)
66
+ inbound_message = EmbeddedProtocol::InboundMessage.new(**kwargs)
67
+ @compiler.write(inbound_message.to_proto)
68
+ end
69
+
70
+ private
71
+
72
+ def receive_message
73
+ outbound_message = EmbeddedProtocol::OutboundMessage.decode(@compiler.read)
74
+ oneof = outbound_message.message
75
+ message = outbound_message.public_send(oneof)
76
+ case oneof
77
+ when :error
78
+ @mutex.synchronize do
79
+ @id = PROTOCOL_ERROR_ID
80
+ message.id == PROTOCOL_ERROR_ID ? @observers.values : [@observers[message.id]]
81
+ end.each do |observer|
82
+ observer.public_send(oneof, message)
83
+ end
84
+ when :compile_response, :version_response
85
+ @mutex.synchronize { @observers[message.id] }.public_send(oneof, message)
86
+ when :log_event, :canonicalize_request, :import_request, :file_import_request, :function_call_request
87
+ Thread.new(@mutex.synchronize { @observers[message.compilation_id] }) do |observer|
88
+ observer.public_send(oneof, message)
89
+ end
90
+ else
91
+ raise ArgumentError, "Unknown OutboundMessage.message #{message}"
92
+ end
93
+ end
94
+ end
95
+
96
+ private_constant :Dispatcher
97
+ end
98
+ end
@@ -0,0 +1,89 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Sass
4
+ class Embedded
5
+ class Host
6
+ # The {FunctionRegistry} class.
7
+ #
8
+ # It stores sass custom functions and handles function calls.
9
+ class FunctionRegistry
10
+ attr_reader :global_functions
11
+
12
+ def initialize(functions, alert_color:)
13
+ functions = functions.transform_keys(&:to_s)
14
+
15
+ @global_functions = functions.keys
16
+ @functions_by_name = functions.transform_keys do |signature|
17
+ index = signature.index('(')
18
+ if index
19
+ signature.slice(0, index)
20
+ else
21
+ signature
22
+ end
23
+ end
24
+
25
+ @id = 0
26
+ @functions_by_id = {}
27
+ @ids_by_function = {}
28
+
29
+ @highlight = alert_color
30
+ end
31
+
32
+ def register(function)
33
+ return if @ids_by_function.key?(function)
34
+
35
+ id = @id
36
+ @id = id.next
37
+
38
+ @ids_by_function[function] = id
39
+ @functions_by_id[id] = function
40
+
41
+ id
42
+ end
43
+
44
+ def function_call(function_call_request)
45
+ arguments = function_call_request.arguments.map do |argument|
46
+ value_protofier.from_proto(argument)
47
+ end
48
+
49
+ success = value_protofier.to_proto(get(function_call_request).call(arguments))
50
+ accessed_argument_lists = arguments
51
+ .select do |argument|
52
+ argument.is_a?(Sass::Value::ArgumentList) && argument.instance_eval do
53
+ @keywords_accessed
54
+ end
55
+ end
56
+ .map { |argument| argument.instance_eval { @id } }
57
+
58
+ EmbeddedProtocol::InboundMessage::FunctionCallResponse.new(
59
+ id: function_call_request.id,
60
+ success: success,
61
+ accessed_argument_lists: accessed_argument_lists
62
+ )
63
+ rescue StandardError => e
64
+ EmbeddedProtocol::InboundMessage::FunctionCallResponse.new(
65
+ id: function_call_request.id,
66
+ error: e.full_message(highlight: @highlight, order: :top)
67
+ )
68
+ end
69
+
70
+ private
71
+
72
+ def get(function_call_request)
73
+ case function_call_request.identifier
74
+ when :name
75
+ @functions_by_name[function_call_request.name]
76
+ when :function_id
77
+ @functions_by_id[function_call_request.function_id]
78
+ end
79
+ end
80
+
81
+ def value_protofier
82
+ @value_protofier ||= ValueProtofier.new(self)
83
+ end
84
+ end
85
+
86
+ private_constant :FunctionRegistry
87
+ end
88
+ end
89
+ end
@@ -0,0 +1,104 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Sass
4
+ class Embedded
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 = {}
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
+ importer = Structifier.to_struct(importer, :canonicalize, :load, :find_file_url)
30
+
31
+ is_importer = importer.respond_to?(:canonicalize) && importer.respond_to?(:load)
32
+ is_file_importer = importer.respond_to?(:find_file_url)
33
+
34
+ raise ArgumentError, 'importer must be an Importer or a FileImporter' if is_importer == is_file_importer
35
+
36
+ id = @id
37
+ @id = id.next
38
+
39
+ @importers_by_id[id] = importer
40
+ if is_importer
41
+ EmbeddedProtocol::InboundMessage::CompileRequest::Importer.new(
42
+ importer_id: id
43
+ )
44
+ else
45
+ EmbeddedProtocol::InboundMessage::CompileRequest::Importer.new(
46
+ file_importer_id: id
47
+ )
48
+ end
49
+ end
50
+
51
+ def canonicalize(canonicalize_request)
52
+ importer = @importers_by_id[canonicalize_request.importer_id]
53
+ url = importer.canonicalize(canonicalize_request.url, from_import: canonicalize_request.from_import)&.to_s
54
+
55
+ EmbeddedProtocol::InboundMessage::CanonicalizeResponse.new(
56
+ id: canonicalize_request.id,
57
+ url: url
58
+ )
59
+ rescue StandardError => e
60
+ EmbeddedProtocol::InboundMessage::CanonicalizeResponse.new(
61
+ id: canonicalize_request.id,
62
+ error: e.full_message(highlight: @highlight, order: :top)
63
+ )
64
+ end
65
+
66
+ def import(import_request)
67
+ importer = @importers_by_id[import_request.importer_id]
68
+ importer_result = Structifier.to_struct importer.load(import_request.url), :contents, :syntax, :source_map_url
69
+
70
+ EmbeddedProtocol::InboundMessage::ImportResponse.new(
71
+ id: import_request.id,
72
+ success: EmbeddedProtocol::InboundMessage::ImportResponse::ImportSuccess.new(
73
+ contents: importer_result.contents,
74
+ syntax: Protofier.to_proto_syntax(importer_result.syntax),
75
+ source_map_url: (importer_result.source_map_url&.to_s if importer_result.respond_to?(:source_map_url))
76
+ )
77
+ )
78
+ rescue StandardError => e
79
+ EmbeddedProtocol::InboundMessage::ImportResponse.new(
80
+ id: import_request.id,
81
+ error: e.full_message(highlight: @highlight, order: :top)
82
+ )
83
+ end
84
+
85
+ def file_import(file_import_request)
86
+ importer = @importers_by_id[file_import_request.importer_id]
87
+ file_url = importer.find_file_url(file_import_request.url, from_import: file_import_request.from_import)&.to_s
88
+
89
+ EmbeddedProtocol::InboundMessage::FileImportResponse.new(
90
+ id: file_import_request.id,
91
+ file_url: file_url
92
+ )
93
+ rescue StandardError => e
94
+ EmbeddedProtocol::InboundMessage::FileImportResponse.new(
95
+ id: file_import_request.id,
96
+ error: e.full_message(highlight: @highlight, order: :top)
97
+ )
98
+ end
99
+ end
100
+
101
+ private_constant :ImporterRegistry
102
+ end
103
+ end
104
+ end
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Sass
4
+ class Embedded
5
+ class Host
6
+ # The {LoggerRegistry} class.
7
+ #
8
+ # It stores logger and handles log events.
9
+ class LoggerRegistry
10
+ attr_reader :logger
11
+
12
+ def initialize(logger)
13
+ @logger = Structifier.to_struct(logger, :debug, :warn)
14
+ end
15
+
16
+ def log(event)
17
+ case event.type
18
+ when :DEBUG
19
+ if logger.respond_to? :debug
20
+ logger.debug(event.message,
21
+ span: Protofier.from_proto_source_span(event.span))
22
+ else
23
+ warn(event.formatted)
24
+ end
25
+ when :DEPRECATION_WARNING
26
+ if logger.respond_to? :warn
27
+ logger.warn(event.message,
28
+ deprecation: true,
29
+ span: Protofier.from_proto_source_span(event.span),
30
+ stack: event.stack_trace)
31
+ else
32
+ warn(event.formatted)
33
+ end
34
+ when :WARNING
35
+ if logger.respond_to? :warn
36
+ logger.warn(event.message,
37
+ deprecation: false,
38
+ span: Protofier.from_proto_source_span(event.span),
39
+ stack: event.stack_trace)
40
+ else
41
+ warn(event.formatted)
42
+ end
43
+ end
44
+ end
45
+ end
46
+
47
+ private_constant :LoggerRegistry
48
+ end
49
+ end
50
+ end