metanorma-standoc 1.11.4 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (141) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/rake.yml +3 -31
  3. data/.gitignore +23 -0
  4. data/lib/asciidoctor/standoc/base.rb +2 -145
  5. data/lib/asciidoctor/standoc/blocks.rb +2 -238
  6. data/lib/asciidoctor/standoc/blocks_notes.rb +2 -100
  7. data/lib/asciidoctor/standoc/cleanup.rb +2 -208
  8. data/lib/asciidoctor/standoc/cleanup_amend.rb +2 -53
  9. data/lib/asciidoctor/standoc/cleanup_block.rb +2 -172
  10. data/lib/asciidoctor/standoc/cleanup_boilerplate.rb +2 -212
  11. data/lib/asciidoctor/standoc/cleanup_footnotes.rb +2 -108
  12. data/lib/asciidoctor/standoc/cleanup_image.rb +2 -69
  13. data/lib/asciidoctor/standoc/cleanup_inline.rb +2 -189
  14. data/lib/asciidoctor/standoc/cleanup_maths.rb +2 -221
  15. data/lib/asciidoctor/standoc/cleanup_ref.rb +2 -169
  16. data/lib/asciidoctor/standoc/cleanup_ref_dl.rb +2 -103
  17. data/lib/asciidoctor/standoc/cleanup_reqt.rb +2 -110
  18. data/lib/asciidoctor/standoc/cleanup_section.rb +2 -184
  19. data/lib/asciidoctor/standoc/cleanup_section_names.rb +2 -91
  20. data/lib/asciidoctor/standoc/cleanup_symbols.rb +2 -47
  21. data/lib/asciidoctor/standoc/cleanup_table.rb +2 -67
  22. data/lib/asciidoctor/standoc/cleanup_terms.rb +2 -139
  23. data/lib/asciidoctor/standoc/cleanup_terms_designations.rb +2 -198
  24. data/lib/asciidoctor/standoc/cleanup_text.rb +2 -95
  25. data/lib/asciidoctor/standoc/cleanup_toc.rb +3 -0
  26. data/lib/asciidoctor/standoc/cleanup_xref.rb +2 -106
  27. data/lib/asciidoctor/standoc/converter.rb +2 -123
  28. data/lib/asciidoctor/standoc/datamodel/attributes_table_preprocessor.rb +2 -56
  29. data/lib/asciidoctor/standoc/datamodel/diagram_preprocessor.rb +2 -102
  30. data/lib/asciidoctor/standoc/datamodel/plantuml_renderer.rb +3 -404
  31. data/lib/asciidoctor/standoc/deprecated.rb +5 -0
  32. data/lib/asciidoctor/standoc/front.rb +2 -223
  33. data/lib/asciidoctor/standoc/front_contributor.rb +2 -191
  34. data/lib/asciidoctor/standoc/inline.rb +2 -231
  35. data/lib/asciidoctor/standoc/lists.rb +2 -119
  36. data/lib/asciidoctor/standoc/macros.rb +2 -203
  37. data/lib/asciidoctor/standoc/macros_form.rb +2 -62
  38. data/lib/asciidoctor/standoc/macros_note.rb +2 -44
  39. data/lib/asciidoctor/standoc/macros_plantuml.rb +2 -112
  40. data/lib/asciidoctor/standoc/macros_terms.rb +2 -180
  41. data/lib/asciidoctor/standoc/ref.rb +2 -251
  42. data/lib/asciidoctor/standoc/ref_sect.rb +2 -153
  43. data/lib/asciidoctor/standoc/ref_utility.rb +2 -0
  44. data/lib/asciidoctor/standoc/render.rb +2 -114
  45. data/lib/asciidoctor/standoc/reqt.rb +2 -89
  46. data/lib/asciidoctor/standoc/section.rb +2 -207
  47. data/lib/asciidoctor/standoc/table.rb +2 -84
  48. data/lib/asciidoctor/standoc/term_lookup_cleanup.rb +2 -178
  49. data/lib/asciidoctor/standoc/terms.rb +2 -159
  50. data/lib/asciidoctor/standoc/utils.rb +2 -100
  51. data/lib/asciidoctor/standoc/validate.rb +2 -157
  52. data/lib/asciidoctor/standoc/validate_section.rb +2 -54
  53. data/lib/metanorma/standoc/base.rb +149 -0
  54. data/lib/{asciidoctor → metanorma}/standoc/basicdoc.rng +0 -0
  55. data/lib/{asciidoctor → metanorma}/standoc/biblio.rng +0 -0
  56. data/lib/metanorma/standoc/blocks.rb +239 -0
  57. data/lib/metanorma/standoc/blocks_notes.rb +101 -0
  58. data/lib/metanorma/standoc/cleanup.rb +146 -0
  59. data/lib/metanorma/standoc/cleanup_amend.rb +54 -0
  60. data/lib/metanorma/standoc/cleanup_block.rb +173 -0
  61. data/lib/metanorma/standoc/cleanup_boilerplate.rb +213 -0
  62. data/lib/metanorma/standoc/cleanup_footnotes.rb +109 -0
  63. data/lib/metanorma/standoc/cleanup_image.rb +70 -0
  64. data/lib/metanorma/standoc/cleanup_inline.rb +190 -0
  65. data/lib/metanorma/standoc/cleanup_maths.rb +222 -0
  66. data/lib/metanorma/standoc/cleanup_ref.rb +170 -0
  67. data/lib/metanorma/standoc/cleanup_ref_dl.rb +104 -0
  68. data/lib/metanorma/standoc/cleanup_reqt.rb +111 -0
  69. data/lib/metanorma/standoc/cleanup_section.rb +212 -0
  70. data/lib/metanorma/standoc/cleanup_section_names.rb +92 -0
  71. data/lib/metanorma/standoc/cleanup_symbols.rb +48 -0
  72. data/lib/metanorma/standoc/cleanup_table.rb +68 -0
  73. data/lib/metanorma/standoc/cleanup_terms.rb +140 -0
  74. data/lib/metanorma/standoc/cleanup_terms_designations.rb +199 -0
  75. data/lib/metanorma/standoc/cleanup_text.rb +96 -0
  76. data/lib/metanorma/standoc/cleanup_toc.rb +98 -0
  77. data/lib/metanorma/standoc/cleanup_xref.rb +107 -0
  78. data/lib/metanorma/standoc/converter.rb +124 -0
  79. data/lib/metanorma/standoc/datamodel/attributes_table_preprocessor.rb +57 -0
  80. data/lib/metanorma/standoc/datamodel/diagram_preprocessor.rb +103 -0
  81. data/lib/metanorma/standoc/datamodel/plantuml_renderer.rb +409 -0
  82. data/lib/metanorma/standoc/front.rb +224 -0
  83. data/lib/metanorma/standoc/front_contributor.rb +192 -0
  84. data/lib/metanorma/standoc/inline.rb +232 -0
  85. data/lib/{asciidoctor → metanorma}/standoc/isodoc.rng +29 -0
  86. data/lib/metanorma/standoc/lists.rb +120 -0
  87. data/lib/metanorma/standoc/macros.rb +204 -0
  88. data/lib/metanorma/standoc/macros_form.rb +63 -0
  89. data/lib/metanorma/standoc/macros_note.rb +45 -0
  90. data/lib/metanorma/standoc/macros_plantuml.rb +113 -0
  91. data/lib/metanorma/standoc/macros_terms.rb +181 -0
  92. data/lib/metanorma/standoc/ref.rb +243 -0
  93. data/lib/metanorma/standoc/ref_sect.rb +153 -0
  94. data/lib/{asciidoctor/standoc/ref_date_id.rb → metanorma/standoc/ref_utility.rb} +43 -5
  95. data/lib/metanorma/standoc/render.rb +115 -0
  96. data/lib/metanorma/standoc/reqt.rb +90 -0
  97. data/lib/{asciidoctor → metanorma}/standoc/reqt.rng +0 -0
  98. data/lib/metanorma/standoc/section.rb +209 -0
  99. data/lib/metanorma/standoc/table.rb +85 -0
  100. data/lib/metanorma/standoc/term_lookup_cleanup.rb +179 -0
  101. data/lib/metanorma/standoc/terms.rb +160 -0
  102. data/lib/metanorma/standoc/utils.rb +101 -0
  103. data/lib/metanorma/standoc/validate.rb +158 -0
  104. data/lib/metanorma/standoc/validate_section.rb +55 -0
  105. data/lib/metanorma/standoc/version.rb +1 -1
  106. data/lib/{asciidoctor → metanorma}/standoc/views/datamodel/model_representation.adoc.erb +0 -0
  107. data/lib/{asciidoctor → metanorma}/standoc/views/datamodel/plantuml_representation.adoc.erb +0 -0
  108. data/lib/metanorma-standoc.rb +1 -1
  109. data/metanorma-standoc.gemspec +1 -1
  110. data/spec/{asciidoctor → metanorma}/base_spec.rb +27 -10
  111. data/spec/{asciidoctor → metanorma}/blank_spec.rb +1 -1
  112. data/spec/{asciidoctor → metanorma}/blocks_spec.rb +1 -1
  113. data/spec/{asciidoctor → metanorma}/cleanup_blocks_spec.rb +1 -1
  114. data/spec/{asciidoctor → metanorma}/cleanup_sections_spec.rb +1 -1
  115. data/spec/{asciidoctor → metanorma}/cleanup_spec.rb +5 -5
  116. data/spec/{asciidoctor → metanorma}/cleanup_terms_spec.rb +2 -2
  117. data/spec/{asciidoctor → metanorma}/datamodel/attributes_table_preprocessor_spec.rb +1 -1
  118. data/spec/{asciidoctor → metanorma}/datamodel/diagram_preprocessor_spec.rb +1 -1
  119. data/spec/{asciidoctor → metanorma}/inline_spec.rb +1 -1
  120. data/spec/{asciidoctor → metanorma}/isobib_cache_spec.rb +1 -1
  121. data/spec/{asciidoctor → metanorma}/lists_spec.rb +1 -1
  122. data/spec/{asciidoctor → metanorma}/macros_json2text_spec.rb +0 -0
  123. data/spec/{asciidoctor → metanorma}/macros_plantuml_spec.rb +3 -3
  124. data/spec/{asciidoctor → metanorma}/macros_spec.rb +6 -6
  125. data/spec/{asciidoctor → metanorma}/macros_yaml2text_spec.rb +0 -0
  126. data/spec/metanorma/refs_dl_spec.rb +863 -0
  127. data/spec/{asciidoctor → metanorma}/refs_spec.rb +399 -25
  128. data/spec/{asciidoctor → metanorma}/section_spec.rb +42 -17
  129. data/spec/{asciidoctor → metanorma}/table_spec.rb +1 -1
  130. data/spec/{asciidoctor → metanorma}/validate_spec.rb +2 -2
  131. data/spec/vcr_cassettes/dated_iso_ref_joint_iso_iec.yml +42 -42
  132. data/spec/vcr_cassettes/dated_iso_ref_joint_iso_iec1.yml +11 -11
  133. data/spec/vcr_cassettes/isobib_get_123.yml +12 -12
  134. data/spec/vcr_cassettes/isobib_get_123_1.yml +21 -21
  135. data/spec/vcr_cassettes/isobib_get_123_1_fr.yml +81 -81
  136. data/spec/vcr_cassettes/isobib_get_123_2001.yml +10 -10
  137. data/spec/vcr_cassettes/isobib_get_124.yml +11 -11
  138. data/spec/vcr_cassettes/rfcbib_get_rfc8341.yml +13 -13
  139. data/spec/vcr_cassettes/separates_iev_citations_by_top_level_clause.yml +46 -46
  140. metadata +82 -32
  141. data/spec/asciidoctor/refs_dl_spec.rb +0 -864
