module Middleman::Util

def all_files_under(path, &ignore)

def all_files_under(path, &ignore)
  path = Pathname(path)
  if ignore && yield(path)
    []
  elsif path.directory?
    path.children.flat_map do |child|
      all_files_under(child, &ignore)
    end.compact
  elsif path.file?
    [path]
  else
    []
  end
end

def asset_path(app, kind, source, options_hash = ::Middleman::EMPTY_HASH)

def asset_path(app, kind, source, options_hash = ::Middleman::EMPTY_HASH)
  return source if source.to_s.include?('//') || source.to_s.start_with?('data:')
  asset_folder = case kind
                 when :css
                   app.config[:css_dir]
                 when :js
                   app.config[:js_dir]
                 when :images
                   app.config[:images_dir]
                 when :fonts
                   app.config[:fonts_dir]
                 else
                   kind.to_s
                 end
  source = source.to_s.tr(' ', '')
  ignore_extension = IGNORED_ASSET_EXTENSIONS.include? kind # don't append extension
  source << ".#{kind}" unless ignore_extension || source.end_with?(".#{kind}")
  asset_folder = '' if source.start_with?('/') # absolute path
  asset_url(app, source, asset_folder, options_hash)
end

def asset_url(app, path, prefix = '', options_hash = ::Middleman::EMPTY_HASH)

def asset_url(app, path, prefix = '', options_hash = ::Middleman::EMPTY_HASH)
  # Don't touch assets which already have a full path
  return path if path.include?('//') || path.start_with?('data:')
  raise ArgumentError, '#asset_url must be run in a context with current_resource if relative: true' if options_hash[:relative] && !options_hash[:current_resource]
  uri = ::Middleman::Util.parse_uri(path)
  path = uri.path
  # Ensure the url we pass into by_destination_path is not a
  # relative path, since it only takes absolute url paths.
  dest_path = url_for(app, path, options_hash.merge(relative: false))
  resource = app.sitemap.by_path(dest_path) || app.sitemap.by_destination_path(dest_path)
  result = if resource
             resource.url
           else
             path = ::File.join(prefix, path)
             resource = app.sitemap.by_path(path)
             if resource
               resource.url
             else
               ::File.join(app.config[:http_prefix], path)
             end
           end
  final_result = ::Addressable::URI.encode(
    relative_path_from_resource(
      options_hash[:current_resource],
      result,
      options_hash[:relative]
    )
  )
  result_uri = ::Middleman::Util.parse_uri(final_result)
  result_uri.query = uri.query
  result_uri.fragment = uri.fragment
  result_uri.to_s
end

def binary?(filename)

def binary?(filename)
  @binary_cache ||= {}
  return @binary_cache[filename] if @binary_cache.key?(filename)
  @binary_cache[filename] = begin
    path = Pathname(filename)
    ext = path.extname
    without_dot = ext.sub('.', '')
    # We hardcode detecting of gzipped SVG files
    if KNOWN_BINARY_FILE_EXTENSIONS.include?(without_dot)
      true
    elsif ::Tilt.registered?(without_dot)
      false
    else
      dot_ext = ext.to_s[0] == '.' ? ext.dup : ".#{ext}"
      mime = ::Rack::Mime.mime_type(dot_ext, nil)
      if mime
        !nonbinary_mime?(mime)
      else
        file_contents_include_binary_bytes?(path.to_s)
      end
    end
  end
end

def collect_extensions(path)

def collect_extensions(path)
  @@extensions_cache ||= {}
  base_name = ::File.basename(path)
  @@extensions_cache[base_name] ||= begin
    result = []
    step_through_extensions(base_name) { |e| result << e } unless base_name.start_with?('.')
    result
  end
end

def contains_frontmatter?(path, frontmatter_delims)

def contains_frontmatter?(path, frontmatter_delims)
  file = ::File.open(path)
  first_line = file.gets
  first_line = file.gets if first_line =~ /\A(?:[^\r\n]*coding:[^\r\n]*\r?\n)/
  file.close
  possible_openers = possible_delim_openers(frontmatter_delims)
  !first_line.nil? && !first_line.match(possible_openers).nil?
