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
@@ -10,10 +10,10 @@ module Asciidoctor
10
10
  end
11
11
 
12
12
  def reference(node)
13
- noko do |xml|
14
- node.items.each { |item| reference1(node, item.text, xml) }
15
- end.join
16
- end
13
+ noko do |xml|
14
+ node.items.each { |item| reference1(node, item.text, xml) }
15
+ end.join
16
+ end
17
17
 
18
18
  def bibliography_parse(attrs, xml, node)
19
19
  node.option? "bibitem" and return bibitem_parse(attrs, xml, node)
@@ -43,12 +43,12 @@ module Asciidoctor
43
43
  node.attr("style") == "bibliography" or
44
44
  @log.add("AsciiDoc Input", node, "Section not marked up as [bibliography]!")
45
45
  @norm_ref = true
46
- xml.references **attr_code(attrs.merge(
47
- normative: node.attr("normative") || true)) do |xml_section|
48
- xml_section.title { |t| t << node.title }
49
- xml_section << node.content
50
- end
51
- @norm_ref = false
46
+ attrs = attrs.merge(normative: node.attr("normative") || true)
47
+ xml.references **attr_code(attrs) do |xml_section|
48
+ xml_section.title { |t| t << node.title }
49
+ xml_section << node.content
50
+ end
51
+ @norm_ref = false
52
52
  end
53
53
 
54
54
  def global_ievcache_name
@@ -57,6 +57,7 @@ module Asciidoctor
57
57
 
58
58
  def local_ievcache_name(cachename)
59
59
  return nil if cachename.nil?
60
+
60
61
  cachename += "_iev" unless cachename.empty?
61
62
  cachename = "iev" if cachename.empty?
62
63
  "#{cachename}/cache"
@@ -64,10 +65,11 @@ module Asciidoctor
64
65
 
65
66
  def fetch_ref(xml, code, year, **opts)
66
67
  return nil if opts[:no_year]
68
+
67
69
  code = code.sub(/^\([^)]+\)/, "")
68
- #require "byebug"; byebug if opts[:lang] == "fr"
69
70
  hit = @bibdb&.fetch(code, year, opts)
70
71
  return nil if hit.nil?
72
+
71
73
  xml.parent.add_child(smart_render_xml(hit, code, opts))
72
74
  xml
73
75
  rescue RelatonBib::RequestError
@@ -91,10 +93,9 @@ module Asciidoctor
91
93
  "<docidentifier type='metanorma'>#{mn_code(usrlbl)}</docidentifier>"
92
94
  end
93
95
 
94
- def smart_render_xml(x, code, opts)
95
- x.respond_to? :to_xml or return nil
96
- xstr = x.to_xml(lang: opts[:lang])
97
- xml = Nokogiri::XML(xstr)
96
+ def smart_render_xml(xml, code, opts)
97
+ xml.respond_to? :to_xml or return nil
98
+ xml = Nokogiri::XML(xml.to_xml(lang: opts[:lang]))
98
99
  emend_biblio(xml, code, opts[:title], opts[:usrlbl])
99
100
  xml.xpath("//date").each { |d| Metanorma::Utils::endash_date(d) }
100
101
  xml.traverse do |n|
@@ -105,17 +106,19 @@ module Asciidoctor
105
106
 
106
107
  def init_bib_caches(node)
107
108
  return if @no_isobib
109
+
108
110
  global = !@no_isobib_cache && !node.attr("local-cache-only")
109
111
  local = node.attr("local-cache") || node.attr("local-cache-only")
110
112
  local = nil if @no_isobib_cache
111
113
  @bibdb = Relaton::DbCache.init_bib_caches(
112
114
  local_cache: local,
113
115
  flush_caches: node.attr("flush-caches"),
114
- global_cache: global)
116
+ global_cache: global
117
+ )
115
118
  end
116
119
 
117
120
  def init_iev_caches(node)
118
- unless (@no_isobib_cache || @no_isobib)
121
+ unless @no_isobib_cache || @no_isobib
119
122
  node.attr("local-cache-only") or
120
123
  @iev_globalname = global_ievcache_name
