module Sprockets::Resolve

Public Instance Methods

resolve(path, options = {}) click to toggle source

Public: Find Asset URI for given a logical path by searching the environment's load paths.

resolve("application.js")
# => "file:///path/to/app/javascripts/application.js?type=application/javascript"

An accept content type can be given if the logical path doesn't have a format extension.

resolve("application", accept: "application/javascript")
# => "file:///path/to/app/javascripts/application.coffee?type=application/javascript"

The String Asset URI is returned or nil if no results are found.

# File lib/sprockets/resolve.rb, line 23
def resolve(path, options = {})
  path = path.to_s
  paths = options[:load_paths] || config[:paths]
  accept = options[:accept]

  if valid_asset_uri?(path)
    uri, deps = resolve_asset_uri(path)
  elsif absolute_path?(path)
    filename, type, deps = resolve_absolute_path(paths, path, accept)
  elsif relative_path?(path)
    filename, type, pipeline, deps = resolve_relative_path(paths, path, options[:base_path], accept)
  else
    filename, type, pipeline, deps = resolve_logical_path(paths, path, accept)
  end

  if filename
    params = {}
    params[:type] = type if type
    params[:pipeline] = pipeline if pipeline
    params[:pipeline] = options[:pipeline] if options[:pipeline]
    uri = build_asset_uri(filename, params)
  end

  return uri, deps
end
resolve!(path, options = {}) click to toggle source

Public: Same as resolve() but raises a FileNotFound exception instead of nil if no assets are found.

# File lib/sprockets/resolve.rb, line 51
def resolve!(path, options = {})
  uri, deps = resolve(path, options.merge(compat: false))

  unless uri
    message = "couldn't find file '#{path}'"

    if relative_path?(path) && options[:base_path]
      load_path, _ = paths_split(config[:paths], options[:base_path])
      message << " under '#{load_path}'"
    end

    message << " with type '#{options[:accept]}'" if options[:accept]

    raise FileNotFound, message
  end

  return uri, deps
end

Protected Instance Methods

dirname_matches(dirname, basename) click to toggle source
# File lib/sprockets/resolve.rb, line 176
def dirname_matches(dirname, basename)
  candidates = []
  entries = self.entries(dirname)
  entries.each do |entry|
    name, type, _, _ = parse_path_extnames(entry)
    if basename == name
      candidates << [File.join(dirname, entry), type]
    end
  end
  candidates
end
parse_accept_options(mime_type, types) click to toggle source
# File lib/sprockets/resolve.rb, line 135
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
parse_path_extnames(path) click to toggle source

Internal: Returns the name, mime type and `Array` of engine extensions.

"foo.js.coffee.erb"
# => ["foo", "application/javascript", [".coffee", ".erb"]]
# File lib/sprockets/resolve.rb, line 197
def parse_path_extnames(path)
  engines = []
  extname, value = match_path_extname(path, extname_map)

  if extname
    path = path.chomp(extname)
    type, engines, pipeline = value.values_at(:type, :engines, :pipeline)
  end

  return path, type, engines, pipeline
end
path_matches(load_path, logical_name, logical_basename) click to toggle source
# File lib/sprockets/resolve.rb, line 154
def path_matches(load_path, logical_name, logical_basename)
  dirname    = File.dirname(File.join(load_path, logical_name))
  candidates = dirname_matches(dirname, logical_basename)
  deps       = file_digest_dependency_set(dirname)

  result = resolve_alternates(load_path, logical_name)
  result[0].each do |fn|
    candidates << [fn, parse_path_extnames(fn)[1]]
  end
  deps.merge(result[1])

  dirname = File.join(load_path, logical_name)
  if directory? dirname
    result = dirname_matches(dirname, "index")
    candidates.concat(result)
  end

  deps.merge(file_digest_dependency_set(dirname))

  return candidates.select { |fn, _| file?(fn) }, deps
end
resolve_absolute_path(paths, filename, accept) click to toggle source
# File lib/sprockets/resolve.rb, line 76
def resolve_absolute_path(paths, filename, accept)
  deps = Set.new
  filename = File.expand_path(filename)

  # Ensure path is under load paths
  return nil, nil, deps unless paths_split(paths, filename)

  _, mime_type, _, _ = parse_path_extnames(filename)
  type = resolve_transform_type(mime_type, accept)
  return nil, nil, deps if accept && !type

  return nil, nil, deps unless file?(filename)

  deps << build_file_digest_uri(filename)
  return filename, type, deps
end
resolve_alternates(load_path, logical_name) click to toggle source
# File lib/sprockets/resolve.rb, line 188
def resolve_alternates(load_path, logical_name)
  return [], Set.new
end
resolve_asset_uri(uri) click to toggle source
# File lib/sprockets/resolve.rb, line 71
def resolve_asset_uri(uri)
  filename, _ = parse_asset_uri(uri)
  return uri, Set.new([build_file_digest_uri(filename)])
end
resolve_logical_path(paths, logical_path, accept) click to toggle source
# File lib/sprockets/resolve.rb, line 103
def resolve_logical_path(paths, logical_path, accept)
  logical_name, mime_type, _, pipeline = parse_path_extnames(logical_path)
  parsed_accept = parse_accept_options(mime_type, accept)
  transformed_accepts = expand_transform_accepts(parsed_accept)
  filename, mime_type, deps = resolve_under_paths(paths, logical_name, transformed_accepts)

  if filename
    deps << build_file_digest_uri(filename)
    type = resolve_transform_type(mime_type, parsed_accept)
    return filename, type, pipeline, deps
  else
    return nil, nil, nil, deps
  end
end
resolve_relative_path(paths, path, dirname, accept) click to toggle source
# File lib/sprockets/resolve.rb, line 93
def resolve_relative_path(paths, path, dirname, accept)
  filename = File.expand_path(path, dirname)
  load_path, _ = paths_split(paths, dirname)
  if load_path && logical_path = split_subpath(load_path, filename)
    resolve_logical_path([load_path], logical_path, accept)
  else
    return nil, nil, Set.new
  end
end
resolve_under_paths(paths, logical_name, accepts) click to toggle source
# File lib/sprockets/resolve.rb, line 118
def resolve_under_paths(paths, logical_name, accepts)
  all_deps = Set.new
  return nil, nil, all_deps if accepts.empty?

  logical_basename = File.basename(logical_name)
  paths.each do |load_path|
    candidates, deps = path_matches(load_path, logical_name, logical_basename)
    all_deps.merge(deps)
    candidate = find_best_q_match(accepts, candidates) do |c, matcher|
      match_mime_type?(c[1] || "application/octet-stream", matcher)
    end
    return candidate + [all_deps] if candidate
  end

  return nil, nil, all_deps
end