metanorma-standoc 1.11.4 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (141) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/rake.yml +3 -31
  3. data/.gitignore +23 -0
  4. data/lib/asciidoctor/standoc/base.rb +2 -145
  5. data/lib/asciidoctor/standoc/blocks.rb +2 -238
  6. data/lib/asciidoctor/standoc/blocks_notes.rb +2 -100
  7. data/lib/asciidoctor/standoc/cleanup.rb +2 -208
  8. data/lib/asciidoctor/standoc/cleanup_amend.rb +2 -53
  9. data/lib/asciidoctor/standoc/cleanup_block.rb +2 -172
  10. data/lib/asciidoctor/standoc/cleanup_boilerplate.rb +2 -212
  11. data/lib/asciidoctor/standoc/cleanup_footnotes.rb +2 -108
  12. data/lib/asciidoctor/standoc/cleanup_image.rb +2 -69
  13. data/lib/asciidoctor/standoc/cleanup_inline.rb +2 -189
  14. data/lib/asciidoctor/standoc/cleanup_maths.rb +2 -221
  15. data/lib/asciidoctor/standoc/cleanup_ref.rb +2 -169
  16. data/lib/asciidoctor/standoc/cleanup_ref_dl.rb +2 -103
  17. data/lib/asciidoctor/standoc/cleanup_reqt.rb +2 -110
  18. data/lib/asciidoctor/standoc/cleanup_section.rb +2 -184
  19. data/lib/asciidoctor/standoc/cleanup_section_names.rb +2 -91
  20. data/lib/asciidoctor/standoc/cleanup_symbols.rb +2 -47
  21. data/lib/asciidoctor/standoc/cleanup_table.rb +2 -67
  22. data/lib/asciidoctor/standoc/cleanup_terms.rb +2 -139
  23. data/lib/asciidoctor/standoc/cleanup_terms_designations.rb +2 -198
  24. data/lib/asciidoctor/standoc/cleanup_text.rb +2 -95
  25. data/lib/asciidoctor/standoc/cleanup_toc.rb +3 -0
  26. data/lib/asciidoctor/standoc/cleanup_xref.rb +2 -106
  27. data/lib/asciidoctor/standoc/converter.rb +2 -123
  28. data/lib/asciidoctor/standoc/datamodel/attributes_table_preprocessor.rb +2 -56
  29. data/lib/asciidoctor/standoc/datamodel/diagram_preprocessor.rb +2 -102
  30. data/lib/asciidoctor/standoc/datamodel/plantuml_renderer.rb +3 -404
  31. data/lib/asciidoctor/standoc/deprecated.rb +5 -0
  32. data/lib/asciidoctor/standoc/front.rb +2 -223
  33. data/lib/asciidoctor/standoc/front_contributor.rb +2 -191
  34. data/lib/asciidoctor/standoc/inline.rb +2 -231
  35. data/lib/asciidoctor/standoc/lists.rb +2 -119
  36. data/lib/asciidoctor/standoc/macros.rb +2 -203
  37. data/lib/asciidoctor/standoc/macros_form.rb +2 -62
  38. data/lib/asciidoctor/standoc/macros_note.rb +2 -44
  39. data/lib/asciidoctor/standoc/macros_plantuml.rb +2 -112
  40. data/lib/asciidoctor/standoc/macros_terms.rb +2 -180
  41. data/lib/asciidoctor/standoc/ref.rb +2 -251
  42. data/lib/asciidoctor/standoc/ref_sect.rb +2 -153
  43. data/lib/asciidoctor/standoc/ref_utility.rb +2 -0
  44. data/lib/asciidoctor/standoc/render.rb +2 -114
  45. data/lib/asciidoctor/standoc/reqt.rb +2 -89
  46. data/lib/asciidoctor/standoc/section.rb +2 -207
  47. data/lib/asciidoctor/standoc/table.rb +2 -84
  48. data/lib/asciidoctor/standoc/term_lookup_cleanup.rb +2 -178
  49. data/lib/asciidoctor/standoc/terms.rb +2 -159
  50. data/lib/asciidoctor/standoc/utils.rb +2 -100
  51. data/lib/asciidoctor/standoc/validate.rb +2 -157
  52. data/lib/asciidoctor/standoc/validate_section.rb +2 -54
  53. data/lib/metanorma/standoc/base.rb +149 -0
  54. data/lib/{asciidoctor → metanorma}/standoc/basicdoc.rng +0 -0
  55. data/lib/{asciidoctor → metanorma}/standoc/biblio.rng +0 -0
  56. data/lib/metanorma/standoc/blocks.rb +239 -0
  57. data/lib/metanorma/standoc/blocks_notes.rb +101 -0
  58. data/lib/metanorma/standoc/cleanup.rb +146 -0
  59. data/lib/metanorma/standoc/cleanup_amend.rb +54 -0
  60. data/lib/metanorma/standoc/cleanup_block.rb +173 -0
  61. data/lib/metanorma/standoc/cleanup_boilerplate.rb +213 -0
  62. data/lib/metanorma/standoc/cleanup_footnotes.rb +109 -0
  63. data/lib/metanorma/standoc/cleanup_image.rb +70 -0
  64. data/lib/metanorma/standoc/cleanup_inline.rb +190 -0
  65. data/lib/metanorma/standoc/cleanup_maths.rb +222 -0
  66. data/lib/metanorma/standoc/cleanup_ref.rb +170 -0
  67. data/lib/metanorma/standoc/cleanup_ref_dl.rb +104 -0
  68. data/lib/metanorma/standoc/cleanup_reqt.rb +111 -0
  69. data/lib/metanorma/standoc/cleanup_section.rb +212 -0
  70. data/lib/metanorma/standoc/cleanup_section_names.rb +92 -0
  71. data/lib/metanorma/standoc/cleanup_symbols.rb +48 -0
  72. data/lib/metanorma/standoc/cleanup_table.rb +68 -0
  73. data/lib/metanorma/standoc/cleanup_terms.rb +140 -0
  74. data/lib/metanorma/standoc/cleanup_terms_designations.rb +199 -0
  75. data/lib/metanorma/standoc/cleanup_text.rb +96 -0
  76. data/lib/metanorma/standoc/cleanup_toc.rb +98 -0
  77. data/lib/metanorma/standoc/cleanup_xref.rb +107 -0
  78. data/lib/metanorma/standoc/converter.rb +124 -0
  79. data/lib/metanorma/standoc/datamodel/attributes_table_preprocessor.rb +57 -0
  80. data/lib/metanorma/standoc/datamodel/diagram_preprocessor.rb +103 -0
  81. data/lib/metanorma/standoc/datamodel/plantuml_renderer.rb +409 -0
  82. data/lib/metanorma/standoc/front.rb +224 -0
  83. data/lib/metanorma/standoc/front_contributor.rb +192 -0
  84. data/lib/metanorma/standoc/inline.rb +232 -0
  85. data/lib/{asciidoctor → metanorma}/standoc/isodoc.rng +29 -0
  86. data/lib/metanorma/standoc/lists.rb +120 -0
  87. data/lib/metanorma/standoc/macros.rb +204 -0
  88. data/lib/metanorma/standoc/macros_form.rb +63 -0
  89. data/lib/metanorma/standoc/macros_note.rb +45 -0
  90. data/lib/metanorma/standoc/macros_plantuml.rb +113 -0
  91. data/lib/metanorma/standoc/macros_terms.rb +181 -0
  92. data/lib/metanorma/standoc/ref.rb +243 -0
  93. data/lib/metanorma/standoc/ref_sect.rb +153 -0
  94. data/lib/{asciidoctor/standoc/ref_date_id.rb → metanorma/standoc/ref_utility.rb} +43 -5
  95. data/lib/metanorma/standoc/render.rb +115 -0
  96. data/lib/metanorma/standoc/reqt.rb +90 -0
  97. data/lib/{asciidoctor → metanorma}/standoc/reqt.rng +0 -0
  98. data/lib/metanorma/standoc/section.rb +209 -0
  99. data/lib/metanorma/standoc/table.rb +85 -0
  100. data/lib/metanorma/standoc/term_lookup_cleanup.rb +179 -0
  101. data/lib/metanorma/standoc/terms.rb +160 -0
  102. data/lib/metanorma/standoc/utils.rb +101 -0
  103. data/lib/metanorma/standoc/validate.rb +158 -0
  104. data/lib/metanorma/standoc/validate_section.rb +55 -0
  105. data/lib/metanorma/standoc/version.rb +1 -1
  106. data/lib/{asciidoctor → metanorma}/standoc/views/datamodel/model_representation.adoc.erb +0 -0
  107. data/lib/{asciidoctor → metanorma}/standoc/views/datamodel/plantuml_representation.adoc.erb +0 -0
  108. data/lib/metanorma-standoc.rb +1 -1
  109. data/metanorma-standoc.gemspec +1 -1
  110. data/spec/{asciidoctor → metanorma}/base_spec.rb +27 -10
  111. data/spec/{asciidoctor → metanorma}/blank_spec.rb +1 -1
  112. data/spec/{asciidoctor → metanorma}/blocks_spec.rb +1 -1
  113. data/spec/{asciidoctor → metanorma}/cleanup_blocks_spec.rb +1 -1
  114. data/spec/{asciidoctor → metanorma}/cleanup_sections_spec.rb +1 -1
  115. data/spec/{asciidoctor → metanorma}/cleanup_spec.rb +5 -5
  116. data/spec/{asciidoctor → metanorma}/cleanup_terms_spec.rb +2 -2
  117. data/spec/{asciidoctor → metanorma}/datamodel/attributes_table_preprocessor_spec.rb +1 -1
  118. data/spec/{asciidoctor → metanorma}/datamodel/diagram_preprocessor_spec.rb +1 -1
  119. data/spec/{asciidoctor → metanorma}/inline_spec.rb +1 -1
  120. data/spec/{asciidoctor → metanorma}/isobib_cache_spec.rb +1 -1
  121. data/spec/{asciidoctor → metanorma}/lists_spec.rb +1 -1
  122. data/spec/{asciidoctor → metanorma}/macros_json2text_spec.rb +0 -0
  123. data/spec/{asciidoctor → metanorma}/macros_plantuml_spec.rb +3 -3
  124. data/spec/{asciidoctor → metanorma}/macros_spec.rb +6 -6
  125. data/spec/{asciidoctor → metanorma}/macros_yaml2text_spec.rb +0 -0
  126. data/spec/metanorma/refs_dl_spec.rb +863 -0
  127. data/spec/{asciidoctor → metanorma}/refs_spec.rb +399 -25
  128. data/spec/{asciidoctor → metanorma}/section_spec.rb +42 -17
  129. data/spec/{asciidoctor → metanorma}/table_spec.rb +1 -1
  130. data/spec/{asciidoctor → metanorma}/validate_spec.rb +2 -2
  131. data/spec/vcr_cassettes/dated_iso_ref_joint_iso_iec.yml +42 -42
  132. data/spec/vcr_cassettes/dated_iso_ref_joint_iso_iec1.yml +11 -11
  133. data/spec/vcr_cassettes/isobib_get_123.yml +12 -12
  134. data/spec/vcr_cassettes/isobib_get_123_1.yml +21 -21
  135. data/spec/vcr_cassettes/isobib_get_123_1_fr.yml +81 -81
  136. data/spec/vcr_cassettes/isobib_get_123_2001.yml +10 -10
  137. data/spec/vcr_cassettes/isobib_get_124.yml +11 -11
  138. data/spec/vcr_cassettes/rfcbib_get_rfc8341.yml +13 -13
  139. data/spec/vcr_cassettes/separates_iev_citations_by_top_level_clause.yml +46 -46
  140. metadata +82 -32
  141. data/spec/asciidoctor/refs_dl_spec.rb +0 -864
