metanorma-standoc 1.9.2 → 1.10.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (66) 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 -6
  5. data/lib/asciidoctor/standoc/base.rb +3 -1
  6. data/lib/asciidoctor/standoc/biblio.rng +1 -0
  7. data/lib/asciidoctor/standoc/blocks.rb +1 -1
  8. data/lib/asciidoctor/standoc/cleanup.rb +34 -15
  9. data/lib/asciidoctor/standoc/cleanup_block.rb +0 -1
  10. data/lib/asciidoctor/standoc/cleanup_boilerplate.rb +2 -2
  11. data/lib/asciidoctor/standoc/cleanup_footnotes.rb +0 -1
  12. data/lib/asciidoctor/standoc/cleanup_inline.rb +117 -77
  13. data/lib/asciidoctor/standoc/cleanup_maths.rb +0 -1
  14. data/lib/asciidoctor/standoc/cleanup_ref.rb +7 -0
  15. data/lib/asciidoctor/standoc/cleanup_section.rb +73 -137
  16. data/lib/asciidoctor/standoc/cleanup_section_names.rb +75 -0
  17. data/lib/asciidoctor/standoc/cleanup_terms.rb +19 -18
  18. data/lib/asciidoctor/standoc/converter.rb +1 -0
  19. data/lib/asciidoctor/standoc/front.rb +1 -2
  20. data/lib/asciidoctor/standoc/front_contributor.rb +66 -42
  21. data/lib/asciidoctor/standoc/inline.rb +45 -34
  22. data/lib/asciidoctor/standoc/isodoc.rng +66 -10
  23. data/lib/asciidoctor/standoc/macros.rb +7 -5
  24. data/lib/asciidoctor/standoc/macros_plantuml.rb +21 -23
  25. data/lib/asciidoctor/standoc/macros_terms.rb +60 -23
  26. data/lib/asciidoctor/standoc/section.rb +19 -12
  27. data/lib/asciidoctor/standoc/term_lookup_cleanup.rb +87 -33
  28. data/lib/asciidoctor/standoc/terms.rb +1 -1
  29. data/lib/asciidoctor/standoc/utils.rb +0 -1
  30. data/lib/asciidoctor/standoc/validate.rb +22 -8
  31. data/lib/isodoc/html/html_titlepage.html +81 -0
  32. data/lib/isodoc/html/htmlstyle.css +983 -0
  33. data/lib/isodoc/html/htmlstyle.scss +714 -0
  34. data/lib/isodoc/html/scripts.html +71 -0
  35. data/lib/metanorma/standoc/processor.rb +16 -7
  36. data/lib/metanorma/standoc/version.rb +1 -1
  37. data/metanorma-standoc.gemspec +3 -3
  38. data/spec/asciidoctor/base_spec.rb +697 -557
  39. data/spec/asciidoctor/blocks_spec.rb +6 -8
  40. data/spec/asciidoctor/cleanup_sections_spec.rb +14 -14
  41. data/spec/asciidoctor/cleanup_spec.rb +899 -688
  42. data/spec/asciidoctor/inline_spec.rb +62 -14
  43. data/spec/asciidoctor/isobib_cache_spec.rb +4 -6
  44. data/spec/asciidoctor/lists_spec.rb +149 -137
  45. data/spec/asciidoctor/macros_json2text_spec.rb +1 -1
  46. data/spec/asciidoctor/macros_plantuml_spec.rb +8 -8
  47. data/spec/asciidoctor/macros_spec.rb +646 -169
  48. data/spec/asciidoctor/refs_dl_spec.rb +4 -4
  49. data/spec/asciidoctor/refs_spec.rb +1527 -1532
  50. data/spec/asciidoctor/section_spec.rb +58 -22
  51. data/spec/asciidoctor/table_spec.rb +6 -6
  52. data/spec/asciidoctor/validate_spec.rb +352 -304
  53. data/spec/spec_helper.rb +2 -0
  54. data/spec/vcr_cassettes/dated_iso_ref_joint_iso_iec.yml +49 -49
  55. data/spec/vcr_cassettes/isobib_get_123.yml +12 -12
  56. data/spec/vcr_cassettes/isobib_get_123_1.yml +27 -27
  57. data/spec/vcr_cassettes/isobib_get_123_1_fr.yml +35 -35
  58. data/spec/vcr_cassettes/isobib_get_123_2001.yml +14 -14
  59. data/spec/vcr_cassettes/isobib_get_124.yml +14 -14
  60. data/spec/vcr_cassettes/rfcbib_get_rfc8341.yml +14 -14
  61. data/spec/vcr_cassettes/separates_iev_citations_by_top_level_clause.yml +44 -44
  62. metadata +12 -11
  63. data/lib/liquid/custom_blocks/key_iterator.rb +0 -21
  64. data/lib/liquid/custom_blocks/with_json_nested_context.rb +0 -18
  65. data/lib/liquid/custom_blocks/with_yaml_nested_context.rb +0 -19
  66. data/lib/liquid/custom_filters/values.rb +0 -7
