# frozen_string_literal: true require "json" require "time" # Internal: Value object with information about the last build. ViteRuby::Build = Struct.new(:success, :timestamp, :vite_ruby, :digest, :current_digest, :last_build_path, :errors, keyword_init: true) do class << self # Internal: Combines information from a previous build with the current digest. def from_previous(last_build_path, current_digest) new( **parse_metadata(last_build_path), current_digest: current_digest, last_build_path: last_build_path, ) end private # Internal: Reads metadata recorded on the last build, if it exists. def parse_metadata(pathname) return default_metadata unless pathname.exist? JSON.parse(pathname.read.to_s).transform_keys(&:to_sym).slice(*members) rescue JSON::JSONError, Errno::ENOENT, Errno::ENOTDIR default_metadata end # Internal: To make it evident that there's no last build in error messages. def default_metadata {timestamp: "never", digest: "none"} end end # Internal: A build is considered stale when watched files have changed since # the last build, or when a certain time has ellapsed in case of failure. def stale? digest != current_digest || retry_failed? || vite_ruby != ViteRuby::VERSION end # Internal: A build is considered fresh if watched files have not changed, or # the last failed build happened recently. def fresh? !stale? end # Internal: To avoid cascading build failures, if the last build failed and it # happened within a short time window, a new build should not be triggered. def retry_failed? !success && Time.parse(timestamp) + 3 < Time.now # 3 seconds rescue ArgumentError true end # Internal: Returns a new build with the specified result. def with_result(**attrs) self.class.new( **attrs, timestamp: Time.now.strftime("%F %T"), vite_ruby: ViteRuby::VERSION, digest: current_digest, current_digest: current_digest, last_build_path: last_build_path, ) end # Internal: Writes the result of the new build to a local file. def write_to_cache last_build_path.write to_json end # Internal: Returns a JSON string with the metadata of the build. def to_json(*_args) JSON.pretty_generate( success: success, errors: errors, timestamp: timestamp, vite_ruby: vite_ruby, digest: digest, ) end end