sassc-embedded 1.2.0 → 1.3.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: cdd5607c689b8388cf0c07abc26c3769ef50007ddd6b46432b277f7631bceb7f
4
+ data.tar.gz: 510835f24a3d66cf516bfd56acb0efd729d000cde730ef64908dfd5645f5aa12
5
5
  SHA512:
6
- metadata.gz: f5f88d175f876435912bbb8141180dd4c72f3874b3d76604188598499c53c9dcdc5f273e3abdaff8674c93de30553a4be9370ba1b6665bab38a578cc3540ef65
7
- data.tar.gz: 6c26f72589706937100230aa6e7e5e2ddd687f7cead7ce6653354fd556f371e26a07a400012845210c947f2928532ffb0a13c01ecde27b8b4a4eb5c691ec6e32
6
+ metadata.gz: 93bbe6c1e4ff6e2fc4209e9390fd4775f029f0efb60606ab64cf9ee71a6afbc64d658c7572fd9c0719a134e8e192c5e8200d8ac2530e691cb84ae3fc14a31686
7
+ data.tar.gz: 1eed6fff6d57ac4ac56965de504ee876bd6dbbebb93880edefef2de604eb99536660487ae5c1ebcd6991270904f4700b42a54790dd7c233e303a66755120f01d
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.3.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,86 +197,196 @@ 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
+ if ['.sass', '.scss', '.css'].include?(ext)
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
+ @base_url = URL.parse(URL.path_to_file_url("#{File.absolute_path('')}/"))
290
+ @parent_urls = [URL.parse(URL.path_to_file_url(File.absolute_path(@importer.options[:filename] || 'stdin')))]
214
291
  end
215
292
 
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))
293
+ def canonicalize(url, from_import:)
294
+ return url if url.start_with?(Protocol::IMPORT, Protocol::LOADED)
223
295
 
224
- if @importer_results.key?(canonical_url)
225
- return if @importer_results[canonical_url].nil?
296
+ if url.start_with?(Protocol::LOAD)
297
+ url = url.delete_prefix(Protocol::LOAD)
298
+ return url if @importer_results.key?(url)
226
299
 
227
- return canonical_url
300
+ path = URL.parse(url).route_from(@parent_urls.last).to_s
301
+ resolved = resolve_path(path, URL.file_url_to_path(@parent_urls.last.to_s), from_import)
302
+ return resolved.nil? ? nil : URL.path_to_file_url(resolved)
228
303
  end
229
304
 
230
- canonical_url = "sassc-embedded:#{canonical_url}"
305
+ return unless url.start_with?(Protocol::FILE)
231
306
 
232
- imports = @importer.imports(path, @importer.options[:filename])
233
- unless imports.is_a?(Array)
234
- return if imports.path == path
307
+ path = URL.parse(url).route_from(@parent_urls.last).to_s
308
+ parent_path = @parent_urls.last.route_from(@base_url).to_s
235
309
 
236
- imports = [imports]
310
+ imports = @importer.imports(path, parent_path)
311
+ imports = [SassC::Importer::Import.new(path)] if imports.nil?
312
+ imports = [imports] unless imports.is_a?(Array)
313
+ imports.each do |import|
314
+ import.path = File.absolute_path(import.path, File.dirname(parent_path))
237
315
  end
238
316
 
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
-
317
+ import_url = URL.path_to_file_url(File.absolute_path(path, File.dirname(parent_path)))
318
+ canonical_url = "#{Protocol::IMPORT}#{import_url}"
319
+ @importer_results[canonical_url] = imports_to_native(imports)
270
320
  canonical_url
271
321
  end
272
322
 
273
323
  def load(canonical_url)
274
- @importer_results[canonical_url]
324
+ if canonical_url.start_with?(Protocol::IMPORT)
325
+ @importer_results.delete(canonical_url)
326
+ elsif canonical_url.start_with?(Protocol::FILE)
327
+ @parent_urls.push(URL.parse(canonical_url))
328
+ if @importer_results.key?(canonical_url)
329
+ @importer_results.delete(canonical_url)
330
+ else
331
+ path = URL.file_url_to_path(canonical_url)
332
+ {
333
+ contents: File.read(path),
334
+ syntax: syntax(path),
335
+ source_map_url: canonical_url
336
+ }
337
+ end
338
+ elsif canonical_url.start_with?(Protocol::LOADED)
339
+ @parent_urls.pop
340
+ {
341
+ contents: '',
342
+ syntax: 'scss'
343
+ }
344
+ end
345
+ end
346
+
347
+ private
348
+
349
+ def load_paths
350
+ @load_paths ||= (@importer.options[:load_paths] || []) + SassC.load_paths
351
+ end
352
+
353
+ def resolve_path(path, parent_path, from_import)
354
+ [File.dirname(parent_path)].concat(load_paths).each do |load_path|
355
+ resolved = FileImporter.resolve_path(File.absolute_path(path, load_path), from_import)
356
+ return resolved unless resolved.nil?
357
+ end
358
+ nil
359
+ end
360
+
361
+ def syntax(path)
362
+ case File.extname(path)
363
+ when '.sass'
364
+ :indented
365
+ when '.css'
366
+ :css
367
+ else
368
+ :scss
369
+ end
370
+ end
371
+
372
+ def imports_to_native(imports)
373
+ {
374
+ contents: imports.flat_map do |import|
375
+ file_url = URL.path_to_file_url(import.path)
376
+ if import.source
377
+ @importer_results[file_url] = {
378
+ contents: import.source,
379
+ syntax: syntax(import.path),
380
+ source_map_url: file_url
381
+ }
382
+ end
383
+ [
384
+ "@import #{"#{Protocol::LOAD}#{file_url}".inspect};",
385
+ "@import #{"#{Protocol::LOADED}#{file_url}".inspect};"
386
+ ]
387
+ end.join("\n"),
388
+ syntax: :scss
389
+ }
275
390
  end
276
391
  end
277
392
 
@@ -402,6 +517,10 @@ module SassC
402
517
 
403
518
  module_function
404
519
 
520
+ def parse(str)
521
+ PARSER.parse(str)
522
+ end
523
+
405
524
  def escape(str)
406
525
  PARSER.escape(str)
407
526
  end
@@ -413,7 +532,7 @@ module SassC
413
532
  def file_url_to_path(url)
414
533
  return if url.nil?
415
534
 
416
- path = unescape(URI.parse(url).path)
535
+ path = unescape(parse(url).path)
417
536
  path = path[1..] if Gem.win_platform? && path[0].chr == '/' && path[1].chr =~ /[a-z]/i && path[2].chr == ':'
418
537
  path
419
538
  end
@@ -421,7 +540,6 @@ module SassC
421
540
  def path_to_file_url(path)
422
541
  return if path.nil?
423
542
 
424
- path = File.absolute_path(path)
425
543
  path = "/#{path}" unless path.start_with?('/')
426
544
  URI::File.build([nil, escape(path)]).to_s
427
545
  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.3.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.3.0
142
+ source_code_uri: https://github.com/ntkme/sassc-embedded-polyfill-ruby/tree/v1.3.0
143
143
  funding_uri: https://github.com/sponsors/ntkme
144
144
  post_install_message:
145
145
  rdoc_options: []