metanorma-standoc 1.10.6 → 1.11.0.1

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 (63) hide show
  1. checksums.yaml +4 -4
  2. data/README.adoc +19 -23
  3. data/Rakefile +1 -1
  4. data/lib/asciidoctor/standoc/base.rb +10 -17
  5. data/lib/asciidoctor/standoc/basicdoc.rng +21 -4
  6. data/lib/asciidoctor/standoc/blocks.rb +23 -23
  7. data/lib/asciidoctor/standoc/blocks_notes.rb +17 -22
  8. data/lib/asciidoctor/standoc/cleanup.rb +46 -12
  9. data/lib/asciidoctor/standoc/cleanup_block.rb +3 -71
  10. data/lib/asciidoctor/standoc/cleanup_image.rb +6 -7
  11. data/lib/asciidoctor/standoc/cleanup_inline.rb +42 -106
  12. data/lib/asciidoctor/standoc/cleanup_maths.rb +5 -6
  13. data/lib/asciidoctor/standoc/cleanup_ref.rb +5 -0
  14. data/lib/asciidoctor/standoc/cleanup_reqt.rb +5 -24
  15. data/lib/asciidoctor/standoc/cleanup_section_names.rb +5 -5
  16. data/lib/asciidoctor/standoc/cleanup_symbols.rb +48 -0
  17. data/lib/asciidoctor/standoc/cleanup_table.rb +68 -0
  18. data/lib/asciidoctor/standoc/cleanup_terms.rb +37 -77
  19. data/lib/asciidoctor/standoc/cleanup_terms_designations.rb +162 -0
  20. data/lib/asciidoctor/standoc/cleanup_text.rb +5 -2
  21. data/lib/asciidoctor/standoc/cleanup_xref.rb +107 -0
  22. data/lib/asciidoctor/standoc/converter.rb +14 -0
  23. data/lib/asciidoctor/standoc/inline.rb +7 -5
  24. data/lib/asciidoctor/standoc/isodoc.rng +419 -77
  25. data/lib/asciidoctor/standoc/lists.rb +15 -15
  26. data/lib/asciidoctor/standoc/macros.rb +14 -43
  27. data/lib/asciidoctor/standoc/macros_note.rb +45 -0
  28. data/lib/asciidoctor/standoc/macros_plantuml.rb +29 -14
  29. data/lib/asciidoctor/standoc/macros_terms.rb +55 -8
  30. data/lib/asciidoctor/standoc/ref_sect.rb +26 -18
  31. data/lib/asciidoctor/standoc/reqt.rng +23 -2
  32. data/lib/asciidoctor/standoc/term_lookup_cleanup.rb +50 -11
  33. data/lib/asciidoctor/standoc/terms.rb +12 -2
  34. data/lib/asciidoctor/standoc/utils.rb +36 -23
  35. data/lib/asciidoctor/standoc/validate.rb +45 -27
  36. data/lib/asciidoctor/standoc/validate_section.rb +5 -2
  37. data/lib/metanorma/standoc/version.rb +1 -1
  38. data/metanorma-standoc.gemspec +1 -1
  39. data/spec/asciidoctor/base_spec.rb +4 -36
  40. data/spec/asciidoctor/blank_spec.rb +37 -0
  41. data/spec/asciidoctor/blocks_spec.rb +208 -49
  42. data/spec/asciidoctor/cleanup_sections_spec.rb +153 -12
  43. data/spec/asciidoctor/cleanup_spec.rb +104 -285
  44. data/spec/asciidoctor/cleanup_terms_spec.rb +990 -0
  45. data/spec/asciidoctor/inline_spec.rb +38 -2
  46. data/spec/asciidoctor/lists_spec.rb +6 -6
  47. data/spec/asciidoctor/macros_plantuml_spec.rb +37 -2
  48. data/spec/asciidoctor/macros_spec.rb +191 -114
  49. data/spec/asciidoctor/refs_spec.rb +12 -30
  50. data/spec/asciidoctor/section_spec.rb +18 -18
  51. data/spec/asciidoctor/validate_spec.rb +87 -2
  52. data/spec/fixtures/datamodel_description_sections_tree.xml +3 -2
  53. data/spec/spec_helper.rb +6 -7
  54. data/spec/vcr_cassettes/dated_iso_ref_joint_iso_iec.yml +51 -51
  55. data/spec/vcr_cassettes/dated_iso_ref_joint_iso_iec1.yml +13 -13
  56. data/spec/vcr_cassettes/isobib_get_123.yml +13 -13
  57. data/spec/vcr_cassettes/isobib_get_123_1.yml +26 -26
  58. data/spec/vcr_cassettes/isobib_get_123_1_fr.yml +34 -34
  59. data/spec/vcr_cassettes/isobib_get_123_2001.yml +12 -12
  60. data/spec/vcr_cassettes/isobib_get_124.yml +13 -13
  61. data/spec/vcr_cassettes/rfcbib_get_rfc8341.yml +16 -16
  62. data/spec/vcr_cassettes/separates_iev_citations_by_top_level_clause.yml +51 -49
  63. metadata +12 -5