rescue EOFError, IOError, ::Errno::ENOENT
  false
end

def current_directory

Returns:
  • (Array) -

Parameters:
  • path (String) -- The glob path.
def current_directory
  result = ::Dir.pwd
  return result unless RUBY_PLATFORM =~ /darwin/
  result.encode('UTF-8', 'UTF-8-MAC')
end

def extract_response_text(response)

def extract_response_text(response)
  # The rack spec states all response bodies must respond to each
  result = ''
  response.each do |part, _|
    result << part
  end
  result
end

def file_contents_include_binary_bytes?(filename)

def file_contents_include_binary_bytes?(filename)
  binary_bytes = [0, 1, 2, 3, 4, 5, 6, 11, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 28, 29, 30, 31]
  s = ::File.read(filename, 4096) || ''
  s.each_byte do |c|
    return true if binary_bytes.include?(c)
  end
  false
end

def find_related_files(app, files)

def find_related_files(app, files)
  return [] if files.empty?
  file_set = ::Set.new(files)
  all_extensions = files.flat_map { |f| collect_extensions(f.to_s) }
  sass_type_aliasing = ['.scss', '.sass']
  erb_type_aliasing = ['.erb', '.haml', '.slim']
  all_extensions |= sass_type_aliasing unless (all_extensions & sass_type_aliasing).empty?
  all_extensions |= erb_type_aliasing unless (all_extensions & erb_type_aliasing).empty?
  all_extensions.uniq!
  app.sitemap.without_ignored.to_a.select do |r|
    if r.file_descriptor
      local_extensions = collect_extensions(r.file_descriptor[:full_path].to_s)
      local_extensions |= sass_type_aliasing unless (local_extensions & sass_type_aliasing).empty?
      local_extensions |= erb_type_aliasing unless (local_extensions & erb_type_aliasing).empty?
      local_extensions.uniq!
      !(all_extensions & local_extensions).empty? && !file_set.include?(r.file_descriptor[:full_path])
    else
      false
    end
  end.map(&:file_descriptor)
end

def full_path(path, app)

def full_path(path, app)
  resource = app.sitemap.by_destination_path(path)
  unless resource
    # Try it with /index.html at the end
    indexed_path = ::File.join(path.sub(%r{/$}, ''), app.config[:index_file])
    resource = app.sitemap.by_destination_path(indexed_path)
  end
  if resource
    '/' + resource.destination_path
  else
    '/' + normalize_path(path)
  end
end

def glob_directory(path)

Returns:
  • (Array) -

Parameters:
  • path (String) -- The glob path.
def glob_directory(path)
  results = ::Dir[path]
  return results unless RUBY_PLATFORM =~ /darwin/
  results.map { |r| r.encode('UTF-8', 'UTF-8-MAC') }
end

def hash_file(path)

def hash_file(path)
  # puts "Read (hash): #{path}"
  if ENV['MIDDLEMAN_SHELL_OUT_TO_GIT_HASH'] == 'true'
    output, status = ::Open3.capture2e("git hash-object #{::Shellwords.escape(path)}")
    raise "Failed to get hash for '#{path}' from git." if status.exitstatus != 0 || output.empty?
    output.strip
  else
    ::Digest::SHA1.file(path).hexdigest
  end
end

def hash_string(data)

def hash_string(data)
  ::Digest::SHA1.hexdigest(data)
end

def instrument(name, payload = {}, &block)

Facade for ActiveSupport/Notification
def instrument(name, payload = {}, &block)
  suffixed_name = /\.middleman$/.match?(name) ? name.dup : "#{name}.middleman"
  ::ActiveSupport::Notifications.instrument(suffixed_name, payload, &block)
end

def nonbinary_mime?(mime)

