lib/jekyll/assets/plugins/srcmap/writer.rb
# Frozen-string-literal: true
# Copyright: 2012 - 2020 - ISC License
# Author: Jordon Bedwell
# Encoding: utf-8
module Jekyll
module Assets
module Plugins
module SrcMap
class Writer < Sprockets::Exporters::Base
alias env environment
def skip?(_)
!env.asset_config[:source_maps] ||
!asset.metadata[:map]
end
# --
def call
clean_file!
clean_sources!
write_map!
write_src!
end
# --
# Provides our custom manifest key, full of files.
# @note We push everything from the file we are writing to the maps.
# @return [Array<String>]
# --
def files
@files ||= begin
key = "sourceMapFiles"
out = env.manifest.data[key] ||= []
unless Manifest.keep_keys.include?(key)
Manifest.keep_keys << key
end
out
end
end
# --
# @return [HashWithIndifferentAccess]
# @note do not modify the original map.
# Provides a modifible SourceMap
# --
private
def map
@map ||= asset.metadata[:map]
.with_indifferent_access
end
# --
# @return [HashWithIndifferentAccess]
# @note this is frozen so you can't modify.
# Provides an unmodifiable SourceMap
# --
private
def original_map
@original_map ||= asset.metadata[:map]
.with_indifferent_access.freeze
end
# --
# @note something like _assets/*
# Makes sure that the name sits in the asset path.
# @return [String]
# --
private
def clean_file!
map[:file] = base.join(map[:file]).to_s
end
# --
private
def clean_sources!
if map[:sources]
then map[:sources] = map[:sources].map do |v|
base.join(strip_src(v))
end
else
map[:sections].each do |v|
v[:map][:sources] = v[:map][:sources].map do |vv|
base.join(strip_src(vv))
end
end
end
map
end
# --
private
def strip_src(path)
path = Pathutil.new(path)
base = path.basename.gsub(%r!\.source!, "")
return path.dirname.join(base).to_s unless path.dirname == "."
base.to_s if path.dirname == "."
end
# --
# @note we shim this on name.
# Privates the base directory in the source.
# @return [String]
# --
private
def base
Pathutil.new(asset.filename.sub(env.jekyll
.in_source_dir + "/", "")).dirname
end
# --
# rubocop:disable Layout/BlockEndNewline
# rubocop:disable Layout/MultilineBlockLayout
# rubocop:disable Style/BlockDelimiters
# --
private
def map_files
return original_map[:sources] if original_map.key?(:sources)
original_map[:sections].map { |v| v[:map][:sources] \
if v.key?(:map) }.flatten.compact
end
# --
# rubocop:enable Layout/BlockEndNewline
# rubocop:enable Layout/MultilineBlockLayout
# rubocop:enable Style/BlockDelimiters
# --
private
def write_map!
path = SrcMap.map_path(asset: asset, env: env)
write(env.in_dest_dir(path)) do |f|
files.push(path)
f.write(map.to_json)
files.uniq!
end
end
# --
private
def strip_base(asset)
return asset if asset.is_a?(Sprockets::Asset)
asset.sub(base + "/", "")
end
# --
private
def write_src!
[asset_path, map_files].flatten.compact.uniq.each do |v|
next unless (v = env.find_asset(strip_base(v), pipeline: :source))
path = map_path(v.filename)
write(environment.in_dest_dir(path)) do |f|
f.write(v.source)
files.push(path.to_s)
.uniq!
end
end
end
# --
private
def asset_path
base.join(env.strip_paths(@asset.filename)).to_s
end
# --
private
def map_path(file)
asset = base.join(env.strip_paths(file))
SrcMap.path({
asset: asset, env: env
})
end
end
# --
Hook.register :env, :after_init, priority: 3 do
register_exporter("*/*", Writer)
end
end
end
end
end