metanorma-iso 1.3.25 → 1.4.2

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 (59) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/macos.yml +0 -1
  3. data/.github/workflows/ubuntu.yml +6 -3
  4. data/.github/workflows/windows.yml +0 -1
  5. data/Gemfile +1 -0
  6. data/Rakefile +2 -0
  7. data/lib/asciidoctor/iso/base.rb +16 -13
  8. data/lib/asciidoctor/iso/biblio.rng +14 -4
  9. data/lib/asciidoctor/iso/cleanup.rb +1 -1
  10. data/lib/asciidoctor/iso/front.rb +3 -155
  11. data/lib/asciidoctor/iso/front_id.rb +196 -0
  12. data/lib/asciidoctor/iso/isodoc.rng +444 -1
  13. data/lib/asciidoctor/iso/isostandard.rng +10 -1
  14. data/lib/asciidoctor/iso/reqt.rng +23 -0
  15. data/lib/asciidoctor/iso/term_lookup_cleanup.rb +7 -10
  16. data/lib/asciidoctor/iso/validate.rb +1 -5
  17. data/lib/asciidoctor/iso/validate_requirements.rb +1 -1
  18. data/lib/asciidoctor/iso/validate_style.rb +6 -5
  19. data/lib/asciidoctor/iso/validate_title.rb +1 -1
  20. data/lib/isodoc/iso/base_convert.rb +67 -112
  21. data/lib/isodoc/iso/html/header.html +5 -1
  22. data/lib/isodoc/iso/html/html_iso_titlepage.html +9 -0
  23. data/lib/isodoc/iso/html/htmlstyle.scss +0 -1
  24. data/lib/isodoc/iso/html/isodoc.scss +25 -1
  25. data/lib/isodoc/iso/html/style-human.scss +8 -1
  26. data/lib/isodoc/iso/html/style-iso.scss +8 -1
  27. data/lib/isodoc/iso/html/word_iso_intro.html +4 -0
  28. data/lib/isodoc/iso/html/word_iso_titlepage.html +4 -4
  29. data/lib/isodoc/iso/html/wordstyle.scss +20 -7
  30. data/lib/isodoc/iso/iso.amendment.xsl +5114 -0
  31. data/lib/isodoc/iso/iso.international-standard.xsl +1258 -530
  32. data/lib/isodoc/iso/metadata.rb +31 -27
  33. data/lib/isodoc/iso/pdf_convert.rb +5 -11
  34. data/lib/isodoc/iso/presentation_xml_convert.rb +13 -0
  35. data/lib/isodoc/iso/sections.rb +66 -0
  36. data/lib/isodoc/iso/sts_convert.rb +31 -0
  37. data/lib/isodoc/iso/xref.rb +111 -0
  38. data/lib/metanorma-iso.rb +2 -0
  39. data/lib/metanorma/iso/processor.rb +14 -8
  40. data/lib/metanorma/iso/version.rb +1 -1
  41. data/metanorma-iso.gemspec +6 -2
  42. data/spec/asciidoctor-iso/amd_spec.rb +412 -4
  43. data/spec/asciidoctor-iso/base_spec.rb +18 -16
  44. data/spec/asciidoctor-iso/cleanup_spec.rb +2 -2
  45. data/spec/asciidoctor-iso/macros_spec.rb +33 -17
  46. data/spec/asciidoctor-iso/refs_spec.rb +1 -1
  47. data/spec/asciidoctor-iso/table_spec.rb +1 -1
  48. data/spec/isodoc/amd_spec.rb +652 -0
  49. data/spec/isodoc/blocks_spec.rb +112 -27
  50. data/spec/isodoc/inline_spec.rb +2 -2
  51. data/spec/isodoc/metadata_spec.rb +88 -4
  52. data/spec/isodoc/postproc_spec.rb +9 -9
  53. data/spec/isodoc/ref_spec.rb +6 -6
  54. data/spec/isodoc/section_spec.rb +28 -1
  55. data/spec/isodoc/table_spec.rb +8 -8
  56. data/spec/isodoc/terms_spec.rb +4 -4
  57. data/spec/isodoc/xref_spec.rb +24 -18
  58. data/spec/metanorma/processor_spec.rb +2 -2
  59. metadata +73 -11
