metanorma-standoc 1.3.24 → 1.3.29
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.github/workflows/macos.yml +10 -1
- data/.github/workflows/ubuntu.yml +13 -3
- data/.github/workflows/windows.yml +8 -1
- data/lib/asciidoctor/standoc/base.rb +29 -11
- data/lib/asciidoctor/standoc/biblio.rng +75 -28
- data/lib/asciidoctor/standoc/blocks.rb +12 -5
- data/lib/asciidoctor/standoc/cleanup.rb +17 -8
- data/lib/asciidoctor/standoc/cleanup_block.rb +3 -0
- data/lib/asciidoctor/standoc/cleanup_boilerplate.rb +1 -3
- data/lib/asciidoctor/standoc/cleanup_inline.rb +3 -0
- data/lib/asciidoctor/standoc/cleanup_ref.rb +15 -6
- data/lib/asciidoctor/standoc/cleanup_section.rb +36 -8
- data/lib/asciidoctor/standoc/front.rb +5 -3
- data/lib/asciidoctor/standoc/inline.rb +43 -18
- data/lib/asciidoctor/standoc/isodoc.rng +31 -1
- data/lib/asciidoctor/standoc/macros.rb +2 -1
- data/lib/asciidoctor/standoc/macros_yaml2text.rb +142 -0
- data/lib/asciidoctor/standoc/ref.rb +6 -4
- data/lib/asciidoctor/standoc/section.rb +41 -9
- data/lib/asciidoctor/standoc/utils.rb +2 -11
- data/lib/asciidoctor/standoc/validate.rb +8 -2
- data/lib/asciidoctor/standoc/validate_section.rb +1 -3
- data/lib/metanorma/standoc/latexml_requirement.rb +14 -12
- data/lib/metanorma/standoc/version.rb +1 -1
- data/metanorma-standoc.gemspec +2 -2
- data/spec/asciidoctor-standoc/base_spec.rb +8 -0
- data/spec/asciidoctor-standoc/blocks_spec.rb +74 -2
- data/spec/asciidoctor-standoc/cleanup_spec.rb +75 -28
- data/spec/asciidoctor-standoc/inline_spec.rb +4 -3
- data/spec/asciidoctor-standoc/macros_spec.rb +9 -8
- data/spec/asciidoctor-standoc/macros_yaml2text_spec.rb +564 -0
- data/spec/asciidoctor-standoc/refs_dl_spec.rb +91 -3
- data/spec/asciidoctor-standoc/refs_spec.rb +272 -166
- data/spec/asciidoctor-standoc/section_spec.rb +197 -6
- data/spec/asciidoctor-standoc/validate_spec.rb +67 -2
- data/spec/assets/codes.yml +695 -0
- data/spec/assets/xref_error.adoc +7 -0
- data/spec/examples/codes_table.html +3174 -0
- data/spec/metanorma/processor_spec.rb +2 -2
- data/spec/spec_helper.rb +1 -0
- data/spec/vcr_cassettes/dated_iso_ref_joint_iso_iec.yml +77 -271
- data/spec/vcr_cassettes/isobib_get_123.yml +36 -82
- data/spec/vcr_cassettes/isobib_get_123_2001.yml +17 -40
- data/spec/vcr_cassettes/isobib_get_124.yml +19 -101
- data/spec/vcr_cassettes/rfcbib_get_rfc8341.yml +8 -8
- data/spec/vcr_cassettes/separates_iev_citations_by_top_level_clause.yml +34 -34
- metadata +11 -6
| @@ -131,10 +131,13 @@ module Asciidoctor | |
| 131 131 | 
             
                  def note_cleanup(xmldoc)
         | 
| 132 132 | 
             
                    q = "//note[following-sibling::*[not(local-name() = 'note')]]"
         | 
| 133 133 | 
             
                    xmldoc.xpath(q).each do |n|
         | 
| 134 | 
            +
                      next if n["keep-separate"] == "true"
         | 
| 134 135 | 
             
                      next unless n.ancestors("table").empty?
         | 
| 135 136 | 
             
                      prev = n.previous_element || next
         | 
| 136 137 | 
             
                      n.parent = prev if ELEMS_ALLOW_NOTES.include? prev.name
         | 
| 137 138 | 
             
                    end
         | 
| 139 | 
            +
                    xmldoc.xpath("//note[@keep-separate]").each { |n| n.delete("keep-separate") }
         | 
| 140 | 
            +
                    xmldoc.xpath("//termnote[@keep-separate]").each { |n| n.delete("keep-separate") }
         | 
| 138 141 | 
             
                  end
         | 
| 139 142 |  | 
| 140 143 | 
             
                  def requirement_cleanup(x)
         | 
| @@ -18,7 +18,6 @@ module Asciidoctor | |
| 18 18 | 
             
                    source.each do |s|
         | 
| 19 19 | 
             
                      @anchors[s["bibitemid"]] or
         | 
| 20 20 | 
             
                        @log.add("Crossreferences", nil, "term source #{s['bibitemid']} not referenced")
         | 