def nonbinary_mime?(mime)
  if mime.start_with?('text/')
    true
  elsif mime.include?('xml') && !mime.include?('officedocument')
    true
  elsif mime.include?('json')
    true
  elsif mime.include?('javascript')
    true
  else
    false
  end
end

def normalize_path(path)

def normalize_path(path)
  return path unless path.is_a?(String)
  # The tr call works around a bug in Ruby's Unicode handling
  ::URI.decode(path).sub(%r{^/}, '').tr('', '')
end

def parse_uri(uri)

def parse_uri(uri)
  ::Addressable::URI.parse(uri)
end

def path_match(matcher, path)

def path_match(matcher, path)
  if matcher.is_a?(String)
    if matcher.include? '*'
      ::File.fnmatch(matcher, path)
    else
      path == matcher
    end
  elsif matcher.respond_to?(:match)
    !matcher.match(path).nil?
  elsif matcher.respond_to?(:call)
    matcher.call(path)
  else
    ::File.fnmatch(matcher.to_s, path)
  end
end

def possible_delim_openers(frontmatter_delims)

def possible_delim_openers(frontmatter_delims)
  all_possible = frontmatter_delims
                 .values
                 .flatten(1)
                 .map(&:first)
                 .uniq
  /\A#{::Regexp.union(all_possible)}/
end

def read_file(path, bytes = nil)

def read_file(path, bytes = nil)
  # puts "Read: #{path}"
  File.read(path, bytes)
end

def recursively_enhance(obj)

def recursively_enhance(obj)
  if obj.is_a? ::Array
    obj.map { |e| recursively_enhance(e) }
  elsif obj.is_a? ::Hash
    EnhancedHash.new(obj)
  else
    obj
  end
end

def relative_path_from_resource(curr_resource, resource_url, relative)

def relative_path_from_resource(curr_resource, resource_url, relative)
  # Switch to the relative path between resource and the given resource
  # if we've been asked to.
  if relative
    # Output urls relative to the destination path, not the source path
    current_dir = Pathname('/' + curr_resource.destination_path).dirname
    relative_path = Pathname(resource_url).relative_path_from(current_dir).to_s
    # Put back the trailing slash to avoid unnecessary Apache redirects
    relative_path << '/' if resource_url.end_with?('/') && !relative_path.end_with?('/')
    relative_path
  else
    resource_url
  end
end

def remove_templating_extensions(path)

def remove_templating_extensions(path)
  step_through_extensions(path)
end

def rewrite_paths(body, path, exts, app, &_block)

