metanorma-standoc 1.10.6 → 1.11.0.1

Sign up to get free protection for your applications and to get access to all the features.
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