| 21 | 
            -
                                  #warn "term source #{s['bibitemid']} not referenced" 
         | 
| 22 21 | 
             
                    end
         | 
| 23 22 | 
             
                    if source.empty? && term.nil?
         | 
| 24 23 | 
             
                      div.next = @no_terms_boilerplate
         | 
| @@ -49,8 +48,7 @@ module Asciidoctor | |
| 49 48 | 
             
                  TERM_CLAUSE = "//sections/terms | "\
         | 
| 50 49 | 
             
                    "//sections/clause[descendant::terms]".freeze
         | 
| 51 50 |  | 
| 52 | 
            -
                  NORM_REF = "//bibliography/references[ | 
| 53 | 
            -
                    "title = 'Normative references']".freeze
         | 
| 51 | 
            +
                  NORM_REF = "//bibliography/references[@normative = 'true']".freeze
         | 
| 54 52 |  | 
| 55 53 | 
             
                  def boilerplate_isodoc(xmldoc)
         | 
| 56 54 | 
             
                    x = xmldoc.dup
         | 
| @@ -90,6 +90,9 @@ module Asciidoctor | |
| 90 90 | 
             
                  end
         | 
| 91 91 |  | 
| 92 92 | 
             
                  def origin_cleanup(xmldoc)
         | 
| 93 | 
            +
                    xmldoc.xpath("//origin/concept[termref]").each do |x|
         | 
| 94 | 
            +
                      x.replace(x.children)
         | 
| 95 | 
            +
                    end
         | 
| 93 96 | 
             
                    xmldoc.xpath("//origin").each do |x|
         | 
| 94 97 | 
             
                      x["citeas"] = @anchors&.dig(x["bibitemid"], :xref) ||
         | 
