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