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
@@ -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,8 +7,8 @@ require "iev"
7
7
  module Asciidoctor
8
8
  module Standoc
9
9
  module Validate
10
- SOURCELOCALITY = "./termsource/origin//locality[@type = 'clause']/"\
11
- "referenceFrom".freeze
10
+ SOURCELOCALITY = "./origin//locality[@type = 'clause']/"\
11
+ "referenceFrom".freeze
12
12
 
13
13
  def init_iev
14
14
  return nil if @no_isobib
@@ -21,24 +21,35 @@ 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)
44
+ @fatalerror = []
45
+ xref_validate(doc)
37
46
  section_validate(doc)
38
47
  norm_ref_validate(doc)
39
48
  repeat_id_validate(doc.root)
40
49
  iev_validate(doc.root)
41
- concept_validate(doc)
50
+ concept_validate(doc, "concept", "refterm")
51
+ concept_validate(doc, "related", "preferred//name")
52
+ @fatalerror.empty? or clean_abort(@fatalerror.join("\n"), doc.to_xml)
42
53
  end
43
54
 
44
55
  def norm_ref_validate(doc)
@@ -51,30 +62,30 @@ module Asciidoctor
51
62
  "Numeric reference in normative references")
52
63
  found = true
53
64
  end
54
- found and
55
- clean_abort("Numeric reference in normative references", doc.to_xml)
65
+ found and @fatalerror << "Numeric reference in normative references"
56
66
  end
57
67
 
58
- def concept_validate(doc)
68
+ def concept_validate(doc, tag, refterm)
59
69
  found = false
60
- doc.xpath("//concept/xref").each do |x|
70
+ doc.xpath("//#{tag}/xref").each do |x|
61
71
  next if doc.at("//term[@id = '#{x['target']}']")
62
72
  next if doc.at("//definitions//dt[@id = '#{x['target']}']")
63
73
 
64
- ref = x&.at("../refterm")&.text
65
- @log.add("Anchors", x, "Concept #{ref} is pointing to "\
74
+ ref = x&.at("../#{refterm}")&.text
75
+ @log.add("Anchors", x,
76
+ "#{tag.capitalize} #{ref} is pointing to "\
66
77
  "#{x['target']}, which is not a term or symbol")
67
78
  found = true
68
79
  end
69
- found and clean_abort("Concept not cross-referencing term or symbol",
70
- doc.to_xml)
80
+ found and
81
+ @fatalerror << "#{tag.capitalize} not cross-referencing term or symbol"
71
82
  end
72
83
 
73
84
  def repeat_id_validate1(ids, elem)
74
85
  if ids[elem["id"]]
75
86
  @log.add("Anchors", elem, "Anchor #{elem['id']} has already been "\
76
- "used at line #{ids[elem['id']]}")
77
- raise StandardError.new "Error: multiple instances of same ID"
87
+ "used at line #{ids[elem['id']]}")
88
+ @fatalerror << "Multiple instances of same ID: #{elem['id']}"
78
89
  else
79
90
  ids[elem["id"]] = elem.line
80
91
  end
@@ -83,12 +94,8 @@ module Asciidoctor
83
94
 
84
95
  def repeat_id_validate(doc)
85
96
  ids = {}
86
- begin
87
- doc.xpath("//*[@id]").each do |x|
88
- ids = repeat_id_validate1(ids, x)
89
- end
90
- rescue StandardError => e
91
- clean_abort(e.message, doc.to_xml)
97
+ doc.xpath("//*[@id]").each do |x|
98
+ ids = repeat_id_validate1(ids, x)
92
99
  end
93
100
  end
94
101
 
@@ -130,6 +137,17 @@ module Asciidoctor
130
137
  doc
131
138
  end
132
139
 
140
+ # manually check for xref/@target, xref/@to integrity
141
+ def xref_validate(doc)
142
+ ids = doc.xpath("//*/@id").each_with_object({}) { |x, m| m[x.text] = 1 }
143
+ doc.xpath("//xref/@target | //xref/@to").each do |x|
144
+ next if ids[x.text]
145
+
146
+ @log.add("Anchors", x.parent,
147
+ "Crossreference target #{x.text} is undefined")
148
+ end
149
+ end
150
+
133
151
  def validate(doc)
134
152
  content_validate(doc)