| 95 98 | 
             
                        @log.add("Crossreferences", x,
         | 
| @@ -5,7 +5,7 @@ module Asciidoctor | |
| 5 5 | 
             
              module Standoc
         | 
| 6 6 | 
             
                module Cleanup
         | 
| 7 7 | 
             
                  def biblio_reorder(xmldoc)
         | 
| 8 | 
            -
                    xmldoc.xpath("//references[ | 
| 8 | 
            +
                    xmldoc.xpath("//references[@normative = 'false']").each do |r|
         | 
| 9 9 | 
             
                      biblio_reorder1(r)
         | 
| 10 10 | 
             
                    end
         | 
| 11 11 | 
             
                  end
         | 
| @@ -49,8 +49,8 @@ module Asciidoctor | |
| 49 49 | 
             
                  # consecutively, but that standards codes are preserved as is:
         | 
| 50 50 | 
             
                  # only numeric references are renumbered
         | 
| 51 51 | 
             
                  def biblio_renumber(xmldoc)
         | 
| 52 | 
            -
                    r = xmldoc.at("//references[ | 
| 53 | 
            -
                                  "//clause[ | 
| 52 | 
            +
                    r = xmldoc.at("//references[@normative = 'false'] | "\
         | 
| 53 | 
            +
                                  "//clause[.//references[@normative = 'false']]") or return
         | 
| 54 54 | 
             
                    r.xpath(".//bibitem[not(ancestor::bibitem)]").each_with_index do |b, i|
         | 
| 55 55 | 
             
                      next unless docid = b.at("./docidentifier[@type = 'metanorma']")
         | 
| 56 56 | 
             
                      next unless  /^\[\d+\]$/.match(docid.text)
         | 
| @@ -67,18 +67,23 @@ module Asciidoctor | |
| 67 67 | 
             
                  end
         | 
| 68 68 |  | 
| 69 69 | 
             
                  def normref_cleanup(xmldoc)
         | 
| 70 | 
            -
                    r = xmldoc.at(NORM_REF) || return
         | 
| 71 | 
            -
                     | 
| 72 | 
            -
                    preface = r.xpath("./title/following-sibling::*") &
         | 
| 70 | 
            +
                    r = xmldoc.at(self.class::NORM_REF) || return
         | 
| 71 | 
            +
                    preface = r.xpath("./title/following-sibling::*") & # intersection
         | 
| 73 72 | 
             
                      r.xpath("./bibitem[1]/preceding-sibling::*")
         | 
| 74 73 | 
             
                    preface.each { |n| n.remove }
         | 
| 75 74 | 
             
                  end
         | 
| 76 75 |  | 
| 77 76 | 
             
                  def biblio_cleanup(xmldoc)
         | 
| 78 77 | 
             
                    biblio_reorder(xmldoc)
         | 
| 78 | 
            +
                    biblio_nested(xmldoc)
         | 
| 79 79 | 
             
                    biblio_renumber(xmldoc)
         | 
| 80 | 
            +
                  end
         | 
| 81 | 
            +
             | 
| 82 | 
            +
                  def biblio_nested(xmldoc)
         | 
| 80 83 | 
             
                    xmldoc.xpath("//references[references]").each do |t|
         | 
| 81 84 | 
             
                      t.name = "clause"
         | 
| 85 | 
            +
                      t.xpath("./references").each { |r| r["normative"] = t["normative"] }
         | 
| 86 | 
            +
                      t.delete("normative")
         | 
| 82 87 | 
             
                    end
         | 
| 83 88 | 
             
                  end
         | 
| 84 89 |  | 
| @@ -187,6 +192,10 @@ module Asciidoctor | |
| 187 192 | 
             
                    end
         | 
| 188 193 | 
             
                    bib
         | 
| 189 194 | 
             
                  end
         | 
| 195 | 
            +
             | 
| 196 | 
            +
                  def fetch_termbase(termbase, id)
         | 
| 197 | 
            +
                    ""
         | 
| 198 | 
            +
                  end
         | 
| 190 199 | 
             
                end
         | 
| 191 200 | 
             
              end
         | 
| 192 201 | 
             
            end
         | 
| @@ -11,7 +11,7 @@ module Asciidoctor | |
| 11 11 | 
             
                module Cleanup
         | 
| 12 12 | 
             
                  def make_preface(x, s)
         | 
| 13 13 | 
             
                    if x.at("//foreword | //introduction | //acknowledgements | "\
         | 
| 14 | 
            -
                        " | 
| 14 | 
            +
                        "//*[@preface]")
         | 
| 15 15 | 
             
                      preface = s.add_previous_sibling("<preface/>").first
         | 
| 16 16 | 
             
                      f = x.at("//foreword") and preface.add_child f.remove
         | 
| 17 17 | 
             
                      f = x.at("//introduction") and preface.add_child f.remove
         | 
| @@ -22,7 +22,7 @@ module Asciidoctor | |
| 22 22 | 
             
                  end
         | 
| 23 23 |  | 
| 24 24 | 
             
                  def move_clauses_into_preface(x, preface)
         | 
| 25 | 
            -
                    x.xpath(" | 
| 25 | 
            +
                    x.xpath("//*[@preface]").each do |c|
         | 
| 26 26 | 
             
                      c.delete("preface")
         | 
| 27 27 | 
             
                      preface.add_child c.remove
         | 
| 28 28 | 
             
                    end
         | 
| @@ -66,9 +66,22 @@ module Asciidoctor | |
| 66 66 | 
             
                  def sections_order_cleanup(x)
         | 
| 67 67 | 
             
                    s = x.at("//sections")
         | 
| 68 68 | 
             
                    make_preface(x, s)
         | 
| 69 | 
            +
                    make_annexes(x)
         | 
| 69 70 | 
             
                    make_bibliography(x, s)
         | 
| 70 71 | 
             
                    x.xpath("//sections/annex").reverse_each { |r| s.next = r.remove }
         | 
| 71 72 | 
             
                  end
         | 
| 73 | 
            +
                  
         | 
| 74 | 
            +
                  def make_annexes(x)
         | 
| 75 | 
            +
                    x.xpath("//*[@annex]").each do |y|
         | 
| 76 | 
            +
                      y.delete("annex")
         | 
| 77 | 
            +
                      next if y.name == "annex" || !y.ancestors("annex").empty?
         | 
| 78 | 
            +
                      y.wrap("<annex/>")
         | 
| 79 | 
            +
                      y.parent["id"] = "_#{UUIDTools::UUID.random_create}"
         | 
| 80 | 
            +
                      y.parent["obligation"] = y["obligation"]
         | 
| 81 | 
            +
                      y.parent["language"] = y["language"]
         | 
| 82 | 
            +
                      y.parent["script"] = y["script"]
         | 
| 83 | 
            +
                    end
         | 
| 84 | 
            +
                  end
         | 
| 72 85 |  | 
| 73 86 | 
             
                  def maxlevel(x)
         | 
| 74 87 | 
             
                    max = 5
         | 
| @@ -117,7 +130,7 @@ module Asciidoctor | |
| 117 130 | 
             
                  end
         | 
| 118 131 |  | 
| 119 132 | 
             
                  def obligations_cleanup_inherit(x)
         | 
| 120 | 
            -
                    x.xpath("//annex | //clause").each do |r|
         | 
| 133 | 
            +
                    x.xpath("//annex | //clause[not(ancestor::boilerplate)]").each do |r|
         | 
| 121 134 | 
             
                      r["obligation"] = "normative" unless r["obligation"]
         | 
| 122 135 | 
             
                    end
         | 
| 123 136 | 
             
                    x.xpath(Utils::SUBCLAUSE_XPATH).each do |r|
         | 
| @@ -192,7 +205,16 @@ module Asciidoctor | |
| 192 205 | 
             
                    end
         | 
| 193 206 | 
             
                  end
         | 
| 194 207 |  | 
| 208 | 
            +
                  def termdef_from_termbase(xmldoc)
         | 
| 209 | 
            +
                    xmldoc.xpath("//term").each do |x|
         | 
| 210 | 
            +
                      if c = x.at("./origin/termref") and !x.at("./definition")
         | 
| 211 | 
            +
                        x.at("./origin").previous = fetch_termbase(c["base"], c.text)
         | 
| 212 | 
            +
                      end
         | 
| 213 | 
            +
                    end
         | 
| 214 | 
            +
                  end
         | 
| 215 | 
            +
             | 
| 195 216 | 
             
                  def termdef_cleanup(xmldoc)
         | 
| 217 | 
            +
                    termdef_from_termbase(xmldoc)
         | 
| 196 218 | 
             
                    termdef_unnest_cleanup(xmldoc)
         | 
| 197 219 | 
             
                    termdef_stem_cleanup(xmldoc)
         | 
| 198 220 | 
             
                    termdomain_cleanup(xmldoc)
         | 
| @@ -209,15 +231,21 @@ module Asciidoctor | |
| 209 231 | 
             
                  # Numbers sort *after* letters; we use thorn to force that sort order.
         | 
| 210 232 | 
             
                  def symbol_key(x)
         | 
| 211 233 | 
             
                    key = x.dup
         | 
| 212 | 
            -
                    key. | 
| 213 | 
            -
                       | 
| 234 | 
            +
                    key.traverse do |n|
         | 
| 235 | 
            +
                      next unless n.name == "math"
         | 
| 236 | 
            +
                      n.replace(grkletters(MathML2AsciiMath.m2a(n.to_xml)))
         | 
| 214 237 | 
             
                    end
         | 
| 215 | 
            -
                    ret = Nokogiri::XML( | 
| 216 | 
            -
                    HTMLEntities.new.decode(ret.text). | 
| 238 | 
            +
                    ret = Nokogiri::XML(key.to_xml)
         | 
| 239 | 
            +
                    HTMLEntities.new.decode(ret.text).
         | 
| 240 | 
            +
                      gsub(/[\[\]\{\}<>\(\)]/, "").strip.
         | 
| 217 241 | 
             
                      gsub(/[[:punct]]|[_^]/, ":\\0").gsub(/`/, "").
         | 
| 218 242 | 
             
                      gsub(/[0-9]+/, "þ\\0")
         | 
| 219 243 | 
             
                  end
         | 
| 220 244 |  | 
| 245 | 
            +
                  def grkletters(x)
         | 
| 246 | 
            +
                    x.gsub(/\b(alpha|beta|gamma|delta|epsilon|zeta|eta|theta|iota|kappa|lambda|mu|nu|xi|omicron|pi|rho|sigma|tau|upsilon|phi|chi|psi|omega)\b/i, "&\\1;")
         | 
| 247 | 
            +
                  end
         | 
| 248 | 
            +
             | 
| 221 249 | 
             
                  def extract_symbols_list(dl)
         | 
| 222 250 | 
             
                    dl_out = []
         | 
| 223 251 | 
             
                    dl.xpath("./dt | ./dd").each do |dtd|
         | 
| @@ -233,7 +261,7 @@ module Asciidoctor | |
| 233 261 | 
             
                  def symbols_cleanup(docxml)
         | 
| 234 262 | 
             
                    docxml.xpath("//definitions/dl").each do |dl|
         | 
| 235 263 | 
             
                      dl_out = extract_symbols_list(dl)
         | 
| 236 | 
            -
                      dl_out.sort! { |a, b| a[:key] <=> b[:key] }
         | 
| 264 | 
            +
                      dl_out.sort! { |a, b| a[:key] <=> b[:key] || a[:dt] <=> b[:dt] }
         | 
| 237 265 | 
             
                      dl.children = dl_out.map { |d| d[:dt].to_s + d[:dd].to_s }.join("\n")
         | 
| 238 266 | 
             
                    end
         | 
| 239 267 | 
             
                    docxml
         | 
| @@ -78,7 +78,9 @@ module Asciidoctor | |
| 78 78 |  | 
| 79 79 | 
             
                  def datetypes
         | 
| 80 80 | 
             
                    %w{ published accessed created implemented obsoleted
         | 
| 81 | 
            -
                        confirmed updated issued circulated unchanged received  | 
| 81 | 
            +
                        confirmed updated issued circulated unchanged received 
         | 
| 82 | 
            +
                        vote-started vote-ended
         | 
| 83 | 
            +
                    }
         | 
| 82 84 | 
             
                  end
         | 
| 83 85 |  | 
| 84 86 | 
             
                  def metadata_date(node, xml)
         | 
| @@ -190,8 +192,8 @@ module Asciidoctor | |
| 190 192 | 
             
                    ["en"].each do |lang|
         | 
| 191 193 | 
             
                      at = { language: lang, format: "text/plain" }
         | 
| 192 194 | 
             
                      xml.title **attr_code(at) do |t|
         | 
| 193 | 
            -
                        t << Utils::asciidoc_sub(node.attr("title") || node.attr("title-en") ||
         | 
| 194 | 
            -
             | 
| 195 | 
            +
                        t << (Utils::asciidoc_sub(node.attr("title") || node.attr("title-en")) ||
         | 
| 196 | 
            +
                              node.title)
         | 
| 195 197 | 
             
                      end
         | 
| 196 198 | 
             
                    end
         | 
| 197 199 | 
             
                  end
         | 
| @@ -3,6 +3,7 @@ require "htmlentities" | |
| 3 3 | 
             
            require "unicode2latex"
         | 
| 4 4 | 
             
            require "mime/types"
         | 
| 5 5 | 
             
            require "base64"
         | 
| 6 | 
            +
            require 'English'
         | 
| 6 7 |  | 
| 7 8 | 
             
            module Asciidoctor
         | 
| 8 9 | 
             
              module Standoc
         | 
| @@ -106,23 +107,47 @@ module Asciidoctor | |
| 106 107 | 
             
                      gsub(/"/, '"').gsub(/
/, "\n")
         | 
| 107 108 | 
             
                  end
         | 
| 108 109 |  | 
| 110 | 
            +
                  def latex_run1(lxm_input, cmd)
         | 
| 111 | 
            +
                    IO.popen(cmd, "r+", external_encoding: "UTF-8") do |io|
         | 
| 112 | 
            +
                      io.write(lxm_input)
         | 
| 113 | 
            +
                      io.close_write
         | 
| 114 | 
            +
                      io.read
         | 
| 115 | 
            +
                    end
         | 
| 116 | 
            +
                  end
         | 
| 117 | 
            +
             | 
| 118 | 
            +
                  def latex_run(lxm_input)
         | 
| 119 | 
            +
                    results = nil
         | 
| 120 | 
            +
                    Metanorma::Standoc::Requirements[:latexml].cmd.each_with_index do |cmd, i|
         | 
| 121 | 
            +
                      warn "Retrying with #{cmd}" if i > 0
         | 
| 122 | 
            +
                      results = latex_run1(lxm_input, cmd)
         | 
| 123 | 
            +
                      if $CHILD_STATUS.to_i.zero?
         | 
| 124 | 
            +
                        warn "Success!" if i > 0
         | 
| 125 | 
            +
                        break
         | 
| 126 | 
            +
                      end
         | 
| 127 | 
            +
                    end
         | 
| 128 | 
            +
                    $CHILD_STATUS.to_i.zero? ? results : nil
         | 
| 129 | 
            +
                  end
         | 
| 130 | 
            +
             | 
| 131 | 
            +
                  def latex_parse(text)
         | 
| 132 | 
            +
                    lxm_input = Unicode2LaTeX.unicode2latex(HTMLEntities.new.decode(text))
         | 
| 133 | 
            +
                    results = latex_run(lxm_input)
         | 
| 134 | 
            +
                    results.nil? and
         | 
| 135 | 
            +
                      @log.add('Math', nil,
         | 
| 136 | 
            +
                               "latexmlmath failed to process equation:\n#{lxm_input}")
         | 
| 137 | 
            +
                    results
         | 
| 138 | 
            +
                  end
         | 
| 139 | 
            +
             | 
| 109 140 | 
             
                  def stem_parse(text, xml, style)
         | 
| 110 141 | 
             
                    if /<([^:>&]+:)?math(\s+[^>&]+)?> |
         | 
| 111 142 | 
             
                      <([^:>&]+:)?math(\s+[^>&]+)?>/x.match text
         | 
| 112 143 | 
             
                      math = xml_encode(text)
         | 
| 113 144 | 
             
                      xml.stem math, **{ type: "MathML" }
         | 
| 114 145 | 
             
                    elsif style == :latexmath
         | 
| 115 | 
            -
                       | 
| 116 | 
            -
                      latexmlmath_input =
         | 
| 117 | 
            -
                        Unicode2LaTeX::unicode2latex(HTMLEntities.new.decode(text)).
         | 
| 118 | 
            -
                        gsub(/'/, '\\').gsub(/\n/, " ")
         | 
| 119 | 
            -
                      latex = IO.popen(latex_cmd, "r+", external_encoding: "UTF-8") do |io|
         | 
| 120 | 
            -
                        io.write(latexmlmath_input)
         | 
| 121 | 
            -
                        io.close_write
         | 
| 122 | 
            -
                        io.read
         | 
| 123 | 
            -
                      end
         | 
| 146 | 
            +
                      latex = latex_parse(text) or return xml.stem **{ type: "MathML" }
         | 
| 124 147 | 
             
                      xml.stem **{ type: "MathML" } do |s|
         | 
| 125 | 
            -
                         | 
| 148 | 
            +
                        math = Nokogiri::XML.fragment(latex.sub(/<\?[^>]+>/, "")).elements[0]
         | 
| 149 | 
            +
                        math.delete("alttext")
         | 
| 150 | 
            +
                        s.parent.children = math
         | 
| 126 151 | 
             
                      end
         | 
| 127 152 | 
             
                    else
         | 
| 128 153 | 
             
                      xml.stem text, **{ type: "AsciiMath" }
         | 
| @@ -172,14 +197,14 @@ module Asciidoctor | |
| 172 197 | 
             
                    types = /^data:/.match(uri) ? datauri2mime(uri) : MIME::Types.type_for(uri)
         | 
| 173 198 | 
             
                    type = types.first.to_s
         | 
| 174 199 | 
             
                    uri = uri.sub(%r{^data:image/\*;}, "data:#{type};")
         | 
| 175 | 
            -
                    attr_code(src:  | 
| 176 | 
            -
             | 
| 177 | 
            -
             | 
| 178 | 
            -
             | 
| 179 | 
            -
             | 
| 180 | 
            -
             | 
| 181 | 
            -
             | 
| 182 | 
            -
             | 
| 200 | 
            +
                    attr_code(src: uri, #@datauriimage ? datauri(uri) : uri,
         | 
| 201 | 
            +
                              id: Utils::anchor_or_uuid,
         | 
| 202 | 
            +
                              mimetype: type,
         | 
| 203 | 
            +
                              height: node.attr("height") || "auto",
         | 
| 204 | 
            +
                              width: node.attr("width") || "auto" ,
         | 
| 205 | 
            +
                              filename: node.attr("filename"),
         | 
| 206 | 
            +
                              title: node.attr("titleattr"),
         | 
| 207 | 
            +
                              alt: node.alt == node.attr("default-alt") ? nil : node.alt)
         | 
| 183 208 | 
             
                  end
         | 
| 184 209 |  | 
| 185 210 | 
             
                  def inline_image(node)
         | 
| @@ -129,6 +129,9 @@ | |
| 129 129 | 
             
                        </choice>
         | 
| 130 130 | 
             
                      </attribute>
         | 
| 131 131 | 
             
                    </optional>
         | 
| 132 | 
            +
                    <attribute name="normative">
         | 
| 133 | 
            +
                      <data type="boolean"/>
         | 
| 134 | 
            +
                    </attribute>
         | 
| 132 135 | 
             
                    <optional>
         | 
| 133 136 | 
             
                      <ref name="section-title"/>
         | 
| 134 137 | 
             
                    </optional>
         | 
| @@ -305,6 +308,21 @@ | |
| 305 308 | 
             
                </define>
         | 
| 306 309 | 
             
              </include>
         | 
| 307 310 | 
             
              <!-- end overrides -->
         | 
| 311 | 
            +
              <define name="TextElement" combine="choice">
         | 
| 312 | 
            +
                <ref name="concept"/>
         | 
| 313 | 
            +
              </define>
         | 
| 314 | 
            +
              <define name="concept">
         | 
| 315 | 
            +
                <element name="concept">
         | 
| 316 | 
            +
                  <optional>
         | 
| 317 | 
            +
                    <attribute name="term"/>
         | 
| 318 | 
            +
                  </optional>
         | 
| 319 | 
            +
                  <choice>
         | 
| 320 | 
            +
                    <ref name="eref"/>
         | 
| 321 | 
            +
                    <ref name="xref"/>
         | 
| 322 | 
            +
                    <ref name="termref"/>
         | 
| 323 | 
            +
                  </choice>
         | 
| 324 | 
            +
                </element>
         | 
| 325 | 
            +
              </define>
         | 
| 308 326 | 
             
              <define name="BasicBlock" combine="choice">
         | 
| 309 327 | 
             
                <choice>
         | 
| 310 328 | 
             
                  <ref name="requirement"/>
         | 
| @@ -911,7 +929,10 @@ | |
| 911 929 | 
             
              </define>
         | 
| 912 930 | 
             
              <define name="origin">
         | 
| 913 931 | 
             
                <element name="origin">
         | 
| 914 | 
            -
                  < | 
| 932 | 
            +
                  <choice>
         | 
| 933 | 
            +
                    <ref name="erefType"/>
         | 
| 934 | 
            +
                    <ref name="termref"/>
         | 
| 935 | 
            +
                  </choice>
         | 
| 915 936 | 
             
                </element>
         | 
| 916 937 | 
             
              </define>
         | 
| 917 938 | 
             
              <define name="modification">
         | 
| @@ -919,6 +940,15 @@ | |
| 919 940 | 
             
                  <ref name="paragraph"/>
         | 
| 920 941 | 
             
                </element>
         | 
| 921 942 | 
             
              </define>
         | 
| 943 | 
            +
              <define name="termref">
         | 
| 944 | 
            +
                <element name="termref">
         | 
| 945 | 
            +
                  <attribute name="base"/>
         | 
| 946 | 
            +
                  <attribute name="target"/>
         | 
| 947 | 
            +
                  <optional>
         | 
| 948 | 
            +
                    <text/>
         | 
| 949 | 
            +
                  </optional>
         | 
| 950 | 
            +
                </element>
         | 
| 951 | 
            +
              </define>
         | 
| 922 952 | 
             
              <define name="structuredidentifier">
         | 
| 923 953 | 
             
                <element name="structuredidentifier">
         | 
| 924 954 | 
             
                  <optional>
         | 
| @@ -2,6 +2,7 @@ require "asciidoctor/extensions" | |
| 2 2 | 
             
            require "fileutils"
         | 
| 3 3 | 
             
            require "uuidtools"
         | 
| 4 4 | 
             
            require_relative "./macros_plantuml.rb"
         | 
| 5 | 
            +
            require_relative "./macros_yaml2text.rb"
         | 
| 5 6 |  | 
| 6 7 | 
             
            module Asciidoctor
         | 
| 7 8 | 
             
              module Standoc
         | 
| @@ -58,7 +59,7 @@ module Asciidoctor | |
| 58 59 | 
             
                  named :concept
         | 
| 59 60 | 
             
                  name_positional_attributes "id", "word", "term"
         | 
| 60 61 | 
             
                  #match %r{concept:(?<target>[^\[]*)\[(?<content>|.*?[^\\])\]$}
         | 
| 61 | 
            -
                  match /\{\{(?<content>|.*?[^\\])\}\} | 
| 62 | 
            +
                  match /\{\{(?<content>|.*?[^\\])\}\}/
         | 
| 62 63 | 
             
                  using_format :short
         | 
| 63 64 |  | 
| 64 65 | 
             
                  # deal with locality attrs and their disruption of positional attrs
         | 
| @@ -0,0 +1,142 @@ | |
| 1 | 
            +
            require 'ostruct'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module Asciidoctor
         | 
| 4 | 
            +
              module Standoc
         | 
| 5 | 
            +
                class YamlBlockStruct < OpenStruct
         | 
| 6 | 
            +
                  def to_a
         | 
| 7 | 
            +
                    @table.to_h.keys
         | 
| 8 | 
            +
                  end
         | 
| 9 | 
            +
             | 
| 10 | 
            +
                  def values
         | 
| 11 | 
            +
                    @table.to_h.values
         | 
| 12 | 
            +
                  end
         | 
| 13 | 
            +
             | 
| 14 | 
            +
                  def each
         | 
| 15 | 
            +
                    return to_a.each unless block_given?
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                    to_a.each do |key|
         | 
| 18 | 
            +
                      yield(key)
         | 
| 19 | 
            +
                    end
         | 
| 20 | 
            +
                  end
         | 
| 21 | 
            +
                end
         | 
| 22 | 
            +
             | 
| 23 | 
            +
                class YamlContextRenderer
         | 
| 24 | 
            +
                  attr_reader :context_object, :context_name
         | 
| 25 | 
            +
             | 
| 26 | 
            +
                  def initialize(context_object:, context_name:)
         | 
| 27 | 
            +
                    @context_object = context_object
         | 
| 28 | 
            +
                    @context_name = context_name
         | 
| 29 | 
            +
                  end
         | 
| 30 | 
            +
             | 
| 31 | 
            +
                  def respond_to_missing?(name)
         | 
| 32 | 
            +
                    respond_to?(name)
         | 
| 33 | 
            +
                  end
         | 
| 34 | 
            +
             | 
| 35 | 
            +
                  def method_missing(name, *_args)
         | 
| 36 | 
            +
                    return context_object if name.to_s == context_name
         | 
| 37 | 
            +
             | 
| 38 | 
            +
                    super
         | 
| 39 | 
            +
                  end
         | 
| 40 | 
            +
             | 
| 41 | 
            +
                  def render(template)
         | 
| 42 | 
            +
                    ERB.new(template).result(binding)
         | 
| 43 | 
            +
                  end
         | 
| 44 | 
            +
                end
         | 
| 45 | 
            +
             | 
| 46 | 
            +
                class Yaml2TextPreprocessor < Asciidoctor::Extensions::Preprocessor
         | 
| 47 | 
            +
                  BLOCK_START_REGEXP = /\{(.+?)\.\*,(.+),(.+)\}/.freeze
         | 
| 48 | 
            +
                  BLOCK_END_REGEXP = /\A\{[A-Z]+\}\z/.freeze
         | 
| 49 | 
            +
                  # search document for block `yaml2text`
         | 
| 50 | 
            +
                  #   after that take template from block and read file into this template
         | 
| 51 | 
            +
                  #   example:
         | 
| 52 | 
            +
                  #     [yaml2text,foobar.yaml]
         | 
| 53 | 
            +
                  #     ----
         | 
| 54 | 
            +
                  #     === {item.name}
         | 
| 55 | 
            +
                  #     {item.desc}
         | 
| 56 | 
            +
                  #
         | 
| 57 | 
            +
                  #     {item.symbol}:: {item.symbol_def}
         | 
| 58 | 
            +
                  #     ----
         | 
| 59 | 
            +
                  #
         | 
| 60 | 
            +
                  #   with content of `foobar.yaml` file equal to:
         | 
| 61 | 
            +
                  #     - name: spaghetti
         | 
| 62 | 
            +
                  #       desc: wheat noodles of 9mm diameter
         | 
| 63 | 
            +
                  #       symbol: SPAG
         | 
| 64 | 
            +
                  #       symbol_def: the situation is message like spaghetti at a kid's meal
         | 
| 65 | 
            +
                  #
         | 
| 66 | 
            +
                  #   will produce:
         | 
| 67 | 
            +
                  #     === spaghetti
         | 
| 68 | 
            +
                  #     wheat noodles of 9mm diameter
         | 
| 69 | 
            +
                  #
         | 
| 70 | 
            +
                  #     SPAG:: the situation is message like spaghetti at a kid's meal
         | 
| 71 | 
            +
                  def process(document, reader)
         | 
| 72 | 
            +
                    input_lines = reader.readlines.to_enum
         | 
| 73 | 
            +
                    Reader.new(processed_lines(document, input_lines))
         | 
| 74 | 
            +
                  end
         | 
| 75 | 
            +
             | 
| 76 | 
            +
                  private
         | 
| 77 | 
            +
             | 
| 78 | 
            +
                  def processed_lines(document, input_lines)
         | 
| 79 | 
            +
                    result = []
         | 
| 80 | 
            +
                    loop do
         | 
| 81 | 
            +
                      line = input_lines.next
         | 
| 82 | 
            +
                      if yaml_block_match = line.match(/^\[yaml2text,(.+?),(.+?)\]/)
         | 
| 83 | 
            +
                        mark = input_lines.next
         | 
| 84 | 
            +
                        current_yaml_block = []
         | 
| 85 | 
            +
                        while (yaml_block_line = input_lines.next) != mark
         | 
| 86 | 
            +
                          current_yaml_block.push(yaml_block_line)
         | 
| 87 | 
            +
                        end
         | 
| 88 | 
            +
                        content = nested_open_struct_from_yaml(yaml_block_match[1], document)
         | 
| 89 | 
            +
                        result.push(*
         | 
| 90 | 
            +
                          parse_blocks_recursively(lines: current_yaml_block,
         | 
| 91 | 
            +
                                                   attributes: content,
         | 
| 92 | 
            +
                                                   context_name: yaml_block_match[2]))
         | 
| 93 | 
            +
                      else
         | 
| 94 | 
            +
                        result.push(line)
         | 
| 95 | 
            +
                      end
         | 
| 96 | 
            +
                    end
         | 
| 97 | 
            +
                    result
         | 
| 98 | 
            +
                  end
         | 
| 99 | 
            +
             | 
| 100 | 
            +
                  def nested_open_struct_from_yaml(file_path, document)
         | 
| 101 | 
            +
                    docfile_directory = File.dirname(document.attributes['docfile'] || '.')
         | 
| 102 | 
            +
                    yaml_file_path = document.path_resolver.system_path(file_path, docfile_directory)
         | 
| 103 | 
            +
                    content = YAML.safe_load(File.read(yaml_file_path))
         | 
| 104 | 
            +
                    # Load content as json, then parse with JSON as nested open_struct
         | 
| 105 | 
            +
                    JSON.parse(content.to_json, object_class: YamlBlockStruct)
         | 
| 106 | 
            +
                  end
         | 
| 107 | 
            +
             | 
| 108 | 
            +
                  def parse_blocks_recursively(lines:,
         | 
| 109 | 
            +
                                               attributes:,
         | 
| 110 | 
            +
                                               context_name:,
         | 
| 111 | 
            +
                                               parent_context: nil)
         | 
| 112 | 
            +
                    lines = lines.to_enum
         | 
| 113 | 
            +
                    result = []
         | 
| 114 | 
            +
                    loop do
         | 
| 115 | 
            +
                      line = lines.next
         | 
| 116 | 
            +
                      if line.match(BLOCK_START_REGEXP)
         | 
| 117 | 
            +
                        line.gsub!(BLOCK_START_REGEXP, '<% \1.each.with_index do |\2,index| %>')
         | 
| 118 | 
            +
                      end
         | 
| 119 | 
            +
             | 
| 120 | 
            +
                      if line.match(BLOCK_END_REGEXP)
         | 
| 121 | 
            +
                        line.gsub!(BLOCK_END_REGEXP, '<% end %>')
         | 
| 122 | 
            +
                      end
         | 
| 123 | 
            +
                      line = line.gsub(/{(.+?[^}]*)}/, '<%= \1 %>').gsub(/[a-z\.]+\#/, 'index')
         | 
| 124 | 
            +
                      result.push(line)
         | 
| 125 | 
            +
                    end
         | 
| 126 | 
            +
                    result = parse_context_block(context_lines: result,
         | 
| 127 | 
            +
                                                 context_items: attributes,
         | 
| 128 | 
            +
                                                 context_name: context_name,
         | 
| 129 | 
            +
                                                 parent_context: parent_context)
         | 
| 130 | 
            +
                    result
         | 
| 131 | 
            +
                  end
         | 
| 132 | 
            +
             | 
| 133 | 
            +
                  def parse_context_block(context_lines:,
         | 
| 134 | 
            +
                                          context_items:,
         | 
| 135 | 
            +
                                          context_name:,
         | 
| 136 | 
            +
                                          parent_context: nil)
         | 
| 137 | 
            +
                    renderer = YamlContextRenderer.new(context_object: context_items, context_name: context_name)
         | 
| 138 | 
            +
                    renderer.render(context_lines.join('\n')).split('\n')
         | 
| 139 | 
            +
                  end
         | 
| 140 | 
            +
                end
         | 
| 141 | 
            +
              end
         | 
| 142 | 
            +
            end
         |