@@ -0,0 +1,173 @@
1
+ require "date"
2
+ require "htmlentities"
3
+
4
+ module Metanorma
5
+ module Standoc
6
+ module Cleanup
7
+ def para_cleanup(xmldoc)
8
+ ["//p[not(ancestor::bibdata)]", "//ol[not(ancestor::bibdata)]",
9
+ "//ul[not(ancestor::bibdata)]", "//quote[not(ancestor::bibdata)]",
10
+ "//note[not(ancestor::bibitem or "\
11
+ "ancestor::table or ancestor::bibdata)]"].each do |w|
12
+ inject_id(xmldoc, w)
13
+ end
14
+ end
15
+
16
+ def inject_id(xmldoc, path)
17
+ xmldoc.xpath(path).each do |x|
18
+ x["id"] ||= Metanorma::Utils::anchor_or_uuid
19
+ end
20
+ end
21
+
22
+ # include where definition list inside stem block
23
+ def formula_cleanup(formula)
24
+ formula_cleanup_where1(formula)
25
+ formula_cleanup_where2(formula)
26
+ end
27
+
28
+ def formula_cleanup_where1(formula)
29
+ q = "//formula/following-sibling::*[1][self::dl]"
30
+ formula.xpath(q).each do |s|
31
+ s["key"] == "true" and s.previous_element << s.remove
32
+ end
33
+ end
34
+
35
+ def formula_cleanup_where2(formula)
36
+ q = "//formula/following-sibling::*[1][self::p]"
37
+ formula.xpath(q).each do |s|
38
+ if s.text =~ /^\s*where[^a-z]*$/i && s&.next_element&.name == "dl"
39
+ s.next_element["key"] = "true"
40
+ s.previous_element << s.next_element.remove
41
+ s.remove
42
+ end
43
+ end
44
+ end
45
+
46
+ def figure_dl_cleanup1(xmldoc)
47
+ q = "//figure/following-sibling::*[self::dl]"
48
+ xmldoc.xpath(q).each do |s|
49
+ s["key"] == "true" and s.previous_element << s.remove
50
+ end
51
+ end
52
+
53
+ # include key definition list inside figure
54
+ def figure_dl_cleanup2(xmldoc)
55
+ q = "//figure/following-sibling::*[self::p]"
56
+ xmldoc.xpath(q).each do |s|
57
+ if s.text =~ /^\s*key[^a-z]*$/i && s&.next_element&.name == "dl"
58
+ s.next_element["key"] = "true"
59
+ s.previous_element << s.next_element.remove
60
+ s.remove
61
+ end
62
+ end
63
+ end
64
+
65
+ # examples containing only figures become subfigures of figures
66
+ def subfigure_cleanup(xmldoc)
67
+ xmldoc.xpath("//example[figure]").each do |e|
68
+ next unless e.elements.map(&:name).reject do |m|
69
+ %w(name figure).include? m
70
+ end.empty?
71
+
72
+ e.name = "figure"
73
+ end
74
+ end
75
+
76
+ def figure_cleanup(xmldoc)
77
+ figure_footnote_cleanup(xmldoc)
78
+ figure_dl_cleanup1(xmldoc)
79
+ figure_dl_cleanup2(xmldoc)
80
+ subfigure_cleanup(xmldoc)
81
+ end
82
+
83
+ ELEMS_ALLOW_NOTES = %w[p formula ul ol dl figure].freeze
84
+
85
+ # if a note is at the end of a section, it is left alone
86
+ # if a note is followed by a non-note block,
87
+ # it is moved inside its preceding block if it is not delimited
88
+ # (so there was no way of making that block include the note)
89
+ def note_cleanup(xmldoc)
90
+ q = "//note[following-sibling::*[not(local-name() = 'note')]]"
91
+ xmldoc.xpath(q).each do |n|
92
+ next if n["keep-separate"] == "true" || !n.ancestors("table").empty?
93
+
94
+ prev = n.previous_element || next
95
+ n.parent = prev if ELEMS_ALLOW_NOTES.include? prev.name
96
+ end
97
+ xmldoc.xpath("//note[@keep-separate] | "\
98
+ "//termnote[@keep-separate]").each do |n|
99
+ n.delete("keep-separate")
100
+ end
101
+ end
102
+
103
+ def link_callouts_to_annotations(callouts, annotations)
104
+ callouts.each_with_index do |c, i|
105
+ c["target"] = "_#{UUIDTools::UUID.random_create}"
106
+ annotations[i]["id"] = c["target"]
107
+ end
108
+ end
109
+
110
+ def align_callouts_to_annotations(xmldoc)
111
+ xmldoc.xpath("//sourcecode").each do |x|
112
+ callouts = x.elements.select { |e| e.name == "callout" }
113
+ annotations = x.elements.select { |e| e.name == "annotation" }
114
+ callouts.size == annotations.size and
115
+ link_callouts_to_annotations(callouts, annotations)
116
+ end
117
+ end
118
+
119
+ def merge_annotations_into_sourcecode(xmldoc)
120
+ xmldoc.xpath("//sourcecode").each do |x|
121
+ while x&.next_element&.name == "annotation"
122
+ x.next_element.parent = x
123
+ end
124
+ end
125
+ end
126
+
127
+ def callout_cleanup(xmldoc)
128
+ merge_annotations_into_sourcecode(xmldoc)
129
+ align_callouts_to_annotations(xmldoc)
130
+ end
131
+
132
+ def sourcecode_cleanup(xmldoc)
133
+ xmldoc.xpath("//sourcecode").each do |x|
134
+ x.traverse do |n|
135
+ next unless n.text?
136
+ next unless /#{Regexp.escape(@sourcecode_markup_start)}/
137
+ .match?(n.text)
138
+
139
+ n.replace(sourcecode_markup(n))
140
+ end
141
+ end
142
+ end
143
+
144
+ def safe_noko(text, doc)
145
+ Nokogiri::XML::Text.new(text, doc).to_xml(
146
+ encoding: "US-ASCII",
147
+ save_with: Nokogiri::XML::Node::SaveOptions::NO_DECLARATION,
148
+ )
149
+ end
150
+
151
+ def sourcecode_markup(node)
152
+ node.text.split(/(#{Regexp.escape(@sourcecode_markup_start)}|
153
+ #{Regexp.escape(@sourcecode_markup_end)})/x)
154
+ .each_slice(4).map.with_object([]) do |a, acc|
155
+ acc << safe_noko(a[0], node.document)
156
+ next unless a.size == 4
157
+
158
+ acc << Asciidoctor.convert(
159
+ a[2], doctype: :inline, backend: (self&.backend&.to_sym || :standoc)
160
+ )
161
+ end.join
162
+ end
163
+
164
+ def form_cleanup(xmldoc)
165
+ xmldoc.xpath("//select").each do |s|
166
+ while s&.next_element&.name == "option"
167
+ s << s.next_element
168
+ end
169
+ end
170
+ end
171
+ end
172
+ end
173
+ end
@@ -0,0 +1,213 @@
1
+ module Metanorma
2
+ module Standoc
3
+ module Cleanup
4
+ def external_terms_boilerplate(sources)
5
+ @i18n.l10n(
6
+ @i18n.external_terms_boilerplate.gsub(/%/, sources || "???"),
7
+ @lang, @script
8
+ )
9
+ end
10
+
11
+ def internal_external_terms_boilerplate(sources)
12
+ @i18n.l10n(
13
+ @i18n.internal_external_terms_boilerplate.gsub(/%/, sources || "??"),
14
+ @lang, @script
15
+ )
16
+ end
17
+
18
+ def term_defs_boilerplate(div, source, term, _preface, isodoc)
19
+ a = @i18n.term_def_boilerplate and div.next = a
20
+ source.each do |s|
21
+ @anchors[s["bibitemid"]] or
22
+ @log.add("Crossreferences", nil,
23
+ "term source #{s['bibitemid']} not referenced")
24
+ end
25
+ a = if source.empty? && term.nil?
26
+ @i18n.no_terms_boilerplate
27
+ else
28
+ term_defs_boilerplate_cont(source, term, isodoc)
29
+ end
30
+ a and div.next = a
31
+ end
32
+
33
+ def term_defs_boilerplate_cont(src, term, isodoc)
34
+ sources = isodoc.sentence_join(src.map do |s|
35
+ %{<eref bibitemid="#{s['bibitemid']}"/>}
36
+ end)
37
+ if src.empty? then @i18n.internal_terms_boilerplate
38
+ elsif term.nil? then external_terms_boilerplate(sources)
39
+ else
40
+ internal_external_terms_boilerplate(sources)
41
+ end
42
+ end
43
+
44
+ def norm_ref_preface(ref)
45
+ if ref.at("./note[@type = 'boilerplate']")
46
+ unwrap_boilerplate_clauses(ref, ".")
47
+ else
48
+ refs = ref.elements.select do |e|
49
+ %w(references bibitem).include? e.name
50
+ end
51
+ pref = refs.empty? ? @i18n.norm_empty_pref : @i18n.norm_with_refs_pref
52
+ ref.at("./title").next = "<p>#{pref}</p>"
53
+ end
54
+ end
55
+
56
+ TERM_CLAUSE = "//sections/terms | "\
57
+ "//sections/clause[descendant::terms]".freeze
58
+
59
+ NORM_REF = "//bibliography/references[@normative = 'true'] | "\
60
+ "//bibliography/clause[.//references[@normative = 'true']]"
61
+ .freeze
62
+
63
+ def boilerplate_isodoc(xmldoc)
64
+ x = xmldoc.dup
65
+ x.root.add_namespace(nil, self.class::XML_NAMESPACE)
66
+ xml = Nokogiri::XML(x.to_xml)
67
+ @isodoc ||= isodoc(@lang, @script)
68
+ @isodoc.info(xml, nil)
69
+ @isodoc
70
+ end
71
+
72
+ def termdef_boilerplate_cleanup(xmldoc)
73
+ # termdef_remove_initial_paras(xmldoc)
74
+ end
75
+
76
+ def termdef_remove_initial_paras(xmldoc)
77
+ xmldoc.xpath("//terms/p | //terms/ul").each(&:remove)
78
+ end
79
+
80
+ def unwrap_boilerplate_clauses(xmldoc, xpath)
81
+ xmldoc.xpath(xpath).each do |f|
82
+ f.xpath(".//clause[@type = 'boilerplate'] | "\
83
+ ".//note[@type = 'boilerplate']").each do |c|
84
+ c&.at("./title")&.remove
85
+ c.replace(c.children)
86
+ end
87
+ end
88
+ end
89
+
90
+ def termdef_boilerplate_insert(xmldoc, isodoc, once = false)
91
+ xmldoc.xpath(self.class::TERM_CLAUSE).each do |f|
92
+ next if f.at("./clause[@type = 'boilerplate']")
93
+
94
+ term_defs_boilerplate(f.at("./title"),
95
+ xmldoc.xpath(".//termdocsource"),
96
+ f.at(".//term"), f.at(".//p"), isodoc)
97
+ break if once
98
+ end
99
+ end
100
+
101
+ def boilerplate_cleanup(xmldoc)
102
+ isodoc = boilerplate_isodoc(xmldoc)
103
+ termdef_boilerplate_cleanup(xmldoc)
104
+ termdef_boilerplate_insert(xmldoc, isodoc)
105
+ unwrap_boilerplate_clauses(xmldoc, self.class::TERM_CLAUSE)
106
+ f = xmldoc.at(self.class::NORM_REF) and norm_ref_preface(f)
107
+ initial_boilerplate(xmldoc, isodoc)
108
+ end
109
+
110
+ def initial_boilerplate(xml, isodoc)
111
+ return if xml.at("//boilerplate")
112
+
113
+ preface = xml.at("//preface") || xml.at("//sections") ||
114
+ xml.at("//annex") || xml.at("//references") || return
115
+ b = boilerplate(xml, isodoc) or return
116
+ preface.previous = b
117
+ end
118
+
119
+ def boilerplate_file(_xmldoc)
120
+ File.join(@libdir, "boilerplate.xml")
121
+ end
122
+
123
+ def boilerplate(xml, conv)
124
+ file = boilerplate_file(xml)
125
+ if @boilerplateauthority
126
+ file = File.join(@localdir,
127
+ @boilerplateauthority)
128
+ end
129
+ (!file.nil? and File.exists?(file)) or return
130
+ conv.populate_template(File.read(file, encoding: "UTF-8"), nil)
131
+ end
132
+
133
+ def bibdata_cleanup(xmldoc)
134
+ bibdata_anchor_cleanup(xmldoc)
135
+ bibdata_docidentifier_cleanup(xmldoc)
136
+ biblio_indirect_erefs(xmldoc, @internal_eref_namespaces&.uniq)
137
+ end
138
+
139
+ def bibdata_anchor_cleanup(xmldoc)
140
+ xmldoc.xpath("//bibdata//bibitem | //bibdata//note").each do |b|
141
+ b.delete("id")
142
+ end
143
+ end
144
+
145
+ def bibdata_docidentifier_cleanup(xmldoc)
146
+ ins = xmldoc.at("//bibdata/docidentifier")
147
+ xmldoc.xpath("//bibdata/docidentifier").each_with_index do |b, i|
148
+ next if i.zero?
149
+
150
+ ins.next = b.remove
151
+ ins = ins.next
152
+ end
153
+ end
154
+
155
+ def gather_indirect_erefs(xmldoc, prefix)
156
+ xmldoc.xpath("//eref[@type = '#{prefix}']")
157
+ .each_with_object({}) do |e, m|
158
+ e.delete("type")
159
+ m[e["bibitemid"]] = true
160
+ end.keys
161
+ end
162
+
163
+ def insert_indirect_biblio(xmldoc, refs, prefix)
164
+ ins = xmldoc.at("bibliography") or
165
+ xmldoc.root << "<bibliography/>" and ins = xmldoc.at("bibliography")
166
+ ins = ins.add_child("<references hidden='true' normative='false'/>").first
167
+ refs.each do |x|
168
+ ins << <<~BIB
169
+ <bibitem id="#{x}" type="internal">
170
+ <docidentifier type="repository">#{x.sub(/^#{prefix}_/, "#{prefix}/")}</docidentifier>
171
+ </bibitem>
172
+ BIB
173
+ end
174
+ end
175
+
176
+ def indirect_eref_to_xref(eref, ident)
177
+ loc = eref&.at("./localityStack[locality[@type = 'anchor']]")
178
+ &.remove&.text ||
179
+ eref&.at("./locality[@type = 'anchor']")&.remove&.text || ident
180
+ eref.name = "xref"
181
+ eref.delete("bibitemid")
182
+ eref.delete("citeas")
183
+ eref["target"] = loc
184
+ unless eref.document.at("//*[@id = '#{loc}']")
185
+ eref.children = %(** Missing target #{loc})
186
+ eref["target"] = ident
187
+ end
188
+ end
189
+
190
+ def resolve_local_indirect_erefs(xmldoc, refs, prefix)
191
+ refs.each_with_object([]) do |r, m|
192
+ id = r.sub(/^#{prefix}_/, "")
193
+ if n = xmldoc.at("//*[@id = '#{id}']") and
194
+ n.at("./ancestor-or-self::*[@type = '#{prefix}']")
195
+ xmldoc.xpath("//eref[@bibitemid = '#{r}']").each do |e|
196
+ indirect_eref_to_xref(e, id)
197
+ end
198
+ else m << r
199
+ end
200
+ end
201
+ end
202
+
203
+ def biblio_indirect_erefs(xmldoc, prefixes)
204
+ prefixes&.each do |prefix|
205
+ refs = gather_indirect_erefs(xmldoc, prefix)
206
+ refs = resolve_local_indirect_erefs(xmldoc, refs, prefix)
207
+ refs.empty? and next
208
+ insert_indirect_biblio(xmldoc, refs, prefix)
209
+ end
210
+ end
211
+ end
212
+ end
213
+ end
@@ -0,0 +1,109 @@
1
+ require "date"
2
+ require "htmlentities"
3
+ require "json"
4
+
5
+ module Metanorma
6
+ module Standoc
7
+ module Cleanup
8
+ def footnote_content(fn)
9
+ c = fn.children.respond_to?(:to_xml) ? fn.children.to_xml : fn.children
10
+ c.gsub(/ id="[^"]+"/, "")
11
+ end
12
+
13
+ # include footnotes inside figure if they are the only content
14
+ # of the paras following
15
+ def figure_footnote_cleanup(xmldoc)
16
+ nomatches = false
17
+ until nomatches
18
+ q = "//figure/following-sibling::*[1][self::p and *[1][self::fn]]"
19
+ nomatches = true
20
+ xmldoc.xpath(q).each do |s|
21
+ next if s.children.map { |c| c.text? && /[[:alpha:]]/.match(c.text) }.any?
22
+
23
+ s.previous_element << s.first_element_child.remove
24
+ s.remove
25
+ nomatches = false
26
+ end
27
+ end
28
+ end
29
+
30
+ def table_footnote_renumber1(fn, i, seen)
31
+ content = footnote_content(fn)
32
+ if seen[content] then outnum = seen[content]
33
+ else
34
+ i += 1
35
+ outnum = i
36
+ seen[content] = outnum
37
+ end
38
+ fn["reference"] = (outnum - 1 + "a".ord).chr
39
+ fn["table"] = true
40
+ [i, seen]
41
+ end
42
+
43
+ def table_footnote_renumber(xmldoc)
44
+ xmldoc.xpath("//table | //figure").each do |t|
45
+ seen = {}
46
+ i = 0
47
+ t.xpath(".//fn[not(ancestor::name)]").each do |fn|
48
+ i, seen = table_footnote_renumber1(fn, i, seen)
49
+ end
50
+ end
51
+ end
52
+
53
+ def other_footnote_renumber1(fn, i, seen)
54
+ unless fn["table"]
55
+ content = footnote_content(fn)
56
+ if seen[content] then outnum = seen[content]
57
+ else
58
+ i += 1
59
+ outnum = i
60
+ seen[content] = outnum
61
+ end
62
+ fn["reference"] = outnum.to_s
63
+ end
64
+ [i, seen]
65
+ end
66
+
67
+ def other_footnote_renumber(xmldoc)
68
+ seen = {}
69
+ i = 0
70
+ xmldoc.xpath("//fn").each do |fn|
71
+ i, seen = other_footnote_renumber1(fn, i, seen)
72
+ end
73
+ end
74
+
75
+ def title_footnote_move(xmldoc)
76
+ ins = xmldoc.at("//bibdata/language")
77
+ xmldoc.xpath("//bibdata/title//fn").each do |f|
78
+ f.name = "note"
79
+ f["type"] = "title-footnote"
80
+ f.delete("reference")
81
+ ins.previous = f.remove
82
+ end
83
+ end
84
+
85
+ def footnote_block_cleanup(xmldoc)
86
+ xmldoc.xpath("//footnoteblock").each do |f|
87
+ f.name = 'fn'
88
+ if id = xmldoc.at("//*[@id = '#{f.text}']")
89
+ f.children = id.remove.children
90
+ else
91
+ @log.add("Crossreferences", f,
92
+ "Could not resolve footnoteblock:[#{f.text}]")
93
+ f.children = "[ERROR]"
94
+ end
95
+ end
96
+ end
97
+
98
+ def footnote_cleanup(xmldoc)
99
+ footnote_block_cleanup(xmldoc)
100
+ title_footnote_move(xmldoc)
101
+ table_footnote_renumber(xmldoc)
102
+ other_footnote_renumber(xmldoc)
103
+ xmldoc.xpath("//fn").each do |fn|
104
+ fn.delete("table")
105
+ end
106
+ end
107
+ end
108
+ end
109
+ end
@@ -0,0 +1,70 @@
1
+ module Metanorma
2
+ module Standoc
3
+ module Cleanup
4
+ def svgmap_cleanup(xmldoc)
5
+ svgmap_moveattrs(xmldoc)
6
+ svgmap_populate(xmldoc)
7
+ Metanorma::Utils::svgmap_rewrite(xmldoc, @localdir)
8
+ end
9
+
10
+ def guid?(str)
11
+ /^_[0-9A-F]{8}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{12}$/i
12
+ .match(str)
13
+ end
14
+
15
+ def svgmap_moveattrs(xmldoc)
16
+ xmldoc.xpath("//svgmap").each do |s|
17
+ f = s.at(".//figure") or next
18
+ (t = s.at("./name")) && !f.at("./name") and
19
+ f.children.first.previous = t.remove
20
+ if s["id"] && guid?(f["id"])
21
+ f["id"] = s["id"]
22
+ s.delete("id")
23
+ end
24
+ svgmap_moveattrs1(s, f)
25
+ end
26
+ end
27
+
28
+ def svgmap_moveattrs1(svgmap, figure)
29
+ %w(unnumbered number subsequence keep-with-next
30
+ keep-lines-together tag multilingual-rendering).each do |a|
31
+ next if figure[a] || !svgmap[a]
32
+
33
+ figure[a] = svgmap[a]
34
+ svgmap.delete(a)
35
+ end
36
+ end
37
+
38
+ def svgmap_populate(xmldoc)
39
+ xmldoc.xpath("//svgmap").each do |s|
40
+ s1 = s.dup
41
+ s.children.remove
42
+ f = s1.at(".//figure") and s << f
43
+ s1.xpath(".//li").each do |li|
44
+ t = li&.at(".//eref | .//link | .//xref") or next
45
+ href = t.xpath("./following-sibling::node()")
46
+ href.empty? or
47
+ s << %[<target href="#{svgmap_target(href)}">#{t.to_xml}</target>]
48
+ end
49
+ end
50
+ end
51
+
52
+ def svgmap_target(nodeset)
53
+ nodeset.each do |n|
54
+ next unless n.name == "link"
55
+
56
+ n.children = n["target"]
57
+ end
58
+ nodeset.text.sub(/^[,; ]/, "").strip
59
+ end
60
+
61
+ def img_cleanup(xmldoc)
62
+ return xmldoc unless @datauriimage
63
+
64
+ xmldoc.xpath("//image").each do |i|
65
+ i["src"] = Metanorma::Utils::datauri(i["src"], @localdir)
66
+ end
67
+ end
68
+ end
69
+ end
70
+ end