class Confinement::Compiler

Constants

PARCEL_FILES_OUTPUT_REGEX
PARCEL_FILE_OUTPUT_REGEX

Public Class Methods

new(config) click to toggle source
# File lib/confinement.rb, line 633
def initialize(config)
  @config = config
  @logger = config.logger
end

Public Instance Methods

compile_assets(site) click to toggle source
# File lib/confinement.rb, line 647
def compile_assets(site)
  @logger.info { "compiling assets" }
  create_destination_directory
  asset_files = site.asset_blobs.send(:lookup)
  asset_paths = asset_files.values

  command = [
    "yarn",
    "run",
    "parcel",
    "build",
    "--no-cache",
    "--dist-dir", @config.compiler.output_assets_path.to_s,
    "--public-url", @config.compiler.output_assets_path.basename.to_s,
    *asset_paths.select(&:entrypoint?).map(&:input_path).map(&:to_s)
  ]

  @logger.debug { "running: #{command.join(" ")}" }

  out, status = Open3.capture2(*command)

  if !status.success?
    @logger.fatal { "asset compilation failed" }
    raise "Asset compilation failed"
  end

  matches = PARCEL_FILES_OUTPUT_REGEX.match(out)[1]

  if !matches
    @logger.fatal { "asset compilation ouptut parsing failed" }
    raise "Asset compilation output parsing failed"
  end

  processed_file_paths = matches.split("\n\n")

  processed_file_paths.map do |file|
    output_file, *input_files = file.strip.split(/\n(?:└|├)── /)

    output_path = @config.root.concat(output_file[PARCEL_FILE_OUTPUT_REGEX, 1])

    input_files.each do |input_file|
      input_path = @config.root.concat(input_file[PARCEL_FILE_OUTPUT_REGEX, 1])

      if !asset_files.key?(input_path)
        next
      end

      url_path = output_path.relative_path_from(@config.compiler.output_root_path)
      @logger.debug { "processesd asset: #{input_path}, #{url_path}, #{output_path}" }
      asset_files[input_path].url_path = url_path.to_s
      asset_files[input_path].output_path = output_path
      asset_files[input_path].body = output_path.read
    end
  end

  @logger.info { "finished compiling assets" }
end
compile_contents(site) click to toggle source
# File lib/confinement.rb, line 705
def compile_contents(site)
  @logger.info { "compiling contents" }
  create_destination_directory
  contents = site.route_identifiers.send(:lookup).values
  contents.each do |content|
    compile_content(site, content)
  end
  @logger.info { "finished compiling contents" }
end
compile_everything(site) click to toggle source
# File lib/confinement.rb, line 638
def compile_everything(site)
  # Assets first since it's almost always a dependency of contents
  compile_assets(site)
  compile_contents(site)
end
partial_compilation_dirty?(before:, after:) click to toggle source
# File lib/confinement.rb, line 715
def partial_compilation_dirty?(before:, after:)
  return true if !before.key?(:asset_blobs)
  return true if !after.key?(:asset_blobs)

  before_assets = before[:asset_blobs].send(:lookup)
  after_assets = after[:asset_blobs].send(:lookup)

  return true if before_assets.keys.sort != after_assets.keys.sort
  return true if before_assets.any? { |k, v| v.input_path != after_assets[k].input_path }
  return true if before_assets.any? { |k, v| v.entrypoint? != after_assets[k].entrypoint? }

  false
end

Private Instance Methods

compile_content(site, content) click to toggle source
# File lib/confinement.rb, line 745
def compile_content(site, content)
  @logger.debug { "compiling content: #{content.input_path}, #{content.renderers}" }
  view_context = Rendering::ViewContext.new(
    routes: site.route_identifiers,
    layouts: site.layout_blobs,
    assets: site.asset_blobs,
    contents: site.content_blobs,
    locals: content.locals,
    frontmatter: content.frontmatter
  )

  site.view_context_helpers.each do |helper|
    view_context.extend(helper)
  end

  rendered_body = view_context.render(content, layout: content.layout) || ""

  content.output_path =
    if content.url_path[-1] == "/"
      @config.compiler.output_root_path.concat(content.url_path, @config.compiler.output_directory_index)
    else
      @config.compiler.output_root_path.concat(content.url_path)
    end

  if content.output_path.exist?
    if content.output_path.read == rendered_body
      return
    end
  end

  if !@config.compiler.output_root_path.include?(content.output_path)
    return
  end

  if !content.output_path.dirname.directory?
    content.output_path.dirname.mkpath
  end

  content.output_path.write(rendered_body)

  nil
end
create_destination_directory() click to toggle source
# File lib/confinement.rb, line 731
def create_destination_directory
  destination = @config.compiler.output_root_path

  if destination.exist?
    return
  end

  if !destination.dirname.exist?
    raise Error::PathDoesNotExist, "Destination's parent path does not exist: #{destination.dirname}"
  end

  destination.mkpath
end