@@ -0,0 +1,160 @@
1
+ module Metanorma
2
+ module Standoc
3
+ module Section
4
+ def in_terms?
5
+ @term_def
6
+ end
7
+
8
+ def nonterm_symbols_parse(attrs, xml, node)
9
+ defs = @definitions
10
+ @definitions = false
11
+ clause_parse(attrs, xml, node)
12
+ @definitions = defs
13
+ end
14
+
15
+ def symbols_attrs(node, attr)
16
+ case sectiontype1(node)
17
+ when "symbols" then attr.merge(type: "symbols")
18
+ when "abbreviated terms", "abbreviations"
19
+ attr.merge(type: "abbreviated_terms")
20
+ else
21
+ attr
22
+ end
23
+ end
24
+
25
+ def symbols_parse(attr, xml, node)
26
+ node.role == "nonterm" and return nonterm_symbols_parse(attr, xml, node)
27
+ xml.definitions **attr_code(attr) do |xml_section|
28
+ xml_section.title { |t| t << node.title }
29
+ defs = @definitions
30
+ termdefs = @term_def
31
+ @definitions = true
32
+ @term_def = false
33
+ xml_section << node.content
34
+ @definitions = defs
35
+ @term_def = termdefs
36
+ end
37
+ end
38
+
39
+ def nonterm_term_def_subclause_parse(attrs, xml, node)
40
+ defs = @term_def
41
+ @term_def = false
42
+ clause_parse(attrs, xml, node)
43
+ @term_def = defs
44
+ end
45
+
46
+ def terms_boilerplate_parse(attrs, xml, node)
47
+ defs = @term_def
48
+ @term_def = false
49
+ clause_parse(attrs.merge(type: "boilerplate"), xml, node)
50
+ @term_def = defs
51
+ end
52
+
53
+ # subclause contains subclauses
54
+ def term_def_subclause_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)
59
+ st = sectiontype(node, false)
60
+ return symbols_parse(attrs, xml, node) if @definitions
61
+
62
+ sub = node.find_by(context: :section) { |s| s.level == node.level + 1 }
63
+ sub.empty? || (return term_def_parse(attrs, xml, node, false))
64
+ st == "symbols and abbreviated terms" and
65
+ return symbols_parse(attrs, xml, node)
66
+ st == "terms and definitions" and return clause_parse(attrs, xml, node)
67
+ term_def_subclause_parse1(attrs, xml, node)
68
+ end
69
+
70
+ def term_def_subclause_parse1(attrs, xml, node)
71
+ xml.term **attr_code(attrs) do |xml_section|
72
+ term_designation(xml_section, node, "preferred", node.title)
73
+ xml_section << node.content
74
+ end
75
+ end
76
+
77
+ def term_def_parse(attrs, xml, node, _toplevel)
78
+ xml.terms **attr_code(attrs) do |section|
79
+ section.title { |t| t << node.title }
80
+ (s = node.attr("source")) && s.split(",").each do |s1|
81
+ section.termdocsource(nil, **attr_code(bibitemid: s1))
82
+ end
83
+ section << node.content
84
+ end
85
+ end
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
+
95
+ def term_source_attrs(_node, seen_xref)
96
+ { case: seen_xref.children[0]["case"],
97
+ droploc: seen_xref.children[0]["droploc"],
98
+ bibitemid: seen_xref.children[0]["target"],
99
+ format: seen_xref.children[0]["format"], type: "inline" }
100
+ end
101
+
102
+ def add_term_source(node, xml_t, seen_xref, match)
103
+ if seen_xref.children[0].name == "concept"
104
+ xml_t.origin { |o| o << seen_xref.children[0].to_xml }
105
+ else
106
+ attrs = term_source_attrs(node, seen_xref)
107
+ attrs.delete(:text)
108
+ xml_t.origin **attr_code(attrs) do |o|
109
+ o << seen_xref.children[0].children.to_xml
110
+ end
111
+ end
112
+ add_term_source_mod(xml_t, match)
113
+ end
114
+
115
+ def add_term_source_mod(xml_t, match)
116
+ match[:text] && xml_t.modification do |mod|
117
+ mod.p { |p| p << match[:text].sub(/^\s+/, "") }
118
+ end
119
+ end
120
+
121
+ TERM_REFERENCE_RE_STR = <<~REGEXP.freeze
122
+ ^(?<xref><(xref|concept)[^>]+>(.*?</(xref|concept)>)?)
123
+ (,\s(?<text>.*))?
124
+ $
125
+ REGEXP
126
+ TERM_REFERENCE_RE =
127
+ Regexp.new(TERM_REFERENCE_RE_STR.gsub(/\s/, "").gsub(/_/, "\\s"),
128
+ Regexp::IGNORECASE | Regexp::MULTILINE)
129
+
130
+ def extract_termsource_refs(text, node)
131
+ matched = TERM_REFERENCE_RE.match text
132
+ matched.nil? and @log.add("AsciiDoc Input", node,
133
+ "term reference not in expected format:"\
134
+ "#{text}")
135
+ matched
136
+ end
137
+
138
+ def termsource(node)
139
+ matched = extract_termsource_refs(node.content, node) || return
140
+ noko do |xml|
141
+ status = node.attr("status") ||
142
+ (matched[:text] ? "modified" : "identical")
143
+ attrs = { status: status, type: node.attr("type") || "authoritative" }
144
+ xml.termsource **attrs do |xml_t|
145
+ seen_xref = Nokogiri::XML.fragment(matched[:xref])
146
+ add_term_source(node, xml_t, seen_xref, matched)
147
+ end
148
+ end.join("\n")
149
+ end
150
+
151
+ def termdefinition(node)
152
+ noko do |xml|
153
+ xml.definition do |d|
154
+ d << node.content
155
+ end
156
+ end.join("\n")
157
+ end
158
+ end
159
+ end
160
+ end
@@ -0,0 +1,101 @@
1
+ require "date"
2
+ require "nokogiri"
3
+ require "htmlentities"
4
+ require "json"
5
+ require "pathname"
6
+ require "uuidtools"
7
+
8
+ module Metanorma
9
+ module Standoc
10
+ module Utils
11
+ def convert(node, transform = nil, opts = {})
12
+ transform ||= node.node_name
13
+ opts.empty? ? (send transform, node) : (send transform, node, opts)
14
+ end
15
+
16
+ def document_ns_attributes(_doc)
17
+ nil
18
+ end
19
+
20
+ NOKOHEAD = <<~HERE.freeze
21
+ <!DOCTYPE html SYSTEM
22
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
23
+ <html xmlns="http://www.w3.org/1999/xhtml">
24
+ <head> <title></title> <meta charset="UTF-8" /> </head>
25
+ <body> </body> </html>
26
+ HERE
27
+
28
+ # block for processing XML document fragments as XHTML,
29
+ # to allow for HTMLentities
30
+ # Unescape special chars used in Asciidoctor substitution processing
31
+ def noko(&block)
32
+ doc = ::Nokogiri::XML.parse(NOKOHEAD)
33
+ fragment = doc.fragment("")
34
+ ::Nokogiri::XML::Builder.with fragment, &block
35
+ fragment.to_xml(encoding: "US-ASCII", indent: 0).lines.map do |l|
36
+ l.gsub(/>\n$/, ">").gsub(/\s*\n$/m, " ").gsub("&#150;", "\u0096")
37
+ .gsub("&#151;", "\u0097").gsub("&#x96;", "\u0096")
38
+ .gsub("&#x97;", "\u0097")
39
+ end
40
+ end
41
+
42
+ def attr_code(attributes)
43
+ attributes.compact.transform_values do |v|
44
+ v.is_a?(String) ? HTMLEntities.new.decode(v) : v
45
+ end
46
+ end
47
+
48
+ # if the contents of node are blocks, output them to out;
49
+ # else, wrap them in <p>
50
+ def wrap_in_para(node, out)
51
+ if node.blocks? then out << node.content
52
+ else
53
+ out.p { |p| p << node.content }
54
+ end
55
+ end
56
+
57
+ SUBCLAUSE_XPATH = "//clause[not(parent::sections)]"\
58
+ "[not(ancestor::boilerplate)]".freeze
59
+
60
+ def isodoc(lang, script, i18nyaml = nil)
61
+ conv = html_converter(EmptyAttr.new)
62
+ i18n = conv.i18n_init(lang, script, i18nyaml)
63
+ conv.metadata_init(lang, script, i18n)
64
+ conv
65
+ end
66
+
67
+ def dl_to_attrs(elem, dlist, name)
68
+ e = dlist.at("./dt[text()='#{name}']") or return
69
+ val = e.at("./following::dd/p") || e.at("./following::dd") or return
70
+ elem[name] = val.text
71
+ end
72
+
73
+ def dl_to_elems(ins, elem, dlist, name)
74
+ a = elem.at("./#{name}[last()]")
75
+ ins = a if a
76
+ dlist.xpath("./dt[text()='#{name}']").each do |e|
77
+ v = e.at("./following::dd")
78
+ e = v.elements and e.size == 1 && e.first.name == "p" and v = e.first
79
+ v.name = name
80
+ ins.next = v
81
+ ins = ins.next
82
+ end
83
+ ins
84
+ end
85
+
86
+ def term_expr(elem)
87
+ "<expression><name>#{elem}</name></expression>"
88
+ end
89
+
90
+ class EmptyAttr
91
+ def attr(_any_attribute)
92
+ nil
93
+ end
94
+
95
+ def attributes
96
+ {}
97
+ end
98
+ end
99
+ end
100
+ end
101
+ end
@@ -0,0 +1,158 @@
1
+ require "metanorma/standoc/utils"
2
+ require_relative "./validate_section"
3
+ require "nokogiri"
4
+ require "jing"
5
+ require "iev"
6
+
7
+ module Metanorma
8
+ module Standoc
9
+ module Validate
10
+ SOURCELOCALITY = "./origin//locality[@type = 'clause']/"\
11
+ "referenceFrom".freeze
12
+
13
+ def init_iev
14
+ return nil if @no_isobib
15
+ return @iev if @iev
16
+
17
+ @iev = Iev::Db.new(@iev_globalname, @iev_localname) unless @no_isobib
18
+ @iev
19
+ end
20
+
21
+ def iev_validate(xmldoc)
22
+ @iev = init_iev or return
23
+ xmldoc.xpath("//term").each do |t|
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)
28
+ end
29
+ end
30
+ end
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
+
43
+ def content_validate(doc)
44
+ @fatalerror = []
45
+ xref_validate(doc)
46
+ section_validate(doc)
47
+ norm_ref_validate(doc)
48
+ repeat_id_validate(doc.root)
49
+ iev_validate(doc.root)
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)
53
+ end
54
+
55
+ def norm_ref_validate(doc)
56
+ found = false
57
+ doc.xpath("//references[@normative = 'true']/bibitem").each do |b|
58
+ next unless docid = b.at("./docidentifier[@type = 'metanorma']")
59
+ next unless /^\[\d+\]$/.match?(docid.text)
60
+
61
+ @log.add("Bibliography", b,
62
+ "Numeric reference in normative references")
63
+ found = true
64
+ end
65
+ found and @fatalerror << "Numeric reference in normative references"
66
+ end
67
+
68
+ def concept_validate(doc, tag, refterm)
69
+ found = false
70
+ doc.xpath("//#{tag}/xref").each do |x|
71
+ next if doc.at("//term[@id = '#{x['target']}']")
72
+ next if doc.at("//definitions//dt[@id = '#{x['target']}']")
73
+
74
+ ref = x&.at("../#{refterm}")&.text
75
+ @log.add("Anchors", x,
76
+ "#{tag.capitalize} #{ref} is pointing to "\
77
+ "#{x['target']}, which is not a term or symbol")
78
+ found = true
79
+ end
80
+ found and
81
+ @fatalerror << "#{tag.capitalize} not cross-referencing term or symbol"
82
+ end
83
+
84
+ def repeat_id_validate1(ids, elem)
85
+ if ids[elem["id"]]
86
+ @log.add("Anchors", elem, "Anchor #{elem['id']} has already been "\
87
+ "used at line #{ids[elem['id']]}")
88
+ @fatalerror << "Multiple instances of same ID: #{elem['id']}"
89
+ else
90
+ ids[elem["id"]] = elem.line
91
+ end
92
+ ids
93
+ end
94
+
95
+ def repeat_id_validate(doc)
96
+ ids = {}
97
+ doc.xpath("//*[@id]").each do |x|
98
+ ids = repeat_id_validate1(ids, x)
99
+ end
100
+ end
101
+
102
+ def schema_validate(doc, schema)
103
+ Tempfile.open(["tmp", ".xml"], encoding: "UTF-8") do |f|
104
+ schema_validate1(f, doc, schema)
105
+ rescue Jing::Error => e
106
+ clean_abort("Jing failed with error: #{e}", doc.to_xml)
107
+ ensure
108
+ f.close!
109
+ end
110
+ end
111
+
112
+ def schema_validate1(file, doc, schema)
113
+ file.write(doc.to_xml)
114
+ file.close
115
+ errors = Jing.new(schema, encoding: "UTF-8").validate(file.path)
116
+ warn "Syntax Valid!" if errors.none?
117
+ errors.each do |e|
118
+ @log.add("Metanorma XML Syntax",
119
+ "XML Line #{'%06d' % e[:line]}:#{e[:column]}", e[:message])
120
+ end
121
+ end
122
+
123
+ # RelaxNG cannot cope well with wildcard attributes. So we strip
124
+ # any attributes from FormattedString instances (which can contain
125
+ # xs:any markup, and are signalled with @format) before validation.
126
+ def formattedstr_strip(doc)
127
+ doc.xpath("//*[@format] | //stem | //bibdata//description | "\
128
+ "//formattedref | //bibdata//note | //bibdata/abstract | "\
129
+ "//bibitem/abstract | //bibitem/note | //misc-container")
130
+ .each do |n|
131
+ n.elements.each do |e|
132
+ e.traverse do |e1|
133
+ e1.element? and e1.each { |k, _v| e1.delete(k) }
134
+ end
135
+ end
136
+ end
137
+ doc
138
+ end
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
+
151
+ def validate(doc)
152
+ content_validate(doc)
153
+ schema_validate(formattedstr_strip(doc.dup),
154
+ File.join(File.dirname(__FILE__), "isodoc.rng"))
155
+ end
156
+ end
157
+ end
158
+ end
@@ -0,0 +1,55 @@
1
+ require "nokogiri"
2
+
3
+ module Metanorma
4
+ module Standoc
5
+ module Validate
6
+ def section_validate(doc)
7
+ sourcecode_style(doc.root)
8
+ hanging_para_style(doc.root)
9
+ asset_style(doc.root)
10
+ end
11
+
12
+ def sourcecode_style(root)
13
+ root.xpath("//sourcecode").each do |x|
14
+ callouts = x.elements.select { |e| e.name == "callout" }
15
+ annotations = x.elements.select { |e| e.name == "annotation" }
16
+ if callouts.size != annotations.size
17
+ @log.add("AsciiDoc Input", x,
18
+ "mismatch of callouts and annotations")
19
+ end
20
+ end
21
+ end
22
+
23
+ def style_warning(node, msg, text = nil)
24
+ w = msg
25
+ w += ": #{text}" if text
26
+ @log.add("Metanorma XML Style Warning", node, w)
27
+ end
28
+
29
+ def asset_title_style(root)
30
+ root.xpath("//figure[image][not(name)]").each do |node|
31
+ style_warning(node, "Figure should have title", nil)
32
+ end
33
+ root.xpath("//table[not(name)]").each do |node|
34
+ style_warning(node, "Table should have title", nil)
35
+ end
36
+ end
37
+
38
+ def asset_style(root)
39
+ asset_title_style(root)
40
+ end
41
+
42
+ def hanging_para_style(root)
43
+ root.xpath("//clause | //annex | //foreword | //introduction | "\
44
+ "//acknowledgements").each do |c|
45
+ next unless c.at("./clause")
46
+ next if c.elements.reject do |n|
47
+ %w(clause title).include? n.name
48
+ end.empty?
49
+
50
+ style_warning(c, "Hanging paragraph in clause")
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
@@ -19,6 +19,6 @@ module Metanorma
19
19
  end
