sassc-embedded 1.2.0 → 1.4.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: 165d1e520918392a01a808a20da523f4f573d762684c279f83dcf75202659c46
4
- data.tar.gz: 80bf5a80e154a4be31c013489bd807a7c8ffdac4ffc1f143baf76c81e61326f0
3
+ metadata.gz: 2c93f068bcc4406780bad76da750f2b265943a971456d3b56a14b0bdb2f0be8a
4
+ data.tar.gz: c851519ef1b2f08fe4370f4669b9df263b7264844911df873de30273748b4675
5
5
  SHA512:
6
- metadata.gz: f5f88d175f876435912bbb8141180dd4c72f3874b3d76604188598499c53c9dcdc5f273e3abdaff8674c93de30553a4be9370ba1b6665bab38a578cc3540ef65
7
- data.tar.gz: 6c26f72589706937100230aa6e7e5e2ddd687f7cead7ce6653354fd556f371e26a07a400012845210c947f2928532ffb0a13c01ecde27b8b4a4eb5c691ec6e32
6
+ metadata.gz: 14f22ec99ba45f9fddf083a1bccab5b34b3c48e745cfd30c53078c504d90d3e870c27effc1c9ae20b32ead54602dffadfa48b59993a61fa82991c9cafa1cd856
7
+ data.tar.gz: 6a1d3fde2932a3c83932bb6601ad7e5ac0d945d69f69d0d5acf36c378401afdd3cbc7cb00dcb835b10be697fdbdb378bbcffd1e957e2995e686f3d10f546c6b7
data/README.md CHANGED
@@ -51,6 +51,4 @@ See [rubydoc.info/gems/sassc](https://rubydoc.info/gems/sassc) for full API docu
51
51
 
52
52
  4. Option `:line_comments` is ignored.
53
53
 
54
- 5. Argument `parent_path` in `Importer#imports(path, parent_path)` is set to value of option `:filename`.
55
-
56
54
  See [the dart-sass documentation](https://github.com/sass/dart-sass#behavioral-differences-from-ruby-sass) for other differences.
@@ -2,6 +2,6 @@
2
2
 
3
3
  module SassC
4
4
  module Embedded
5
- VERSION = '1.2.0'
5
+ VERSION = '1.4.0'
6
6
  end
7
7
  end
@@ -17,7 +17,7 @@ module SassC
17
17
 
18
18
  result = ::Sass.compile_string(
19
19
  @template,
20
- importer: nil,
20
+ importer: import_handler.setup(nil),
21
21
  load_paths: load_paths,
22
22
  syntax: syntax,
23
23
  url: file_url,
@@ -26,8 +26,8 @@ module SassC
26
26
  source_map_include_sources: source_map_contents?,
27
27
  style: output_style,
28
28
 
29
- functions: FunctionsHandler.new(@options).setup(nil, functions: @functions),
30
- importers: ImportHandler.new(@options).setup(nil),
29
+ functions: functions_handler.setup(nil, functions: @functions),
30
+ importers: [],
31
31
 
32
32
  alert_ascii: @options.fetch(:alert_ascii, false),
33
33
  alert_color: @options.fetch(:alert_color, nil),
@@ -45,30 +45,25 @@ module SassC
45
45
  rescue ::Sass::CompileError => e
46
46
  line = e.span&.start&.line
47
47
  line += 1 unless line.nil?
48
- path = URL.file_url_to_path(e.span&.url)
48
+ url = e.span&.url
49
+ path = url&.start_with?('file:') ? URL.file_url_to_path(url) : nil
49
50
  path = relative_path(Dir.pwd, path) unless path.nil?
50
51
  raise SyntaxError.new(e.message, filename: path, line: line)
51
52
  end
52
53
 
53
54
  private
54
55
 
56
+ def file_url
57
+ @file_url ||= URL.path_to_file_url(File.absolute_path(filename || 'stdin'))
58
+ end
59
+
55
60
  def output_path
56
61
  @output_path ||= @options.fetch(
57
62
  :output_path,
58
- ("#{File.basename(filename, File.extname(filename))}.css" if filename)
63
+ ("#{filename.delete_suffix(File.extname(filename))}.css" if filename)
59
64
  )
60
65
  end
61
66
 
62
- def file_url
63
- @file_url ||= URL.path_to_file_url(filename || 'stdin')
64
- end
65
-
66
- def syntax
67
- syntax = @options.fetch(:syntax, :scss)
68
- syntax = :indented if syntax.to_sym == :sass
69
- syntax
70
- end
71
-
72
67
  def output_style
73
68
  @output_style ||= begin
74
69
  style = @options.fetch(:style, :sass_style_nested).to_s
@@ -87,8 +82,18 @@ module SassC
87
82
  end
88
83
  end
89
84
 
85
+ def syntax
86
+ syntax = @options.fetch(:syntax, :scss)
87
+ syntax = :indented if syntax.to_sym == :sass
88
+ syntax
89
+ end
90
+
90
91
  def load_paths
91
- @load_paths ||= (@options[:load_paths] || []) + SassC.load_paths
92
+ @load_paths ||= if @options[:importer].nil?
93
+ (@options[:load_paths] || []) + SassC.load_paths
94
+ else
95
+ []
96
+ end
92
97
  end
93
98
 
94
99
  def post_process_source_map(source_map)
@@ -192,92 +197,218 @@ module SassC
192
197
 
193
198
  class ImportHandler
194
199
  def setup(_native_options)
195
- if @importer
196
- [FileImporter.new, Importer.new(@importer)]
197
- else
198
- []
199
- end
200
+ Importer.new(@importer) if @importer
200
201
  end
201
202
 
202
203
  class FileImporter
203
- def find_file_url(url, **)
204
- return url if url.start_with?('file:')
204
+ class << self
205
+ def resolve_path(path, from_import)
206
+ ext = File.extname(path)
207
+ unless ext.empty?
208
+ if from_import
209
+ result = exactly_one(try_path("#{without_ext(path)}.import#{ext}"))
210
+ return result unless result.nil?
211
+ end
212
+ return exactly_one(try_path(path))
213
+ end
214
+
215
+ if from_import
216
+ result = exactly_one(try_path_with_ext("#{path}.import"))
217
+ return result unless result.nil?
218
+ end
219
+
220
+ result = exactly_one(try_path_with_ext(path))
221
+ return result unless result.nil?
222
+
223
+ try_path_as_dir(path, from_import)
224
+ end
225
+
226
+ private
227
+
228
+ def try_path_with_ext(path)
229
+ result = try_path("#{path}.sass") + try_path("#{path}.scss")
230
+ result.empty? ? try_path("#{path}.css") : result
231
+ end
232
+
233
+ def try_path(path)
234
+ partial = File.join(File.dirname(path), "_#{File.basename(path)}")
235
+ result = []
236
+ result.push(partial) if file_exist?(partial)
237
+ result.push(path) if file_exist?(path)
238
+ result
239
+ end
240
+
241
+ def try_path_as_dir(path, from_import)
242
+ return unless dir_exist? path
243
+
244
+ if from_import
245
+ result = exactly_one(try_path_with_ext(File.join(path, 'index.import')))
246
+ return result unless result.nil?
247
+ end
248
+
249
+ exactly_one(try_path_with_ext(File.join(path, 'index')))
250
+ end
251
+
252
+ def exactly_one(paths)
253
+ return if paths.empty?
254
+ return paths.first if paths.length == 1
255
+
256
+ raise "It's not clear which file to import. Found:\n#{paths.map { |path| " #{path}" }.join("\n")}"
257
+ end
258
+
259
+ def file_exist?(path)
260
+ File.exist?(path) && File.file?(path)
261
+ end
262
+
263
+ def dir_exist?(path)
264
+ File.exist?(path) && File.directory?(path)
265
+ end
266
+
267
+ def without_ext(path)
268
+ ext = File.extname(path)
269
+ path.delete_suffix(ext)
270
+ end
205
271
  end
206
272
  end
207
273
 
208
274
  private_constant :FileImporter
209
275
 
210
276
  class Importer
277
+ module Protocol
278
+ FILE = 'file:'
279
+ IMPORT = 'sassc-embedded-import:'
280
+ LOAD = 'sassc-embedded-load:'
281
+ LOADED = 'sassc-embedded-loaded:'
282
+ end
283
+
284
+ private_constant :Protocol
285
+
211
286
  def initialize(importer)
212
287
  @importer = importer
213
288
  @importer_results = {}
289
+ @parent_urls = [URL.path_to_file_url(File.absolute_path(@importer.options[:filename] || 'stdin'))]
214
290
  end
215
291
 
216
- def canonicalize(url, **)
217
- path = if url.start_with?('file:')
218
- URL.file_url_to_path(url)
219
- else
220
- URL.unescape(url)
221
- end
222
- canonical_url = URL.path_to_file_url(File.absolute_path(path))
292
+ def canonicalize(url, from_import:)
293
+ return url if url.start_with?(Protocol::IMPORT, Protocol::LOADED)
223
294
 
224
- if @importer_results.key?(canonical_url)
225
- return if @importer_results[canonical_url].nil?
295
+ if url.start_with?(Protocol::LOAD)
296
+ url = url.delete_prefix(Protocol::LOAD)
297
+ return url if @importer_results.key?(url)
226
298
 
227
- return canonical_url
299
+ path = URL.parse(url).route_from(@parent_urls.last).to_s
300
+ resolved = resolve_path(path, URL.file_url_to_path(@parent_urls.last.to_s), from_import)
301
+ return resolved.nil? ? nil : URL.path_to_file_url(resolved)
228
302
  end
229
303
 
230
- canonical_url = "sassc-embedded:#{canonical_url}"
304
+ return unless url.start_with?(Protocol::FILE)
231
305
 
232
- imports = @importer.imports(path, @importer.options[:filename])
233
- unless imports.is_a?(Array)
234
- return if imports.path == path
306
+ path = URL.parse(url).route_from(@parent_urls.last).to_s
307
+ parent_path = URL.file_url_to_path(@parent_urls.last)
235
308
 
236
- imports = [imports]
309
+ imports = @importer.imports(path, parent_path)
310
+ imports = [SassC::Importer::Import.new(path)] if imports.nil?
311
+ imports = [imports] unless imports.is_a?(Array)
312
+ imports.each do |import|
313
+ import.path = File.absolute_path(import.path, File.dirname(parent_path))
237
314
  end
238
315
 
239
- dirname = File.dirname(@importer.options.fetch(:filename, 'stdin'))
240
- contents = imports.map do |import|
241
- import_url = URL.path_to_file_url(File.absolute_path(import.path, dirname))
242
- @importer_results[import_url] = if import.source
243
- {
244
- contents: import.source,
245
- syntax: case import.path
246
- when /\.sass$/i
247
- :indented
248
- when /\.css$/i
249
- :css
250
- else
251
- :scss
252
- end,
253
- source_map_url: if import.source_map_path
254
- URL.path_to_file_url(
255
- File.absolute_path(
256
- import.source_map_path, dirname
257
- )
258
- )
259
- end
260
- }
261
- end
262
- "@import #{import_url.inspect};"
263
- end.join("\n")
264
-
265
- @importer_results[canonical_url] = {
266
- contents: contents,
267
- syntax: :scss
268
- }
269
-
316
+ import_url = URL.path_to_file_url(File.absolute_path(path, File.dirname(parent_path)))
317
+ canonical_url = "#{Protocol::IMPORT}#{import_url}"
318
+ @importer_results[canonical_url] = imports_to_native(imports)
270
319
  canonical_url
271
320
  end
272
321
 
273
322
  def load(canonical_url)
274
- @importer_results[canonical_url]
323
+ if canonical_url.start_with?(Protocol::IMPORT)
324
+ @importer_results.delete(canonical_url)
325
+ elsif canonical_url.start_with?(Protocol::FILE)
326
+ @parent_urls.push(canonical_url)
327
+ if @importer_results.key?(canonical_url)
328
+ @importer_results.delete(canonical_url)
329
+ else
330
+ path = URL.file_url_to_path(canonical_url)
331
+ {
332
+ contents: File.read(path),
333
+ syntax: syntax(path),
334
+ source_map_url: canonical_url
335
+ }
336
+ end
337
+ elsif canonical_url.start_with?(Protocol::LOADED)
338
+ @parent_urls.pop
339
+ {
340
+ contents: '',
341
+ syntax: :scss
342
+ }
343
+ end
344
+ end
345
+
346
+ private
347
+
348
+ def load_paths
349
+ @load_paths ||= (@importer.options[:load_paths] || []) + SassC.load_paths
350
+ end
351
+
352
+ def resolve_path(path, parent_path, from_import)
353
+ [File.dirname(parent_path)].concat(load_paths).each do |load_path|
354
+ resolved = FileImporter.resolve_path(File.absolute_path(path, load_path), from_import)
355
+ return resolved unless resolved.nil?
356
+ end
357
+ nil
358
+ end
359
+
360
+ def syntax(path)
361
+ case File.extname(path)
362
+ when '.sass'
363
+ :indented
364
+ when '.css'
365
+ :css
366
+ else
367
+ :scss
368
+ end
369
+ end
370
+
371
+ def imports_to_native(imports)
372
+ {
373
+ contents: imports.flat_map do |import|
374
+ file_url = URL.path_to_file_url(import.path)
375
+ if import.source
376
+ @importer_results[file_url] = if import.source.is_a?(Hash)
377
+ {
378
+ contents: import.source[:contents],
379
+ syntax: import.source[:syntax],
380
+ source_map_url: file_url
381
+ }
382
+ else
383
+ {
384
+ contents: import.source,
385
+ syntax: syntax(import.path),
386
+ source_map_url: file_url
387
+ }
388
+ end
389
+ end
390
+ [
391
+ "@import #{"#{Protocol::LOAD}#{file_url}".inspect};",
392
+ "@import #{"#{Protocol::LOADED}#{file_url}".inspect};"
393
+ ]
394
+ end.join("\n"),
395
+ syntax: :scss
396
+ }
275
397
  end
276
398
  end
277
399
 
278
400
  private_constant :Importer
279
401
  end
280
402
 
403
+ class Sass2Scss
404
+ def self.convert(sass)
405
+ {
406
+ contents: sass,
407
+ syntax: :indented
408
+ }
409
+ end
410
+ end
411
+
281
412
  module Script
282
413
  module ValueConversion
283
414
  def self.from_native(value, options)
@@ -402,6 +533,10 @@ module SassC
402
533
 
403
534
  module_function
404
535
 
536
+ def parse(str)
537
+ PARSER.parse(str)
538
+ end
539
+
405
540
  def escape(str)
406
541
  PARSER.escape(str)
407
542
  end
@@ -413,7 +548,7 @@ module SassC
413
548
  def file_url_to_path(url)
414
549
  return if url.nil?
415
550
 
416
- path = unescape(URI.parse(url).path)
551
+ path = unescape(parse(url).path)
417
552
  path = path[1..] if Gem.win_platform? && path[0].chr == '/' && path[1].chr =~ /[a-z]/i && path[2].chr == ':'
418
553
  path
419
554
  end
@@ -421,7 +556,6 @@ module SassC
421
556
  def path_to_file_url(path)
422
557
  return if path.nil?
423
558
 
424
- path = File.absolute_path(path)
425
559
  path = "/#{path}" unless path.start_with?('/')
426
560
  URI::File.build([nil, escape(path)]).to_s
427
561
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sassc-embedded
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.0
4
+ version: 1.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - なつき
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-03-27 00:00:00.000000000 Z
11
+ date: 2022-04-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: sassc
@@ -138,8 +138,8 @@ homepage: https://github.com/ntkme/sassc-embedded-polyfill-ruby
138
138
  licenses:
139
139
  - MIT
140
140
  metadata:
141
- documentation_uri: https://rubydoc.info/gems/sassc-embedded/1.2.0
142
- source_code_uri: https://github.com/ntkme/sassc-embedded-polyfill-ruby/tree/v1.2.0
141
+ documentation_uri: https://rubydoc.info/gems/sassc-embedded/1.4.0
142
+ source_code_uri: https://github.com/ntkme/sassc-embedded-polyfill-ruby/tree/v1.4.0
143
143
  funding_uri: https://github.com/sponsors/ntkme
144
144
  post_install_message:
145
145
  rdoc_options: []