sass-embedded 0.9.1 → 0.11.0

Sign up to get free protection for your applications and to get access to all the features.
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