class SassC::ImportHandler::ImportCache
def canonicalize(url, context)
def canonicalize(url, context) if url.start_with?(Protocol::IMPORT) canonical_url = @canonical_urls.delete(url) unless @importer_results.key?(canonical_url) path = URL.unescape(canonical_url) parent_path = URL.file_url_to_path(@parent_urls.last) canonical_url = resolve_file_url(path, parent_path, context.from_import) return unless canonical_url # Temporarily disable FileImporter optimization # https://github.com/sass/dart-sass/issues/2208 # # if ['.sass', '.scss', '.css'].include?(File.extname(URL.file_url_to_path(canonical_url))) # @canonical_urls[url] = canonical_url # return nil # end end @parent_urls.push(canonical_url) canonical_url elsif url.start_with?(Protocol::LOADED) @parent_urls.pop Protocol::LOADED else parent_url = @parent_urls.last url = URL.join(parent_url, url) return unless url.start_with?(Protocol::FILE) path = URL.file_urls_to_relative_path(url, parent_url) parent_path = URL.file_url_to_path(parent_url) imports = @importer.imports(path, parent_path) imports = [SassC::Importer::Import.new(path)] if imports.nil? imports = [imports] unless imports.is_a?(Array) canonical_url = "#{Protocol::IMPORT}#{url}" @importer_results[canonical_url] = imports_to_native(imports, File.dirname(parent_path), context.from_import) canonical_url end end
def find_file_url(url, _context)
def find_file_url(url, _context) canonical_url = @canonical_urls.delete(url) return unless canonical_url @parent_urls.push(canonical_url) canonical_url end
def imports_to_native(imports, parent_dir, from_import)
def imports_to_native(imports, parent_dir, from_import) { contents: imports.flat_map do |import| if import.source canonical_url = URL.path_to_file_url(File.absolute_path(import.path, parent_dir)) @importer_results[canonical_url] = if import.source.is_a?(Hash) { contents: import.source[:contents], syntax: import.source[:syntax], source_map_url: canonical_url } else { contents: import.source, syntax: syntax(import.path), source_map_url: canonical_url } end else canonical_url = URL.escape(import.path) end import_url = "#{Protocol::IMPORT}#{canonical_url}" loaded_url = "#{Protocol::LOADED}#{canonical_url}" @canonical_urls[import_url] = canonical_url at_rule = from_import ? '@import' : '@forward' <<~SCSS #{at_rule} #{Script::Value::String.quote(import_url)}; #{at_rule} #{Script::Value::String.quote(loaded_url)}; SCSS end.join("\n"), syntax: :scss } end
def initialize(importer)
def initialize(importer) @importer = importer @canonical_urls = {} @importer_results = {} @load_paths = (@importer.options[:load_paths] || []) + SassC.load_paths @parent_urls = [URL.path_to_file_url(File.absolute_path(@importer.options[:filename] || 'stdin'))] end
def load(canonical_url)
def load(canonical_url) if @importer_results.key?(canonical_url) @importer_results.delete(canonical_url) elsif canonical_url.start_with?(Protocol::FILE) path = URL.file_url_to_path(canonical_url) { contents: File.read(path), syntax: syntax(path), source_map_url: canonical_url } elsif canonical_url.start_with?(Protocol::LOADED) { contents: '', syntax: :scss } end end
def resolve_file_url(path, parent_path, from_import)
def resolve_file_url(path, parent_path, from_import) [File.dirname(parent_path)].concat(@load_paths).each do |load_path| resolved = FileSystemImporter.resolve_path(File.absolute_path(path, load_path), from_import) return URL.path_to_file_url(resolved) unless resolved.nil? end nil end
def syntax(path)
def syntax(path) case File.extname(path) when '.sass' :indented when '.css' :css else :scss end end