@@ -75,7 +75,7 @@ module Asciidoctor
75
75
  def supply_br(lines)
76
76
  ignore = false
77
77
  lines.each_with_index do |l, i|
78
- /^(--+|====+|\|===|\.\.\.\.+|\*\*\*\*+|\+\+\+\++|\`\`\`\`+|____\+)$/
78
+ /^(--+|====+|\|===|\.\.\.\.+|\*\*\*\*+|\+\+\+\++|````+|____\+)$/
79
79
  .match(l) && (ignore = !ignore)
80
80
  next if l.empty? || l.match(/ \+$/) || /^\[.*\]$/.match?(l) || ignore
81
81
  next if i == lines.size - 1 ||
@@ -107,7 +107,7 @@ module Asciidoctor
107
107
  if (attributes.size == 1) && attributes.key?("text")
108
108
  rt = attributes["text"]
109
109
  elsif (attributes.size == 2) && attributes.key?(1) &&
110
- attributes.key?("rpbegin")
110
+ attributes.key?("rpbegin")
111
111
  rt = attributes[1] || ""
112
112
  else
113
113
  rpbegin = attributes["rpbegin"]
@@ -143,7 +143,7 @@ module Asciidoctor
143
143
  para.set_attr("caption", "TODO")
144
144
  para.lines[0].sub!(/^TODO: /, "")
145
145
  todo = Block.new(parent, :admonition, attributes: para.attributes,
146
- source: para.lines, content_model: :compound)
146
+ source: para.lines, content_model: :compound)
147
147
  parent.blocks[parent.blocks.index(para)] = todo
148
148
  end
149
149
  end
@@ -168,9 +168,11 @@ module Asciidoctor
168
168
  def process(parent, target, attrs)
169
169
  /^(?<lang>[^-]*)(-(?<script>.*))?$/ =~ target
170
170
  out = Asciidoctor::Inline.new(parent, :quoted, attrs["text"]).convert
171
- script ?
172
- %{<variant lang=#{lang} script=#{script}>#{out}</variant>} :
171
+ if script
172
+ %{<variant lang=#{lang} script=#{script}>#{out}</variant>}
173
+ else
173
174
  %{<variant lang=#{lang}>#{out}</variant>}
175
+ end
174
176
  end
175
177
  end
176
178
 
@@ -4,18 +4,17 @@ module Asciidoctor
4
4
  # https://stackoverflow.com/questions/2108727/which-in-ruby-checking-if-program-exists-in-path-from-ruby
5
5
  def self.plantuml_installed?
6
6
  cmd = "plantuml"
7
- exts = ENV['PATHEXT'] ? ENV['PATHEXT'].split(';') : ['']
8
- ENV['PATH'].split(File::PATH_SEPARATOR).each do |path|
7
+ exts = ENV["PATHEXT"] ? ENV["PATHEXT"].split(";") : [""]
8
+ ENV["PATH"].split(File::PATH_SEPARATOR).each do |path|
9
9
  exts.each do |ext|
10
10
  exe = File.join(path, "#{cmd}#{ext}")
11
11
  return exe if File.executable?(exe) && !File.directory?(exe)
12
12
  end
13
13
  end
14
14
  raise "PlantUML not installed"
15
- nil
16
15
  end
17
16
 
18
- def self.run umlfile, outfile
17
+ def self.run(umlfile, outfile)
19
18
  system "plantuml #{umlfile.path}" or (warn $? and return false)
20
19
  i = 0
21
20
  until !Gem.win_platform? || File.exist?(outfile) || i == 15
@@ -29,9 +28,9 @@ module Asciidoctor
29
28
  # sleep need for windows because dot works in separate process and
30
29
  # plantuml process may finish earlier then dot, as result png file
31
30
  # maybe not created yet after plantuml finish
32
- def self.generate_file parent, reader
31
+ def self.generate_file(parent, reader)
33
32
  localdir = Metanorma::Utils::localdir(parent.document)
34
- imagesdir = parent.document.attr('imagesdir')
33
+ imagesdir = parent.document.attr("imagesdir")
35
34
  umlfile, outfile = save_plantuml parent, reader, localdir
36
35
  run(umlfile, outfile) or raise "No image output from PlantUML (#{umlfile}, #{outfile})!"
37
36
  umlfile.unlink
@@ -40,7 +39,7 @@ module Asciidoctor
40
39
  File.writable?(localdir) or raise "Destination path #{path} not writable for PlantUML!"
41
40
  path.mkpath
42
41
  File.writable?(path) or raise "Destination path #{path} not writable for PlantUML!"
43
- #File.exist?(path) or raise "Destination path #{path} already exists for PlantUML!"
42
+ # File.exist?(path) or raise "Destination path #{path} already exists for PlantUML!"
44
43
 
45
44
  # Warning: metanorma/metanorma-standoc#187
46
45
  # Windows Ruby 2.4 will crash if a Tempfile is "mv"ed.
@@ -51,21 +50,21 @@ module Asciidoctor
51
50
  imagesdir ? filename : File.join(path, filename)
52
51
  end
53
52
 
54
- def self.save_plantuml parent, reader, localdir
53
+ def self.save_plantuml(_parent, reader, _localdir)
55
54
  src = reader.source
56
55
  reader.lines.first.sub(/\s+$/, "").match /^@startuml($| )/ or
57
56
  src = "@startuml\n#{src}\n@enduml\n"
58
57
  /^@startuml (?<fn>[^\n]+)\n/ =~ src
59
- Tempfile.open(["plantuml", ".pml"], :encoding => "utf-8") do |f|
58
+ Tempfile.open(["plantuml", ".pml"], encoding: "utf-8") do |f|
60
59
  f.write(src)
61
60
  [f, File.join(File.dirname(f.path),
62
- (fn || File.basename(f.path, ".pml")) + ".png")]
61
+ "#{fn || File.basename(f.path, '.pml')}.png")]
63
62
  end
64
63
  end
65
64
 
66
- def self.generate_attrs attrs
67
- through_attrs = %w(id align float title role width height alt).
68
- inject({}) do |memo, key|
65
+ def self.generate_attrs(attrs)
66
+ %w(id align float title role width height alt)
67
+ .inject({}) do |memo, key|
69
68
  memo[key] = attrs[key] if attrs.has_key? key
70
69
  memo
71
70
  end
@@ -81,19 +80,18 @@ module Asciidoctor
81
80
  def abort(parent, reader, attrs, msg)
82
81
  warn msg
83
82
  attrs["language"] = "plantuml"
84
- create_listing_block parent, reader.source, attrs.reject { |k, v| k == 1 }
83
+ create_listing_block parent, reader.source,
84
+ (attrs.reject { |k, _v| k == 1 })
85
85
  end
86
86
 
87
87
  def process(parent, reader, attrs)
88
- begin
89
- PlantUMLBlockMacroBackend.plantuml_installed?
90
- filename = PlantUMLBlockMacroBackend.generate_file(parent, reader)
91
- through_attrs = PlantUMLBlockMacroBackend.generate_attrs attrs
92
- through_attrs["target"] = filename
93
- create_image_block parent, through_attrs
94
- rescue StandardError => e
95
- abort(parent, reader, attrs, e.message)
96
- end
88
+ PlantUMLBlockMacroBackend.plantuml_installed?
89
+ filename = PlantUMLBlockMacroBackend.generate_file(parent, reader)
90
+ through_attrs = PlantUMLBlockMacroBackend.generate_attrs attrs
91
+ through_attrs["target"] = filename
92
+ create_image_block parent, through_attrs
93
+ rescue StandardError => e
94
+ abort(parent, reader, attrs, e.message)
97
95
  end
98
96
  end
99
97
  end
@@ -1,3 +1,5 @@
1
+ require "csv"
2
+
1
3
  module Asciidoctor
2
4
  module Standoc
3
5
  class AltTermInlineMacro < Asciidoctor::Extensions::InlineMacroProcessor
@@ -36,46 +38,81 @@ module Asciidoctor
36
38
  end
37
39
  end
38
40
 
39
- # Macro to transform `term[X,Y]` into em, termxref xml
40
41
  class TermRefInlineMacro < Asciidoctor::Extensions::InlineMacroProcessor
41
42
  use_dsl
42
43
  named :term
43
- name_positional_attributes 'name', 'termxref'
44
+ name_positional_attributes "name", "termxref"
45
+ using_format :short
46
+
47
+ def process(_parent, _target, attrs)
48
+ termref = attrs["termxref"] || attrs["name"]
49
+ "<concept type='term'><termxref>#{attrs['name']}</termxref>"\
50
+ "<renderterm>#{termref}</renderterm><xrefrender/></concept>"
51
+ end
52
+ end
53
+
54
+ class SymbolRefInlineMacro < Asciidoctor::Extensions::InlineMacroProcessor
55
+ use_dsl
56
+ named :symbol
57
+ name_positional_attributes "name", "termxref"
44
58
  using_format :short
45
59
 
46
60
  def process(_parent, _target, attrs)
47
- termref = attrs['termxref'] || attrs['name']
48
- "<em>#{attrs['name']}</em> (<termxref>#{termref}</termxref>)"
61
+ termref = attrs["termxref"] || attrs["name"]
62
+ "<concept type='symbol'><termxref>#{attrs['name']}</termxref>"\
63
+ "<renderterm>#{termref}</renderterm><xrefrender/></concept>"
49
64
  end
50
65
  end
51
66
 
67
+ # Possibilities:
68
+ # {{<<id>>, term}}
69
+ # {{<<id>>, term, text}}
70
+ # {{<<termbase:id>>, term}}
71
+ # {{<<termbase:id>>, term, text}}
72
+ # {{term}} equivalent to term:[term]
73
+ # {{term, text}} equivalent to term:[term, text]
74
+ # text may optionally be followed by crossreference-rendering, options=""
52
75
  class ConceptInlineMacro < Asciidoctor::Extensions::InlineMacroProcessor
53
76
  use_dsl
54
77
  named :concept
55
- name_positional_attributes "id", "word", "term"
56
- # match %r{concept:(?<target>[^\[]*)\[(?<content>|.*?[^\\])\]$}
57
78
  match /\{\{(?<content>|.*?[^\\])\}\}/
58
79
  using_format :short
59
80
 
60
- # deal with locality attrs and their disruption of positional attrs
61
- def preprocess_attrs(attrs)
62
- attrs.delete("term") if attrs["term"] && !attrs["word"]
63
- attrs.delete(3) if attrs[3] == attrs["term"]
64
- a = attrs.keys.reject { |k| k.is_a?(String) || [1, 2].include?(k) }
65
- attrs["word"] ||= attrs[a[0]] if !a.empty?
66
- attrs["term"] ||= attrs[a[1]] if a.length > 1
67
- attrs
81
+ def preprocess_attrs(target)
82
+ m = /^(?<id>&lt;&lt;.+?&gt;&gt;)?(?<rest>.*)$/.match(target)
83
+ ret = { id: m[:id]&.sub(/^&lt;&lt;/, "")&.sub(/&gt;&gt;$/, "") }
84
+ if m2 = /^(?<rest>.*?)(?<opt>,option=.+)$/.match(m[:rest].sub(/^,/, ""))
85
+ ret[:opt] = CSV.parse_line(m2[:opt].sub(/^,option=/, "")
86
+ .sub(/^"(.+)"$/, "\\1").sub(/^'(.+)'$/, "\\1"))
87
+ attrs = CSV.parse_line(m2[:rest]) || []
88
+ else
89
+ attrs = CSV.parse_line(m[:rest].sub(/^,/, "")) || []
90
+ end
91
+ ret.merge(term: attrs[0], word: attrs[1] || attrs[0],
92
+ xrefrender: attrs[2])
93
+ end
94
+
95
+ def generate_attrs(opts)
96
+ ret = ""
97
+ opts.include?("noital") and ret += " ital='false'"
98
+ opts.include?("noref") and ret += " ref='false'"
99
+ opts.include?("ital") and ret += " ital='true'"
100
+ opts.include?("ref") and ret += " ref='true'"
101
+ ret
68
102
  end
69
103
 
70
- def process(parent, _target, attr)
71
- attr = preprocess_attrs(attr)
72
- localities = attr.keys.reject { |k| %w(id word term).include? k }.
73
- reject { |k| k.is_a? Numeric }.
74
- map { |k| "#{k}=#{attr[k]}" }.join(",")
75
- text = [localities, attr["word"]].reject{ |k| k.nil? || k.empty? }.
76
- join(",")
77
- out = Asciidoctor::Inline.new(parent, :quoted, text).convert
78
- %{<concept key="#{attr['id']}" term="#{attr['term']}">#{out}</concept>}
104
+ def process(parent, target, _attrs)
105
+ attrs = preprocess_attrs(target)
106
+ termout = Asciidoctor::Inline.new(parent, :quoted, attrs[:term]).convert
107
+ wordout = Asciidoctor::Inline.new(parent, :quoted, attrs[:word]).convert
108
+ xrefout = Asciidoctor::Inline.new(parent, :quoted,
109
+ attrs[:xrefrender]).convert
110
+ optout = generate_attrs(attrs[:opt] || [])
111
+ attrs[:id] and return "<concept#{optout} key='#{attrs[:id]}'><refterm>"\
112
+ "#{termout}</refterm><renderterm>#{wordout}</renderterm>"\
113
+ "<xrefrender>#{xrefout}</xrefrender></concept>"
114
+ "<concept#{optout}><termxref>#{termout}</termxref><renderterm>"\
115
+ "#{wordout}</renderterm><xrefrender>#{xrefout}</xrefrender></concept>"
79
116
  end
80
117
  end
81
118
  end
@@ -12,7 +12,7 @@ module Asciidoctor
12
12
  def sectiontype1(node)
13
13
  node&.attr("heading")&.downcase ||
14
14
  node.title.gsub(%r{<index>.*?</index>}m, "").gsub(/<[^>]+>/, "")
15
- .strip.downcase
15
+ .strip.downcase
16
16
  end
17
17
 
18
18
  def sectiontype(node, level = true)
@@ -21,6 +21,7 @@ module Asciidoctor
21
21
  return ret1 if "symbols and abbreviated terms" == ret1
22
22
  return nil unless !level || node.level == 1
23
23
  return nil if @seen_headers.include? ret
24
+
24
25
  @seen_headers << ret
25
26
  ret1
26
27
  end
@@ -48,11 +49,14 @@ module Asciidoctor
48
49
  script: node.attributes["script"],
49
50
  number: node.attributes["number"],
50
51
  type: node.attributes["type"],
51
- annex: ( ((node.attr("style") == "appendix" || node.role == "appendix") &&
52
- node.level == 1) ? true : nil),
53
- preface: (
54
- (node.role == "preface" || node.attr("style") == "preface") ? true : nil) }
52
+ annex: (if (node.attr("style") == "appendix" || node.role == "appendix") &&
53
+ node.level == 1
54
+ true
55
+ end),
56
+ preface: (
57
+ node.role == "preface" || node.attr("style") == "preface" ? true : nil) }
55
58
  return ret unless node.attributes["change"]
59
+
56
60
  ret.merge(change: node.attributes["change"],
57
61
  path: node.attributes["path"],
58
62
  path_end: node.attributes["path_end"],
@@ -75,7 +79,7 @@ module Asciidoctor
75
79
  symbols_parse(symbols_attrs(node, a), xml, node)
76
80
  when "acknowledgements"
77
81
  acknowledgements_parse(a, xml, node)
78
- when "bibliography"
82
+ when "bibliography"
79
83
  bibliography_parse(a, xml, node)
80
84
  else
81
85
  if @term_def then term_def_subclause_parse(a, xml, node)
@@ -88,9 +92,9 @@ module Asciidoctor
88
92
  bibliography_parse(a, xml, node)
89
93
  elsif node.attr("style") == "bibliography"
90
94
  bibliography_parse(a, xml, node)
91
- elsif node.attr("style") == "abstract"
95
+ elsif node.attr("style") == "abstract"
92
96
  abstract_parse(a, xml, node)
93
- elsif node.attr("style") == "index"
97
+ elsif node.attr("style") == "index"
94
98
  indexsect_parse(a, xml, node)
95
99
  elsif node.attr("style") == "appendix" && node.level == 1
96
100
  annex_parse(a, xml, node)
@@ -102,10 +106,13 @@ module Asciidoctor
102
106
  end
103
107
 
104
108
  def set_obligation(attrs, node)
105
- attrs[:obligation] = node.attributes.has_key?("obligation") ?
106
- node.attr("obligation") :
107
- node.parent.attributes.has_key?("obligation") ?
108
- node.parent.attr("obligation") : "normative"
109
+ attrs[:obligation] = if node.attributes.has_key?("obligation")
110
+ node.attr("obligation")
111
+ elsif node.parent.attributes.has_key?("obligation")
112
+ node.parent.attr("obligation")
113
+ else
114
+ "normative"
115
+ end
109
116
  end
110
117
 
111
118
  def preamble(node)
@@ -3,81 +3,135 @@
3
3
  module Asciidoctor
4
4
  module Standoc
5
5
  # Intelligent term lookup xml modifier
6
- # Lookup all `term` and `calause` tags and replace `termxref` tags with
7
- # `xref`:target tag
8
6
  class TermLookupCleanup
9
- AUTOMATIC_GENERATED_ID_REGEXP = /\A_/
10
- EXISTING_TERM_REGEXP = /\Aterm-/
7
+ AUTOMATIC_GENERATED_ID_REGEXP = /\A_/.freeze
8
+ EXISTING_TERM_REGEXP = /\Aterm-/.freeze
9
+ EXISTING_SYMBOL_REGEXP = /\Asymbol-/.freeze
11
10
 
12
11
  attr_reader :xmldoc, :termlookup, :log
13
12
 
14
13
  def initialize(xmldoc, log)
15
14
  @xmldoc = xmldoc
16
15
  @log = log
17
- @termlookup = {}
16
+ @termlookup = { term: {}, symbol: {} }
17
+ @idhash = {}
18
18
  end
19
19
 
20
20
  def call
21
+ @idhash = populate_idhash
21
22
  @termlookup = replace_automatic_generated_ids_terms
22
23
  set_termxref_tags_target
24
+ concept_cleanup
23
25
  end
24
26
 
25
27
  private
26
28
 
29
+ def concept_cleanup
30
+ xmldoc.xpath("//concept").each do |n|
31
+ n.delete("type")
32
+ end
33
+ end
34
+
35
+ def populate_idhash
36
+ xmldoc.xpath("//*[@id]").each_with_object({}) do |n, mem|
37
+ next unless /^(term|symbol)-/.match?(n["id"])
38
+
39
+ mem[n["id"]] = true
40
+ end
41
+ end
42
+
27
43
  def set_termxref_tags_target
28
- xmldoc.xpath('//termxref').each do |node|
44
+ xmldoc.xpath("//termxref").each do |node|
29
45
  target = normalize_ref_id(node.text)
30
- if termlookup[target].nil?
46
+ if termlookup[:term][target].nil? && termlookup[:symbol][target].nil?
31
47
  remove_missing_ref(node, target)
32
48
  next
33
49
  end
34
- modify_ref_node(node, target)
50
+ x = node.at("../xrefrender")
51
+ modify_ref_node(x, target)
52
+ node.name = "refterm"
35
53
  end
36
54
  end
37
55
 
38
56
  def remove_missing_ref(node, target)
39
- log.add('AsciiDoc Input', node,
57
+ if node.at("../concept[@type = 'symbol']")
58
+ remove_missing_ref_symbol(node, target)
59
+ else
60
+ remove_missing_ref_term(node, target)
61
+ end
62
+ end
63
+
64
+ def remove_missing_ref_term(node, target)
65
+ log.add("AsciiDoc Input", node,
40
66
  %(Error: Term reference in `term[#{target}]` missing: \
41
67
  "#{target}" is not defined in document))
