sass-embedded 0.9.3 → 0.13.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: 703341c81359bb39d78fd9fc9ce7e1c9a43b68be31b2e24b353183d4ff25b07e
4
- data.tar.gz: 22c68deb8adc71b70bc3e96f24807af57e66d903ee9a873a07f01b46ba8acc81
3
+ metadata.gz: 11917ed4d9543adf380300ee5ba1db25d8681a69db35b6e4fe6ac83b4e1b07a6
4
+ data.tar.gz: ca18113ebee1ba530183bb477e4f927c0966903caa12174bba54382006ab5a8d
5
5
  SHA512:
6
- metadata.gz: bf61a14aceb6cf027d9c35815252de2e1aed21d87a9e8634f8a00fe63d8d1c31df8541d187b537c719c209b984f4367b6c947eeca4c02f7414469d76d0609393
7
- data.tar.gz: 9f4f71ee5eee804ff46d21fa27684bccf99c27d72d5be4fd0c018384018a737ad782916ac0a1fa5a53a5d0d592fb4c7d74e5cb99dc947ea7874f93065476c05c
6
+ metadata.gz: 420269d9de74346fcceb81c391b7eafef25b9001d4c3ce67959bb1d6da1d4a6838c1ae9a22f794fc31b44ad2961ed55ecbf94f0bf980dc316ee7a6e51b87b88d
7
+ data.tar.gz: dd7bb981674b7a19f91169c402e540ff2d77abf50461383b7431a986cab21f06c7de8124825050325cfb8296f8066a95b2a03ebdd3c3da754aeb50bf4cf998aa
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
@@ -1,40 +1,64 @@
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
+ source_map_include_sources:,
24
+ style:,
25
+
21
26
  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
27
+ importers:,
28
+
29
+ alert_ascii:,
30
+ alert_color:,
31
+ logger:,
32
+ quiet_deps:,
33
+ verbose:)
34
+ @path = path
35
+ @source = source
36
+
37
+ @importer = importer
38
+ @load_paths = load_paths
39
+ @syntax = syntax
40
+ @url = url
41
+
30
42
  @source_map = source_map
31
- @out_file = out_file
32
- @global_functions = functions.keys
43
+ @source_map_include_sources = source_map_include_sources
44
+ @style = style
45
+
46
+ @global_functions = functions.keys.map(&:to_s)
47
+
33
48
  @functions = functions.transform_keys do |key|
34
49
  key.to_s.split('(')[0].chomp
35
50
  end
36
- @importer = importer
37
- @import_responses = {}
51
+ @importers = importers
52
+
53
+ @alert_ascii = alert_ascii
54
+ @alert_color = alert_color
55
+
56
+ %i[debug warn].each do |sym|
57
+ instance_variable_set("@#{sym}".to_sym, get_method(logger, sym))
58
+ end
59
+
60
+ @quiet_deps = quiet_deps
61
+ @verbose = verbose
38
62
 
39
63
  super(channel)
40
64
 
@@ -52,9 +76,9 @@ module Sass
52
76
  super(nil, message)
53
77
  end
54
78
  when EmbeddedProtocol::OutboundMessage::LogEvent
55
- return unless message.compilation_id == id && $stderr.tty?
79
+ return unless message.compilation_id == id
56
80
 
57
- warn message.formatted
81
+ log message
58
82
  when EmbeddedProtocol::OutboundMessage::CanonicalizeRequest
59
83
  return unless message.compilation_id == id
60
84
 
@@ -68,7 +92,11 @@ module Sass
68
92
  send_message import_response message
69
93
  end
70
94
  when EmbeddedProtocol::OutboundMessage::FileImportRequest
71
- raise NotImplementedError, 'FileImportRequest is not implemented'
95
+ return unless message.compilation_id == id
96
+
97
+ Thread.new do
98
+ send_message file_import_response message
99
+ end
72
100
  when EmbeddedProtocol::OutboundMessage::FunctionCallRequest
73
101
  return unless message.compilation_id == id
74
102
 
@@ -84,94 +112,115 @@ module Sass
84
112
 
85
113
  private
86
114
 
