sass-embedded 0.7.27 → 0.8.2

Sign up to get free protection for your applications and to get access to all the features.
data/lib/sass/compile.rb DELETED
@@ -1,249 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Sass
4
- # The {Observer} for {Embedded#render}.
5
- class CompileContext
6
- include Observer
7
-
8
- def initialize(transport, id,
9
- data:,
10
- file:,
11
- indented_syntax:,
12
- include_paths:,
13
- output_style:,
14
- source_map:,
15
- out_file:,
16
- functions:,
17
- importer:)
18
- raise ArgumentError, 'either data or file must be set' if file.nil? && data.nil?
19
-
20
- @id = id
21
- @data = data
22
- @file = file
23
- @indented_syntax = indented_syntax
24
- @include_paths = include_paths
25
- @output_style = output_style
26
- @source_map = source_map
27
- @out_file = out_file
28
- @global_functions = functions.keys
29
- @functions = functions.transform_keys do |key|
30
- key.to_s.split('(')[0].chomp
31
- end
32
- @importer = importer
33
- @import_responses = {}
34
-
35
- super(transport)
36
-
37
- send_message compile_request
38
- end
39
-
40
- def update(error, message)
41
- raise error unless error.nil?
42
-
43
- case message
44
- when EmbeddedProtocol::OutboundMessage::CompileResponse
45
- return unless message.id == @id
46
-
47
- Thread.new do
48
- super(nil, message)
49
- end
50
- when EmbeddedProtocol::OutboundMessage::LogEvent
51
- return unless message.compilation_id == @id && $stderr.tty?
52
-
53
- warn message.formatted
54
- when EmbeddedProtocol::OutboundMessage::CanonicalizeRequest
55
- return unless message.compilation_id == @id
56
-
57
- Thread.new do
58
- send_message canonicalize_response message
59
- end
60
- when EmbeddedProtocol::OutboundMessage::ImportRequest
61
- return unless message.compilation_id == @id
62
-
63
- Thread.new do
64
- send_message import_response message
65
- end
66
- when EmbeddedProtocol::OutboundMessage::FileImportRequest
67
- raise NotImplementedError, 'FileImportRequest is not implemented'
68
- when EmbeddedProtocol::OutboundMessage::FunctionCallRequest
69
- return unless message.compilation_id == @id
70
-
71
- Thread.new do
72
- send_message function_call_response message
73
- end
74
- end
75
- rescue StandardError => e
76
- Thread.new do
77
- super(e, nil)
78
- end
79
- end
80
-
81
- private
82
-
83
- def compile_request
84
- EmbeddedProtocol::InboundMessage::CompileRequest.new(
85
- id: @id,
86
- string: string,
87
- path: path,
88
- style: style,
89
- source_map: source_map,
90
- importers: importers,
91
- global_functions: global_functions,
92
- alert_color: $stderr.tty?,
93
- alert_ascii: Platform::OS == 'windows'
94
- )
95
- end
96
-
97
- def canonicalize_response(canonicalize_request)
98
- url = Util.file_uri_from_path(File.absolute_path(canonicalize_request.url, (@file.nil? ? 'stdin' : @file)))
99
-
100
- begin
101
- result = @importer[canonicalize_request.importer_id].call canonicalize_request.url, @file
102
- raise result if result.is_a? StandardError
103
- rescue StandardError => e
104
- return EmbeddedProtocol::InboundMessage::CanonicalizeResponse.new(
105
- id: canonicalize_request.id,
106
- error: e.message
107
- )
108
- end
109
-
110
- if result&.key? :contents
111
- @import_responses[url] = EmbeddedProtocol::InboundMessage::ImportResponse.new(
112
- id: canonicalize_request.id,
113
- success: EmbeddedProtocol::InboundMessage::ImportResponse::ImportSuccess.new(
114
- contents: result[:contents],
115
- syntax: EmbeddedProtocol::Syntax::SCSS,
116
- source_map_url: nil
117
- )
118
- )
119
- EmbeddedProtocol::InboundMessage::CanonicalizeResponse.new(
120
- id: canonicalize_request.id,
121
- url: url
122
- )
123
- elsif result&.key? :file
124
- canonicalized_url = Util.file_uri_from_path(File.absolute_path(result[:file]))
125
-
126
- # TODO: FileImportRequest is not supported yet.
127
- # Workaround by reading contents and return it when server asks
128
- @import_responses[canonicalized_url] = EmbeddedProtocol::InboundMessage::ImportResponse.new(
129
- id: canonicalize_request.id,
130
- success: EmbeddedProtocol::InboundMessage::ImportResponse::ImportSuccess.new(
131
- contents: File.read(result[:file]),
132
- syntax: EmbeddedProtocol::Syntax::SCSS,
133
- source_map_url: nil
134
- )
135
- )
136
-
137
- EmbeddedProtocol::InboundMessage::CanonicalizeResponse.new(
138
- id: canonicalize_request.id,
139
- url: canonicalized_url
140
- )
141
- else
142
- EmbeddedProtocol::InboundMessage::CanonicalizeResponse.new(
143
- id: canonicalize_request.id
144
- )
145
- end
146
- end
147
-
148
- def import_response(import_request)
149
- url = import_request.url
150
-
151
- if @import_responses.key? url
152
- @import_responses[url].id = import_request.id
153
- else
154
- @import_responses[url] = EmbeddedProtocol::InboundMessage::ImportResponse.new(
155
- id: import_request.id,
156
- error: "Failed to import: #{url}"
157
- )
158
- end
159
-
160
- @import_responses[url]
161
- end
162
-
163
- def function_call_response(function_call_request)
164
- # TODO: convert argument_list to **kwargs
165
- EmbeddedProtocol::InboundMessage::FunctionCallResponse.new(
166
- id: function_call_request.id,
167
- success: @functions[function_call_request.name].call(*function_call_request.arguments),
168
- accessed_argument_lists: function_call_request.arguments
169
- .filter { |argument| argument.value == :argument_list }
170
- .map { |argument| argument.argument_list.id }
171
- )
172
- rescue StandardError => e
173
- EmbeddedProtocol::InboundMessage::FunctionCallResponse.new(
174
- id: function_call_request.id,
175
- error: e.message
176
- )
177
- end
178
-
179
- def syntax
180
- if @indented_syntax == true
181
- EmbeddedProtocol::Syntax::INDENTED
182
- else
183
- EmbeddedProtocol::Syntax::SCSS
184
- end
185
- end
186
-
187
- def url
188
- return if @file.nil?
189
-
190
- Util.file_uri_from_path File.absolute_path @file
191
- end
192
-
193
- def string
194
- return if @data.nil?
195
-
196
- EmbeddedProtocol::InboundMessage::CompileRequest::StringInput.new(
197
- source: @data,
198
- url: url,
199
- syntax: syntax
200
- )
201
- end
202
-
203
- def path
204
- @file if @data.nil?
205
- end
206
-
207
- def style
208
- case @output_style&.to_sym
209
- when :expanded
210
- EmbeddedProtocol::OutputStyle::EXPANDED
211
- when :compressed
212
- EmbeddedProtocol::OutputStyle::COMPRESSED
213
- else
214
- raise ArgumentError, 'output_style must be one of :expanded, :compressed'
215
- end
216
- end
217
-
218
- def source_map
219
- @source_map.is_a?(String) || (@source_map == true && !@out_file.nil?)
220
- end
221
-
222
- attr_reader :global_functions
223
-
224
- # Order
225
- # 1. Loading a file relative to the file in which the @use or @import appeared.
226
- # 2. Each custom importer.
227
- # 3. Loading a file relative to the current working directory.
228
- # 4. Each load path in includePaths
229
- # 5. Each load path specified in the SASS_PATH environment variable, which should
230
- # be semicolon-separated on Windows and colon-separated elsewhere.
231
- def importers
232
- custom_importers = @importer.map.with_index do |_, id|
233
- EmbeddedProtocol::InboundMessage::CompileRequest::Importer.new(
234
- importer_id: id
235
- )
236
- end
237
-
238
- include_path_importers = @include_paths
239
- .concat(Sass.include_paths)
240
- .map do |include_path|
241
- EmbeddedProtocol::InboundMessage::CompileRequest::Importer.new(
242
- path: File.absolute_path(include_path)
243
- )
244
- end
245
-
246
- custom_importers.concat include_path_importers
247
- end
248
- end
249
- end
data/lib/sass/error.rb DELETED
@@ -1,27 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Sass
4
- class Error < StandardError; end
5
-
6
- class ProtocolError < Error; end
7
-
8
- # The {Error} raised by {Embedded#render}.
9
- class RenderError < Error
10
- attr_reader :formatted, :file, :line, :column, :status
11
-
12
- def initialize(message, formatted, file, line, column, status)
13
- super(message)
14
- @formatted = formatted
15
- @file = file
16
- @line = line
17
- @column = column
18
- @status = status
19
- end
20
-
21
- def backtrace
22
- return nil if super.nil?
23
-
24
- ["#{@file}:#{@line}:#{@column}"] + super
25
- end
26
- end
27
- end
data/lib/sass/info.rb DELETED
@@ -1,33 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Sass
4
- # The {Observer} for {Embedded#info}.
5
- class VersionContext
6
- include Observer
7
-
8
- def initialize(transport, id)
9
- @id = id
10
-
11
- super(transport)
12
-
13
- send_message EmbeddedProtocol::InboundMessage::VersionRequest.new(id: @id)
14
- end
15
-
16
- def update(error, message)
17
- raise error unless error.nil?
18
-
19
- case message
20
- when EmbeddedProtocol::OutboundMessage::VersionResponse
21
- return unless message.id == @id
22
-
23
- Thread.new do
24
- super(nil, message)
25
- end
26
- end
27
- rescue StandardError => e
28
- Thread.new do
29
- super(e, nil)
30
- end
31
- end
32
- end
33
- end
data/lib/sass/observer.rb DELETED
@@ -1,40 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Sass
4
- # The {Observer} module for receiving messages from {Transport}.
5
- module Observer
6
- def initialize(transport)
7
- @transport = transport
8
- @mutex = Mutex.new
9
- @condition_variable = ConditionVariable.new
10
- @error = nil
11
- @message = nil
12
- @transport.add_observer self
13
- end
14
-
15
- def receive_message
16
- @mutex.synchronize do
17
- @condition_variable.wait(@mutex) if @error.nil? && @message.nil?
18
- end
19
-
20
- raise @error unless @error.nil?
21
-
22
- @message
23
- end
24
-
25
- def update(error, message)
26
- @transport.delete_observer self
27
- @mutex.synchronize do
28
- @error = error
29
- @message = message
30
- @condition_variable.broadcast
31
- end
32
- end
33
-
34
- private
35
-
36
- def send_message(message)
37
- @transport.send_message(message)
38
- end
39
- end
40
- end
data/lib/sass/platform.rb DELETED
@@ -1,53 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Sass
4
- module Platform
5
- OS = case RbConfig::CONFIG['host_os'].downcase
6
- when /linux/
7
- 'linux'
8
- when /darwin/
9
- 'darwin'
10
- when /freebsd/
11
- 'freebsd'
12
- when /netbsd/
13
- 'netbsd'
14
- when /openbsd/
15
- 'openbsd'
16
- when /dragonfly/
17
- 'dragonflybsd'
18
- when /sunos|solaris/
19
- 'solaris'
20
- when /mingw|mswin/
21
- 'windows'
22
- else
23
- RbConfig::CONFIG['host_os'].downcase
24
- end
25
-
26
- OSVERSION = RbConfig::CONFIG['host_os'].gsub(/[^\d]/, '').to_i
27
-
28
- CPU = RbConfig::CONFIG['host_cpu']
29
-
30
- ARCH = case CPU.downcase
31
- when /amd64|x86_64|x64/
32
- 'x86_64'
33
- when /i\d86|x86|i86pc/
34
- 'i386'
35
- when /ppc64|powerpc64/
36
- 'powerpc64'
37
- when /ppc|powerpc/
38
- 'powerpc'
39
- when /sparcv9|sparc64/
40
- 'sparcv9'
41
- when /arm64|aarch64/ # MacOS calls it "arm64", other operating systems "aarch64"
42
- 'aarch64'
43
- when /^arm/
44
- if OS == 'darwin' # Ruby before 3.0 reports "arm" instead of "arm64" as host_cpu on darwin
45
- 'aarch64'
46
- else
47
- 'arm'
48
- end
49
- else
50
- RbConfig::CONFIG['host_cpu']
51
- end
52
- end
53
- end
data/lib/sass/result.rb DELETED
@@ -1,30 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Sass
4
- # The {RenderResult} of {Embedded#render}.
5
- class RenderResult
6
- include Struct
7
-
8
- attr_reader :css, :map, :stats
9
-
10
- def initialize(css, map, stats)
11
- @css = css
12
- @map = map
13
- @stats = stats
14
- end
15
- end
16
-
17
- # The {RenderResultStats} of {Embedded#render}.
18
- class RenderResultStats
19
- include Struct
20
-
21
- attr_reader :entry, :start, :end, :duration
22
-
23
- def initialize(entry, start, finish, duration)
24
- @entry = entry
25
- @start = start
26
- @end = finish
27
- @duration = duration
28
- end
29
- end
30
- end
data/lib/sass/struct.rb DELETED
@@ -1,20 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Sass
4
- # The {Struct} module.
5
- module Struct
6
- def [](key)
7
- instance_variable_get("@#{key}".to_sym)
8
- end
9
-
10
- def to_h
11
- instance_variables.map do |variable|
12
- [variable[1..].to_sym, instance_variable_get(variable)]
13
- end.to_h
14
- end
15
-
16
- def to_s
17
- to_h.to_s
18
- end
19
- end
20
- end
@@ -1,133 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'open3'
4
- require 'observer'
5
- require_relative '../../ext/sass/embedded_sass_pb'
6
-
7
- module Sass
8
- # The {::Observable} {Transport} for low level communication with
9
- # `dart-sass-embedded` using protocol buffers via stdio. Received messages
10
- # can be observed by an {Observer}.
11
- class Transport
12
- include Observable
13
-
14
- DART_SASS_EMBEDDED = File.absolute_path(
15
- "../../ext/sass/sass_embedded/dart-sass-embedded#{Platform::OS == 'windows' ? '.bat' : ''}", __dir__
16
- )
17
-
18
- PROTOCOL_ERROR_ID = 4_294_967_295
19
-
20
- ONEOF_MESSAGE = EmbeddedProtocol::InboundMessage
21
- .descriptor
22
- .lookup_oneof('message')
23
- .collect do |field_descriptor|
24
- [field_descriptor.subtype, field_descriptor.name]
25
- end.to_h
26
-
27
- private_constant :ONEOF_MESSAGE
28
-
29
- def initialize
30
- @observerable_mutex = Mutex.new
31
- @stdin_mutex = Mutex.new
32
- @stdin, @stdout, @stderr, @wait_thread = Open3.popen3(DART_SASS_EMBEDDED)
33
-
34
- [@stdin, @stdout].each(&:binmode)
35
-
36
- poll do
37
- warn(@stderr.readline, uplevel: 1)
38
- end
39
- poll do
40
- receive_proto read
41
- end
42
- end
43
-
44
- def add_observer(*args)
45
- @observerable_mutex.synchronize do
46
- super(*args)
47
- end
48
- end
49
-
50
- def send_message(message)
51
- write EmbeddedProtocol::InboundMessage.new(
52
- ONEOF_MESSAGE[message.class.descriptor] => message
53
- ).to_proto
54
- end
55
-
56
- def close
57
- delete_observers
58
- @stdin.close unless @stdin.closed?
59
- @stdout.close unless @stdout.closed?
60
- @stderr.close unless @stderr.closed?
61
- nil
62
- end
63
-
64
- def closed?
65
- @stdin.closed?
66
- end
67
-
68
- private
69
-
70
- def poll
71
- Thread.new do
72
- loop do
73
- yield
74
- rescue StandardError => e
75
- notify_observers(e, nil)
76
- close
77
- break
78
- end
79
- end
80
- end
81
-
82
- def notify_observers(*args)
83
- @observerable_mutex.synchronize do
84
- changed
85
- super(*args)
86
- end
87
- end
88
-
89
- def receive_proto(proto)
90
- payload = EmbeddedProtocol::OutboundMessage.decode(proto)
91
- message = payload[payload.message.to_s]
92
- case message
93
- when EmbeddedProtocol::ProtocolError
94
- raise ProtocolError, message.message
95
- else
96
- notify_observers(nil, message)
97
- end
98
- end
99
-
100
- def read
101
- length = read_varint(@stdout)
102
- @stdout.read(length)
103
- end
104
-
105
- def write(payload)
106
- @stdin_mutex.synchronize do
107
- write_varint(@stdin, payload.length)
108
- @stdin.write payload
109
- end
110
- end
111
-
112
- def read_varint(readable)
113
- value = bits = 0
114
- loop do
115
- byte = readable.readbyte
116
- value |= (byte & 0x7f) << bits
117
- bits += 7
118
- break if byte < 0x80
119
- end
120
- value
121
- end
122
-
123
- def write_varint(writeable, value)
124
- bytes = []
125
- until value < 0x80
126
- bytes << (0x80 | (value & 0x7f))
127
- value >>= 7
128
- end
129
- bytes << value
130
- writeable.write bytes.pack('C*')
131
- end
132
- end
133
- end
data/lib/sass/util.rb DELETED
@@ -1,31 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'pathname'
4
- require 'uri'
5
-
6
- module Sass
7
- # The {Util} module.
8
- module Util
9
- module_function
10
-
11
- URI_PARSER = URI::Parser.new({ RESERVED: ';/?:@&=+$,' })
12
-
13
- private_constant :URI_PARSER
14
-
15
- def file_uri_from_path(path)
16
- "file://#{Platform::OS == 'windows' ? File::SEPARATOR : ''}#{URI_PARSER.escape(path)}"
17
- end
18
-
19
- def path_from_file_uri(file_uri)
20
- URI_PARSER.unescape(file_uri[(Platform::OS == 'windows' ? 8 : 7)..])
21
- end
22
-
23
- def relative_path(from, to)
24
- Pathname.new(File.absolute_path(to)).relative_path_from(Pathname.new(File.absolute_path(from))).to_s
25
- end
26
-
27
- def now
28
- (Time.now.to_f * 1000).to_i
29
- end
30
- end
31
- end