def rewrite_paths(body, path, exts, app, &_block)
  sorted_exts = exts.to_a.sort_by { |ext| -ext.size }
  matcher = /([\'\"\(,]\s*|# sourceMappingURL=)([^\s\'\"\)\(>]+(#{::Regexp.union(sorted_exts)}))/
  url_fn_prefix = 'url('
  body.dup.gsub(matcher) do |match|
    opening_character = Regexp.last_match(1)
    asset_path = Regexp.last_match(2)
    if asset_path.start_with?(url_fn_prefix)
      opening_character << url_fn_prefix
      asset_path = asset_path[url_fn_prefix.length..-1]
    end
    current_resource = app.sitemap.by_destination_path(path)
    begin
      uri = ::Middleman::Util.parse_uri(asset_path)
      if uri.relative? && uri.host.nil? && asset_path !~ /^[^\/].*[a-z]+\.[a-z]+\/.*/
        dest_path = ::Middleman::Util.url_for(app, asset_path, relative: false, current_resource: current_resource)
        resource = app.sitemap.by_destination_path(dest_path)
        if resource && (result = yield(asset_path))
          "#{opening_character}#{result}"
        else
          match
        end
      else
        match
      end
    rescue ::Addressable::URI::InvalidURIError
      match
    end
  end
end

def should_ignore?(validator, value)

def should_ignore?(validator, value)
  if validator.is_a? Regexp
    # Treat as Regexp
    !validator.match(value).nil?
  elsif validator.respond_to? :call
    # Treat as proc
    validator.call(value)
  elsif validator.is_a? String
    # Treat as glob
    File.fnmatch(value, validator)
  else
    # If some unknown thing, don't ignore
    false
  end
end

def static_file?(path, frontmatter_delims)

def static_file?(path, frontmatter_delims)
  path = Pathname(path)
  ext = path.extname
  without_dot = ext.sub('.', '')
  if KNOWN_NON_STATIC_FILE_EXTENSIONS.include?(without_dot) || contains_frontmatter?(path, frontmatter_delims)
    false
  else
    !::Tilt.registered?(without_dot)
  end
end

def step_through_extensions(path)

def step_through_extensions(path)
  while (ext = File.extname(path))
    break if ext.empty? || !::Middleman::Util.tilt_class(ext)
    yield ext if block_given?
    # Strip templating extensions as long as Tilt knows them
    path = path[0..-(ext.length + 1)]
  end
  yield ::File.extname(path) if block_given?
  path
end

def strip_leading_slash(path)

def strip_leading_slash(path)
  path.sub(%r{^/}, '')
end

def tilt_class(path)

def tilt_class(path)
  ::Tilt[path]
end

def url_for(app, path_or_resource, options_hash = ::Middleman::EMPTY_HASH)

def url_for(app, path_or_resource, options_hash = ::Middleman::EMPTY_HASH)
  if path_or_resource.is_a?(String) || path_or_resource.is_a?(Symbol)
    r = app.sitemap.by_page_id(path_or_resource)
    path_or_resource = r || path_or_resource.to_s
  end
  # Handle Resources and other things which define their own url method
  url = if path_or_resource.respond_to?(:url)
          path_or_resource.url
        else
          path_or_resource.dup
        end
  # Try to parse URL
  begin
    uri = ::Middleman::Util.parse_uri(url)
  rescue ::Addressable::URI::InvalidURIError
    # Nothing we can do with it, it's not really a URI
    return url
  end
  relative = options_hash[:relative]
  raise "Can't use the relative option with an external URL" if relative && uri.host
  # Allow people to turn on relative paths for all links with
  # set :relative_links, true
  # but still override on a case by case basis with the :relative parameter.
  effective_relative = relative || false
  effective_relative = true if relative.nil? && app.config[:relative_links]
  # Try to find a sitemap resource corresponding to the desired path
  this_resource = options_hash[:current_resource]
  if path_or_resource.is_a?(::Middleman::Sitemap::Resource)
    resource = path_or_resource
    resource_url = url
  elsif this_resource && uri.path && !uri.host
    # Handle relative urls
    url_path = Pathname(uri.path)
    current_source_dir = Pathname('/' + this_resource.path).dirname
    url_path = current_source_dir.join(url_path) if url_path.relative?
    resource = app.sitemap.by_path(url_path.to_s)
    if resource
      resource_url = resource.url
    else
      # Try to find a resource relative to destination paths
      url_path = Pathname(uri.path)
      current_source_dir = Pathname('/' + this_resource.destination_path).dirname
      url_path = current_source_dir.join(url_path) if url_path.relative?
      resource = app.sitemap.by_destination_path(url_path.to_s)
      resource_url = resource.url if resource
    end
  elsif options_hash[:find_resource] && uri.path && !uri.host
    resource = app.sitemap.by_path(uri.path)
    resource_url = resource.url if resource
  end
  if resource
    uri.path = if this_resource
                 ::Addressable::URI.encode(
                   relative_path_from_resource(
                     this_resource,
                     resource_url,
                     effective_relative
                   )
                 )
               else
                 resource_url
               end
  end
  # Support a :query option that can be a string or hash
  query = options_hash[:query]
  if query
    uri.query = query.respond_to?(:to_param) ? query.to_param : query.to_s
  end
  # Support a :fragment or :anchor option just like Padrino
  fragment = options_hash[:anchor] || options_hash[:fragment]
  uri.fragment = fragment.to_s if fragment
  # Finally make the URL back into a string
  uri.to_s
end