20
20
 
21
21
  module Standoc
22
- VERSION = "1.11.4".freeze
22
+ VERSION = "2.0.0".freeze
23
23
  end
24
24
  end
@@ -1,6 +1,6 @@
1
1
  require "asciidoctor" unless defined? Asciidoctor::Converter
2
2
  require_relative "isodoc/pdf_convert"
3
- require_relative "asciidoctor/standoc/converter"
3
+ require_relative "metanorma/standoc/converter"
4
4
  require_relative "metanorma/standoc/version"
5
5
  require "asciidoctor/extensions"
6
6
 
@@ -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.3.0"
31
- spec.add_dependency "isodoc", "~> 1.8.0"
31
+ spec.add_dependency "isodoc", "~> 2.0.0"
32
32
  spec.add_dependency "metanorma-plugin-datastruct"
33
33
  spec.add_dependency "metanorma-plugin-lutaml"
34
34
  spec.add_dependency "ruby-jing"
@@ -1,7 +1,7 @@
1
1
  require "spec_helper"
2
2
  require "fileutils"
3
3
 
4
- RSpec.describe Asciidoctor::Standoc do
4
+ RSpec.describe Metanorma::Standoc do
5
5
  it "has a version number" do
6
6
  expect(Metanorma::Standoc::VERSION).not_to be nil
