metanorma-standoc 1.9.0 → 1.10.0

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.
Files changed (72) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/rake.yml +3 -13
  3. data/.hound.yml +3 -1
  4. data/.rubocop.yml +4 -8
  5. data/lib/asciidoctor/standoc/base.rb +31 -35
  6. data/lib/asciidoctor/standoc/biblio.rng +1 -0
  7. data/lib/asciidoctor/standoc/blocks.rb +25 -9
  8. data/lib/asciidoctor/standoc/blocks_notes.rb +41 -24
  9. data/lib/asciidoctor/standoc/cleanup.rb +59 -84
  10. data/lib/asciidoctor/standoc/cleanup_block.rb +63 -85
  11. data/lib/asciidoctor/standoc/cleanup_boilerplate.rb +28 -15
  12. data/lib/asciidoctor/standoc/cleanup_footnotes.rb +1 -0
  13. data/lib/asciidoctor/standoc/cleanup_image.rb +71 -0
  14. data/lib/asciidoctor/standoc/cleanup_inline.rb +117 -77
  15. data/lib/asciidoctor/standoc/cleanup_maths.rb +36 -27
  16. data/lib/asciidoctor/standoc/cleanup_ref.rb +31 -15
  17. data/lib/asciidoctor/standoc/cleanup_ref_dl.rb +1 -1
  18. data/lib/asciidoctor/standoc/cleanup_reqt.rb +47 -0
  19. data/lib/asciidoctor/standoc/cleanup_section.rb +77 -135
  20. data/lib/asciidoctor/standoc/cleanup_section_names.rb +75 -0
  21. data/lib/asciidoctor/standoc/cleanup_terms.rb +19 -18
  22. data/lib/asciidoctor/standoc/converter.rb +7 -2
  23. data/lib/asciidoctor/standoc/datamodel/plantuml_renderer.rb +67 -66
  24. data/lib/asciidoctor/standoc/front.rb +35 -18
  25. data/lib/asciidoctor/standoc/front_contributor.rb +70 -45
  26. data/lib/asciidoctor/standoc/inline.rb +45 -34
  27. data/lib/asciidoctor/standoc/isodoc.rng +209 -4
  28. data/lib/asciidoctor/standoc/lists.rb +4 -2
  29. data/lib/asciidoctor/standoc/macros.rb +11 -11
  30. data/lib/asciidoctor/standoc/macros_form.rb +63 -0
  31. data/lib/asciidoctor/standoc/macros_plantuml.rb +19 -21
  32. data/lib/asciidoctor/standoc/macros_terms.rb +33 -23
  33. data/lib/asciidoctor/standoc/ref.rb +87 -112
  34. data/lib/asciidoctor/standoc/ref_date_id.rb +62 -0
  35. data/lib/asciidoctor/standoc/ref_sect.rb +20 -17
  36. data/lib/asciidoctor/standoc/section.rb +3 -1
  37. data/lib/asciidoctor/standoc/term_lookup_cleanup.rb +40 -27
  38. data/lib/asciidoctor/standoc/terms.rb +25 -18
  39. data/lib/asciidoctor/standoc/utils.rb +35 -9
  40. data/lib/asciidoctor/standoc/validate.rb +48 -33
  41. data/lib/metanorma-standoc.rb +0 -1
  42. data/lib/metanorma/standoc/version.rb +1 -1
  43. data/metanorma-standoc.gemspec +4 -4
  44. data/spec/asciidoctor/base_spec.rb +701 -508
  45. data/spec/asciidoctor/blocks_spec.rb +831 -738
  46. data/spec/asciidoctor/cleanup_sections_spec.rb +51 -14
  47. data/spec/asciidoctor/cleanup_spec.rb +889 -682
  48. data/spec/asciidoctor/inline_spec.rb +62 -14
  49. data/spec/asciidoctor/isobib_cache_spec.rb +404 -358
  50. data/spec/asciidoctor/lists_spec.rb +149 -137
  51. data/spec/asciidoctor/macros_plantuml_spec.rb +8 -8
  52. data/spec/asciidoctor/macros_spec.rb +923 -503
  53. data/spec/asciidoctor/macros_yaml2text_spec.rb +1 -1
  54. data/spec/asciidoctor/refs_dl_spec.rb +4 -4
  55. data/spec/asciidoctor/refs_spec.rb +1528 -1533
  56. data/spec/asciidoctor/section_spec.rb +405 -299
  57. data/spec/asciidoctor/table_spec.rb +6 -6
  58. data/spec/asciidoctor/validate_spec.rb +342 -304
  59. data/spec/spec_helper.rb +13 -9
  60. data/spec/vcr_cassettes/dated_iso_ref_joint_iso_iec.yml +54 -54
  61. data/spec/vcr_cassettes/isobib_get_123.yml +13 -13
  62. data/spec/vcr_cassettes/isobib_get_123_1.yml +25 -25
  63. data/spec/vcr_cassettes/isobib_get_123_1_fr.yml +37 -37
  64. data/spec/vcr_cassettes/isobib_get_123_2001.yml +12 -12
  65. data/spec/vcr_cassettes/isobib_get_124.yml +13 -13
  66. data/spec/vcr_cassettes/rfcbib_get_rfc8341.yml +14 -14
  67. data/spec/vcr_cassettes/separates_iev_citations_by_top_level_clause.yml +46 -46
  68. metadata +16 -15
  69. data/lib/liquid/custom_blocks/key_iterator.rb +0 -21
  70. data/lib/liquid/custom_blocks/with_json_nested_context.rb +0 -18
  71. data/lib/liquid/custom_blocks/with_yaml_nested_context.rb +0 -19
  72. data/lib/liquid/custom_filters/values.rb +0 -7
