sass-embedded 0.9.1 → 0.11.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: '018d03c0959c9166e685ae375315eb0604c338dc892b2ea40f1a29fac1b17147'
4
- data.tar.gz: a1ce2a1eb5bc15b7ea9e8001fc6ca799d704407ac3e4fb79fc98863e873ac613
3
+ metadata.gz: 8d392419747bbe1cffb4c3843a60a8de343a07fc938c1ad061ce8cde4519fd4a
4
+ data.tar.gz: 358c8083d14d6d27d84d6091cad64dd39e35c1076295e030b668386b4856098a
5
5
  SHA512:
6
- metadata.gz: 886030b4eef8a3d79f67786c61e0c532c868f8faa83cb906a53efe809bfc16b0cfea3067bf2ad1e66b7a0a361c006557f3aae72ae3dab66c9738617fa054d19a
7
- data.tar.gz: e808634a40e6e486b3478b227db1feee9879deac1653d042fa80614df29ab63add1253a9e53fac90ece0970092cceaca7904accd144bd2a724ada37928312d2b
6
+ metadata.gz: 3a50de89e870d5d4fe054eb0702da7774fba5e445e65fba3efb9364d6ed140bbb07cb1dec2d06bee96d08cf79017c383a921def2487c78468c2a3fe2c3e6a54e
7
+ data.tar.gz: e746cc7db807ab73557e03d342d7a5f88d81b7c581a5969d2a63dec1a63699828bc49fcfa1fa4d80ac5edb8452495b15bc8c2e5163127d4985276490c3259e98
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,11 @@ 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
+ Thread.new do
76
+ log message
77
+ end
58
78
  when EmbeddedProtocol::OutboundMessage::CanonicalizeRequest
59
79
  return unless message.compilation_id == id
60
80
 
@@ -68,7 +88,11 @@ module Sass
68
88
  send_message import_response message
69
89
  end
70
90
  when EmbeddedProtocol::OutboundMessage::FileImportRequest
71
- raise NotImplementedError, 'FileImportRequest is not implemented'
91
+ return unless message.compilation_id == id
92
+
93
+ Thread.new do
94
+ send_message file_import_response message
95
+ end
72
96
  when EmbeddedProtocol::OutboundMessage::FunctionCallRequest
73
97
  return unless message.compilation_id == id
74
98
 
@@ -84,94 +108,107 @@ module Sass
84
108
 
85
109
  private
86
110
 
111
+ def log(event)
112
+ case event.type
113
+ when :DEBUG
114
+ if @logger.respond_to? :debug
115
+ @logger.debug(event.message, span: Logger::SourceSpan.from_proto(event.span))
116
+ else
117
+ Kernel.warn(event.formatted)
118
+ end
119
+ when :DEPRECATION_WARNING
120
+ if @logger.respond_to? :warn
121
+ @logger.warn(event.message, deprecation: true, span: Logger::SourceSpan.from_proto(event.span),
122
+ stack: event.stack_trace)
123
+ else
124
+ Kernel.warn(event.formatted)
125
+ end
126
+ when :WARNING
127
+ if @logger.respond_to? :warn
128
+ @logger.warn(event.message, deprecation: false, span: Logger::SourceSpan.from_proto(event.span),
129
+ stack: event.stack_trace)
130
+ else
131
+ Kernel.warn(event.formatted)
132
+ end
133
+ end
134
+ end
135
+
87
136
  def compile_request
88
137
  EmbeddedProtocol::InboundMessage::CompileRequest.new(
89
138
  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'
139
+ string: unless @source.nil?
140
+ EmbeddedProtocol::InboundMessage::CompileRequest::StringInput.new(
141
+ source: @source,
142
+ url: @url,
143
+ syntax: to_proto_syntax(@syntax),
144
+ importer: @importer.nil? ? nil : to_proto_importer(@importer, @importers.length)
145
+ )
146
+ end,
147
+ path: @path,
148
+ style: to_proto_output_style(@style),
149
+ source_map: @source_map,
150
+ importers: to_proto_importers(@importers, @load_paths),
151
+ global_functions: @global_functions,
152
+ alert_ascii: @alert_ascii,
153
+ alert_color: @alert_color
98
154
  )
99
155
  end
100
156
 
101
157
  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
158
+ url = importer_with_id(canonicalize_request.importer_id).canonicalize canonicalize_request.url
113
159
 
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
- )
140
-
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
160
+ EmbeddedProtocol::InboundMessage::CanonicalizeResponse.new(
161
+ id: canonicalize_request.id,
162
+ url: url
163
+ )
164
+ rescue StandardError => e
165
+ EmbeddedProtocol::InboundMessage::CanonicalizeResponse.new(
166
+ id: canonicalize_request.id,
167
+ error: e.message
168
+ )
150
169
  end