7
7
  end
@@ -26,7 +26,7 @@ RSpec.describe Asciidoctor::Standoc do
26
26
  <stage>published</stage>
27
27
  </status>
28
28
  <copyright>
29
- <from>2021</from>
29
+ <from>#{Time.now.year}</from>
30
30
  </copyright>
31
31
  <ext>
32
32
  <doctype>article</doctype>
@@ -222,6 +222,9 @@ RSpec.describe Asciidoctor::Standoc do
222
222
  :isbn: ISBN-13
223
223
  :isbn10: ISBN-10
224
224
  :classification: a:b, c
225
+ :toclevels: 2
226
+ :doctoclevels: 3
227
+ :htmltoclevels: 4
225
228
  INPUT
226
229
  output = <<~OUTPUT
227
230
  <?xml version="1.0" encoding="UTF-8"?>
@@ -481,6 +484,20 @@ RSpec.describe Asciidoctor::Standoc do
481
484
  </ics>
482
485
  </ext>
483
486
  </bibdata>
487
+ <misc-container>
488
+ <presentation-metadata>
489
+ <name>TOC Heading Levels</name>
490
+ <value>2</value>
491
+ </presentation-metadata>
492
+ <presentation-metadata>
493
+ <name>TOC Heading Levels</name>
494
+ <value>2</value>
495
+ </presentation-metadata>
496
+ <presentation-metadata>
497
+ <name>TOC Heading Levels</name>
498
+ <value>2</value>
499
+ </presentation-metadata>
500
+ </misc-container>
484
501
  <sections/>