@@ -91,6 +91,12 @@
91
91
  </define>
92
92
  <define name="sections">
93
93
  <element name="sections">
94
+ <zeroOrMore>
95
+ <choice>
96
+ <ref name="note"/>
97
+ <ref name="admonition"/>
98
+ </choice>
99
+ </zeroOrMore>
94
100
  <ref name="clause"/>
95
101
  <optional>
96
102
  <choice>
@@ -356,6 +362,9 @@
356
362
  <data type="boolean"/>
357
363
  </attribute>
358
364
  </optional>
365
+ <optional>
366
+ <attribute name="number"/>
367
+ </optional>
359
368
  <optional>
360
369
  <attribute name="subsequence"/>
361
370
  </optional>
@@ -512,7 +521,7 @@
512
521
  </attribute>
513
522
  </optional>
514
523
  <oneOrMore>
515
- <ref name="paragraph-with-footnote"/>
524
+ <ref name="BasicBlock"/>
516
525
  </oneOrMore>
517
526
  </element>
518
527
  </define>
@@ -30,9 +30,22 @@
30
30
  <data type="boolean"/>
31
31
  </attribute>
32
32
  </optional>
33
+ <optional>
34
+ <attribute name="number"/>
35
+ </optional>
33
36
  <optional>
34
37
  <attribute name="subsequence"/>
35
38
  </optional>
39
+ <optional>
40
+ <attribute name="keep-with-next">
41
+ <data type="boolean"/>
42
+ </attribute>
43
+ </optional>
44
+ <optional>
45
+ <attribute name="keep-lines-together">
46
+ <data type="boolean"/>
47
+ </attribute>
48
+ </optional>
36
49
  <attribute name="id">
37
50
  <data type="ID"/>
38
51
  </attribute>
@@ -141,6 +154,16 @@
141
154
  <data type="boolean"/>
142
155
  </attribute>
143
156
  </optional>
157
+ <optional>
158
+ <attribute name="keep-with-next">
159
+ <data type="boolean"/>
160
+ </attribute>
161
+ </optional>
162
+ <optional>
163
+ <attribute name="keep-lines-together">
164
+ <data type="boolean"/>
165
+ </attribute>
166
+ </optional>
144
167
  <oneOrMore>
145
168
  <ref name="BasicBlock"/>
146
169
  </oneOrMore>
@@ -31,23 +31,20 @@ module Asciidoctor
31
31
  remove_missing_ref(node, target)
32
32
  next
33
33
  end
34
-
35
34
  modify_ref_node(node, target)
36
35
  end
37
36
  end
38
37
 
39
38
  def remove_missing_ref(node, target)
40
- log.add('AsciiDoc Input',
41
- node,
39
+ log.add('AsciiDoc Input', node,
42
40
  %(Error: Term reference in `term[#{target}]` missing: \
43
41
  "#{target}" is not defined in document))
44
- # Term ref have parentess around it - (ref),
45
- # if no target remove parentes and render as text
46
- node.next.remove
47
42
  term_name_node = node.previous.previous
48
43
  term_name_node.remove
49
- node.previous.remove
50
- node.add_previous_sibling(term_name_node.text)
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)
51
48
  node.remove
52
49
  end
53
50
 
@@ -60,15 +57,15 @@ module Asciidoctor
60
57
 
61
58
  def replace_automatic_generated_ids_terms
62
59
  xmldoc.xpath('//term').each.with_object({}) do |term_node, res|
63
- next if AUTOMATIC_GENERATED_ID_REGEXP.match(term_node['id']).nil?
64
-
65
60
  normalize_id_and_memorize(term_node, res, './preferred')
66
61
  end
