sass-embedded 0.9.0 → 0.10.0

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c5bcaee2299b4f0b9d4d1d23b25773fdad87d1a294a4a34eeec0028d1f89a25c
4
- data.tar.gz: 75ce2615300b0d59e73f715ae43007baf09a9818ea56d80b8be4d54b1f561c69
3
+ metadata.gz: e3c01d861dce5149bb56f25e6cb89e54d21a26bc4e50486298f860b2386198b7
4
+ data.tar.gz: 36f04488a3118b833f6210766e590a617fe7204dabb31b0908023b32a008ed21
5
5
  SHA512:
6
- metadata.gz: 93cf20b2df8d4c363797df90e459f52c6dedf5e540cb5b6eb1cd110dded76477adf82f6c0bc0652f1b5201f535265053f7838654952a4bcc7f338bcc69c9464a
7
- data.tar.gz: c4190c8fc8e60a37fa834dfdac6fe1842e66d39ac8d0ad9bc1c15ea5c18c16766f19e194be746fc963a5604c740f438c6371aa59c10dd59d452a526fea6cbf0d
6
+ metadata.gz: c7c15d96579e3dc1843c3dfc66709c9a3ae48bcbb7458f0defcc91c313cffb53dc43b01d114c35b13b8a7b8cfae516440037730283d52e5ea506fffa70a9bcac
7
+ data.tar.gz: ae089947ade94c0550e9a066860e89e1c774572ddc1ab7c5b42327f4a9f3fe6db41c4422ce96a9454d63b44ae8675091239278ebd8d6f524438c0f680a3e5e26
data/LICENSE CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2021, なつき
1
+ Copyright (c) 2022, なつき
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining
4
4
  a copy of this software and associated documentation files (the
data/README.md CHANGED
@@ -16,32 +16,12 @@ gem install sass-embedded
16
16
  ## Usage
17
17
 
18
18
  ``` ruby
19
- require "sass"
19
+ require 'sass'
20
20
 
21
- Sass.render(file: "style.scss")
21
+ Sass.compile('style.scss')
22
+ Sass.compile_string('h1 { font-size: 40px; }')
22
23
  ```
23
24
 
24
- ## Options
25
-
26
- `Sass.render(**kwargs)` supports the following options:
27
-
28
- - [`data`](https://sass-lang.com/documentation/js-api#data)
29
- - [`file`](https://sass-lang.com/documentation/js-api#file)
30
- - [`indented_syntax`](https://sass-lang.com/documentation/js-api#indentedsyntax)
31
- - [`include_paths`](https://sass-lang.com/documentation/js-api#includepaths)
32
- - [`output_style`](https://sass-lang.com/documentation/js-api#outputstyle)
33
- - [`indent_type`](https://sass-lang.com/documentation/js-api#indenttype)
34
- - [`indent_width`](https://sass-lang.com/documentation/js-api#indentwidth)
35
- - [`linefeed`](https://sass-lang.com/documentation/js-api#linefeed)
36
- - [`source_map`](https://sass-lang.com/documentation/js-api#sourcemap)
37
- - [`out_file`](https://sass-lang.com/documentation/js-api#outfile)
38
- - [`omit_source_map_url`](https://sass-lang.com/documentation/js-api#omitsourcemapurl)
39
- - [`source_map_contents`](https://sass-lang.com/documentation/js-api#sourcemapcontents)
40
- - [`source_map_embed`](https://sass-lang.com/documentation/js-api#sourcemapembed)
41
- - [`source_map_root`](https://sass-lang.com/documentation/js-api#sourcemaproot)
42
- - [`functions`](https://sass-lang.com/documentation/js-api#functions)
43
- - [`importer`](https://sass-lang.com/documentation/js-api#importer)
44
-
45
25
  ---
46
26
 
47
27
  Disclaimer: this is not an official Google product.
data/ext/sass/extconf.rb CHANGED
@@ -62,9 +62,7 @@ module Sass
62
62
  elsif uri.respond_to? :open
63
63
  puts "curl -fsSLo #{path} -- #{uri}"
64
64
  uri.open do |source|
65
- File.open(path, 'wb') do |destination|
66
- destination.write source.read
67
- end
65
+ File.binwrite(path, source.read)
68
66
  end
69
67
  else
70
68
  raise
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'logger/source_span'
4
+
5
+ module Sass
6
+ # The {CompileError} raised by {Embedded#compile} or {Embedded#compile_string}.
7
+ class CompileError < StandardError
8
+ attr_accessor :sass_message, :sass_stack, :span
9
+
10
+ def initialize(message, sass_message, sass_stack, span)
11
+ super(message)
12
+ @sass_message = sass_message
13
+ @sass_stack = sass_stack
14
+ @span = span
15
+ end
16
+
17
+ def self.from_proto(compile_failure)
18
+ CompileError.new(compile_failure.formatted,
19
+ compile_failure.message,
20
+ compile_failure.stack_trace,
21
+ Logger::SourceSpan.from_proto(compile_failure.span))
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Sass
4
+ # The {CompileResult} of {Embedded#compile} or {Embedded#compile_string}.
5
+ class CompileResult
6
+ attr_reader :css, :source_map, :loaded_urls
7
+
8
+ def initialize(css, source_map, loaded_urls)
9
+ @css = css
10
+ @source_map = source_map == '' ? nil : source_map
11
+ @loaded_urls = loaded_urls
12
+ end
13
+
14
+ def self.from_proto(compile_success)
15
+ CompileResult.new(compile_success.css, compile_success.source_map, compile_success.loaded_urls)
16
+ end
17
+ end
18
+ end
@@ -29,7 +29,7 @@ module Sass
29
29
  @mutex.synchronize do
30
30
  begin
31
31
  id = @compiler.add_observer(observer)
32
- rescue IOError
32
+ rescue ProtocolError
33
33
  @compiler = Compiler.new
34
34
  id = @compiler.add_observer(observer)
35
35
  end
@@ -1,40 +1,58 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative '../embedded_protocol'
4
+ require_relative '../logger/source_span'
4
5
  require_relative 'observer'
5
- require_relative 'util'
6
6
 
7
7
  module Sass
8
8
  class Embedded
9
- # The {Observer} for {Embedded#render}.
9
+ # The {Observer} for {Embedded#compile}.
10
10
  class CompileContext
11
11
  include Observer
12
12
 
13
13
  def initialize(channel,
14
- data:,
15
- file:,
16
- indented_syntax:,
17
- include_paths:,
18
- output_style:,
14
+ path:,
15
+ source:,
16
+
17
+ importer:,
18
+ load_paths:,
19
+ syntax:,
20
+ url:,
21
+
19
22
  source_map:,
20
- out_file:,
23
+ style:,
24
+
21
25
  functions:,
22
- importer:)
23
- raise ArgumentError, 'either data or file must be set' if file.nil? && data.nil?
24
-
25
- @data = data
26
- @file = file
27
- @indented_syntax = indented_syntax
28
- @include_paths = include_paths
29
- @output_style = output_style
26
+ importers:,
27
+
28
+ alert_ascii:,
29
+ alert_color:,
30
+ logger:,
31
+ quiet_deps:,
32
+ verbose:)
33
+ @path = path
34
+ @source = source
35
+
36
+ @importer = importer
37
+ @load_paths = load_paths
38
+ @syntax = syntax
39
+ @url = url
40
+
30
41
  @source_map = source_map
31
- @out_file = out_file
32
- @global_functions = functions.keys
42
+ @style = style
43
+
44
+ @global_functions = functions.keys.map(&:to_s)
45
+
33
46
  @functions = functions.transform_keys do |key|
34
47
  key.to_s.split('(')[0].chomp
35
48
  end
36
- @importer = importer
37
- @import_responses = {}
49
+ @importers = importers
50
+
51
+ @alert_ascii = alert_ascii
52
+ @alert_color = alert_color
53
+ @logger = logger
54
+ @quiet_deps = quiet_deps
55
+ @verbose = verbose
38
56
 
39
57
  super(channel)
40
58
 
@@ -52,9 +70,9 @@ module Sass
52
70
  super(nil, message)
53
71
  end
54
72
  when EmbeddedProtocol::OutboundMessage::LogEvent
55
- return unless message.compilation_id == id && $stderr.tty?
73
+ return unless message.compilation_id == id
56
74
 
57
- warn message.formatted
75
+ log message
58
76
  when EmbeddedProtocol::OutboundMessage::CanonicalizeRequest
59
77
  return unless message.compilation_id == id
60
78
 
@@ -68,7 +86,11 @@ module Sass
68
86
  send_message import_response message
69
87
  end
70
88
  when EmbeddedProtocol::OutboundMessage::FileImportRequest
71
- raise NotImplementedError, 'FileImportRequest is not implemented'
89
+ return unless message.compilation_id == id
90
+
91
+ Thread.new do
92
+ send_message file_import_response message
93
+ end
72
94
  when EmbeddedProtocol::OutboundMessage::FunctionCallRequest
73
95
  return unless message.compilation_id == id
74
96
 
@@ -84,94 +106,107 @@ module Sass
84
106
 
85
107
  private
86
108
 
109
+ def log(event)
110
+ case event.type
111
+ when :DEBUG
112
+ if @logger.respond_to? :debug
113
+ @logger.debug(event.message, span: Logger::SourceSpan.from_proto(event.span))
114
+ else
115
+ Kernel.warn(event.formatted)
116
+ end
117
+ when :DEPRECATION_WARNING
118
+ if @logger.respond_to? :warn
119
+ @logger.warn(event.message, deprecation: true, span: Logger::SourceSpan.from_proto(event.span),
120
+ stack: event.stack_trace)
121
+ else
122
+ Kernel.warn(event.formatted)
123
+ end
124
+ when :WARNING
125
+ if @logger.respond_to? :warn
126
+ @logger.warn(event.message, deprecation: false, span: Logger::SourceSpan.from_proto(event.span),
127
+ stack: event.stack_trace)
128
+ else
129
+ Kernel.warn(event.formatted)
130
+ end
131
+ end
132
+ end
133
+
87
134
  def compile_request
88
135
  EmbeddedProtocol::InboundMessage::CompileRequest.new(
89
136
  id: id,
90
- string: string,
91
- path: path,
92
- style: style,
93
- source_map: source_map,
94
- importers: importers,
95
- global_functions: global_functions,
96
- alert_color: $stderr.tty?,
97
- alert_ascii: Platform::OS == 'windows'
137
+ string: unless @source.nil?
138
+ EmbeddedProtocol::InboundMessage::CompileRequest::StringInput.new(
139
+ source: @source,
140
+ url: @url,
141
+ syntax: to_proto_syntax(@syntax),
142
+ importer: @importer.nil? ? nil : to_proto_importer(@importer, @importers.length)
143
+ )
144
+ end,
145
+ path: @path,
146
+ style: to_proto_output_style(@style),
147
+ source_map: @source_map,
148
+ importers: to_proto_importers(@importers, @load_paths),
149
+ global_functions: @global_functions,
150
+ alert_ascii: @alert_ascii,
151
+ alert_color: @alert_color
98
152
  )
99
153
  end
100
154
 
101
155
  def canonicalize_response(canonicalize_request)
102
- url = Util.file_uri_from_path(File.absolute_path(canonicalize_request.url, (@file.nil? ? 'stdin' : @file)))
103
-
104
- begin
105
- result = @importer[canonicalize_request.importer_id].call canonicalize_request.url, @file
106
- raise result if result.is_a? StandardError
107
- rescue StandardError => e
108
- return EmbeddedProtocol::InboundMessage::CanonicalizeResponse.new(
109
- id: canonicalize_request.id,
110
- error: e.message
111
- )
112
- end
113
-
114
- if result&.key? :contents
115
- @import_responses[url] = EmbeddedProtocol::InboundMessage::ImportResponse.new(
116
- id: canonicalize_request.id,
117
- success: EmbeddedProtocol::InboundMessage::ImportResponse::ImportSuccess.new(
118
- contents: result[:contents],
119
- syntax: EmbeddedProtocol::Syntax::SCSS,
120
- source_map_url: nil
121
- )
122
- )
123
- EmbeddedProtocol::InboundMessage::CanonicalizeResponse.new(
124
- id: canonicalize_request.id,
125
- url: url
126
- )
127
- elsif result&.key? :file
128
- canonicalized_url = Util.file_uri_from_path(File.absolute_path(result[:file]))
129
-
130
- # TODO: FileImportRequest is not supported yet.
131
- # Workaround by reading contents and return it when server asks
132
- @import_responses[canonicalized_url] = EmbeddedProtocol::InboundMessage::ImportResponse.new(
133
- id: canonicalize_request.id,
134
- success: EmbeddedProtocol::InboundMessage::ImportResponse::ImportSuccess.new(
135
- contents: File.read(result[:file]),
136
- syntax: EmbeddedProtocol::Syntax::SCSS,
137
- source_map_url: nil
138
- )
139
- )
156
+ url = importer_with_id(canonicalize_request.importer_id).canonicalize canonicalize_request.url
140
157
 
141
- EmbeddedProtocol::InboundMessage::CanonicalizeResponse.new(
142
- id: canonicalize_request.id,
143
- url: canonicalized_url
144
- )
145
- else
146
- EmbeddedProtocol::InboundMessage::CanonicalizeResponse.new(
147
- id: canonicalize_request.id
148
- )
149
- end
158
+ EmbeddedProtocol::InboundMessage::CanonicalizeResponse.new(
159
+ id: canonicalize_request.id,
160
+ url: url
161
+ )
162
+ rescue StandardError => e
163
+ EmbeddedProtocol::InboundMessage::CanonicalizeResponse.new(
164
+ id: canonicalize_request.id,
165
+ error: e.message
166
+ )
150
167
  end
151
168
 
152
169
  def import_response(import_request)
153
- url = import_request.url
154
-
155
- if @import_responses.key? url
156
- @import_responses[url].id = import_request.id
157
- else
158
- @import_responses[url] = EmbeddedProtocol::InboundMessage::ImportResponse.new(
159
- id: import_request.id,
160
- error: "Failed to import: #{url}"
170
+ importer_result = importer_with_id(import_request.importer_id).load import_request.url
171
+
172
+ EmbeddedProtocol::InboundMessage::ImportResponse.new(
173
+ id: import_request.id,
174
+ success: EmbeddedProtocol::InboundMessage::ImportResponse::ImportSuccess.new(
175
+ contents: importer_result.contents,
176
+ syntax: to_proto_syntax(importer_result.syntax),
177
+ source_map_url: importer_result.source_map_url
161
178
  )
162
- end
179
+ )
180
+ rescue StandardError => e
181
+ EmbeddedProtocol::InboundMessage::ImportResponse.new(
182
+ id: import_request.id,
183
+ error: e.message
184
+ )
185
+ end
163
186
 
164
- @import_responses[url]
187
+ def file_import_response(file_import_request)
188
+ file_importer = importer_with_id(file_import_request.importer_id)
189
+ file_url = file_importer.find_file_url file_import_request.url,
190
+ from_import: file_import_request.from_import
191
+
192
+ EmbeddedProtocol::InboundMessage::FileImportResponse.new(
193
+ id: file_import_request.id,
194
+ file_url: file_url
195
+ )
196
+ rescue StandardError => e
197
+ EmbeddedProtocol::InboundMessage::FileImportResponse.new(
198
+ id: file_import_request.id,
199
+ error: e.message
200
+ )
165
201
  end
166
202
 
167
203
  def function_call_response(function_call_request)
168
- # TODO: convert argument_list to **kwargs
169
204
  EmbeddedProtocol::InboundMessage::FunctionCallResponse.new(
170
205
  id: function_call_request.id,
171
206
  success: @functions[function_call_request.name].call(*function_call_request.arguments),
172
207
  accessed_argument_lists: function_call_request.arguments
173
- .filter { |argument| argument.value == :argument_list }
174
- .map { |argument| argument.argument_list.id }
208
+ .filter { |argument| argument.value == :argument_list }
209
+ .map { |argument| argument.argument_list.id }
175
210
  )
176
211
  rescue StandardError => e
177
212
  EmbeddedProtocol::InboundMessage::FunctionCallResponse.new(
@@ -180,36 +215,21 @@ module Sass
180
215
  )
181
216
  end
182
217
 
183
- def syntax
184
- if @indented_syntax == true
218
+ def to_proto_syntax(syntax)
219
+ case syntax&.to_sym
220
+ when :scss
221
+ EmbeddedProtocol::Syntax::SCSS
222
+ when :indented
185
223
  EmbeddedProtocol::Syntax::INDENTED
224
+ when :css
225
+ EmbeddedProtocol::Syntax::CSS
186
226
  else
187
- EmbeddedProtocol::Syntax::SCSS
227
+ raise ArgumentError, 'syntax must be one of :scss, :indented, :css'
188
228
  end
189
229
  end
190
230
 
191
- def url
192
- return if @file.nil?
193
-
194
- Util.file_uri_from_path File.absolute_path @file
195
- end
196
-
197
- def string
198
- return if @data.nil?
199
-
200
- EmbeddedProtocol::InboundMessage::CompileRequest::StringInput.new(
201
- source: @data,
202
- url: url,
203
- syntax: syntax
204
- )
205
- end
206
-
207
- def path
208
- @file if @data.nil?
209
- end
210
-
211
- def style
212
- case @output_style&.to_sym
231
+ def to_proto_output_style(style)
232
+ case style&.to_sym
213
233
  when :expanded
214
234
  EmbeddedProtocol::OutputStyle::EXPANDED
215
235
  when :compressed
@@ -219,35 +239,40 @@ module Sass
219
239
  end
220
240
  end
221
241
 
222
- def source_map
223
- @source_map.is_a?(String) || (@source_map == true && !@out_file.nil?)
224
- end
225
-
226
- attr_reader :global_functions
227
-
228
- # Order
229
- # 1. Loading a file relative to the file in which the @use or @import appeared.
230
- # 2. Each custom importer.
231
- # 3. Loading a file relative to the current working directory.
232
- # 4. Each load path in includePaths
233
- # 5. Each load path specified in the SASS_PATH environment variable, which should
234
- # be semicolon-separated on Windows and colon-separated elsewhere.
235
- def importers
236
- custom_importers = @importer.map.with_index do |_, id|
242
+ def to_proto_importer(importer, id)
243
+ if importer.respond_to?(:canonicalize) && importer.respond_to?(:load)
237
244
  EmbeddedProtocol::InboundMessage::CompileRequest::Importer.new(
238
245
  importer_id: id
239
246
  )
247
+ elsif importer.respond_to?(:find_file_url)
248
+ EmbeddedProtocol::InboundMessage::CompileRequest::Importer.new(
249
+ file_importer_id: id
250
+ )
251
+ else
252
+ raise ArgumentError, 'importer must be an Importer or a FileImporter'
240
253
  end
254
+ end
241
255
 
242
- include_path_importers = @include_paths
243
- .concat(Embedded.include_paths)
244
- .map do |include_path|
245
- EmbeddedProtocol::InboundMessage::CompileRequest::Importer.new(
246
- path: File.absolute_path(include_path)
256
+ def to_proto_importers(importers, load_paths)
257
+ proto_importers = importers.map.with_index do |importer, id|
258
+ to_proto_importer(importer, id)
259
+ end
260
+
261
+ load_paths.each do |load_path|
262
+ proto_importers << EmbeddedProtocol::InboundMessage::CompileRequest::Importer.new(
263
+ path: File.absolute_path(load_path)
247
264
  )
248
265
  end
249
266
 
250
- custom_importers.concat include_path_importers
267
+ proto_importers
268
+ end
269
+
270
+ def importer_with_id(id)
271
+ if id == @importers.length
272
+ @importer
273
+ else
274
+ @importers[id]
275
+ end
251
276
  end
252
277
  end
253
278
  end
@@ -3,7 +3,7 @@
3
3
  module Sass
4
4
  class Embedded
5
5
  class Compiler
6
- REQUIREMENTS = '~> 1.0.0-beta.11'
6
+ REQUIREMENTS = '~> 1.0.0-beta.16'
7
7
  end
8
8
  end
9
9
  end
@@ -4,7 +4,7 @@ require 'observer'
4
4
  require 'open3'
5
5
  require_relative '../embedded_protocol'
6
6
  require_relative 'compiler/path'
7
- require_relative 'error'
7
+ require_relative 'protocol_error'
8
8
 
9
9
  module Sass
10
10
  class Embedded
@@ -17,9 +17,9 @@ module Sass
17
17
  ONEOF_MESSAGE = EmbeddedProtocol::InboundMessage
18
18
  .descriptor
19
19
  .lookup_oneof('message')
20
- .collect do |field_descriptor|
20
+ .to_h do |field_descriptor|
21
21
  [field_descriptor.subtype, field_descriptor.name]
22
- end.to_h
22
+ end
23
23
 
24
24
  private_constant :ONEOF_MESSAGE
25
25
 
@@ -41,7 +41,7 @@ module Sass
41
41
 
42
42
  def add_observer(*args)
43
43
  @observerable_mutex.synchronize do
44
- raise IOError, 'half-closed compiler' if half_closed?
44
+ raise ProtocolError, 'half-closed compiler' if half_closed?
45
45
 
46
46
  super(*args)
47
47
 
@@ -25,6 +25,7 @@ module Sass
25
25
 
26
26
  def update(error, message)
27
27
  @subscription.unsubscribe
28
+
28
29
  @mutex.synchronize do
29
30
  @error = error
30
31
  @message = message
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Sass
4
+ class Embedded
5
+ class ProtocolError < StandardError; end
6
+ end
7
+ end