485
502
  </standard-document>
486
503
  OUTPUT
@@ -742,7 +759,7 @@ RSpec.describe Asciidoctor::Standoc do
742
759
  <stage>published</stage>
743
760
  </status>
744
761
  <copyright>
745
- <from>2021</from>
762
+ <from>#{Time.now.year}</from>
746
763
  </copyright>
747
764
  <ext>
748
765
  <doctype>article</doctype>
@@ -870,7 +887,7 @@ RSpec.describe Asciidoctor::Standoc do
870
887
  <stage>published</stage>
871
888
  </status>
872
889
  <copyright>
873
- <from>2021</from>
890
+ <from>#{Time.now.year}</from>
874
891
  </copyright>
875
892
  <relation type='isCitedIn'>
876
893
  <description>normatively cited in</description>
@@ -1000,21 +1017,21 @@ QU1FOiB0ZXN0Cgo=
1000
1017
 
1001
1018
  it "process mn2pdf attributes" do
1002
1019
  node = Nokogiri::XML("<fake/>").at("fake")
1003
- node[Asciidoctor::Standoc::Base::FONTS_MANIFEST] =
1020
+ node[Metanorma::Standoc::Base::FONTS_MANIFEST] =
1004
1021
  "passed/as/font/manifest/to/mn2pdf.jar"