151
170
 
152
171
  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}"
172
+ importer_result = importer_with_id(import_request.importer_id).load import_request.url
173
+
174
+ EmbeddedProtocol::InboundMessage::ImportResponse.new(
175
+ id: import_request.id,
176
+ success: EmbeddedProtocol::InboundMessage::ImportResponse::ImportSuccess.new(
177
+ contents: importer_result.contents,
178
+ syntax: to_proto_syntax(importer_result.syntax),
179
+ source_map_url: importer_result.source_map_url
161
180
  )
162
- end
181
+ )
182
+ rescue StandardError => e
183
+ EmbeddedProtocol::InboundMessage::ImportResponse.new(
184
+ id: import_request.id,
185
+ error: e.message
186
+ )
187
+ end
163
188
 
164
- @import_responses[url]
189
+ def file_import_response(file_import_request)
190
+ file_importer = importer_with_id(file_import_request.importer_id)
191
+ file_url = file_importer.find_file_url file_import_request.url,
192
+ from_import: file_import_request.from_import
193
+
194
+ EmbeddedProtocol::InboundMessage::FileImportResponse.new(
195
+ id: file_import_request.id,
196
+ file_url: file_url
197
+ )
198
+ rescue StandardError => e
199
+ EmbeddedProtocol::InboundMessage::FileImportResponse.new(
200
+ id: file_import_request.id,
201
+ error: e.message
202
+ )
165
203
  end
166
204
 
167
205
  def function_call_response(function_call_request)
168
- # TODO: convert argument_list to **kwargs
169
206
  EmbeddedProtocol::InboundMessage::FunctionCallResponse.new(
170
207
  id: function_call_request.id,
171
208
  success: @functions[function_call_request.name].call(*function_call_request.arguments),
172
209
  accessed_argument_lists: function_call_request.arguments
173
- .filter { |argument| argument.value == :argument_list }
174
- .map { |argument| argument.argument_list.id }
210
+ .filter { |argument| argument.value == :argument_list }
211
+ .map { |argument| argument.argument_list.id }
175
212
  )
176
213
  rescue StandardError => e
177
214
  EmbeddedProtocol::InboundMessage::FunctionCallResponse.new(
@@ -180,36 +217,21 @@ module Sass
180
217
  )
181
218
  end
182
219
 
183
- def syntax
184
- if @indented_syntax == true
220
+ def to_proto_syntax(syntax)
221
+ case syntax&.to_sym
222
+ when :scss
223
+ EmbeddedProtocol::Syntax::SCSS
224
+ when :indented
185
225
  EmbeddedProtocol::Syntax::INDENTED
226
+ when :css
227
+ EmbeddedProtocol::Syntax::CSS
186
228
  else
187
- EmbeddedProtocol::Syntax::SCSS
229
+ raise ArgumentError, 'syntax must be one of :scss, :indented, :css'
188
230
  end
189
231
  end
190
232
 
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
233
+ def to_proto_output_style(style)
234
+ case style&.to_sym
213
235
  when :expanded
214
236
  EmbeddedProtocol::OutputStyle::EXPANDED
215
237
  when :compressed
@@ -219,35 +241,40 @@ module Sass
219
241
  end
220
242
  end
221
243
 
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|
244
+ def to_proto_importer(importer, id)
245
+ if importer.respond_to?(:canonicalize) && importer.respond_to?(:load)
237
246
  EmbeddedProtocol::InboundMessage::CompileRequest::Importer.new(
238
247
  importer_id: id
239
248
  )
249
+ elsif importer.respond_to?(:find_file_url)
250
+ EmbeddedProtocol::InboundMessage::CompileRequest::Importer.new(
251
+ file_importer_id: id
252
+ )
253
+ else
254
+ raise ArgumentError, 'importer must be an Importer or a FileImporter'
240
255
  end
256
+ end
241
257
 
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)
258
+ def to_proto_importers(importers, load_paths)
259
+ proto_importers = importers.map.with_index do |importer, id|
260
+ to_proto_importer(importer, id)
261
+ end
262
+
263
+ load_paths.each do |load_path|
264
+ proto_importers << EmbeddedProtocol::InboundMessage::CompileRequest::Importer.new(
265
+ path: File.absolute_path(load_path)
247
266
  )
248
267
  end
249
268
 
250
- custom_importers.concat include_path_importers
269
+ proto_importers
270
+ end
271
+
272
+ def importer_with_id(id)
273
+ if id == @importers.length
274
+ @importer
275
+ else
276
+ @importers[id]
277
+ end
251
278
  end
252
279
  end
253
280
  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
 
@@ -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