@@ -37,14 +37,15 @@ module Asciidoctor
37
37
  end
38
38
  end
39
39
 
40
- def insert_thead(s)
41
- thead = s.at("./thead")
40
+ def insert_thead(table)
41
+ thead = table.at("./thead")
42
42
  return thead unless thead.nil?
43
- if tname = s.at("./name")
43
+
44
+ if tname = table.at("./name")
44
45
  thead = tname.add_next_sibling("<thead/>").first
45
46
  return thead
46
47
  end
47
- s.children.first.add_previous_sibling("<thead/>").first
48
+ table.children.first.add_previous_sibling("<thead/>").first
48
49
  end
49
50
 
50
51
  def header_rows_cleanup(xmldoc)
@@ -80,21 +81,21 @@ module Asciidoctor
80
81
  end
81
82
 
82
83
  # include where definition list inside stem block
83
- def formula_cleanup(x)
84
- formula_cleanup_where1(x)
85
- formula_cleanup_where2(x)
84
+ def formula_cleanup(formula)
85
+ formula_cleanup_where1(formula)
86
+ formula_cleanup_where2(formula)
86
87
  end
87
88
 
88
- def formula_cleanup_where1(x)
89
+ def formula_cleanup_where1(formula)
89
90
  q = "//formula/following-sibling::*[1][self::dl]"
90
- x.xpath(q).each do |s|
91
+ formula.xpath(q).each do |s|
91
92
  s["key"] == "true" and s.previous_element << s.remove
92
93
  end
93
94
  end
94
95
 
95
- def formula_cleanup_where2(x)
96
+ def formula_cleanup_where2(formula)
96
97
  q = "//formula/following-sibling::*[1][self::p]"
97
- x.xpath(q).each do |s|
98
+ formula.xpath(q).each do |s|
98
99
  if s.text =~ /^\s*where[^a-z]*$/i && s&.next_element&.name == "dl"
99
100
  s.next_element["key"] = "true"
100
101
  s.previous_element << s.next_element.remove
@@ -125,9 +126,10 @@ module Asciidoctor
125
126
  # examples containing only figures become subfigures of figures
126
127
  def subfigure_cleanup(xmldoc)
127
128
  xmldoc.xpath("//example[figure]").each do |e|
128
- next unless e.elements.map { |m| m.name }.reject do |m|
129
+ next unless e.elements.map(&:name).reject do |m|
129
130
  %w(name figure).include? m
130
131
  end.empty?
132
+
131
133
  e.name = "figure"
132
134
  end
133
135
  end
@@ -142,7 +144,7 @@ module Asciidoctor
142
144
  ELEMS_ALLOW_NOTES = %w[p formula ul ol dl figure].freeze
143
145
 
144
146
  # if a note is at the end of a section, it is left alone
145
- # if a note is followed by a non-note block,
147
+ # if a note is followed by a non-note block,
146
148
  # it is moved inside its preceding block if it is not delimited
147
149
  # (so there was no way of making that block include the note)
148
150
  def note_cleanup(xmldoc)
@@ -150,6 +152,7 @@ module Asciidoctor
150
152
  xmldoc.xpath(q).each do |n|