@@ -4,10 +4,10 @@ module Asciidoctor
4
4
  def li(xml_ul, item)
5
5
  xml_ul.li do |xml_li|
6
6
  if item.blocks?
7
- xml_li.p(**id_attr(item)) { |t| t << item.text }
7
+ xml_li.p(**attr_code(id_attr(item))) { |t| t << item.text }
8
8
  xml_li << item.content
9
9
  else
10
- xml_li.p(**id_attr(item)) { |p| p << item.text }
10
+ xml_li.p(**attr_code(id_attr(item))) { |p| p << item.text }
11
11
  end
12
12
  end
13
13
  end
@@ -15,10 +15,10 @@ module Asciidoctor
15
15
  def ul_li(xml_ul, item)
16
16
  xml_ul.li **ul_li_attrs(item) do |xml_li|
17
17
  if item.blocks?
18
- xml_li.p(**id_attr(item)) { |t| t << item.text }
18
+ xml_li.p(**attr_code(id_attr(item))) { |t| t << item.text }
19
19
  xml_li << item.content
20
20
  else
21
- xml_li.p(**id_attr(item)) { |p| p << item.text }
21
+ xml_li.p(**attr_code(id_attr(item))) { |p| p << item.text }
22
22
  end
23
23
  end
24
24
  end
@@ -57,9 +57,8 @@ module Asciidoctor
57
57
  end
58
58
 
59
59
  def ol_attrs(node)
60
- attr_code(keep_attrs(node)
61
- .merge(id: Metanorma::Utils::anchor_or_uuid(node),
62
- type: olist_style(node.style)))
60
+ attr_code(id_attr(node).merge(keep_attrs(node)
61
+ .merge(type: olist_style(node.style))))
63
62
  end
64
63
 
65
64
  def olist(node)
@@ -79,22 +78,23 @@ module Asciidoctor
79
78
  end
80
79
  end
81
80
 
82
- def dd(dd, xml_dl)
83
- if dd.nil?
81
+ def dd(ddefn, xml_dl)
82
+ if ddefn.nil?
84
83
  xml_dl.dd
85
84
  return
86
85
  end
87
86
  xml_dl.dd do |xml_dd|
88
- xml_dd.p { |t| t << dd.text } if dd.text?
89
- xml_dd << dd.content if dd.blocks?
87
+ xml_dd.p { |t| t << ddefn.text } if ddefn.text?
88
+ xml_dd << ddefn.content if ddefn.blocks?
90
89
  end
91
90
  end
92
91
 
93
92
  def dl_attrs(node)
94
- attr_code(keep_attrs(node)
95
- .merge(id: Metanorma::Utils::anchor_or_uuid(node),
96
- metadata: node.option?("metadata") ? "true" : nil,
97
- key: node.option?("key") ? "true" : nil))
93
+ attr_code(id_attr(node).merge(keep_attrs(node)
94
+ .merge(
95
+ metadata: node.option?("metadata") ? "true" : nil,
96
+ key: node.option?("key") ? "true" : nil,
97
+ )))
98
98
  end
99
99
 
100
100
  def dlist(node)
@@ -6,6 +6,7 @@ require "csv"
6
6
  require_relative "./macros_plantuml"
7
7
  require_relative "./macros_terms"
8
8
  require_relative "./macros_form"
9
+ require_relative "./macros_note"
9
10
  require_relative "./datamodel/attributes_table_preprocessor"
10
11
  require_relative "./datamodel/diagram_preprocessor"
11
12
  require "metanorma-plugin-datastruct"
@@ -41,7 +42,7 @@ module Asciidoctor
41
42
  def process(_parent, target, attr)
42
43
  args = preprocess_attrs(attr) or return
43
44
  ret = "<index-xref also='#{target == 'also'}'>"\
