require "json" require "stepmod/utils/smrl_description_converter" require "stepmod/utils/smrl_resource_converter" require "stepmod/utils/converters/express_note" require "stepmod/utils/converters/express_example" require "stepmod/utils/converters/express_figure" require "stepmod/utils/converters/express_table" module Stepmod module Utils class StepmodFileAnnotator attr_reader :express_file, :resource_docs_cache_file, :stepmod_dir # @param express_file [String] path to the exp file needed to annotate # @param resource_docs_cache_file [String] output of ./stepmod-build-resource-docs-cache def initialize(express_file:, resource_docs_cache_file:, stepmod_dir: nil) @express_file = express_file @resource_docs_cache_file = resource_docs_cache_file @stepmod_dir = stepmod_dir || Dir.pwd end def call match = File.basename(express_file).match('^(arm|mim|bom)\.exp$') descriptions_base = match ? "#{match.captures[0]}_descriptions.xml" : "descriptions.xml" descriptions_file = File.join(File.dirname(express_file), descriptions_base) output_express = File.read(express_file) resource_docs_cache = JSON.parse(File.read(resource_docs_cache_file)) if File.exists?(descriptions_file) descriptions = Nokogiri::XML(File.read(descriptions_file)).root added_resource_descriptions = {} descriptions.xpath("ext_description").each do |description| # Add base resource from linked path if exists, eg "language_schema.language.wr:WR1" -> "language_schema" base_linked = description["linkend"].to_s.split(".").first if added_resource_descriptions[base_linked].nil? base_reource_doc_dir = resource_docs_cache[description["linkend"].to_s.split(".").first] if base_reource_doc_dir output_express << convert_from_resource_file( base_reource_doc_dir, stepmod_dir, base_linked, descriptions_file ) end added_resource_descriptions[base_linked] = true end resource_docs_dir = resource_docs_cache[description["linkend"]] # Convert content description # when a schema description is available from resource.xml and also descriptions.xml, the description from resource.xml is only used. # https://github.com/metanorma/annotated-express/issues/32#issuecomment-792609078 if description.text.strip.length.positive? && resource_docs_dir.nil? output_express << convert_from_description_text( descriptions_file, description ) end # Add converted description from exact linked path if resource_docs_dir && added_resource_descriptions[description["linkend"]].nil? output_express << convert_from_resource_file(resource_docs_dir, stepmod_dir, description["linkend"], descriptions_file) added_resource_descriptions[description["linkend"]] = true end end end output_express rescue StandardError => e puts "[ERROR]!!! #{e.message}" puts e.backtrace end private def convert_from_description_text(descriptions_file, description) Dir.chdir(File.dirname(descriptions_file)) do wrapper = "#{description}" notes = description.xpath("note") examples = description.xpath("example") figures = description.xpath("figure") tables = description.xpath("table") converted_description = <<~DESCRIPTION #{Stepmod::Utils::SmrlDescriptionConverter.convert(wrapper, no_notes_examples: true)} DESCRIPTION if description["linkend"].nil? raise StandardError.new("[stepmod-file-annotator] ERROR: no linkend for #{descriptions_file}!") end converted_figures = figures.map do |figure| Stepmod::Utils::Converters::ExpressFigure .new .convert(figure, schema_and_entity: description["linkend"]) end.join converted_tables = tables.map do |table| Stepmod::Utils::Converters::ExpressTable .new .convert(table, schema_and_entity: description["linkend"]) end.join converted_notes = notes.map do |note| Stepmod::Utils::Converters::ExpressNote .new .convert(note, schema_and_entity: description["linkend"]) end.join converted_examples = examples.map do |example| Stepmod::Utils::Converters::ExpressExample .new .convert(example, schema_and_entity: description["linkend"]) end.join [ converted_description, converted_figures, converted_tables, converted_examples, converted_notes, ].join("") end end def convert_from_resource_file(resource_docs_dir, stepmod_dir, linked, descriptions_file) resource_docs_file = File.join(stepmod_dir, "data/resource_docs", resource_docs_dir, "resource.xml") # puts(resource_docs_file) resource_docs = Nokogiri::XML(File.read(resource_docs_file)).root schema = resource_docs.xpath("schema[@name='#{linked}']") Dir.chdir(File.dirname(descriptions_file)) do wrapper = "#{schema}" "\n" + Stepmod::Utils::SmrlResourceConverter.convert( wrapper, { no_notes_examples: false, schema_and_entity: linked } ) end end end end end