115
+ def log(event)
116
+ case event.type
117
+ when :DEBUG
118
+ if @debug.nil?
119
+ Kernel.warn(event.formatted)
120
+ else
121
+ @debug.call(event.message, span: Logger::SourceSpan.from_proto(event.span))
122
+ end
123
+ when :DEPRECATION_WARNING
124
+ if @warn.nil?
125
+ Kernel.warn(event.formatted)
126
+ else
127
+ @warn.call(event.message, deprecation: true,
128
+ span: Logger::SourceSpan.from_proto(event.span),
129
+ stack: event.stack_trace)
130
+ end
131
+ when :WARNING
132
+ if @warn.nil?
133
+ Kernel.warn(event.formatted)
134
+ else
135
+ @warn.call(event.message, deprecation: false,
136
+ span: Logger::SourceSpan.from_proto(event.span),
137
+ stack: event.stack_trace)
138
+ end
139
+ end
140
+ end
141
+
87
142
  def compile_request
88
143
  EmbeddedProtocol::InboundMessage::CompileRequest.new(
89
144
  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'
145
+ string: unless @source.nil?
146
+ EmbeddedProtocol::InboundMessage::CompileRequest::StringInput.new(
147
+ source: @source,
148
+ url: @url,
149
+ syntax: to_proto_syntax(@syntax),
150
+ importer: @importer.nil? ? nil : to_proto_importer(@importer, @importers.length)
151
+ )
152
+ end,
153
+ path: @path,
154
+ style: to_proto_output_style(@style),
155
+ source_map: @source_map,
156
+ source_map_include_sources: @source_map_include_sources,
157
+ importers: to_proto_importers(@importers, @load_paths),
158
+ global_functions: @global_functions,
159
+ alert_ascii: @alert_ascii,
160
+ alert_color: @alert_color
98
161
  )
99
162
  end
100
163
 
101
164
  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
165
+ importer = importer_with_id(canonicalize_request.importer_id)
166
+ url = get_method(importer, :canonicalize).call canonicalize_request.url,
167
+ from_import: canonicalize_request.from_import
113
168
 
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
- )
169
+ EmbeddedProtocol::InboundMessage::CanonicalizeResponse.new(
170
+ id: canonicalize_request.id,
171
+ url: url
172
+ )
173
+ rescue StandardError => e
174
+ EmbeddedProtocol::InboundMessage::CanonicalizeResponse.new(
175
+ id: canonicalize_request.id,
176
+ error: e.message
177
+ )
178
+ end
140
179
 
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
180
+ def import_response(import_request)
181
+ importer = importer_with_id(import_request.importer_id)
182
+ importer_result = get_method(importer, :load).call import_request.url
183
+
184
+ EmbeddedProtocol::InboundMessage::ImportResponse.new(
185
+ id: import_request.id,
186
+ success: EmbeddedProtocol::InboundMessage::ImportResponse::ImportSuccess.new(
187
+ contents: get_attr(importer_result, :contents),
188
+ syntax: to_proto_syntax(get_attr(importer_result, :syntax)),
189
+ source_map_url: get_attr(importer_result, :source_map_url)
148
190
  )
149
- end
191
+ )
192
+ rescue StandardError => e
193
+ EmbeddedProtocol::InboundMessage::ImportResponse.new(
194
+ id: import_request.id,
195
+ error: e.message
196
+ )
150
197
  end
151
198
 
152
- def import_response(import_request)
153
- url = import_request.url
199
+ def file_import_response(file_import_request)
200
+ file_importer = importer_with_id(file_import_request.importer_id)
201
+ file_url = get_method(file_importer, :find_file_url).call file_import_request.url,
202
+ from_import: file_import_request.from_import
154
203
 
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}"
161
- )
162
- end
204
+ raise "file_url must be a file: URL, was \"#{file_url}\"" if !file_url.nil? && !file_url.start_with?('file:')
163
205
 
164
- @import_responses[url]
206
+ EmbeddedProtocol::InboundMessage::FileImportResponse.new(
207
+ id: file_import_request.id,
208
+ file_url: file_url
209
+ )
210
+ rescue StandardError => e
211
+ EmbeddedProtocol::InboundMessage::FileImportResponse.new(
212
+ id: file_import_request.id,
213
+ error: e.message
214
+ )
165
215
  end
166
216
 
167
217
  def function_call_response(function_call_request)