151
153
  next if n["keep-separate"] == "true"
152
154
  next unless n.ancestors("table").empty?
155
+
153
156
  prev = n.previous_element || next
154
157
  n.parent = prev if ELEMS_ALLOW_NOTES.include? prev.name
155
158
  end
@@ -159,100 +162,75 @@ module Asciidoctor
159
162
  end
160
163
  end
161
164
 
162
- def requirement_cleanup(x)
163
- requirement_descriptions(x)
164
- requirement_inherit(x)
165
- end
166
-
167
- def requirement_inherit(x)
168
- x.xpath("//requirement | //recommendation | //permission").each do |r|
169
- ins = r.at("./classification") ||
170
- r.at("./description | ./measurementtarget | ./specification | "\
171
- "./verification | ./import | ./description | ./requirement | "\
172
- "./recommendation | ./permission")
173
- r.xpath("./*//inherit").each { |i| ins.previous = i }
165
+ def link_callouts_to_annotations(callouts, annotations)
166
+ callouts.each_with_index do |c, i|
167
+ c["target"] = "_#{UUIDTools::UUID.random_create}"
168
+ annotations[i]["id"] = c["target"]
174
169
  end
175
170
  end
176
171
 
177
- def requirement_descriptions(x)
178
- x.xpath("//requirement | //recommendation | //permission").each do |r|
179
- r.children.each do |e|
180
- unless e.element? && (reqt_subpart(e.name) ||
181
- %w(requirement recommendation permission).include?(e.name))
182
- t = Nokogiri::XML::Element.new("description", x)
183
- e.before(t)
184
- t.children = e.remove
185
- end
186
- end
187
- requirement_cleanup1(r)
172
+ def align_callouts_to_annotations(xmldoc)
173
+ xmldoc.xpath("//sourcecode").each do |x|
174
+ callouts = x.elements.select { |e| e.name == "callout" }
175
+ annotations = x.elements.select { |e| e.name == "annotation" }
176
+ callouts.size == annotations.size and
177
+ link_callouts_to_annotations(callouts, annotations)
188
178
  end
189
179
  end
190
180
 
191
- def requirement_cleanup1(r)
192
- while d = r.at("./description[following-sibling::*[1]"\
193
- "[self::description]]")
194
- n = d.next.remove
195
- d << n.children
196
- end
197
- r.xpath("./description[normalize-space(.)='']").each do |d|
198
- d.replace("\n")
181
+ def merge_annotations_into_sourcecode(xmldoc)
182
+ xmldoc.xpath("//sourcecode").each do |x|
183
+ while x&.next_element&.name == "annotation"
184
+ x.next_element.parent = x
185
+ end
199
186
  end
200
187
  end
201
188
 
202
- def svgmap_cleanup(xmldoc)
203
- svgmap_moveattrs(xmldoc)
204
- svgmap_populate(xmldoc)
205
- Metanorma::Utils::svgmap_rewrite(xmldoc, @localdir)
189
+ def callout_cleanup(xmldoc)
190
+ merge_annotations_into_sourcecode(xmldoc)
191
+ align_callouts_to_annotations(xmldoc)
206
192
  end
207
193
 
208
- def guid?(x)
209
- /^_[0-9A-F]{8}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{12}$/i.
210
- match(x)
211
- end
194
+ def sourcecode_cleanup(xmldoc)
195
+ xmldoc.xpath("//sourcecode").each do |x|
196
+ x.traverse do |n|
197
+ next unless n.text?
198
+ next unless /#{Regexp.escape(@sourcecode_markup_start)}/
199
+ .match?(n.text)
212
200
 
213
- def svgmap_moveattrs(xmldoc)
214
- xmldoc.xpath("//svgmap").each do |s|
215
- f = s.at(".//figure") or next
216
- if t = s.at("./name") and !f.at("./name")
217
- f.children.first.previous = t.remove
201
+ n.replace(sourcecode_markup(n))
218
202
  end
219
- if s["id"] && guid?(f["id"])
220
- f["id"] = s["id"]
221
- s.delete("id")
222
- end
223
- svgmap_moveattrs1(s, f)
224
203
  end
225
204
  end
226
205
 
227
- def svgmap_moveattrs1(s, f)
228
- %w(unnumbered number subsequence keep-with-next
229
- keep-lines-together).each do |a|
230
- next if f[a] || !s[a]
231
- f[a] = s[a]
232
- s.delete(a)
233
- end
206
+ def safe_noko(text, doc)
207
+ Nokogiri::XML::Text.new(text, doc).to_xml(
208
+ encoding: "US-ASCII",
209
+ save_with: Nokogiri::XML::Node::SaveOptions::NO_DECLARATION
210
+ )
234
211
  end