42
- term_name_node = node.previous.previous
43
- term_name_node.remove
44
- term_name_node.name = "strong"
45
- term_name_node.children.first.content =
46
- %(term "#{term_name_node.text}" not resolved)
47
- node.add_previous_sibling(term_name_node)
48
- node.remove
68
+ node.name = "strong"
69
+ node.at("../xrefrender").remove
70
+ display = node&.at("../renderterm")&.remove&.children
71
+ display = [] if display.nil? || display&.to_xml == node.text
72
+ d = display.empty? ? "" : ", display <tt>#{display.to_xml}</tt>"
73
+ node.children = "term <tt>#{node.text}</tt>#{d} "\
74
+ "not resolved via ID <tt>#{target}</tt>"
75
+ end
76
+
77
+ def remove_missing_ref_symbol(node, target)
78
+ log.add("AsciiDoc Input", node,
79
+ %(Error: Symbol reference in `symbol[#{target}]` missing: \
80
+ "#{target}" is not defined in document))
81
+ node.name = "strong"
82
+ node.at("../xrefrender").remove
83
+ display = node&.at("../renderterm")&.remove&.children
84
+ display = [] if display.nil? || display&.to_xml == node.text
85
+ d = display.empty? ? "" : ", display <tt>#{display.to_xml}</tt>"
86
+ node.children = "symbol <tt>#{node.text}</tt>#{d} "\
87
+ "not resolved via ID <tt>#{target}</tt>"
49
88
  end
