# frozen_string_literal: true require 'listen' require 'pathname' module Archival Change = Struct.new(:path, :type) def listen(config = {}) @config = Config.new(config.merge(dev_mode: true)) builder = Builder.new(@config) Logger.benchmark('built') do builder.write_all end ignore = %r{/dist/} listener = Listen.to(@config.root, ignore: ignore) do |modified, added, removed| changes = { pages: [], objects: [], assets: [], layout: [], config: [] } add_change = lambda { |file, type| c_type = change_type(file) changes[c_type] << change(file, type) unless c_type == :none } added.each do |file| add_change.call(file, :added) end modified.each do |file| add_change.call(file, :modified) end removed.each do |file| add_change.call(file, :removed) end @server.refresh_client if rebuild?(builder, changes) end listener.start serve_helpers end module_function :listen class << self private def child?(parent, child) path = Pathname.new(child) return true if path.fnmatch?(File.join(parent, '**')) false end def change(file, type) c = Change.new c.path = Pathname.new(file).relative_path_from(@config.root) c.type = type c end def change_type(file) # a page was modified, rebuild the pages. return :pages if child?(File.join(@config.root, @config.pages_dir), file) # an object was modified, rebuild the objects. return :objects if child?(File.join(@config.root, @config.objects_dir), file) # an asset was changed, which just means to copy or delete it @config.assets_dirs.each do |dir| return :assets if child?(File.join(@config.root, dir), file) end # a static file was changed - copy or delete those too. return :assets if child?(File.join(@config.root, @config.static_dir), file) # other special files return :layout if child?(File.join(@config.root, 'layout'), file) return :config if ['manifest.toml', 'objects.toml'].include? File.basename(file) :none end def rebuild?(builder, changes) return false if changes.values.all?(&:empty?) Logger.benchmark('rebuilt') do if changes[:pages].length || changes[:objects].length builder.update_pages(changes[:pages], changes[:objects]) end builder.update_assets(changes[:assets]) if changes[:assets].length if changes[:assets].length || changes[:layouts] || changes[:config] # TODO: optimization: this could operate on the known subset of # changes instead... builder.full_rebuild end builder.write_all end true end def serve_helpers @server = HelperServer.new(@config.helper_port, @config.build_dir) @server.start end end end