135
153
  schema_validate(formattedstr_strip(doc.dup),
@@ -14,7 +14,8 @@ module Asciidoctor
14
14
  callouts = x.elements.select { |e| e.name == "callout" }
15
15
  annotations = x.elements.select { |e| e.name == "annotation" }
16
16
  if callouts.size != annotations.size
17
- @log.add("AsciiDoc Input", x, "mismatch of callouts and annotations")
17
+ @log.add("AsciiDoc Input", x,
18
+ "mismatch of callouts and annotations")
18
19
  end
19
20
  end
20
21
  end
@@ -42,7 +43,9 @@ module Asciidoctor
42
43
  root.xpath("//clause | //annex | //foreword | //introduction | "\
43
44
  "//acknowledgements").each do |c|
44
45
  next unless c.at("./clause")
45
- next if c.elements.reject { |n| %w(clause title).include? n.name }.empty?
46
+ next if c.elements.reject do |n|
47
+ %w(clause title).include? n.name
48
+ end.empty?
46
49
 
47
50
  style_warning(c, "Hanging paragraph in clause")
48
51
  end
@@ -19,6 +19,6 @@ module Metanorma
19
19
  end
20
20
 
21
21
  module Standoc
22
- VERSION = "1.10.6".freeze
22
+ VERSION = "1.11.0.1".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"
@@ -6,39 +6,6 @@ RSpec.describe Asciidoctor::Standoc do
6
6
  expect(Metanorma::Standoc::VERSION).not_to be nil
7
7
  end
8
8
 
9
- it "processes a blank document" do
10
- input = <<~INPUT
11
- #{ASCIIDOC_BLANK_HDR}
12
- INPUT
13
- output = <<~OUTPUT
14
- #{BLANK_HDR}
15
- <sections/>
16
- </standard-document>
17
- OUTPUT
18
- expect(xmlpp(Asciidoctor.convert(input, *OPTIONS)))
19
- .to be_equivalent_to xmlpp(output)
20
- end
21
-
22
- it "converts a blank document" do
23
- FileUtils.rm_f "test.doc"
24
- input = <<~INPUT
25
- = Document title
26
- Author
27
- :docfile: test.adoc
28
- :novalid:
29
- INPUT
30
- output = <<~OUTPUT
31
- #{BLANK_HDR}
32
- <sections/>
33
- </standard-document>
34
- OUTPUT
35
- expect(xmlpp(Asciidoctor.convert(input, *OPTIONS)))
36
- .to be_equivalent_to xmlpp(output)
37
- expect(File.exist?("test.doc")).to be true
38
- expect(File.exist?("test.pdf")).to be true
39
- expect(File.exist?("htmlstyle.css")).to be false
40
- end
41
-
42
9
  it "assigns default scripts to major languages" do
43
10
  FileUtils.rm_f "test.doc"
44
11
  input = <<~INPUT
@@ -992,14 +959,15 @@ QU1FOiB0ZXN0Cgo=
992
959
 
993
960
  it "process mn2pdf attributes" do
994
961
  node = Nokogiri::XML("<fake/>").at("fake")
995
- 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"
996
964
 
997
965
  options = Asciidoctor::Standoc::Converter
998
966
  .new(:standoc, header_footer: true)
999
967
  .doc_extract_attributes(node)
1000
968
 
1001
- expect(options.dig(:mn2pdf, :font_manifest_file))
1002
- .to eq(node["mn2pdf-font-manifest-file"])
969
+ expect(options.dig(:mn2pdf, :font_manifest))
970
+ .to eq(node[Asciidoctor::Standoc::Base::FONTS_MANIFEST])
1003
971
  end
1004
972
 
1005
973
  private
@@ -0,0 +1,37 @@
1
+ require "spec_helper"
2
+ require "fileutils"
3
+
4
+ RSpec.describe Asciidoctor::Standoc do
5
+ it "processes a blank document" do
6
+ input = <<~INPUT
7
+ #{ASCIIDOC_BLANK_HDR}
8
+ INPUT
9
+ output = <<~OUTPUT
10
+ #{BLANK_HDR}
11
+ <sections/>
12
+ </standard-document>
13
+ OUTPUT
14
+ expect(xmlpp(Asciidoctor.convert(input, *OPTIONS)))
15
+ .to be_equivalent_to xmlpp(output)
16
+ end
17
+
18
+ it "converts a blank document" do
19
+ FileUtils.rm_f "test.doc"
20
+ input = <<~INPUT
21
+ = Document title
22
+ Author
23
+ :docfile: test.adoc
24
+ :novalid:
25
+ INPUT
26
+ output = <<~OUTPUT
27
+ #{BLANK_HDR}
28
+ <sections/>
29
+ </standard-document>
30
+ OUTPUT
31
+ expect(xmlpp(Asciidoctor.convert(input, *OPTIONS)))
32
+ .to be_equivalent_to xmlpp(output)
33
+ expect(File.exist?("test.doc")).to be true
34
+ expect(File.exist?("test.pdf")).to be true
35
+ expect(File.exist?("htmlstyle.css")).to be false
36
+ end
37
+ end