50
89
 
51
90
  def modify_ref_node(node, target)
52
- node.name = 'xref'
53
- node['target'] = termlookup[target]
54
- node.children.remove
55
- node.remove_attribute('defaultref')
91
+ node.name = "xref"
92
+ s = termlookup[:symbol][target]
93
+ t = termlookup[:term][target]
94
+ type = node.parent["type"]
95
+ if type == "term" || !type && t
96
+ node["target"] = t
97
+ elsif type == "symbol" || !type && s
98
+ node["target"] = s
99
+ end
56
100
  end
57
101
 
58
102
  def replace_automatic_generated_ids_terms
59
- xmldoc.xpath('//term').each.with_object({}) do |term_node, res|
60
- normalize_id_and_memorize(term_node, res, './preferred')
103
+ r = xmldoc.xpath("//term").each.with_object({}) do |n, res|
104
+ normalize_id_and_memorize(n, res, "./preferred", "term")
61
105
  end
106
+ s = xmldoc.xpath("//definitions//dt").each.with_object({}) do |n, res|
107
+ normalize_id_and_memorize(n, res, ".", "symbol")
108
+ end
109
+ { term: r, symbol: s }
62
110
  end
63
111
 
64
- def normalize_id_and_memorize(term_node, res_table, text_selector)
65
- term_text = normalize_ref_id(term_node.at(text_selector).text)
66
- unless AUTOMATIC_GENERATED_ID_REGEXP.match(term_node['id']).nil?
67
- term_node['id'] = unique_text_id(term_text)
68
- end
69
- res_table[term_text] = term_node['id']
112
+ def normalize_id_and_memorize(node, res_table, text_selector, prefix)
113
+ term_text = normalize_ref_id(node.at(text_selector).text)
114
+ unless AUTOMATIC_GENERATED_ID_REGEXP.match(node["id"]).nil? &&
115
+ !node["id"].nil?
116
+ id = unique_text_id(term_text, prefix)
117
+ node["id"] = id
118
+ @idhash[id] = true
119
+ end
120
+ res_table[term_text] = node["id"]
70
121
  end
71
122
 
72
123
  def normalize_ref_id(text)
73
- text.downcase.gsub(/[[:space:]]/, '-')
124
+ text.downcase.gsub(/[[:space:]]/, "-")
74
125
  end
75
126
 
76
- def unique_text_id(text)
77
- return "term-#{text}" if xmldoc.at("//*[@id = 'term-#{text}']").nil?
127
+ def unique_text_id(text, prefix)
128
+ unless @idhash["#{prefix}-#{text}"]
129
+ return "#{prefix}-#{text}"
130
+ end
131
+
78
132
  (1..Float::INFINITY).lazy.each do |index|
79
- if xmldoc.at("//*[@id = 'term-#{text}-#{index}']").nil?
80
- break("term-#{text}-#{index}")
133
+ unless @idhash["#{prefix}-#{text}-#{index}"]
134
+ break("#{prefix}-#{text}-#{index}")
81
135
  end
82
136
  end
83
137
  end