sassc-embedded 1.2.0 → 1.4.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: 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: []