44
- "<primary>#{args[:primary]}</primary>"
45
+ "<primary>#{args[:primary]}</primary>"
45
46
  ret += "<secondary>#{args[:secondary]}</secondary>" if args[:secondary]
46
47
  ret += "<tertiary>#{args[:tertiary]}</tertiary>" if args[:tertiary]
47
48
  ret + "<target>#{args[:target]}</target></index-xref>"
@@ -50,7 +51,7 @@ module Asciidoctor
50
51
 
51
52
  class IndexRangeInlineMacro < Asciidoctor::Extensions::InlineMacroProcessor
52
53
  use_dsl
53
- named "index-range".to_sym
54
+ named :"index-range"
54
55
  parse_content_as :text
55
56
 
56
57
  def process(parent, target, attr)
@@ -121,35 +122,6 @@ module Asciidoctor
121
122
  end
122
123
  end
123
124
 
124
- class ToDoAdmonitionBlock < Extensions::BlockProcessor
125
- use_dsl
126
- named :TODO
127
- on_contexts :example, :paragraph
128
-
129
- def process(parent, reader, attrs)
130
- attrs["name"] = "todo"
131
- attrs["caption"] = "TODO"
132
- create_block(parent, :admonition, reader.lines, attrs,
133
- content_model: :compound)
134
- end
135
- end
136
-
137
- class ToDoInlineAdmonitionBlock < Extensions::Treeprocessor
138
- def process(document)
139
- (document.find_by context: :paragraph).each do |para|
140
- next unless /^TODO: /.match? para.lines[0]
141
-
142
- parent = para.parent
143
- para.set_attr("name", "todo")
144
- para.set_attr("caption", "TODO")
145
- para.lines[0].sub!(/^TODO: /, "")
146
- todo = Block.new(parent, :admonition, attributes: para.attributes,
147
- source: para.lines, content_model: :compound)
148
- parent.blocks[parent.blocks.index(para)] = todo
149
- end
150
- end
151
- end
152
-
153
125
  class AutonumberInlineMacro < Extensions::InlineMacroProcessor
154
126
  use_dsl
155
127
  named :autonumber
@@ -177,18 +149,6 @@ module Asciidoctor
177
149
  end
178
150
  end
179
151
 