67
62
  end
68
63
 
69
64
  def normalize_id_and_memorize(term_node, res_table, text_selector)
70
65
  term_text = normalize_ref_id(term_node.at(text_selector).text)
66
+ unless AUTOMATIC_GENERATED_ID_REGEXP.match(term_node['id']).nil?
71
67
  term_node['id'] = unique_text_id(term_text)
68
+ end
72
69
  res_table[term_text] = term_node['id']
73
70
  end
74
71
 
@@ -170,11 +170,7 @@ module Asciidoctor
170
170
 
171
171
  def bibitem_validate(xmldoc)
172
172
  xmldoc.xpath("//bibitem[date/on = '–']").each do |b|
173
- found = false
174
- b.xpath("./note").each do |n|
175
- found = true if /^ISO DATE:/.match n.text
176
- end
177
- found or
173
+ b.at("./note[@type = 'ISO DATE']") or
178
174
  @log.add("Style", b,
179
175
  "Reference #{b&.at("./@id")&.text} does not have an "\
180
176
  "associated footnote indicating unpublished status")
@@ -16,7 +16,7 @@ module Asciidoctor
16
16
  (is|are)_not_(allowed | permitted |
17
17
  acceptable | permissible) |
18
18
  (is|are)_not_to_be |
19
- do_not )
19
+ [.,:;]_do_not )
20
20
  \\b
21
21
  REGEXP
22
22
  REQUIREMENT_RE =
@@ -1,6 +1,6 @@
1
1
  require "metanorma-standoc"
2
2
  require "nokogiri"
3
- require "pp"
3
+ require "tokenizer"
4
4
 
5
5
  module Asciidoctor
6
6
  module ISO
@@ -70,7 +70,7 @@ module Asciidoctor
70
70
  # and a negative match on its preceding token
71
71
  def style_two_regex_not_prev(n, text, re, re_prev, warning)
72
72
  return if text.nil?
73
- arr = text.split(/\W+/)
73
+ arr = Tokenizer::WhitespaceTokenizer.new.tokenize(text)
74
74
  arr.each_index do |i|
75
75
  m = re.match arr[i]
76
76
  m_prev = i.zero? ? nil : re_prev.match(arr[i - 1])
@@ -91,9 +91,10 @@ module Asciidoctor
91
91
  # ISO/IEC DIR 2, 9.1
92
92
  # ISO/IEC DIR 2, Table B.1
93
93
  def style_number(n, t)
94
- style_two_regex_not_prev(n, t, /^(?<num>-?[0-9]{4,}[,0-9]*)$/,
95
- %r{(\bISO|\bIEC|\bIEEE/)$},
96
- "number not broken up in threes")
94
+ style_two_regex_not_prev(
95
+ n, t, /^(?<num>-?[0-9]{4,}[,0-9]*)$/,
96
+ %r{\b(ISO|IEC|IEEE/|(in|January|February|March|April|May|June|August|September|October|November|December)\b)$},
97
+ "number not broken up in threes")
97
98
  style_regex(/\b(?<num>[0-9]+\.[0-9]+)/i,
98
99
  "possible decimal point", n, t)