121
124
  @iev_localname = local_ievcache_name(node.attr("local-cache") ||
@@ -10,7 +10,9 @@ module Asciidoctor
10
10
  @norm_ref = false
11
11
 
12
12
  def sectiontype1(node)
13
- node&.attr("heading")&.downcase || node.title.gsub(/<[^>]+>/, "").downcase
13
+ node&.attr("heading")&.downcase ||
14
+ node.title.gsub(%r{<index>.*?</index>}m, "").gsub(/<[^>]+>/, "")
15
+ .strip.downcase
14
16
  end
15
17
 
16
18
  def sectiontype(node, level = true)
@@ -3,11 +3,9 @@
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
11
9
 
12
10
  attr_reader :xmldoc, :termlookup, :log
13
11
 
@@ -15,68 +13,83 @@ module Asciidoctor
15
13
  @xmldoc = xmldoc
16
14
  @log = log
17
15
  @termlookup = {}
16
+ @idhash = {}
18
17
  end
19
18
 
20
19
  def call
20
+ @idhash = populate_idhash
21
21
  @termlookup = replace_automatic_generated_ids_terms
22
22
  set_termxref_tags_target
23
23
  end
24
24
 
25
25
  private
26
26
 
27
+ def populate_idhash
28
+ xmldoc.xpath("//*[@id]").each_with_object({}) do |n, mem|
29
+ next unless /^term-/.match?(n["id"])
30
+
31
+ mem[n["id"]] = true
32
+ end
33
+ end
34
+
27
35
  def set_termxref_tags_target
28
- xmldoc.xpath('//termxref').each do |node|
36
+ xmldoc.xpath("//termxref").each do |node|
29
37
  target = normalize_ref_id(node.text)
30
38
  if termlookup[target].nil?
31
39
  remove_missing_ref(node, target)
32
40
  next
33
41
  end
34
- modify_ref_node(node, target)
42
+ x = node.at("../xrefrender")
43
+ modify_ref_node(x, target)
44
+ node.name = "refterm"
35
45
  end
36
46
  end
37
47
 
38
48
  def remove_missing_ref(node, target)
39
- log.add('AsciiDoc Input', node,
49
+ log.add("AsciiDoc Input", node,
40
50
  %(Error: Term reference in `term[#{target}]` missing: \
41
51
  "#{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
52
+ node.name = "strong"
53
+ node.at("../xrefrender").remove
54
+ display = node&.at("../renderterm")&.remove&.children
55
+ display = [] if display.nil? || display&.to_xml == node.text
56
+ d = display.empty? ? "" : ", display <tt>#{display.to_xml}</tt>"
57
+ node.children = "term <tt>#{node.text}</tt>#{d} "\
58
+ "not resolved via ID <tt>#{target}</tt>"
49
59
  end
50
60
 
51
61
  def modify_ref_node(node, target)
52
- node.name = 'xref'
53
- node['target'] = termlookup[target]
54
- node.children.remove
55
- node.remove_attribute('defaultref')
62
+ node.name = "xref"
63
+ node["target"] = termlookup[target]
56
64
  end
57
65
 
58
66
  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')
67
+ xmldoc.xpath("//term").each.with_object({}) do |term_node, res|
68
+ normalize_id_and_memorize(term_node, res, "./preferred")
61
69
  end
62
70
  end
63
71
 
64
72
  def normalize_id_and_memorize(term_node, res_table, text_selector)
65
73
  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']
74
+ unless AUTOMATIC_GENERATED_ID_REGEXP.match(term_node["id"]).nil?
75
+ id = unique_text_id(term_text)
76
+ term_node["id"] = id
77
+ @idhash[id] = true
78
+ end
79
+ res_table[term_text] = term_node["id"]
70
80
  end
71
81
 
72
82
  def normalize_ref_id(text)
73
- text.downcase.gsub(/[[:space:]]/, '-')
83
+ text.downcase.gsub(/[[:space:]]/, "-")
74
84
  end
75
85
 
76
86
  def unique_text_id(text)
77
- return "term-#{text}" if xmldoc.at("//*[@id = 'term-#{text}']").nil?
87
+ unless @idhash["term-#{text}"]
88
+ return "term-#{text}"
89
+ end
90
+
78
91
  (1..Float::INFINITY).lazy.each do |index|
79
- if xmldoc.at("//*[@id = 'term-#{text}-#{index}']").nil?
92
+ unless @idhash["term-#{text}-#{index}"]
80
93
  break("term-#{text}-#{index}")
81
94
  end
82
95
  end
@@ -12,12 +12,13 @@ module Asciidoctor
12
12
  @definitions = defs
13
13
  end
14
14
 
15
- def symbols_attrs(node, a)
15
+ def symbols_attrs(node, attr)
16
16
  case sectiontype1(node)
17
- when "symbols" then a.merge(type: "symbols")
18
- when "abbreviated terms", "abbreviations" then a.merge(type: "abbreviated_terms")
17
+ when "symbols" then attr.merge(type: "symbols")
18
+ when "abbreviated terms", "abbreviations"
19
+ attr.merge(type: "abbreviated_terms")
19
20
  else
20
- a
21
+ attr
21
22
  end
22
23
  end
23
24
 
@@ -51,13 +52,17 @@ module Asciidoctor
51
52
 
52
53
  # subclause contains subclauses
53
54
  def term_def_subclause_parse(attrs, xml, node)
54
- node.role == "nonterm" and return nonterm_term_def_subclause_parse(attrs, xml, node)
55
- node.role == "boilerplate" and return terms_boilerplate_parse(attrs, xml, node)
55
+ node.role == "nonterm" and
56
+ return nonterm_term_def_subclause_parse(attrs, xml, node)
57
+ node.role == "boilerplate" and
58
+ return terms_boilerplate_parse(attrs, xml, node)
56
59
  st = sectiontype(node, false)
57
60
  return symbols_parse(attrs, xml, node) if @definitions
61
+
58
62
  sub = node.find_by(context: :section) { |s| s.level == node.level + 1 }
59
63
  sub.empty? || (return term_def_parse(attrs, xml, node, false))
60
- st == "symbols and abbreviated terms" and (return symbols_parse(attrs, xml, node))
64
+ st == "symbols and abbreviated terms" and
65
+ return symbols_parse(attrs, xml, node)
61
66
  st == "terms and definitions" and return clause_parse(attrs, xml, node)
62
67
  term_def_subclause_parse1(attrs, xml, node)
63
68
  end
@@ -69,7 +74,7 @@ module Asciidoctor
69
74
  end
70
75
  end
71
76
 
72
- def term_def_parse(attrs, xml, node, toplevel)
77
+ def term_def_parse(attrs, xml, node, _toplevel)
73
78
  xml.terms **attr_code(attrs) do |section|
74
79
  section.title { |t| t << node.title }
75
80
  (s = node.attr("source")) && s.split(/,/).each do |s1|
@@ -79,14 +84,14 @@ module Asciidoctor
79
84
  end
80
85
  end
81
86
 
82
- def term_source_attrs(node, seen_xref)
83
- { case: seen_xref.children[0]["case"],
84
- droploc: seen_xref.children[0]["droploc"],
85
- bibitemid: seen_xref.children[0]["target"],
86
- format: seen_xref.children[0]["format"], type: "inline" }
87
+ def term_source_attrs(_node, seen_xref)
88
+ { case: seen_xref.children[0]["case"],
89
+ droploc: seen_xref.children[0]["droploc"],
90
+ bibitemid: seen_xref.children[0]["target"],
91
+ format: seen_xref.children[0]["format"], type: "inline" }
87
92
  end
88
93
 
89
- def add_term_source(node, xml_t, seen_xref, m)
94
+ def add_term_source(node, xml_t, seen_xref, match)
90
95
  if seen_xref.children[0].name == "concept"
91
96
  xml_t.origin { |o| o << seen_xref.children[0].to_xml }
92
97
  else
@@ -94,13 +99,13 @@ module Asciidoctor
94
99
  attrs.delete(:text)
95
100
  xml_t.origin seen_xref.children[0].content, **attr_code(attrs)
96
101
  end
97
- m[:text] && xml_t.modification do |mod|
98
- mod.p { |p| p << m[:text].sub(/^\s+/, "") }
102
+ match[:text] && xml_t.modification do |mod|
103
+ mod.p { |p| p << match[:text].sub(/^\s+/, "") }
99
104
  end
100
105
  end
101
106
 
102
107
  TERM_REFERENCE_RE_STR = <<~REGEXP.freeze
103
- ^(?<xref><(xref|concept)[^>]+>([^<]*</(xref|concept)>)?)
108
+ ^(?<xref><(xref|concept)[^>]+>(.*?</(xref|concept)>)?)
104
109
  (,\s(?<text>.*))?
105
110
  $
106
111
  REGEXP
@@ -110,7 +115,9 @@ module Asciidoctor
110
115
 
111
116
  def extract_termsource_refs(text, node)
112
117
  matched = TERM_REFERENCE_RE.match text
113
- matched.nil? and @log.add("AsciiDoc Input", node, "term reference not in expected format: #{text}")
118
+ matched.nil? and @log.add("AsciiDoc Input", node,
119
+ "term reference not in expected format:"\
120
+ "#{text}")
114
121
  matched
115
122
  end
116
123
 
@@ -19,11 +19,11 @@ module Asciidoctor
19
19
  end
20
20
 
21
21
  NOKOHEAD = <<~HERE.freeze
22
- <!DOCTYPE html SYSTEM
23
- "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
24
- <html xmlns="http://www.w3.org/1999/xhtml">
25
- <head> <title></title> <meta charset="UTF-8" /> </head>
26
- <body> </body> </html>
22
+ <!DOCTYPE html SYSTEM
23
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
24
+ <html xmlns="http://www.w3.org/1999/xhtml">
25
+ <head> <title></title> <meta charset="UTF-8" /> </head>
26
+ <body> </body> </html>
27
27
  HERE
28
28
 
29
29
  # block for processing XML document fragments as XHTML,
@@ -34,9 +34,9 @@ module Asciidoctor
34
34
  fragment = doc.fragment("")
35
35
  ::Nokogiri::XML::Builder.with fragment, &block
36
36
  fragment.to_xml(encoding: "US-ASCII", indent: 0).lines.map do |l|
37
- l.gsub(/>\n$/, ">").gsub(/\s*\n$/m, " ").gsub("&#150;", "\u0096").
38
- gsub("&#151;", "\u0097").gsub("&#x96;", "\u0096").
39
- gsub("&#x97;", "\u0097")
37
+ l.gsub(/>\n$/, ">").gsub(/\s*\n$/m, " ").gsub("&#150;", "\u0096")
38
+ .gsub("&#151;", "\u0097").gsub("&#x96;", "\u0096")
39
+ .gsub("&#x97;", "\u0097")
40
40
  end
41
41
  end
42
42
 
@@ -66,10 +66,36 @@ module Asciidoctor
66
66
  conv
67
67
  end
68
68
 
69
+ def default_script(lang)
70
+ case lang
71
+ when "ar", "fa"
72
+ "Arab"
73
+ when "ur"
74
+ "Aran"
75
+ when "ru", "bg"
76
+ "Cyrl"
77
+ when "hi"
78
+ "Deva"
79
+ when "el"
80
+ "Grek"
81
+ when "zh"
82
+ "Hans"
83
+ when "ko"
84
+ "Kore"
85
+ when "he"
86
+ "Hebr"
87
+ when "ja"
88
+ "Jpan"
89
+ else
90
+ "Latn"
91
+ end
92
+ end
93
+
69
94
  class EmptyAttr
70
- def attr(_x)
95
+ def attr(_any_attribute)
71
96
  nil
72
97
  end
98
+
73
99
  def attributes
74
100
  {}
75
101
  end
@@ -1,5 +1,5 @@
1
1
  require "asciidoctor/standoc/utils"
2
- require_relative "./validate_section.rb"
2
+ require_relative "./validate_section"
3
3
  require "nokogiri"
4
4
  require "jing"
5
5
  require "iev"
@@ -7,22 +7,22 @@ require "iev"
7
7
  module Asciidoctor
8
8
  module Standoc
9
9
  module Validate
10
-
11
10
  SOURCELOCALITY = "./termsource/origin//locality[@type = 'clause']/"\
12
11
  "referenceFrom".freeze
13
12
 
14
13
  def init_iev
15
14
  return nil if @no_isobib
16
15
  return @iev if @iev
16
+
17
17
  @iev = Iev::Db.new(@iev_globalname, @iev_localname) unless @no_isobib
18
18
  @iev
19
19
  end
20
20
 
21
21
  def iev_validate(xmldoc)
22
+ @iev = init_iev or return
22
23
  xmldoc.xpath("//term").each do |t|
23
24
  /^IEC 60050-/.match(t&.at("./termsource/origin/@citeas")&.text) &&
24
25
  loc = t.xpath(SOURCELOCALITY)&.text or next
25
- @iev = init_iev or return
26
26
  iev = @iev.fetch(loc, xmldoc&.at("//language")&.text || "en") or next
27
27
  pref = t.xpath("./preferred").inject([]) do |m, x|
28
28
  m << x&.text&.downcase
@@ -38,29 +38,44 @@ module Asciidoctor
38
38
  norm_ref_validate(doc)
39
39
  repeat_id_validate(doc.root)
40
40
  iev_validate(doc.root)
41
+ concept_validate(doc)
41
42
  end
42
43
 
43
44
  def norm_ref_validate(doc)
44
45
  found = false
45
46
  doc.xpath("//references[@normative = 'true']/bibitem").each do |b|
46
47
  next unless docid = b.at("./docidentifier[@type = 'metanorma']")
47
- next unless /^\[\d+\]$/.match(docid.text)
48
- @log.add("Bibliography", b, "Numeric reference in normative references")
48
+ next unless /^\[\d+\]$/.match?(docid.text)
49
+
50
+ @log.add("Bibliography", b,
51
+ "Numeric reference in normative references")
49
52
  found = true
50
53
  end
51
- if found
52
- clean_exit
53
- abort("Numeric reference in normative references")
54
+ found and
55
+ clean_abort("Numeric reference in normative references", doc.to_xml)
56
+ end
57
+
58
+ def concept_validate(doc)
59
+ found = false
60
+ doc.xpath("//concept/xref").each do |x|
61
+ next if doc.at("//term[@id = '#{x['target']}']")
62
+
63
+ ref = x&.at("../refterm")&.text
64
+ @log.add("Anchors", x, "Concept #{ref} is pointing to "\
65
+ "#{x['target']}, which is not a term")
66
+ found = true
54
67
  end
68
+ found and
69
+ clean_abort("Concept not cross-referencing term", doc.to_xml)
55
70
  end
56
71
 
57
- def repeat_id_validate1(ids, x)
58
- if ids[x["id"]]
59
- @log.add("Anchors", x, "Anchor #{x['id']} has already been used "\
60
- "at line #{ids[x['id']]}")
72
+ def repeat_id_validate1(ids, elem)
73
+ if ids[elem["id"]]
74
+ @log.add("Anchors", elem, "Anchor #{elem['id']} has already been "\
75
+ "used at line #{ids[elem['id']]}")
61
76
  raise StandardError.new "Error: multiple instances of same ID"
62
77
  else
63
- ids[x["id"]] = x.line
78
+ ids[elem["id"]] = elem.line
64
79
  end
65
80
  ids
66
81
  end
@@ -72,29 +87,28 @@ module Asciidoctor
72
87
  ids = repeat_id_validate1(ids, x)
73
88
  end
74
89
  rescue StandardError => e
75
- clean_exit
76
- abort(e.message)
90
+ clean_abort(e.message, doc.to_xml)
77
91
  end
78
92
  end
79
93
 
80
94
  def schema_validate(doc, schema)
81
- Tempfile.open(["tmp", ".xml"], :encoding => 'UTF-8') do |f|
82
- begin
83
- f.write(doc.to_xml)
84
- f.close
85
- errors = Jing.new(schema).validate(f.path)
86
- warn "Syntax Valid!" if errors.none?
87
- errors.each do |e|
88
- @log.add("Metanorma XML Syntax",
89
- "XML Line #{"%06d" % e[:line]}:#{e[:column]}",
90
- e[:message])
91
- end
92
- rescue Jing::Error => e
93
- clean_exit
94
- abort "Jing failed with error: #{e}"
95
- ensure
96
- f.close!
97
- end
95
+ Tempfile.open(["tmp", ".xml"], encoding: "UTF-8") do |f|
96
+ schema_validate1(f, doc, schema)
97
+ rescue Jing::Error => e
98
+ clean_abort("Jing failed with error: #{e}", doc.to_xml)
99
+ ensure
100
+ f.close!
101
+ end
102
+ end
103
+
104
+ def schema_validate1(file, doc, schema)
105
+ file.write(doc.to_xml)
106
+ file.close
107
+ errors = Jing.new(schema).validate(file.path)
108
+ warn "Syntax Valid!" if errors.none?
109
+ errors.each do |e|
110
+ @log.add("Metanorma XML Syntax",
111
+ "XML Line #{'%06d' % e[:line]}:#{e[:column]}", e[:message])
98
112
  end
99
113
  end
100
114
 
@@ -104,7 +118,8 @@ module Asciidoctor
104
118
  def formattedstr_strip(doc)
105
119
  doc.xpath("//*[@format] | //stem | //bibdata//description | "\
106
120
  "//formattedref | //bibdata//note | //bibdata/abstract | "\
107
- "//bibitem/abstract | //bibitem/note | //misc-container").each do |n|
121
+ "//bibitem/abstract | //bibitem/note | //misc-container")
122
+ .each do |n|
108
123
  n.elements.each do |e|
109
124
  e.traverse do |e1|
110
125
  e1.element? and e1.each { |k, _v| e1.delete(k) }