require 'sprockets/asset_uri'
module Sprockets
module Resolve
# Public: Finds the absolute path for a given logical path by searching the
# environment's load paths.
#
# resolve("application.js")
# # => "/path/to/app/javascripts/application.js"
#
# An accept content type can be given if the logical path doesn't have a
# format extension.
#
# resolve("application", accept: "application/javascript")
# # => "/path/to/app/javascripts/application.js"
#
# The String path is returned or nil if no results are found.
def resolve(path, options = {})
logical_name, mime_type, _ = parse_path_extnames(path)
paths = options[:load_paths] || self.paths
if absolute_path?(path)
path = File.expand_path(path)
if paths_split(paths, path) && file?(path)
if accept = options[:accept]
find_best_q_match(accept, [path]) do |candidate, matcher|
match_mime_type?(mime_type || "application/octet-stream", matcher)
end
else
path
end
end
else
accepts = parse_accept_options(mime_type, options[:accept])
filename, _ = resolve_under_paths(paths, logical_name, mime_type, accepts)
filename
end
end
# Public: Find Asset URI for given a logical path by searching the
# environment's load paths.
#
# locate("application.js")
# # => "file:///path/to/app/javascripts/application.js?content_type=application/javascript"
#
# An accept content type can be given if the logical path doesn't have a
# format extension.
#
# locate("application", accept: "application/javascript")
# # => "file:///path/to/app/javascripts/application.coffee?content_type=application/javascript"
#
# The String Asset URI is returned or nil if no results are found.
def locate(path, options = {})
path = path.to_s
accept = options[:accept]
skip_bundle = options.key?(:bundle) ? !options[:bundle] : false
available_encodings = self.encodings.keys + ['identity']
encoding = find_best_q_match(options[:accept_encoding], available_encodings)
paths = options[:load_paths] || self.paths
if absolute_path?(path)
path = File.expand_path(path)
if paths_split(paths, path) && file?(path)
mime_type = parse_path_extnames(path)[1]
_type = resolve_transform_type(mime_type, accept)
if !accept || _type
filename = path
type = _type
end
end
else
logical_name, mime_type, _ = parse_path_extnames(path)
parsed_accept = parse_accept_options(mime_type, accept)
if parsed_accept.empty?
return
end
transformed_accepts = expand_transform_accepts(parsed_accept)
filename, mime_type = resolve_under_paths(paths, logical_name, mime_type, transformed_accepts)
type = resolve_transform_type(mime_type, parsed_accept) if filename
end
if filename
encoding = nil if encoding == 'identity'
AssetURI.build(filename, type: type, skip_bundle: skip_bundle, encoding: encoding)
end
end
protected
def resolve_under_paths(paths, logical_name, mime_type, accepts)
logical_basename = File.basename(logical_name)
paths.each do |load_path|
candidates = path_matches(load_path, logical_name, logical_basename)
candidate = find_best_q_match(accepts, candidates) do |c, matcher|
match_mime_type?(c[1] || "application/octet-stream", matcher)
end
return candidate if candidate
end
nil
end
def parse_accept_options(mime_type, types)
accepts = []
accepts += parse_q_values(types) if types
if mime_type
if accepts.empty? || accepts.any? { |accept, _| match_mime_type?(mime_type, accept) }
accepts = [[mime_type, 1.0]]
else
return []
end
end
if accepts.empty?
accepts << ['*/*', 1.0]
end
accepts
end
def normalize_logical_path(path)
dirname, basename = File.split(path)
path = dirname if basename == 'index'
path
end
def path_matches(load_path, logical_name, logical_basename)
candidates = []
dirname = File.dirname(File.join(load_path, logical_name))
dirname_matches(dirname, logical_basename) { |candidate| candidates << candidate }
resolve_alternates(load_path, logical_name) { |fn| candidates << [fn, parse_path_extnames(fn)[1]] }
dirname_matches(File.join(load_path, logical_name), "index") { |candidate| candidates << candidate }
candidates.select { |fn, _| file?(fn) }
end
def dirname_matches(dirname, basename)
self.entries(dirname).each do |entry|
name, type, _ = parse_path_extnames(entry)
if basename == name
yield [File.join(dirname, entry), type]
end
end
end
def resolve_alternates(load_path, logical_name)
end
# Internal: Returns the name, mime type and `Array` of engine extensions.
#
# "foo.js.coffee.erb"
# # => ["foo", "application/javascript", [".coffee", ".erb"]]
#
def parse_path_extnames(path)
mime_type = nil
engine_extnames = []
len = path.length
path_extnames(path).reverse_each do |extname|
if engines.key?(extname)
mime_type = engine_mime_types[extname]
engine_extnames.unshift(extname)
len -= extname.length
elsif mime_exts.key?(extname)
mime_type = mime_exts[extname]
len -= extname.length
break
else
break
end
end
name = path[0, len]
return [name, mime_type, engine_extnames]
end
end
end