metanorma-standoc 1.10.8 → 1.11.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 (44) hide show
  1. checksums.yaml +4 -4
  2. data/Rakefile +1 -1
  3. data/lib/asciidoctor/standoc/base.rb +5 -4
  4. data/lib/asciidoctor/standoc/cleanup.rb +20 -11
  5. data/lib/asciidoctor/standoc/cleanup_inline.rb +20 -7
  6. data/lib/asciidoctor/standoc/cleanup_maths.rb +5 -6
  7. data/lib/asciidoctor/standoc/cleanup_reqt.rb +2 -21
  8. data/lib/asciidoctor/standoc/cleanup_symbols.rb +48 -0
  9. data/lib/asciidoctor/standoc/cleanup_terms.rb +37 -77
  10. data/lib/asciidoctor/standoc/cleanup_terms_designations.rb +162 -0
  11. data/lib/asciidoctor/standoc/converter.rb +2 -0
  12. data/lib/asciidoctor/standoc/inline.rb +7 -5
  13. data/lib/asciidoctor/standoc/isodoc.rng +218 -27
  14. data/lib/asciidoctor/standoc/macros_plantuml.rb +29 -14
  15. data/lib/asciidoctor/standoc/macros_terms.rb +49 -5
  16. data/lib/asciidoctor/standoc/ref_sect.rb +24 -17
  17. data/lib/asciidoctor/standoc/term_lookup_cleanup.rb +50 -11
  18. data/lib/asciidoctor/standoc/terms.rb +12 -2
  19. data/lib/asciidoctor/standoc/utils.rb +36 -23
  20. data/lib/asciidoctor/standoc/validate.rb +24 -15
  21. data/lib/metanorma/standoc/version.rb +1 -1
  22. data/metanorma-standoc.gemspec +1 -1
  23. data/spec/asciidoctor/base_spec.rb +4 -3
  24. data/spec/asciidoctor/blocks_spec.rb +149 -21
  25. data/spec/asciidoctor/cleanup_sections_spec.rb +7 -7
  26. data/spec/asciidoctor/cleanup_spec.rb +21 -195
  27. data/spec/asciidoctor/cleanup_terms_spec.rb +990 -0
  28. data/spec/asciidoctor/inline_spec.rb +2 -2
  29. data/spec/asciidoctor/macros_plantuml_spec.rb +36 -1
  30. data/spec/asciidoctor/macros_spec.rb +189 -112
  31. data/spec/asciidoctor/refs_spec.rb +2 -24
  32. data/spec/asciidoctor/section_spec.rb +18 -18
  33. data/spec/asciidoctor/validate_spec.rb +59 -2
  34. data/spec/spec_helper.rb +1 -0
  35. data/spec/vcr_cassettes/dated_iso_ref_joint_iso_iec.yml +46 -46
  36. data/spec/vcr_cassettes/dated_iso_ref_joint_iso_iec1.yml +12 -12
  37. data/spec/vcr_cassettes/isobib_get_123.yml +12 -12
  38. data/spec/vcr_cassettes/isobib_get_123_1.yml +26 -26
  39. data/spec/vcr_cassettes/isobib_get_123_1_fr.yml +32 -32
  40. data/spec/vcr_cassettes/isobib_get_123_2001.yml +11 -11
  41. data/spec/vcr_cassettes/isobib_get_124.yml +12 -12
  42. data/spec/vcr_cassettes/rfcbib_get_rfc8341.yml +14 -14
  43. data/spec/vcr_cassettes/separates_iev_citations_by_top_level_clause.yml +45 -65
  44. metadata +8 -5
@@ -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
@@ -69,7 +69,7 @@ module Asciidoctor
69
69
 
70
70
  def term_def_subclause_parse1(attrs, xml, node)
71
71
  xml.term **attr_code(attrs) do |xml_section|
72
- xml_section.preferred { |name| name << node.title }
72
+ term_designation(xml_section, node, "preferred", node.title)
73
73
  xml_section << node.content
74
74
  end
75
75
  end
@@ -84,6 +84,14 @@ module Asciidoctor
84
84
  end
85
85
  end
86
86
 
87
+ def term_designation(xml, _node, tag, text)
88
+ xml.send tag do |p|
89
+ p.expression do |e|
90
+ e.name { |name| name << text }
91
+ end
92
+ end
93
+ end
94
+
87
95
  def term_source_attrs(_node, seen_xref)
