# frozen_string_literal: true require_relative "util" module Metanorma # Metanorma collection's manifest class CollectionManifest # @return [Metanorma::Collection] attr_reader :collection # @param level [String] # @param title [String, nil] # @param docref [ArrayString}>] # @param manifest [Array] def initialize(level, title = nil, docref = [], manifest = []) @level = level @title = title @docref = docref @manifest = manifest @disambig = Util::DisambigFiles.new end class << self # @param mnf [Nokogiri::XML::Element] # @return [Metanorma::CollectionManifest] def from_yaml(mnf) manifest = RelatonBib::HashConverter.array(mnf["manifest"]).map do |m| from_yaml m end docref = RelatonBib::HashConverter.array mnf["docref"] new(mnf["level"], mnf["title"], docref, manifest) end # @param mnf [Nokogiri::XML::Element] # @return [Metanorma::CollectionManifest] def from_xml(mnf) level = mnf.at("level").text title = mnf.at("title")&.text manifest = mnf.xpath("xmlns:manifest").map { |m| from_xml(m) } new(level, title, parse_docref(mnf), manifest) end private # @param mnf [Nokogiri::XML::Element] # @return [Hash{String=>String}] def parse_docref(mnf) mnf.xpath("xmlns:docref").map do |dr| h = { "identifier" => dr.at("identifier").children.to_xml } dr[:fileref] and h["fileref"] = dr[:fileref] h["attachment"] = dr[:attachment] if dr[:attachment] h["sectionsplit"] = dr[:sectionsplit] if dr[:sectionsplit] h["presentation-xml"] = dr[:presentationxml] if dr[:presentationxml] h end end end # @param col [Metanorma::Collection] def collection=(col) @collection = col @manifest.each { |mnf| mnf.collection = col } end # @param dir [String] path to collection # @return [Hash] def documents(dir = "") docs = @docref.each_with_object({}) do |dr, m| next m unless dr["fileref"] m[dr["identifier"]] = Document.parse_file( File.join(dir, dr["fileref"]), dr["attachment"], dr["identifier"] ) m end @manifest.reduce(docs) { |mem, mnf| mem.merge mnf.documents(dir) } end # @param builder [Nokogiri::XML::Builder] def to_xml(builder) builder.manifest do |b| b.level @level b.title @title if @title docref_to_xml b @manifest.each { |m| m.to_xml b } end end # @return [ArrayString}>] def docrefs return @docrefs if @docrefs drfs = @docref.map { |dr| dr } @manifest.reduce(drfs) { |mem, mnf| mem + mnf.docrefs } end def docref_by_id(docid) refs = docrefs dref = refs.detect { |k| k["identifier"] == docid } dref || docrefs.detect { |k| /^#{k["identifier"]}/ =~ docid } end private # @param builder [Nokogiri::XML::Builder] def docref_to_xml(builder) @disambig = Util::DisambigFiles.new @docref.each do |dr| drf = builder.docref do |b| b.identifier do |i| i << dr["identifier"] end end docref_to_xml_attrs(drf, dr) end end def docref_to_xml_attrs(elem, docref) elem[:fileref] = @disambig.source2dest_filename(docref["fileref"]) elem[:attachment] = docref["attachment"] if docref["attachment"] elem[:sectionsplit] = docref["sectionsplit"] if docref["sectionsplit"] elem[:presentationxml] = "true" if docref["presentation-xml"] && docref["presentation-xml"] == "true" || docref["presentation-xml"] == true if collection.directives.include?("documents-inline") id = collection.documents.find_index do |k, _| k == docref["identifier"] end elem[:id] = format("doc%09d", index: id) end end end end