180
- class FootnoteBlockInlineMacro < Asciidoctor::Extensions::InlineMacroProcessor
181
- use_dsl
182
- named :footnoteblock
183
- parse_content_as :text
184
- using_format :short
185
-
186
- def process(parent, _target, attrs)
187
- out = Asciidoctor::Inline.new(parent, :quoted, attrs["text"]).convert
188
- %{<footnoteblock>#{out}</footnoteblock>}
189
- end
190
- end
191
-
192
152
  class AddMacro < Asciidoctor::Extensions::InlineMacroProcessor
193
153
  use_dsl
194
154
  named :add
@@ -229,5 +189,16 @@ module Asciidoctor
229
189
  "<toc>#{content}</toc>"
230
190
  end
231
191
  end
192
+
193
+ class PassInlineMacro < Asciidoctor::Extensions::InlineMacroProcessor
194
+ use_dsl
195
+ named :"pass-format"
196
+
197
+ def process(parent, target, attrs)
198
+ format = target || "metanorma"
199
+ out = Asciidoctor::Inline.new(parent, :quoted, attrs[1]).convert
200
+ %{<passthrough formats="#{format}">#{out}</passthrough>}
201
+ end
202
+ end
232
203
  end
233
204
  end
@@ -0,0 +1,45 @@
1
+ module Asciidoctor
2
+ module Standoc
3
+ class ToDoAdmonitionBlock < Extensions::BlockProcessor
4
+ use_dsl
5
+ named :TODO
6
+ on_contexts :example, :paragraph
7
+
8
+ def process(parent, reader, attrs)
9
+ attrs["name"] = "todo"
10
+ attrs["caption"] = "TODO"
11
+ create_block(parent, :admonition, reader.lines, attrs,
12
+ content_model: :compound)
13
+ end
14
+ end
15
+
16
+ class ToDoInlineAdmonitionBlock < Extensions::Treeprocessor
17
+ def process(document)
18
+ (document.find_by context: :paragraph).each do |para|
19
+ next unless /^TODO: /.match? para.lines[0]
20
+
21
+ parent = para.parent
22
+ para.set_attr("name", "todo")
23
+ para.set_attr("caption", "TODO")
24
+ para.lines[0].sub!(/^TODO: /, "")
25
+ todo = Block.new(parent, :admonition, attributes: para.attributes,
26
+ source: para.lines,
27
+ content_model: :compound)
28
+ parent.blocks[parent.blocks.index(para)] = todo
29
+ end
30
+ end
31
+ end
32
+
33
+ class FootnoteBlockInlineMacro < Asciidoctor::Extensions::InlineMacroProcessor
34
+ use_dsl
35
+ named :footnoteblock
36
+ parse_content_as :text
37
+ using_format :short
38
+
39
+ def process(parent, _target, attrs)
40
+ out = Asciidoctor::Inline.new(parent, :quoted, attrs["text"]).convert
41
+ %{<footnoteblock>#{out}</footnoteblock>}
42
+ end
43
+ end
44
+ end
45
+ end
@@ -28,32 +28,38 @@ module Asciidoctor
28
28
  # sleep need for windows because dot works in separate process and
29
29
  # plantuml process may finish earlier then dot, as result png file
30
30
  # maybe not created yet after plantuml finish
31
+ #
32
+ # # Warning: metanorma/metanorma-standoc#187
33
+ # Windows Ruby 2.4 will crash if a Tempfile is "mv"ed.
34
+ # This is why we need to copy and then unlink.
31
35
  def self.generate_file(parent, reader)
32
36
  localdir = Metanorma::Utils::localdir(parent.document)
33
37
  imagesdir = parent.document.attr("imagesdir")
34
38
  umlfile, outfile = save_plantuml parent, reader, localdir
35
- run(umlfile, outfile) or raise "No image output from PlantUML (#{umlfile}, #{outfile})!"
39
+ run(umlfile, outfile) or
40
+ raise "No image output from PlantUML (#{umlfile}, #{outfile})!"
36
41
  umlfile.unlink
37
42
 
38
- path = Pathname.new(localdir) + (imagesdir || "plantuml")
39
- File.writable?(localdir) or raise "Destination path #{path} not writable for PlantUML!"
40
- path.mkpath
41
- File.writable?(path) or raise "Destination path #{path} not writable for PlantUML!"
42
- # File.exist?(path) or raise "Destination path #{path} already exists for PlantUML!"
43
-
44
- # Warning: metanorma/metanorma-standoc#187
45
- # Windows Ruby 2.4 will crash if a Tempfile is "mv"ed.
46
- # This is why we need to copy and then unlink.
43
+ path = path_prep(localdir, imagesdir)
47
44
  filename = File.basename(outfile.to_s)
48
- FileUtils.cp(outfile, path) && outfile.unlink
45
+ FileUtils.cp(outfile, path) and outfile.unlink
49
46
 
50
47
  imagesdir ? filename : File.join(path, filename)
51
48
  end
52
49
 
50
+ def self.path_prep(localdir, imagesdir)
51
+ path = Pathname.new(localdir) + (imagesdir || "plantuml")
52
+ File.writable?(localdir) or
53
+ raise "Destination path #{path} not writable for PlantUML!"
54
+ path.mkpath
55
+ File.writable?(path) or
56
+ raise "Destination path #{path} not writable for PlantUML!"
57
+ # File.exist?(path) or raise "Destination path #{path} already exists for PlantUML!"
58
+ path
59
+ end
60
+
53
61
  def self.save_plantuml(_parent, reader, _localdir)
54
- src = reader.source
55
- reader.lines.first.sub(/\s+$/, "").match /^@startuml($| )/ or
56
- src = "@startuml\n#{src}\n@enduml\n"
62
+ src = prep_source(reader)
57
63
  /^@startuml (?<fn>[^\n]+)\n/ =~ src
58
64
  Tempfile.open(["plantuml", ".pml"], encoding: "utf-8") do |f|
59
65
  f.write(src)
@@ -62,6 +68,15 @@ module Asciidoctor
62
68
  end
63
69
  end
64
70
 
71
+ def self.prep_source(reader)
72
+ src = reader.source
73
+ reader.lines.first.sub(/\s+$/, "").match /^@startuml($| )/ or
74
+ src = "@startuml\n#{src}\n@enduml\n"
75
+ %r{@enduml\s*$}m.match?(src) or
76
+ raise "@startuml without matching @enduml in PlantUML!"
77
+ src
78
+ end
79
+
65
80
  def self.generate_attrs(attrs)
66
81
  %w(id align float title role width height alt)
67
82
  .inject({}) do |memo, key|
@@ -2,6 +2,18 @@ require "csv"
2
2
 
3
3
  module Asciidoctor
4
4
  module Standoc
5
+ class PreferredTermInlineMacro < Asciidoctor::Extensions::InlineMacroProcessor
6
+ use_dsl
7
+ named :preferred
8
+ parse_content_as :text
9
+ using_format :short
10
+
11
+ def process(parent, _target, attrs)
12
+ out = Asciidoctor::Inline.new(parent, :quoted, attrs["text"]).convert
13
+ %{<preferred><expression><name>#{out}</name></expression></preferred>}
14
+ end
15
+ end
16
+
5
17
  class AltTermInlineMacro < Asciidoctor::Extensions::InlineMacroProcessor
6
18
  use_dsl
7
19
  named :alt
@@ -9,8 +21,9 @@ module Asciidoctor
9
21
  using_format :short
10
22
 
11
23
  def process(parent, _target, attrs)
12
- out = Asciidoctor::Inline.new(parent, :quoted, attrs["text"]).convert
13
- %{<admitted>#{out}</admitted>}
24
+ out = Asciidoctor::Inline.new(parent, :quoted,
25
+ attrs["text"]).convert
26
+ %{<admitted><expression><name>#{out}</name></expression></admitted>}
14
27
  end
15
28
  end
16
29
 
@@ -21,8 +34,9 @@ module Asciidoctor
21
34
  using_format :short
22
35
 
23
36
  def process(parent, _target, attrs)
24
- out = Asciidoctor::Inline.new(parent, :quoted, attrs["text"]).convert
25
- %{<deprecates>#{out}</deprecates>}
37
+ out = Asciidoctor::Inline.new(parent, :quoted,
38
+ attrs["text"]).convert
39
+ %{<deprecates><expression><name>#{out}</name></expression></deprecates>}
26
40
  end
27
41
  end
28
42
 
@@ -33,7 +47,8 @@ module Asciidoctor
33
47
  using_format :short
34
48
 
35
49
  def process(parent, _target, attrs)
36
- out = Asciidoctor::Inline.new(parent, :quoted, attrs["text"]).convert
50
+ out = Asciidoctor::Inline.new(parent, :quoted,
51
+ attrs["text"]).convert
37
52
  %{<domain>#{out}</domain>}
38
53
  end
39
54
  end
@@ -116,9 +131,12 @@ module Asciidoctor
116
131
 
117
132
  def process(parent, target, _attrs)
118
133
  attrs = preprocess_attrs(target)
119
- term = Asciidoctor::Inline.new(parent, :quoted, attrs[:term]).convert
120
- word = Asciidoctor::Inline.new(parent, :quoted, attrs[:word]).convert
121
- xref = Asciidoctor::Inline.new(parent, :quoted, attrs[:render]).convert
134
+ term = Asciidoctor::Inline.new(parent, :quoted,
135
+ attrs[:term]).convert
136
+ word = Asciidoctor::Inline.new(parent, :quoted,
137
+ attrs[:word]).convert
138
+ xref = Asciidoctor::Inline.new(parent, :quoted,
139
+ attrs[:render]).convert
122
140
  opt = generate_attrs(attrs[:opt] || [])
123
141
  if attrs[:id] then "<concept#{opt} key='#{attrs[:id]}'><refterm>"\
124
142
  "#{term}</refterm><renderterm>#{word}</renderterm>"\
@@ -130,5 +148,34 @@ module Asciidoctor
130
148
  raise("processing {{#{target}}}: #{e.message}")
131
149
  end
132
150
  end
151
+
152
+ # Possibilities:
153
+ # related:relation[<<id>>, term]
154
+ # related:relation[<<termbase:id>>, term]
155
+ # related:relation[term] equivalent to a crossreference to term:[term]
156
+ class RelatedTermInlineMacro < Asciidoctor::Extensions::InlineMacroProcessor
157
+ use_dsl
158
+ named :related
159
+ parse_content_as :text
160
+
161
+ def preprocess_attrs(target)
162
+ m = /^(?<id>&lt;&lt;.+?&gt;&gt;, ?)?(?<rest>.*)$/.match(target)
163
+ { id: m[:id]&.sub(/^&lt;&lt;/, "")&.sub(/&gt;&gt;, ?$/, ""),
164
+ term: m[:rest] }
165
+ end
166
+
167
+ def process(parent, target, attrs)
168
+ out = preprocess_attrs(attrs["text"])
169
+ term = Asciidoctor::Inline.new(parent, :quoted,
170
+ out[:term]).convert
171
+ if out[:id] then "<related type='#{target}' key='#{out[:id]}'>"\
172
+ "<refterm>#{term}</refterm></related>"
173
+ else "<related type='#{target}'><termxref>#{term}</termxref>"\
174
+ "<xrefrender>#{term}</xrefrender></related>"
175
+ end
176
+ rescue StandardError => e
177
+ raise("processing related:#{target}[#{attrs['text']}]: #{e.message}")
178
+ end
179
+ end
133
180
  end
134
181
  end
@@ -16,16 +16,14 @@ module Asciidoctor
16
16
  end
17
17
 
18
18
  def bibliography_parse(attrs, xml, node)
19
- node.option? "bibitem" and return bibitem_parse(attrs, xml, node)
20
- node.attr("style") == "bibliography" or
21
- @log.add("AsciiDoc Input", node, "Section not marked up as [bibliography]!")
19
+ x = biblio_prep(attrs, xml, node) and return x
22
20
  @biblio = true
23
- xml.references **attr_code(attrs.merge(
24
- normative: node.attr("normative") || false)) do |xml_section|
25
- xml_section.title { |t| t << node.title }
26
- xml_section << node.content
27
- end
28
- @biblio = false
21
+ attrs = attrs.merge(normative: node.attr("normative") || false)
22
+ xml.references **attr_code(attrs) do |xml_section|
23
+ xml_section.title { |t| t << node.title }
24
+ xml_section << node.content
25
+ end
26
+ @biblio = false
29
27
  end
30
28
 
31
29
  def bibitem_parse(attrs, xml, node)
@@ -33,15 +31,14 @@ module Asciidoctor
33
31
  biblio = @biblio
34
32
  @biblio = false
35
33
  @norm_ref = false
36
- clause_parse(attrs, xml, node)
34
+ ret = clause_parse(attrs, xml, node)
37
35
  @biblio = biblio
38
36
  @norm_ref = norm_ref
37
+ ret
39
38
  end
40
39
 
41
40
  def norm_ref_parse(attrs, xml, node)
42
- node.option? "bibitem" and return bibitem_parse(attrs, xml, node)
43
- node.attr("style") == "bibliography" or
44
- @log.add("AsciiDoc Input", node, "Section not marked up as [bibliography]!")
41
+ x = biblio_prep(attrs, xml, node) and return x
45
42
  @norm_ref = true
46
43
  attrs = attrs.merge(normative: node.attr("normative") || true)
47
44
  xml.references **attr_code(attrs) do |xml_section|
@@ -51,6 +48,17 @@ module Asciidoctor
51
48
  @norm_ref = false
52
49
  end
53
50
 
51
+ def biblio_prep(attrs, xml, node)
52
+ if node.option? "bibitem"
53
+ bibitem_parse(attrs, xml, node)
54
+ else
55
+ node.attr("style") == "bibliography" or
56
+ @log.add("AsciiDoc Input", node,
57
+ "Section not marked up as [bibliography]!")
58
+ nil
59
+ end
60
+ end
61
+
54
62
  def global_ievcache_name
55
63
  "#{Dir.home}/.iev/cache"
56
64
  end
@@ -74,7 +82,7 @@ module Asciidoctor
74
82
  xml
75
83
  rescue RelatonBib::RequestError
76
84
  @log.add("Bibliography", nil, "Could not retrieve #{code}: "\
77
- "no access to online site")
85
+ "no access to online site")
78
86
  nil
79
87
  end
80
88
 
@@ -87,10 +95,10 @@ module Asciidoctor
87
95
  unless xml.at("/bibitem/title[text()]")
88
96
  @log.add("Bibliography", nil,
89
97
  "ERROR: No title retrieved for #{code}")
90
- xml.root << "<title>#{title || "(MISSING TITLE)"}</title>"
98
+ xml.root << "<title>#{title || '(MISSING TITLE)'}</title>"
91
99
  end
92
100
  usrlbl and xml.at("/bibitem/docidentifier").next =
93
- "<docidentifier type='metanorma'>#{mn_code(usrlbl)}</docidentifier>"
101
+ "<docidentifier type='metanorma'>#{mn_code(usrlbl)}</docidentifier>"
94
102
  end
95
103
 
96
104
  def smart_render_xml(xml, code, opts)
@@ -113,7 +121,7 @@ module Asciidoctor
113
121
  @bibdb = Relaton::DbCache.init_bib_caches(
114
122
  local_cache: local,
115
123
  flush_caches: node.attr("flush-caches"),
116
- global_cache: global
124
+ global_cache: global,
117
125
  )
118
126
  end
119
127
 
@@ -128,7 +136,7 @@ module Asciidoctor
128
136
  FileUtils.rm_f @iev_localname unless @iev_localname.nil?
129
137
  end
130
138
  end
131
- #@iev = Iev::Db.new(globalname, localname) unless @no_isobib
139
+ # @iev = Iev::Db.new(globalname, localname) unless @no_isobib
132
140
  end
133
141
  end
134
142
  end
@@ -58,6 +58,14 @@
58
58
  <optional>
59
59
  <attribute name="type"/>
60
60
  </optional>
61
+ <optional>
62
+ <attribute name="tag"/>
63
+ </optional>
64
+ <optional>
65
+ <attribute name="multilingual-rendering">
66
+ <ref name="MultilingualRenderingType"/>
67
+ </attribute>
68
+ </optional>
61
69
  <optional>
62
70
  <ref name="reqtitle"/>
63
71
  </optional>
@@ -101,7 +109,9 @@
101
109
  </define>
102
110
  <define name="label">
103
111
  <element name="label">
104
- <text/>
112
+ <oneOrMore>
113
+ <ref name="TextElement"/>
114
+ </oneOrMore>
105
115
  </element>
106
116
  </define>
107
117
  <define name="subject">
@@ -175,8 +185,19 @@
175
185
  <data type="boolean"/>
176
186
  </attribute>
177
187
  </optional>
188
+ <optional>
189
+ <attribute name="tag"/>
190
+ </optional>
191
+ <optional>
192
+ <attribute name="multilingual-rendering">
193
+ <ref name="MultilingualRenderingType"/>
194
+ </attribute>
195
+ </optional>
178
196
  <oneOrMore>
179
- <ref name="BasicBlock"/>
197
+ <choice>
198
+ <ref name="BasicBlock"/>
199
+ <ref name="component"/>
200
+ </choice>
180
201
  </oneOrMore>
181
202
  </define>
182
203
  <define name="ObligationType">
@@ -1,4 +1,6 @@
1
1
  # frozen_string_literal: true.
2
+ require "asciidoctor/standoc/utils"
3
+
2
4
 
3
5
  module Asciidoctor
4
6
  module Standoc
@@ -13,7 +15,7 @@ module Asciidoctor
13
15
  def initialize(xmldoc, log)
14
16
  @xmldoc = xmldoc
15
17
  @log = log
16
- @termlookup = { term: {}, symbol: {} }
18
+ @termlookup = { term: {}, symbol: {}, secondary2primary: {} }
17
19
  @idhash = {}
18
20
  end
19
21
 
@@ -22,6 +24,7 @@ module Asciidoctor
22
24
  @termlookup = replace_automatic_generated_ids_terms
23
25
  set_termxref_tags_target
24
26
  concept_cleanup
27
+ related_cleanup
25
28
  end
26
29
 
27
30
  private
@@ -29,6 +32,19 @@ module Asciidoctor
29
32
  def concept_cleanup
30
33
  xmldoc.xpath("//concept").each do |n|
31
34
  n.delete("type")
35
+ refterm = n.at("./refterm") or next
36
+ p = @termlookup[:secondary2primary][refterm.text] and
37
+ refterm.children = p
38
+ end
39
+ end
40
+
41
+ def related_cleanup
42
+ xmldoc.xpath("//related").each do |n|
43
+ refterm = n.at("./refterm") or next
44
+ p = @termlookup[:secondary2primary][refterm.text] and
45
+ refterm.children = p
46
+ refterm.replace("<preferred><expression><name>#{refterm.children.to_xml}"\
47
+ "</name></expression></preferred>")
32
48
  end
33
49
  end
34
50
 
@@ -47,8 +63,7 @@ module Asciidoctor
47
63
  remove_missing_ref(node, target)
48
64
  next
49
65
  end
50
- x = node.at("../xrefrender")
51
- modify_ref_node(x, target)
66
+ x = node.at("../xrefrender") and modify_ref_node(x, target)
52
67
  node.name = "refterm"
53
68
  end
54
69
  end
@@ -66,12 +81,12 @@ module Asciidoctor
66
81
  %(Error: Term reference in `term[#{target}]` missing: \
67
82
  "#{target}" is not defined in document))
68
83
  node.name = "strong"
69
- node.at("../xrefrender").remove
84
+ node&.at("../xrefrender")&.remove
70
85
  display = node&.at("../renderterm")&.remove&.children
71
86
  display = [] if display.nil? || display&.to_xml == node.text
72
87
  d = display.empty? ? "" : ", display <tt>#{display.to_xml}</tt>"
73
88
  node.children = "term <tt>#{node.text}</tt>#{d} "\
74
- "not resolved via ID <tt>#{target}</tt>"
89
+ "not resolved via ID <tt>#{target}</tt>"
75
90
  end
76
91
 
77
92
  def remove_missing_ref_symbol(node, target)
@@ -79,12 +94,12 @@ module Asciidoctor
79
94
  %(Error: Symbol reference in `symbol[#{target}]` missing: \
80
95
  "#{target}" is not defined in document))
81
96
  node.name = "strong"
82
- node.at("../xrefrender").remove
97
+ node&.at("../xrefrender")&.remove
83
98
  display = node&.at("../renderterm")&.remove&.children
84
99
  display = [] if display.nil? || display&.to_xml == node.text
85
100
  d = display.empty? ? "" : ", display <tt>#{display.to_xml}</tt>"
86
101
  node.children = "symbol <tt>#{node.text}</tt>#{d} "\
87
- "not resolved via ID <tt>#{target}</tt>"
102
+ "not resolved via ID <tt>#{target}</tt>"
88
103
  end
89
104
 
90
105
  def modify_ref_node(node, target)
@@ -92,24 +107,40 @@ module Asciidoctor
92
107
  s = termlookup[:symbol][target]
93
108
  t = termlookup[:term][target]
94
109
  type = node.parent["type"]
95
- if type == "term" || !type && t
110
+ if type == "term" || ((!type || node.parent.name == "related") && t)
96
111
  node["target"] = t
97
- elsif type == "symbol" || !type && s
112
+ elsif type == "symbol" ||
113
+ ((!type || node.parent.name == "related") && s)
98
114
  node["target"] = s
99
115
  end
100
116
  end
101
117
 
102
118
  def replace_automatic_generated_ids_terms
103
119
  r = xmldoc.xpath("//term").each.with_object({}) do |n, res|
104
- normalize_id_and_memorize(n, res, "./preferred", "term")
120
+ normalize_id_and_memorize(n, res, "./preferred//name",
121
+ "term")
105
122
  end
106
123
  s = xmldoc.xpath("//definitions//dt").each.with_object({}) do |n, res|
107
124
  normalize_id_and_memorize(n, res, ".", "symbol")
108
125
  end
109
- { term: r, symbol: s }
126
+ { term: r, symbol: s, secondary2primary: pref_secondary2primary }
127
+ end
128
+
129
+ def pref_secondary2primary
130
+ xmldoc.xpath("//term").each.with_object({}) do |n, res|
131
+ n.xpath("./preferred//name").each_with_index do |p, i|
132
+ i.zero? and term = p.text
133
+ i.positive? and res[p.text] = term
134
+ end
135
+ end
110
136
  end
111
137
 
112
138
  def normalize_id_and_memorize(node, res_table, text_selector, prefix)
139
+ normalize_id_and_memorize_init(node, res_table, text_selector, prefix)
140
+ memorize_other_pref_terms(node, res_table, text_selector)
141
+ end
142
+
143
+ def normalize_id_and_memorize_init(node, res_table, text_selector, prefix)
113
144
  term_text = normalize_ref_id(node.at(text_selector).text)
114
145
  unless AUTOMATIC_GENERATED_ID_REGEXP.match(node["id"]).nil? &&
115
146
  !node["id"].nil?
@@ -120,6 +151,14 @@ module Asciidoctor
120
151
  res_table[term_text] = node["id"]
121
152
  end
122
153
 
154
+ def memorize_other_pref_terms(node, res_table, text_selector)
155
+ node.xpath(text_selector).each_with_index do |p, i|
156
+ next unless i.positive?
157
+
158
+ res_table[normalize_ref_id(p.text)] = node["id"]
159
+ end
160
+ end
161
+
123
162
  def normalize_ref_id(text)
124
163
  Metanorma::Utils::to_ncname(text.downcase.gsub(/[[:space:]]/, "-"))
125
164
  end