88
96
  { case: seen_xref.children[0]["case"],
89
97
  droploc: seen_xref.children[0]["droploc"],
@@ -124,7 +132,9 @@ module Asciidoctor
124
132
  def termsource(node)
125
133
  matched = extract_termsource_refs(node.content, node) || return
126
134
  noko do |xml|
127
- attrs = { status: matched[:text] ? "modified" : "identical" }
135
+ status = node.attr("status") ||
136
+ (matched[:text] ? "modified" : "identical")
137
+ attrs = { status: status, type: node.attr("type") || "authoritative" }
128
138
  xml.termsource **attrs do |xml_t|
129
139
  seen_xref = Nokogiri::XML.fragment(matched[:xref])
130
140
  add_term_source(node, xml_t, seen_xref, matched)
@@ -40,10 +40,9 @@ module Asciidoctor
40
40
  end
41
41
 
42
42
  def attr_code(attributes)
43
- attributes = attributes.reject { |_, val| val.nil? }.map
44
- attributes.map do |k, v|
45
- [k, (v.is_a? String) ? HTMLEntities.new.decode(v) : v]
46
- end.to_h
43
+ attributes.compact.transform_values do |v|
44
+ v.is_a?(String) ? HTMLEntities.new.decode(v) : v
45
+ end
47
46
  end
48
47
 
49
48
  # if the contents of node are blocks, output them to out;
@@ -56,7 +55,7 @@ module Asciidoctor
56
55
  end
57
56
 
58
57
  SUBCLAUSE_XPATH = "//clause[not(parent::sections)]"\
59
- "[not(ancestor::boilerplate)]".freeze
58
+ "[not(ancestor::boilerplate)]".freeze
60
59
 
61
60
  def isodoc(lang, script, i18nyaml = nil)
62
61
  conv = html_converter(EmptyAttr.new)
@@ -67,29 +66,43 @@ module Asciidoctor
67
66
 
68
67
  def default_script(lang)
69
68
  case lang
70
- when "ar", "fa"
71
- "Arab"
72
- when "ur"
73
- "Aran"
74
- when "ru", "bg"
75
- "Cyrl"
76
- when "hi"
77
- "Deva"
78
- when "el"
79
- "Grek"
80
- when "zh"
81
- "Hans"
82
- when "ko"
83
- "Kore"
84
- when "he"
85
- "Hebr"
86
- when "ja"
87
- "Jpan"
69
+ when "ar", "fa" then "Arab"
70
+ when "ur" then "Aran"
71
+ when "ru", "bg" then "Cyrl"
72
+ when "hi" then "Deva"
73
+ when "el" then "Grek"
74
+ when "zh" then "Hans"
75
+ when "ko" then "Kore"
76
+ when "he" then "Hebr"
77
+ when "ja" then "Jpan"
88
78
  else
89
79
  "Latn"
90
80
  end
91
81
  end
92
82
 
83
+ def dl_to_attrs(elem, dlist, name)
84
+ e = dlist.at("./dt[text()='#{name}']") or return
85
+ val = e.at("./following::dd/p") || e.at("./following::dd") or return
86
+ elem[name] = val.text
87
+ end
88
+
89
+ def dl_to_elems(ins, elem, dlist, name)
90
+ a = elem.at("./#{name}[last()]")
91
+ ins = a if a
92
+ dlist.xpath("./dt[text()='#{name}']").each do |e|
93
+ v = e.at("./following::dd")
94
+ e = v.elements and e.size == 1 && e.first.name == "p" and v = e.first
95
+ v.name = name
96
+ ins.next = v
97
+ ins = ins.next
98
+ end
99
+ ins
100
+ end
101
+
102
+ def term_expr(elem)
103
+ "<expression><name>#{elem}</name></expression>"
104
+ end
105
+
93
106
  class EmptyAttr
94
107
  def attr(_any_attribute)
95
108
  nil
@@ -7,7 +7,7 @@ require "iev"
7
7
  module Asciidoctor
8
8
  module Standoc
9
9
  module Validate
10
- SOURCELOCALITY = "./termsource/origin//locality[@type = 'clause']/"\
10
+ SOURCELOCALITY = "./origin//locality[@type = 'clause']/"\
11
11
  "referenceFrom".freeze
12
12
 
13
13
  def init_iev
@@ -21,18 +21,25 @@ module Asciidoctor
21
21
  def iev_validate(xmldoc)
22
22
  @iev = init_iev or return
23
23
  xmldoc.xpath("//term").each do |t|
24
- /^IEC 60050-/.match(t&.at("./termsource/origin/@citeas")&.text) &&
25
- loc = t.xpath(SOURCELOCALITY)&.text or next
26
- iev = @iev.fetch(loc, xmldoc&.at("//language")&.text || "en") or next
27
- pref = t.xpath("./preferred").inject([]) do |m, x|
28
- m << x&.text&.downcase
24
+ t.xpath(".//termsource").each do |src|
25
+ (/^IEC 60050-/.match(src&.at("./origin/@citeas")&.text) &&
26
+ loc = src.xpath(SOURCELOCALITY)&.text) or next
27
+ iev_validate1(t, loc, xmldoc)
29
28
  end
30
- pref.include?(iev.downcase) or
31
- @log.add("Bibliography", t, %(Term "#{pref[0]}" does not match ) +
32
- %(IEV #{loc} "#{iev}"))
33
29
  end
34
30
  end
35
31
 
32
+ def iev_validate1(term, loc, xmldoc)
33
+ iev = @iev.fetch(loc,
34
+ xmldoc&.at("//language")&.text || "en") or return
35
+ pref = term.xpath("./preferred//name").inject([]) do |m, x|
36
+ m << x&.text&.downcase
37
+ end
38
+ pref.include?(iev.downcase) or
39
+ @log.add("Bibliography", term, %(Term "#{pref[0]}" does not match ) +
40
+ %(IEV #{loc} "#{iev}"))
41
+ end
42
+
36
43
  def content_validate(doc)
37
44
  @fatalerror = []
38
45
  xref_validate(doc)
@@ -40,7 +47,8 @@ module Asciidoctor
40
47
  norm_ref_validate(doc)
41
48
  repeat_id_validate(doc.root)
42
49
  iev_validate(doc.root)
43
- concept_validate(doc)
50
+ concept_validate(doc, "concept", "refterm")
51
+ concept_validate(doc, "related", "preferred//name")
44
52
  @fatalerror.empty? or clean_abort(@fatalerror.join("\n"), doc.to_xml)
45
53
  end
46
54
 
@@ -57,19 +65,20 @@ module Asciidoctor
57
65
  found and @fatalerror << "Numeric reference in normative references"
58
66
  end
59
67
 
60
- def concept_validate(doc)
68
+ def concept_validate(doc, tag, refterm)
61
69
  found = false
62
- doc.xpath("//concept/xref").each do |x|
70
+ doc.xpath("//#{tag}/xref").each do |x|
63
71
  next if doc.at("//term[@id = '#{x['target']}']")
64
72
  next if doc.at("//definitions//dt[@id = '#{x['target']}']")
65
73
 
66
- ref = x&.at("../refterm")&.text
74
+ ref = x&.at("../#{refterm}")&.text
67
75
  @log.add("Anchors", x,
68
- "Concept #{ref} is pointing to "\
76
+ "#{tag.capitalize} #{ref} is pointing to "\
69
77
  "#{x['target']}, which is not a term or symbol")
70
78
  found = true
71
79
  end
72
- found and @fatalerror << "Concept not cross-referencing term or symbol"
80
+ found and
81
+ @fatalerror << "#{tag.capitalize} not cross-referencing term or symbol"
73
82
  end
74
83
 
75
84
  def repeat_id_validate1(ids, elem)
@@ -19,6 +19,6 @@ module Metanorma
19
19
  end
20
20
 
21
21
  module Standoc
22
- VERSION = "1.10.8".freeze
22
+ VERSION = "1.11.0".freeze
23
23
  end
24
24
  end
@@ -28,7 +28,7 @@ Gem::Specification.new do |spec|
28
28
 
29
29
  spec.add_dependency "asciidoctor", "~> 2.0.0"
30
30
  spec.add_dependency "iev", "~> 0.2.1"
31
- spec.add_dependency "isodoc", "~> 1.7.0"
31
+ spec.add_dependency "isodoc", "~> 1.8.0"
32
32
  spec.add_dependency "metanorma-plugin-datastruct"
33
33
  spec.add_dependency "metanorma-plugin-lutaml"
34
34
  spec.add_dependency "ruby-jing"
@@ -959,14 +959,15 @@ QU1FOiB0ZXN0Cgo=
959
959
 
960
960
  it "process mn2pdf attributes" do
961
961
  node = Nokogiri::XML("<fake/>").at("fake")
962
- node["mn2pdf-font-manifest-file"] = "passed/as/font/manifest/to/mn2pdf.jar"
962
+ node[Asciidoctor::Standoc::Base::FONTS_MANIFEST] =
963
+ "passed/as/font/manifest/to/mn2pdf.jar"
963
964
 
964
965
  options = Asciidoctor::Standoc::Converter
965
966
  .new(:standoc, header_footer: true)
966
967
  .doc_extract_attributes(node)
967
968
 
968
- expect(options.dig(:mn2pdf, :font_manifest_file))
969
- .to eq(node["mn2pdf-font-manifest-file"])
969
+ expect(options.dig(:mn2pdf, :font_manifest))
970
+ .to eq(node[Asciidoctor::Standoc::Base::FONTS_MANIFEST])
970
971
  end
971
972
 
972
973
  private