1005
1022
 
1006
- options = Asciidoctor::Standoc::Converter
1023
+ options = Metanorma::Standoc::Converter
1007
1024
  .new(:standoc, header_footer: true)
1008
1025
  .doc_extract_attributes(node)
1009
1026
 
1010
1027
  expect(options.dig(:mn2pdf, :font_manifest))
1011
- .to eq(node[Asciidoctor::Standoc::Base::FONTS_MANIFEST])
1028
+ .to eq(node[Metanorma::Standoc::Base::FONTS_MANIFEST])
1012
1029
  end
1013
1030
 
1014
1031
  private
1015
1032
 
1016
1033
  def mock_org_abbrevs
1017
- allow_any_instance_of(::Asciidoctor::Standoc::Front)
1034
+ allow_any_instance_of(::Metanorma::Standoc::Front)
1018
1035
  .to receive(:org_abbrev).and_return(
1019
1036
  { "International Standards Organization" => "ISO",
1020
1037
  "International Electrotechnical Commission" => "IEC" },
@@ -1022,14 +1039,14 @@ QU1FOiB0ZXN0Cgo=
1022
1039
  end
1023
1040
 
1024
1041
  def mock_default_publisher
1025
- allow_any_instance_of(::Asciidoctor::Standoc::Front)
1042
+ allow_any_instance_of(::Metanorma::Standoc::Front)
1026
1043
  .to receive(:default_publisher).and_return(
1027
1044
  "International Standards Organization",
1028
1045
  )
1029
1046
  end
1030
1047
 
1031
1048
  def mock_relaton_relation_descriptions
1032
- allow_any_instance_of(::Asciidoctor::Standoc::Front)
1049
+ allow_any_instance_of(::Metanorma::Standoc::Front)
1033
1050
  .to receive(:relaton_relation_descriptions).and_return(
1034
1051
  "normatively-cited-in" => "isCitedIn",
1035
1052
  )
@@ -1,7 +1,7 @@
1
1
  require "spec_helper"
2
2
  require "fileutils"
3
3
 
4
- RSpec.describe Asciidoctor::Standoc do
4
+ RSpec.describe Metanorma::Standoc do
5
5
  it "processes a blank document" do
6
6
  input = <<~INPUT
7
7
  #{ASCIIDOC_BLANK_HDR}
@@ -1,7 +1,7 @@
1
1
  require "spec_helper"
2
2
  require "open3"
3
3
 
4
- RSpec.describe Asciidoctor::Standoc do
4
+ RSpec.describe Metanorma::Standoc do
5
5
  it "processes format-specific pass blocks" do
6
6
  input = <<~INPUT
7
7
  #{ASCIIDOC_BLANK_HDR}
@@ -1,7 +1,7 @@
1
1
  require "spec_helper"
2
2
  require "fileutils"
3
3
 
4
- RSpec.describe Asciidoctor::Standoc do
4
+ RSpec.describe Metanorma::Standoc do
5
5
  it "processes svgmap" do
6
6
  FileUtils.cp "spec/fixtures/action_schemaexpg1.svg",
7
7
  "action_schemaexpg1.svg"
@@ -2,7 +2,7 @@ require "spec_helper"
2
2
  require "relaton_iec"
3
3
  require "fileutils"
4
4
 
5
- RSpec.describe Asciidoctor::Standoc do
5
+ RSpec.describe Metanorma::Standoc do
6
6
  it "appends any initial user-supplied text to boilerplate in terms and definitions" do
7
7
  input = <<~INPUT
8
8
  #{ASCIIDOC_BLANK_HDR}