168
- # TODO: convert argument_list to **kwargs
169
218
  EmbeddedProtocol::InboundMessage::FunctionCallResponse.new(
170
219
  id: function_call_request.id,
171
220
  success: @functions[function_call_request.name].call(*function_call_request.arguments),
172
221
  accessed_argument_lists: function_call_request.arguments
173
- .filter { |argument| argument.value == :argument_list }
174
- .map { |argument| argument.argument_list.id }
222
+ .filter { |argument| argument.value == :argument_list }
223
+ .map { |argument| argument.argument_list.id }
175
224
  )
176
225
  rescue StandardError => e
177
226
  EmbeddedProtocol::InboundMessage::FunctionCallResponse.new(
@@ -180,74 +229,93 @@ module Sass
180
229
  )
181
230
  end
182
231
 
183
- def syntax
184
- if @indented_syntax == true
232
+ def to_proto_syntax(syntax)
233
+ case syntax&.to_sym
234
+ when :scss
235
+ EmbeddedProtocol::Syntax::SCSS
236
+ when :indented
185
237
  EmbeddedProtocol::Syntax::INDENTED
238
+ when :css
239
+ EmbeddedProtocol::Syntax::CSS
186
240
  else
187
- EmbeddedProtocol::Syntax::SCSS
241
+ raise ArgumentError, 'syntax must be one of :scss, :indented, :css'
188
242
  end
189
243
  end
190
244
 
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
245
+ def to_proto_output_style(style)
246
+ case style&.to_sym
213
247
  when :expanded
214
248
  EmbeddedProtocol::OutputStyle::EXPANDED
215
249
  when :compressed
216
250
  EmbeddedProtocol::OutputStyle::COMPRESSED
217
251
  else
218
- raise ArgumentError, 'output_style must be one of :expanded, :compressed'
252
+ raise ArgumentError, 'style must be one of :expanded, :compressed'
219
253
  end
220
254
  end
221
255
 
222
- def source_map
223
- @source_map.is_a?(String) || (@source_map == true && !@out_file.nil?)
224
- end
256
+ def to_proto_importer(importer, id)
257
+ is_importer = get_method(importer, :canonicalize) && get_method(importer, :load)
258
+ is_file_importer = get_method(importer, :find_file_url)
225
259
 
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|
260
+ if is_importer && !is_file_importer
237
261
  EmbeddedProtocol::InboundMessage::CompileRequest::Importer.new(
238
262
  importer_id: id
239
263
  )
264
+ elsif is_file_importer && !is_importer
265
+ EmbeddedProtocol::InboundMessage::CompileRequest::Importer.new(
266
+ file_importer_id: id
267
+ )
268
+ else
269
+ raise ArgumentError, 'importer must be an Importer or a FileImporter'
270
+ end
271
+ end
272
+
273
+ def to_proto_importers(importers, load_paths)
274
+ proto_importers = importers.map.with_index do |importer, id|
275
+ to_proto_importer(importer, id)
240
276
  end
241
277
 
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)
278
+ load_paths.each do |load_path|
279
+ proto_importers << EmbeddedProtocol::InboundMessage::CompileRequest::Importer.new(
280
+ path: File.absolute_path(load_path)
247
281
  )
248
282
  end
249
283
 
250
- custom_importers.concat include_path_importers
284
+ proto_importers
285
+ end
286
+
287
+ def importer_with_id(id)
288
+ if id == @importers.length
289
+ @importer
290
+ else
291
+ @importers[id]
292
+ end
293
+ end
294
+
295
+ def get_method(obj, sym)
296
+ sym = sym.to_sym
297
+ if obj.respond_to? sym
298
+ obj.method(sym)
299
+ elsif obj.respond_to? :[]
300
+ if obj[sym].respond_to? :call
301
+ obj[sym]
302
+ elsif obj[sym.to_s].respond_to? :call
303
+ obj[sym.to_s]
304
+ end
305
+ end
306
+ end
307
+
308
+ def get_attr(obj, sym)
309
+ sym = sym.to_sym
310
+ if obj.respond_to? sym
311
+ obj.method(sym).call
312
+ elsif obj.respond_to? :[]
313
+ if obj[sym]
314
+ obj[sym]
315
+ elsif obj[sym.to_s]
316
+ obj[sym.to_s]
317
+ end
318
+ end
251
319
  end
252
320
  end
253
321
  end
@@ -3,7 +3,7 @@
3
3
  module Sass
4
4
  class Embedded
5
5
  class Compiler
6
- REQUIREMENTS = '~> 1.0.0-beta.12'
6
+ REQUIREMENTS = '~> 1.49.6'
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
 
@@ -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