99
100
  style_regex(/\b(?<num>billion[s]?)\b/i,
@@ -36,7 +36,7 @@ module Asciidoctor
36
36
 
37
37
  # ISO/IEC DIR 2, 11.4
38
38
  def title_subpart_validate(root)
39
- docid = root.at("//bibdata/docidentifier[@type = 'iso']")
39
+ docid = root.at("//bibdata/docidentifier[@type = 'ISO']")
40
40
  subpart = /-\d+-\d+/.match docid
41
41
  iec = root.at("//bibdata/contributor[role/@type = 'publisher']/"\
42
42
  "organization[abbreviation = 'IEC' or "\
@@ -1,5 +1,7 @@
1
1
  require "isodoc"
2
2
  require_relative "metadata"
3
+ require_relative "sections"
4
+ require_relative "xref"
3
5
  require "fileutils"
4
6
 
5
7
  module IsoDoc
@@ -9,73 +11,27 @@ module IsoDoc
9
11
  @meta = Metadata.new(lang, script, labels)
10
12
  end
11
13
 
12
- def convert1(docxml, filename, dir)
13
- doctype = docxml&.at(ns("//bibdata/ext/doctype"))&.text
14
- @amd = %w(amendment technical-corrigendum).include? doctype
15
- if @amd
16
- @oldsuppressheadingnumbers = @suppressheadingnumbers
17
- @suppressheadingnumbers = true
18
- end
19
- super
14
+ def xref_init(lang, script, klass, labels, options)
15
+ @xrefs = Xref.new(lang, script, klass, labels, options)
20
16
  end
21
17
 
22
- def annex(isoxml, out)
23
- @amd and @suppressheadingnumbers = @oldsuppressheadingnumbers
24
- super
25
- @amd and @suppressheadingnumbers = true
18
+ def amd(docxml)
19
+ doctype = docxml&.at(ns("//bibdata/ext/doctype"))&.text
20
+ %w(amendment technical-corrigendum).include? doctype
26
21
  end
27
22
 
28
- def anchor_names(docxml)
29
- if @amd
30
- back_anchor_names(docxml)
31
- note_anchor_names(docxml.xpath(ns("//annex//table | //annex//figure")))
32
- note_anchor_names(docxml.xpath(ns("//annex")))
33
- example_anchor_names(docxml.xpath(ns("//annex")))
34
- list_anchor_names(docxml.xpath(ns("//annex")))
35
- else
36
- super
23
+ def convert1(docxml, filename, dir)
24
+ if amd(docxml)
25
+ @oldsuppressheadingnumbers = @suppressheadingnumbers
26
+ @suppressheadingnumbers = true
37
27
  end
28
+ super
38
29
  end
39
30
 
40
31
  def implicit_reference(b)
41
32
  b&.at(ns("./docidentifier"))&.text == "IEV"
42
33
  end
43
34
 
44
- def introduction(isoxml, out)
45
- f = isoxml.at(ns("//introduction")) || return
46
- num = f.at(ns(".//clause")) ? "0" : nil
47
- title_attr = { class: "IntroTitle" }
48
- page_break(out)
49
- out.div **{ class: "Section3", id: f["id"] } do |div|
50
- clause_name(num, @introduction_lbl, div, title_attr)
51
- f.elements.each do |e|
52
- parse(e, div) unless e.name == "title"
53
- end
54
- end
55
- end
56
-
57
- def foreword(isoxml, out)
58
- f = isoxml.at(ns("//foreword")) || return
59
- page_break(out)
60
- out.div **attr_code(id: f["id"]) do |s|
61
- s.h1(**{ class: "ForewordTitle" }) { |h1| h1 << @foreword_lbl }
62
- f.elements.each { |e| parse(e, s) unless e.name == "title" }
63
- end
64
- end
65
-
66
- def initial_anchor_names(d)
67
- super
68
- introduction_names(d.at(ns("//introduction")))
69
- end
70
-
71
- # we can reference 0-number clauses in introduction
72
- def introduction_names(clause)
73
- return if clause.nil?
74
- clause.xpath(ns("./clause")).each_with_index do |c, i|
75
- section_names1(c, "0.#{i + 1}", 2)
76
- end
77
- end
78
-
79
35
  # terms not defined in standoc
80
36
  def error_parse(node, out)
81
37
  case node.name
@@ -85,36 +41,6 @@ module IsoDoc
85
41
  end
86
42
  end
87
43
 
88
- def annex_names(clause, num)
89
- appendix_names(clause, num)
90
- super
91
- end
92
-
93
- def appendix_names(clause, num)
94
- clause.xpath(ns("./appendix")).each_with_index do |c, i|
95
- @anchors[c["id"]] = anchor_struct(i + 1, nil, @appendix_lbl, "clause")
96
- @anchors[c["id"]][:level] = 2
97
- @anchors[c["id"]][:container] = clause["id"]
98
- end
99
- end
100
-
101
- def section_names1(clause, num, level)
102
- @anchors[clause["id"]] =
103
- { label: num, level: level, xref: num }
104
- # subclauses are not prefixed with "Clause"
105
- clause.xpath(ns("./clause | ./terms | ./term | ./definitions | ./references")).
106
- each_with_index do |c, i|
107
- section_names1(c, "#{num}.#{i + 1}", level + 1)
108
- end
109
- end
110
-
111
- def annex_names1(clause, num, level)
112
- @anchors[clause["id"]] = { label: num, xref: num, level: level }
113
- clause.xpath(ns("./clause | ./references")).each_with_index do |c, i|
114
- annex_names1(c, "#{num}.#{i + 1}", level + 1)
115
- end
116
- end
117
-
118
44
  def eref_localities1_zh(target, type, from, to, delim)
119
45
  subsection = from&.text&.match(/\./)
120
46
  ret = (delim == ";") ? ";" : (type == "list") ? "" : delim
@@ -128,6 +54,7 @@ module IsoDoc
128
54
  end
129
55
 
130
56
  def eref_localities1(target, type, from, to, delim, lang = "en")
57
+ return "" if type == "anchor"
131
58
  subsection = from&.text&.match(/\./)
132
59
  type = type.downcase
133
60
  return l10n(eref_localities1_zh(target, type, from, to, delim)) if lang == "zh"
@@ -142,12 +69,12 @@ module IsoDoc
142
69
  end
143
70
 
144
71
  def prefix_container(container, linkend, target)
145
- delim = anchor(target, :type) == "listitem" ? " " : ", "
146
- l10n(anchor(container, :xref) + delim + linkend)
72
+ delim = @xrefs.anchor(target, :type) == "listitem" ? " " : ", "
73
+ l10n(@xrefs.anchor(container, :xref) + delim + linkend)
147
74
  end
148
75
 
149
76
  def example_span_label(node, div, name)
150
- n = get_anchors[node["id"]]
77
+ n = @xrefs.get[node["id"]]
151
78
  div.span **{ class: "example_label" } do |p|
152
79
  lbl = (n.nil? || n[:label].nil? || n[:label].empty?) ? @example_lbl :
153
80
  l10n("#{@example_lbl} #{n[:label]}")
@@ -219,21 +146,6 @@ module IsoDoc
219
146
  ""
220
147
  end
221
148
 
222
- def reference_names(ref)
223
- super
224
- @anchors[ref["id"]] = { xref: @anchors[ref["id"]][:xref].
225
- sub(/ \(All Parts\)/i, "") }
226
- end
227
-
228
- def table_footnote_reference_format(a)
229
- a.content = a.content + ")"
230
- end
231
-
232
- def clause_parse_title(node, div, c1, out)
233
- return inline_header_title(out, node, c1) if c1.nil?
234
- super
235
- end
236
-
237
149
  def cleanup(docxml)
238
150
  super
239
151
  table_th_center(docxml)
@@ -247,14 +159,57 @@ module IsoDoc
247
159
  end
248
160
  end
249
161
 
250
- def hierarchical_formula_names(clause, num)
251
- c = IsoDoc::Function::XrefGen::Counter.new
252
- clause.xpath(ns(".//formula")).each do |t|
253
- next if t["id"].nil? || t["id"].empty?
254
- @anchors[t["id"]] =
255
- anchor_struct("#{num}#{hiersep}#{c.increment(t).print}", t,
256
- t["inequality"] ? @inequality_lbl : @formula_lbl,
257
- "formula", t["unnumbered"])
162
+ def formula_where(dl, out)
163
+ return if dl.nil?
164
+ return super unless (dl&.xpath(ns("./dt"))&.size == 1 &&
165
+ dl&.at(ns("./dd"))&.elements&.size == 1 &&
166
+ dl&.at(ns("./dd/p")))
167
+ out.span **{ class: "zzMoveToFollowing" } do |s|
168
+ s << "#{@where_lbl} "
169
+ dl.at(ns("./dt")).children.each { |n| parse(n, s) }
170
+ s << " "
171
+ end
172
+ parse(dl.at(ns("./dd/p")), out)
173
+ end
174
+
175
+ def admonition_parse(node, out)
176
+ type = node["type"]
177
+ name = admonition_name(node, type)
178
+ out.div **{ id: node["id"], class: admonition_class(node) } do |div|
179
+ node.first_element_child.name == "p" ?
180
+ admonition_p_parse(node, div, name) : admonition_parse1(node, div, name)
181
+ end
182
+ end
183
+
184
+ def admonition_parse1(node, div, name)
185
+ div.p do |p|
186
+ admonition_name_parse(node, p, name) if name
187
+ end
188
+ node.children.each { |n| parse(n, div) unless n.name == "name" }
189
+ end
190
+
191
+ def admonition_p_parse(node, div, name)
192
+ div.p do |p|
193
+ admonition_name_parse(node, p, name) if name
194
+ node.first_element_child.children.each { |n| parse(n, p) }
195
+ end
196
+ node.element_children[1..-1].each { |n| parse(n, div) }
197
+ end
198
+
199
+ def admonition_name_parse(_node, div, name)
200
+ name.children.each { |n| parse(n, div) }
201
+ div << " &mdash; "
202
+ end
203
+
204
+ def figure_name_parse(node, div, name)
205
+ lbl = @xrefs.anchor(node['id'], :label, false)
206
+ lbl = nil if labelled_ancestor(node) && node.ancestors("figure").empty?
207
+ return if lbl.nil? && name.nil?
208
+ div.p **{ class: "FigureTitle", style: "text-align:center;" } do |p|
209
+ figname = node.parent.name == "figure" ? "" : "#{@figure_lbl} "
210
+ lbl.nil? or p << l10n("#{figname}#{lbl}")
211
+ name and !lbl.nil? and p << "&nbsp;&mdash; "
212
+ name and name.children.each { |n| parse(n, div) }
258
213
  end
259
214
  end
260
215
  end
@@ -238,8 +238,12 @@ lang=EN-GB style='font-size:10.0pt;mso-bidi-font-size:11.0pt'>
238
238
  </div>
239
239
 
240
240
  <div style='mso-element:footer' id=f4>
241
-
241
+ {% if ics %}
242
242
  <p class=MsoFooter><b style='mso-bidi-font-weight:normal'><span>ICS {{ ics }}<o:p></o:p></span></b></p>
243
+ {% endif %}
244
+ {% if keywords.size > 0 %}
245
+ <p class=MsoFooter><b>Descriptors:</b> {{ keywords | join: ", " }}</p>
246
+ {% endif %}
243
247
 
244
248
  <p class=MsoFooter style='margin-top:0cm'><span lang=EN-AU style='font-size:
245
249
  10.0pt;mso-ansi-language:EN-AU'>Price based on </span><!--[if supportFields]><span
@@ -61,3 +61,12 @@ name="CVP_Secretariat_Loca">Secretariat: {{ secretariat }}

61
61
  <div id="boilerplate-license-destination"/>
62
62
  </div>
63
63
  {% endif %}
64
+
65
+ {% if ics %}
66
+ <p><b>ICS:</b> {{ ics }}</p>
67
+ {% endif %}
68
+
69
+ {% if keywords.size > 0 %}
70
+ <p><b>Descriptors:</b> {{ keywords | join: ", " }}
71
+ {% endif %}
72
+
@@ -43,4 +43,3 @@ p.MsoCommentSubject, li.MsoCommentSubject, div.MsoCommentSubject
43
43
  mso-ansi-language:EN-GB;
44
44
  mso-fareast-language:EN-US;
45
45
  font-weight:bold;}
46
-