235
212
 
236
- def svgmap_populate(xmldoc)
237
- xmldoc.xpath("//svgmap").each do |s|
238
- s1 = s.dup
239
- s.children.remove
240
- f = s1.at(".//figure") and s << f
241
- s1.xpath(".//li").each do |li|
242
- t = li&.at(".//eref | .//link | .//xref") or next
243
- href = t.xpath("./following-sibling::node()")
244
- href.empty? or
245
- s << %[<target href="#{svgmap_target(href)}">#{t.to_xml}</target>]
246
- end
213
+ def sourcecode_markup(node)
214
+ acc = []
215
+ node.text.split(/(#{Regexp.escape(@sourcecode_markup_start)}|
216
+ #{Regexp.escape(@sourcecode_markup_end)})/x)
217
+ .each_slice(4).map do |a|
218
+ acc << safe_noko(a[0], node.document)
219
+ next unless a.size == 4
220
+
221
+ acc << Asciidoctor.convert(
222
+ a[2], doctype: :inline, backend: (self&.backend&.to_sym || :standoc)
223
+ )
247
224
  end
225
+ acc.join
248
226
  end
249
227
 
250
- def svgmap_target(nodeset)
251
- nodeset.each do |n|
252
- next unless n.name == "link"
253
- n.children = n["target"]
228
+ def form_cleanup(xmldoc)
229
+ xmldoc.xpath("//select").each do |s|
230
+ while s&.next_element&.name == "option"
231
+ s << s.next_element
232
+ end
254
233
  end
255
- nodeset.text.sub(/^[,; ]/, "").strip
256
234
  end
257
235
  end
258
236
  end
@@ -38,17 +38,23 @@ module Asciidoctor
38
38
  end
39
39
  end
40
40
 
41
- def norm_ref_preface(f)
42
- refs = f.elements.select do |e|
43
- ["reference", "bibitem"].include? e.name
41
+ def norm_ref_preface(ref)
42
+ if ref.at("./note[@type = 'boilerplate']")
43
+ unwrap_boilerplate_clauses(ref, ".")
44
+ else
45
+ refs = ref.elements.select do |e|
46
+ %w(references bibitem).include? e.name
47
+ end
48
+ pref = refs.empty? ? @i18n.norm_empty_pref : @i18n.norm_with_refs_pref
49
+ ref.at("./title").next = "<p>#{pref}</p>"
44
50
  end
45
- f.at("./title").next =
46
- "<p>#{(refs.empty? ? @i18n.norm_empty_pref : @i18n.norm_with_refs_pref)}</p>"
47
51
  end
48
52
 
49
- TERM_CLAUSE = "//sections/terms | //sections/clause[descendant::terms]".freeze
53
+ TERM_CLAUSE = "//sections/terms | "\
54
+ "//sections/clause[descendant::terms]".freeze
50
55
 
51
- NORM_REF = "//bibliography/references[@normative = 'true']".freeze
56
+ NORM_REF = "//bibliography/references[@normative = 'true'] | "\
57
+ "//bibliography/clause[.//references[@normative = 'true']]".freeze
52
58
 
53
59
  def boilerplate_isodoc(xmldoc)
54
60
  x = xmldoc.dup
@@ -67,25 +73,32 @@ module Asciidoctor
67
73
  xmldoc.xpath("//terms/p | //terms/ul").each(&:remove)
68
74
  end
69
75
 
70
- def termdef_unwrap_boilerplate_clauses(xmldoc)
71
- xmldoc.xpath(self.class::TERM_CLAUSE).each do |f|
72
- f.xpath(".//clause[@type = 'boilerplate']").each do |c|
76
+ def unwrap_boilerplate_clauses(xmldoc, xpath)
77
+ xmldoc.xpath(xpath).each do |f|
78
+ f.xpath(".//clause[@type = 'boilerplate'] | "\
79
+ ".//note[@type = 'boilerplate']").each do |c|
73
80
  c&.at("./title")&.remove
74
81
  c.replace(c.children)
75
82
  end
76
83
  end
77
84
  end
78
85
 
79
- def boilerplate_cleanup(xmldoc)
80
- isodoc = boilerplate_isodoc(xmldoc)
81
- termdef_boilerplate_cleanup(xmldoc)
86
+ def termdef_boilerplate_insert(xmldoc, isodoc, once = false)
82
87
  xmldoc.xpath(self.class::TERM_CLAUSE).each do |f|
83
88
  next if f.at("./clause[@type = 'boilerplate']")
84
89
 
85
- term_defs_boilerplate(f.at("./title"), xmldoc.xpath(".//termdocsource"),
90
+ term_defs_boilerplate(f.at("./title"),
91
+ xmldoc.xpath(".//termdocsource"),
86
92
  f.at(".//term"), f.at(".//p"), isodoc)
93
+ break if once
87
94
  end
88
- termdef_unwrap_boilerplate_clauses(xmldoc)
95
+ end
96
+
97
+ def boilerplate_cleanup(xmldoc)
98
+ isodoc = boilerplate_isodoc(xmldoc)
99
+ termdef_boilerplate_cleanup(xmldoc)
100
+ termdef_boilerplate_insert(xmldoc, isodoc)
101
+ unwrap_boilerplate_clauses(xmldoc, self.class::TERM_CLAUSE)
89
102
  f = xmldoc.at(self.class::NORM_REF) and norm_ref_preface(f)
90
103
  initial_boilerplate(xmldoc, isodoc)
91
104
  end
@@ -20,6 +20,7 @@ module Asciidoctor
20
20
  nomatches = true
21
21
  xmldoc.xpath(q).each do |s|
22
22
  next if s.children.map { |c| c.text? && /[[:alpha:]]/.match(c.text) }.any?
23
+
23
24
  s.previous_element << s.first_element_child.remove
24
25
  s.remove
25
26
  nomatches = false
@@ -0,0 +1,71 @@
1
+ module Asciidoctor
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
+ if (t = s.at("./name")) && !f.at("./name")
19
+ f.children.first.previous = t.remove
20
+ end
21
+ if s["id"] && guid?(f["id"])
22
+ f["id"] = s["id"]
23
+ s.delete("id")
24
+ end
25
+ svgmap_moveattrs1(s, f)
26
+ end
27
+ end
28
+
29
+ def svgmap_moveattrs1(s, f)
30
+ %w(unnumbered number subsequence keep-with-next
31
+ keep-lines-together).each do |a|
32
+ next if f[a] || !s[a]
33
+
34
+ f[a] = s[a]
35
+ s.delete(a)
36
+ end
37
+ end
38
+
39
+ def svgmap_populate(xmldoc)
40
+ xmldoc.xpath("//svgmap").each do |s|
41
+ s1 = s.dup
42
+ s.children.remove
43
+ f = s1.at(".//figure") and s << f
44
+ s1.xpath(".//li").each do |li|
45
+ t = li&.at(".//eref | .//link | .//xref") or next
46
+ href = t.xpath("./following-sibling::node()")
47
+ href.empty? or
48
+ s << %[<target href="#{svgmap_target(href)}">#{t.to_xml}</target>]
49
+ end
50
+ end
51
+ end
52
+
53
+ def svgmap_target(nodeset)
54
+ nodeset.each do |n|
55
+ next unless n.name == "link"
56
+
57
+ n.children = n["target"]
58
+ end
59
+ nodeset.text.sub(/^[,; ]/, "").strip
60
+ end
61
+
62
+ def img_cleanup(xmldoc)
63
+ return xmldoc unless @datauriimage
64
+
65
+ xmldoc.xpath("//image").each do |i|
66
+ i["src"] = Metanorma::Utils::datauri(i["src"], @localdir)
67
+ end
68
+ end
69
+ end
70
+ end
71
+ end
@@ -3,32 +3,54 @@ require "metanorma-utils"
3
3
  module Asciidoctor
4
4
  module Standoc
5
5
  module Cleanup
6
- def empty_text_before_first_element(x)
7
- x.children.each do |c|
8
- return false if c.text? and /\S/.match(c.text)
6
+ def empty_text_before_first_element(elem)
7
+ elem.children.each do |c|
8
+ return false if c.text? && /\S/.match(c.text)
9
9
  return true if c.element?
10
10
  end
11
11
  true
12
12
  end
13
13
 
14
- def strip_initial_space(x)
15
- if x.children[0].text?
16
- if !/\S/.match(x.children[0].text)
17
- x.children[0].remove
18
- else
19
- x.children[0].content = x.children[0].text.gsub(/^ /, "")
20
- end
14
+ def strip_initial_space(elem)
15
+ return unless elem.children[0].text?
16
+
17
+ if /\S/.match?(elem.children[0].text)
18
+ elem.children[0].content = elem.children[0].text.gsub(/^ /, "")
19
+ else
20
+ elem.children[0].remove
21
21
  end
22
22
  end
23
23
 
24
24
  def bookmark_cleanup(xmldoc)
25
+ li_bookmark_cleanup(xmldoc)
26
+ dt_bookmark_cleanup(xmldoc)
27
+ end
28
+
29
+ def bookmark_to_id(elem, bookmark)
30
+ parent = bookmark.parent
31
+ elem["id"] = bookmark.remove["id"]
32
+ strip_initial_space(parent)
33
+ end
34
+
35
+ def li_bookmark_cleanup(xmldoc)
25
36
  xmldoc.xpath("//li[descendant::bookmark]").each do |x|
26
- if x&.elements&.first&.name == "p" &&
27
- x&.elements&.first&.elements&.first&.name == "bookmark"
28
- if empty_text_before_first_element(x.elements[0])
29
- x["id"] = x.elements[0].elements[0].remove["id"]
30
- strip_initial_space(x.elements[0])
31
- end
37
+ if x.at("./*[1][local-name() = 'p']/"\
38
+ "*[1][local-name() = 'bookmark']") &&
39
+ empty_text_before_first_element(x.elements[0])
40
+ bookmark_to_id(x, x.elements[0].elements[0])
41
+ end
42
+ end
43
+ end
44
+
45
+ def dt_bookmark_cleanup(xmldoc)
46
+ xmldoc.xpath("//dt[descendant::bookmark]").each do |x|
47
+ if x.at("./*[1][local-name() = 'p']/"\
48
+ "*[1][local-name() = 'bookmark']") &&
49
+ empty_text_before_first_element(x.elements[0])
50
+ bookmark_to_id(x, x.elements[0].elements[0])
51
+ elsif x.at("./*[1][local-name() = 'bookmark']") &&
52
+ empty_text_before_first_element(x)
53
+ bookmark_to_id(x, x.elements[0])
32
54
  end
33
55
  end
34
56
  end
@@ -46,65 +68,67 @@ module Asciidoctor
46
68
  LOCALITY_RE = Regexp.new(LOCALITY_REGEX_STR.gsub(/\s/, ""),
47
69
  Regexp::IGNORECASE | Regexp::MULTILINE)
48
70
 
49
- def tq(x)
50
- x.sub(/^"/, "").sub(/"$/, "")
71
+ def tq(text)
72
+ text.sub(/^"/, "").sub(/"$/, "")
51
73
  end
52
74
 
53
- def extract_localities(x)
54
- f = x&.children&.first or return
75
+ def extract_localities(elem)
76
+ f = elem&.children&.first or return
55
77
  f.text? or return
56
78
  head = f.remove.text
57
- tail = x&.children&.remove
58
- extract_localities1(x, head)
59
- tail and x << tail
79
+ tail = elem&.children&.remove
80
+ extract_localities1(elem, head)
81
+ tail and elem << tail
60
82
  end
61
83
 
62
- def extract_localities1(x, text)
63
- b = x.add_child("<localityStack/>").first if LOCALITY_RE.match text
84
+ def extract_localities1(elem, text)
85
+ b = elem.add_child("<localityStack/>").first if LOCALITY_RE.match text
64
86
  while (m = LOCALITY_RE.match text)
65
87
  ref = m[:ref] ? "<referenceFrom>#{tq m[:ref]}</referenceFrom>" : ""
66
88
  refto = m[:to] ? "<referenceTo>#{tq m[:to]}</referenceTo>" : ""
67
89
  loc = m[:locality]&.downcase || m[:locality2]&.downcase
68
90
  b.add_child("<locality type='#{loc}'>#{ref}#{refto}</locality>")
69
91
  text = m[:text]
70
- b = x.add_child("<localityStack/>").first if m[:punct] == ";"
92
+ b = elem.add_child("<localityStack/>").first if m[:punct] == ";"
71
93
  end
72
- x.add_child(text) if text
94
+ elem.add_child(text) if text
73
95
  end
74
96
 
75
- def xref_to_eref(x)
76
- x["bibitemid"] = x["target"]
77
- unless x["citeas"] = @anchors&.dig(x["target"], :xref)
78
- @internal_eref_namespaces.include?(x["type"]) or
79
- @log.add("Crossreferences", x,
80
- "#{x['target']} does not have a corresponding anchor ID in the bibliography!")
97
+ def xref_to_eref(elem)
98
+ elem["bibitemid"] = elem["target"]
99
+ unless elem["citeas"] = @anchors&.dig(elem["target"], :xref)
100
+ @internal_eref_namespaces.include?(elem["type"]) or
101
+ @log.add("Crossreferences", elem,
102
+ "#{elem['target']} does not have a corresponding "\
103
+ "anchor ID in the bibliography!")
81
104
  end
82
- x.delete("target")
83
- extract_localities(x) unless x.children.empty?
105
+ elem.delete("target")
106
+ extract_localities(elem) unless elem.children.empty?
84
107
  end
85
108
 
86
109
  def xref_cleanup(xmldoc)
87
110
  xmldoc.xpath("//xref").each do |x|
88
111
  /:/.match(x["target"]) and xref_to_internal_eref(x)
89
112
  next unless x.name == "xref"
113
+
90
114
  if refid? x["target"]
91
115
  x.name = "eref"
92
116
  xref_to_eref(x)
93
- else
94
- x.delete("type")
117
+ else x.delete("type")
95
118
  end
96
119
  end
97
120
  end
98
121
 
99
- def xref_to_internal_eref(x)
100
- a = x["target"].split(":", 3)
101
- unless a.size < 2 || a[0].empty? || a[1].empty?
102
- x["target"] = "#{a[0]}_#{a[1]}"
103
- a.size > 2 and x.children = %{anchor="#{a[2..-1].join("")}",#{x&.children&.text}}
104
- x["type"] = a[0]
122
+ def xref_to_internal_eref(elem)
123
+ a = elem["target"].split(":", 3)
124
+ unless a.size < 2 || a[0].empty? || a[1].empty?
125
+ elem["target"] = "#{a[0]}_#{a[1]}"
126
+ a.size > 2 and
127
+ elem.children = %{anchor="#{a[2..-1].join}",#{elem&.children&.text}}
128
+ elem["type"] = a[0]
105
129
  @internal_eref_namespaces << a[0]
106
- x.name = "eref"
107
- xref_to_eref(x)
130
+ elem.name = "eref"
131
+ xref_to_eref(elem)
108
132
  end
109
133
  end
110
134
 
@@ -116,10 +140,11 @@ module Asciidoctor
116
140
 
117
141
  def origin_cleanup(xmldoc)
118
142
  xmldoc.xpath("//origin/concept[termref]").each do |x|
119
- x.replace(x.children)
143
+ t = x.at("./termref")
144
+ x.replace(t)
120
145
  end
121
146
  xmldoc.xpath("//origin").each do |x|
122
- x["citeas"] = @anchors&.dig(x["bibitemid"], :xref) ||
147
+ x["citeas"] = @anchors&.dig(x["bibitemid"], :xref) or
123
148
  @log.add("Crossreferences", x,
124
149
  "#{x['bibitemid']} does not have a corresponding anchor "\
125
150
  "ID in the bibliography!")
@@ -128,68 +153,83 @@ module Asciidoctor
128
153
  end
129
154
 
130
155
  def concept_cleanup(xmldoc)
131
- xmldoc.xpath("//concept").each do |x|
132
- x.delete("term") if x["term"].empty?
133
- if /:/.match(x["key"]) then concept_termbase_cleanup(x)
156
+ xmldoc.xpath("//concept[not(termxref)]").each do |x|
157
+ term = x.at("./refterm")
158
+ term&.remove if term&.text&.empty?
159
+ x.children.remove if x&.children&.text&.strip&.empty?
160
+ key_extract_locality(x)
161
+ if /:/.match?(x["key"]) then concept_termbase_cleanup(x)
134
162
  elsif refid? x["key"] then concept_eref_cleanup(x)
135
- else
136
- concept_xref_cleanup(x)
163
+ else concept_xref_cleanup(x)
137
164
  end
138
165
  x.delete("key")
139
166
  end
140
167
  end
141
168
 
142
- def concept_termbase_cleanup(x)
143
- text = x&.children&.first&.remove&.text
144
- termbase, key = x["key"].split(/:/, 2)
145
- x.add_child(%(<termref base="#{termbase}" target="#{key}">) +
146
- "#{text}</termref>")
169
+ def key_extract_locality(elem)
170
+ return unless /,/.match?(elem["key"])
171
+
172
+ elem.add_child("<locality>#{elem['key'].sub(/^[^,]+,/, '')}</locality>")
173
+ elem["key"] = elem["key"].sub(/,.*$/, "")
174
+ end
175
+
176
+ def concept_termbase_cleanup(elem)
177
+ t = elem&.at("./xrefrender")&.remove&.children
178
+ termbase, key = elem["key"].split(/:/, 2)
179
+ elem.add_child(%(<termref base="#{termbase}" target="#{key}">) +
180
+ "#{t&.to_xml}</termref>")
147
181
  end
148
182
 
149
- def concept_xref_cleanup(x)
150
- text = x&.children&.first&.remove&.text
151
- x.add_child(%(<xref target="#{x['key']}">#{text}</xref>))
183
+ def concept_xref_cleanup(elem)
184
+ t = elem&.at("./xrefrender")&.remove&.children
185
+ elem.add_child(%(<xref target="#{elem['key']}">#{t&.to_xml}</xref>))
152
186
  end
153
187
 
154
- def concept_eref_cleanup(x)
155
- x.children = "<eref>#{x.children.to_xml}</eref>"
156
- extract_localities(x.first_element_child)
188
+ def concept_eref_cleanup(elem)
189
+ t = elem&.at("./xrefrender")&.remove&.children&.to_xml
190
+ l = elem&.at("./locality")&.remove&.children&.to_xml
191
+ elem.add_child "<eref bibitemid='#{elem['key']}'>#{l}</eref>"
192
+ extract_localities(elem.elements[-1])
193
+ elem.elements[-1].add_child(t) if t
157
194
  end
158
195
 
159
- def to_xreftarget(s)
160
- return Metanorma::Utils::to_ncname(s) unless /^[^#]+#.+$/.match(s)
161
- /^(?<pref>[^#]+)#(?<suff>.+)$/ =~ s
162
- pref = pref.gsub(%r([#{Metanorma::Utils::NAMECHAR}]), "_")
163
- suff = suff.gsub(%r([#{Metanorma::Utils::NAMECHAR}]), "_")
196
+ def to_xreftarget(str)
197
+ return Metanorma::Utils::to_ncname(str) unless /^[^#]+#.+$/.match?(str)
198
+
199
+ /^(?<pref>[^#]+)#(?<suff>.+)$/ =~ str
200
+ pref = pref.gsub(%r([#{Metanorma::Utils::NAMECHAR}])o, "_")
201
+ suff = suff.gsub(%r([#{Metanorma::Utils::NAMECHAR}])o, "_")
164
202
  "#{pref}##{suff}"
165
203
  end
166
204
 
167
205
  IDREF = "//*/@id | //review/@from | //review/@to | "\
168
206
  "//callout/@target | //citation/@bibitemid | //eref/@bibitemid".freeze
169
207
 
170
- def anchor_cleanup(x)
171
- anchor_cleanup1(x)
172
- xreftarget_cleanup(x)
208
+ def anchor_cleanup(elem)
209
+ anchor_cleanup1(elem)
210
+ xreftarget_cleanup(elem)
173
211
  end
174
212
 
175
- def anchor_cleanup1(x)
176
- x.xpath(IDREF).each do |s|
213
+ def anchor_cleanup1(elem)
214
+ elem.xpath(IDREF).each do |s|
177
215
  if (ret = Metanorma::Utils::to_ncname(s.value)) != (orig = s.value)
178
216
  s.value = ret
179
217
  output = s.parent.dup
180
218
  output.children.remove
181
- @log.add("Anchors", s.parent, "normalised identifier in #{output} from #{orig}")
219
+ @log.add("Anchors", s.parent,
220
+ "normalised identifier in #{output} from #{orig}")
182
221
  end
183
222
  end
184
223
  end
185
224
 
186
- def xreftarget_cleanup(x)
187
- x.xpath("//xref/@target").each do |s|
225
+ def xreftarget_cleanup(elem)
226
+ elem.xpath("//xref/@target").each do |s|
188
227
  if (ret = to_xreftarget(s.value)) != (orig = s.value)
189
228
  s.value = ret
190
229
  output = s.parent.dup
191
230
  output.children.remove
192
- @log.add("Anchors", s.parent, "normalised identifier in #{output} from #{orig}")
231
+ @log.add("Anchors", s.parent,
232
+ "normalised identifier in #{output} from #{orig}")
193
233
  end
194
234
  end
195
235
  end