metanorma-iso 1.3.22 → 1.3.27

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 (69) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/macos.yml +8 -7
  3. data/.github/workflows/ubuntu.yml +8 -7
  4. data/.github/workflows/windows.yml +8 -8
  5. data/Gemfile +2 -0
  6. data/lib/asciidoctor/iso/base.rb +22 -0
  7. data/lib/asciidoctor/iso/biblio.rng +89 -32
  8. data/lib/asciidoctor/iso/cleanup.rb +20 -3
  9. data/lib/asciidoctor/iso/front.rb +16 -107
  10. data/lib/asciidoctor/iso/front_id.rb +196 -0
  11. data/lib/asciidoctor/iso/isodoc.rng +475 -2
  12. data/lib/asciidoctor/iso/isostandard-amd.rng +98 -0
  13. data/lib/asciidoctor/iso/isostandard.rng +12 -1
  14. data/lib/asciidoctor/iso/macros.rb +21 -0
  15. data/lib/asciidoctor/iso/reqt.rng +23 -0
  16. data/lib/asciidoctor/iso/section.rb +18 -32
  17. data/lib/asciidoctor/iso/term_lookup_cleanup.rb +87 -0
  18. data/lib/asciidoctor/iso/validate.rb +41 -25
  19. data/lib/asciidoctor/iso/validate_requirements.rb +1 -1
  20. data/lib/asciidoctor/iso/validate_section.rb +2 -2
  21. data/lib/asciidoctor/iso/validate_style.rb +6 -5
  22. data/lib/asciidoctor/iso/validate_title.rb +1 -1
  23. data/lib/isodoc/iso/base_convert.rb +77 -107
  24. data/lib/isodoc/iso/html/header.html +10 -6
  25. data/lib/isodoc/iso/html/html_iso_titlepage.html +27 -18
  26. data/lib/isodoc/iso/html/isodoc.scss +53 -28
  27. data/lib/isodoc/iso/html/scripts.html +23 -21
  28. data/lib/isodoc/iso/html/style-human.scss +23 -0
  29. data/lib/isodoc/iso/html/style-iso.scss +18 -0
  30. data/lib/isodoc/iso/html/word_iso_intro.html +4 -0
  31. data/lib/isodoc/iso/html/word_iso_titlepage.html +23 -2
  32. data/lib/isodoc/iso/html/wordstyle.scss +80 -39
  33. data/lib/isodoc/iso/html_convert.rb +7 -9
  34. data/lib/isodoc/iso/iso.amendment.xsl +4597 -0
  35. data/lib/isodoc/iso/iso.international-standard.xsl +4597 -0
  36. data/lib/isodoc/iso/metadata.rb +71 -23
  37. data/lib/isodoc/iso/pdf_convert.rb +39 -0
  38. data/lib/isodoc/iso/sections.rb +66 -0
  39. data/lib/isodoc/iso/sts_convert.rb +29 -0
  40. data/lib/isodoc/iso/xref.rb +105 -0
  41. data/lib/metanorma-iso.rb +2 -0
  42. data/lib/metanorma/iso/processor.rb +16 -1
  43. data/lib/metanorma/iso/version.rb +1 -1
  44. data/metanorma-iso.gemspec +4 -1
  45. data/spec/asciidoctor-iso/amd_spec.rb +726 -0
  46. data/spec/asciidoctor-iso/base_spec.rb +38 -21
  47. data/spec/asciidoctor-iso/blocks_spec.rb +6 -6
  48. data/spec/asciidoctor-iso/cleanup_spec.rb +195 -174
  49. data/spec/asciidoctor-iso/inline_spec.rb +2 -1
  50. data/spec/asciidoctor-iso/macros_spec.rb +289 -0
  51. data/spec/asciidoctor-iso/refs_spec.rb +8 -5
  52. data/spec/asciidoctor-iso/section_spec.rb +8 -8
  53. data/spec/assets/iso.xml +64 -1
  54. data/spec/isodoc/amd_spec.rb +652 -0
  55. data/spec/isodoc/blocks_spec.rb +112 -27
  56. data/spec/isodoc/i18n_spec.rb +12 -20
  57. data/spec/isodoc/inline_spec.rb +4 -4
  58. data/spec/isodoc/iso_spec.rb +1 -1
  59. data/spec/isodoc/metadata_spec.rb +92 -4
  60. data/spec/isodoc/postproc_spec.rb +21 -120
  61. data/spec/isodoc/ref_spec.rb +9 -9
  62. data/spec/isodoc/section_spec.rb +36 -13
  63. data/spec/isodoc/table_spec.rb +30 -30
  64. data/spec/isodoc/terms_spec.rb +6 -6
  65. data/spec/isodoc/xref_spec.rb +43 -37
  66. data/spec/metanorma/processor_spec.rb +2 -2
  67. data/spec/spec_helper.rb +11 -0
  68. metadata +58 -5
  69. data/asciidoctor-iso.gemspec.old +0 -50
@@ -0,0 +1,98 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <grammar ns="https://www.metanorma.org/ns/iso" xmlns="http://relaxng.org/ns/structure/1.0" datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes">
3
+ <!-- default namespace isostandard = "https://www.metanorma.com/ns/iso" -->
4
+ <include href="isostandard.rng">
5
+ <start>
6
+ <ref name="iso-standard"/>
7
+ </start>
8
+ <define name="sections">
9
+ <element name="sections">
10
+ <oneOrMore>
11
+ <ref name="clause"/>
12
+ </oneOrMore>
13
+ </element>
14
+ </define>
15
+ <define name="clause">
16
+ <element name="clause">
17
+ <optional>
18
+ <attribute name="type"/>
19
+ </optional>
20
+ <optional>
21
+ <attribute name="change">
22
+ <choice>
23
+ <value>add</value>
24
+ <value>delete</value>
25
+ <value>modify</value>
26
+ </choice>
27
+ </attribute>
28
+ </optional>
29
+ <optional>
30
+ <attribute name="locality"/>
31
+ </optional>
32
+ <ref name="Clause-Section"/>
33
+ </element>
34
+ </define>
35
+ <define name="iso-standard">
36
+ <element name="iso-standard">
37
+ <ref name="bibdata"/>
38
+ <optional>
39
+ <ref name="boilerplate"/>
40
+ </optional>
41
+ <ref name="preface"/>
42
+ <oneOrMore>
43
+ <ref name="sections"/>
44
+ </oneOrMore>
45
+ </element>
46
+ </define>
47
+ <define name="documentnumber">
48
+ <element name="project-number">
49
+ <optional>
50
+ <attribute name="part">
51
+ <data type="int"/>
52
+ </attribute>
53
+ </optional>
54
+ <optional>
55
+ <attribute name="subpart">
56
+ <data type="int"/>
57
+ </attribute>
58
+ </optional>
59
+ <optional>
60
+ <attribute name="amendment">
61
+ <data type="int"/>
62
+ </attribute>
63
+ </optional>
64
+ <optional>
65
+ <attribute name="corrigendum">
66
+ <data type="int"/>
67
+ </attribute>
68
+ </optional>
69
+ <optional>
70
+ <attribute name="origyr">
71
+ <data type="int"/>
72
+ </attribute>
73
+ </optional>
74
+ <text/>
75
+ </element>
76
+ </define>
77
+ <define name="BibDataExtensionType">
78
+ <ref name="doctype"/>
79
+ <ref name="editorialgroup"/>
80
+ <zeroOrMore>
81
+ <ref name="ics"/>
82
+ </zeroOrMore>
83
+ <ref name="structuredidentifier"/>
84
+ <optional>
85
+ <ref name="stagename"/>
86
+ </optional>
87
+ <optional>
88
+ <ref name="updates_document_type"/>
89
+ </optional>
90
+ </define>
91
+ </include>
92
+ <!-- end overrides -->
93
+ <define name="updates_document_type">
94
+ <element name="updates-document-type">
95
+ <ref name="DocumentType"/>
96
+ </element>
97
+ </define>
98
+ </grammar>
@@ -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>
@@ -263,6 +269,8 @@
263
269
  <value>publicly-available-specification</value>
264
270
  <value>international-workshop-agreement</value>
265
271
  <value>guide</value>
272
+ <value>amendment</value>
273
+ <value>technical-corrigendum</value>
266
274
  </choice>
267
275
  </define>
268
276
  <define name="structuredidentifier">
@@ -354,6 +362,9 @@
354
362
  <data type="boolean"/>
355
363
  </attribute>
356
364
  </optional>
365
+ <optional>
366
+ <attribute name="number"/>
367
+ </optional>
357
368
  <optional>
358
369
  <attribute name="subsequence"/>
359
370
  </optional>
@@ -510,7 +521,7 @@
510
521
  </attribute>
511
522
  </optional>
512
523
  <oneOrMore>
513
- <ref name="paragraph-with-footnote"/>
524
+ <ref name="BasicBlock"/>
514
525
  </oneOrMore>
515
526
  </element>
516
527
  </define>
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'asciidoctor/extensions'
4
+
5
+ module Asciidoctor
6
+ module Iso
7
+ # Macro to transform `term[X,Y]` into em, termxref xml
8
+ class TermRefInlineMacro < Asciidoctor::Extensions::InlineMacroProcessor
9
+ use_dsl
10
+
11
+ named :term
12
+ name_positional_attributes 'name', 'termxref'
13
+ using_format :short
14
+
15
+ def process(_parent, _target, attrs)
16
+ termref = attrs['termxref'] || attrs['name']
17
+ "<em>#{attrs['name']}</em> (<termxref>#{termref}</termxref>)"
18
+ end
19
+ end
20
+ end
21
+ end
@@ -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>
@@ -4,38 +4,12 @@ require "uri"
4
4
  module Asciidoctor
5
5
  module ISO
6
6
  class Converter < Standoc::Converter
7
- def section(node)
8
- a = section_attributes(node)
9
- noko do |xml|
10
- case sectiontype(node)
11
- when "foreword" then foreword_parse(a, xml, node)
12
- when "introduction" then introduction_parse(a, xml, node)
13
- when "patent notice" then patent_notice_parse(xml, node)
14
- when "scope" then scope_parse(a, xml, node)
15
- when "normative references" then norm_ref_parse(a, xml, node)
16
- when "terms and definitions"
17
- @term_def = true
18
- term_def_parse(a, xml, node, true)
19
- @term_def = false
20
- when "symbols and abbreviated terms"
21
- symbols_parse(a, xml, node)
22
- when "acknowledgements"
23
- acknowledgements_parse(a, xml, node)
24
- when "bibliography" then bibliography_parse(a, xml, node)
25
- else
26
- if @term_def then term_def_subclause_parse(a, xml, node)
27
- elsif @biblio then bibliography_parse(a, xml, node)
28
- elsif node.attr("style") == "bibliography"
29
- bibliography_parse(a, xml, node)
30
- elsif node.attr("style") == "appendix" && node.level == 1
31
- annex_parse(a, xml, node)
32
- elsif node.option? "appendix"
33
- appendix_parse(a, xml, node)
34
- else
35
- clause_parse(a, xml, node)
36
- end
37
- end
38
- end.join("\n")
7
+ def clause_parse(attrs, xml, node)
8
+ title = node&.attr("heading")&.downcase ||
9
+ node.title.gsub(/<[^>]+>/, "").downcase
10
+ title == "scope" and return scope_parse(attrs, xml, node)
11
+ node.option? "appendix" and return appendix_parse(attrs, xml, node)
12
+ super
39
13
  end
40
14
 
41
15
  def appendix_parse(attrs, xml, node)
@@ -61,6 +35,18 @@ module Asciidoctor
61
35
  xml_section << content
62
36
  end
63
37
  end
38
+
39
+ def section_attributes(node)
40
+ super.merge(
41
+ change: @amd ? node.attr("change") : nil,
42
+ locality: @amd ? node.attr("locality") : nil,
43
+ )
44
+ end
45
+
46
+ def sectiontype(node, level = true)
47
+ return nil if @amd
48
+ super
49
+ end
64
50
  end
65
51
  end
66
52
  end
@@ -0,0 +1,87 @@
1
+ # frozen_string_literal: true.
2
+
3
+ module Asciidoctor
4
+ module ISO
5
+ # Intelligent term lookup xml modifier
6
+ # Lookup all `term` and `calause` tags and replace `termxref` tags with
7
+ # `xref`:target tag
8
+ class TermLookupCleanup
9
+ AUTOMATIC_GENERATED_ID_REGEXP = /\A_/
10
+ EXISTING_TERM_REGEXP = /\Aterm-/
11
+
12
+ attr_reader :xmldoc, :termlookup, :log
13
+
14
+ def initialize(xmldoc, log)
15
+ @xmldoc = xmldoc
16
+ @log = log
17
+ @termlookup = {}
18
+ end
19
+
20
+ def call
21
+ @termlookup = replace_automatic_generated_ids_terms
22
+ set_termxref_tags_target
23
+ end
24
+
25
+ private
26
+
27
+ def set_termxref_tags_target
28
+ xmldoc.xpath('//termxref').each do |node|
29
+ target = normalize_ref_id(node.text)
30
+ if termlookup[target].nil?
31
+ remove_missing_ref(node, target)
32
+ next
33
+ end
34
+ modify_ref_node(node, target)
35
+ end
36
+ end
37
+
38
+ def remove_missing_ref(node, target)
39
+ log.add('AsciiDoc Input', node,
40
+ %(Error: Term reference in `term[#{target}]` missing: \
41
+ "#{target}" is not defined in document))
42
+ term_name_node = node.previous.previous
43
+ term_name_node.remove
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)
48
+ node.remove
49
+ end
50
+
51
+ def modify_ref_node(node, target)
52
+ node.name = 'xref'
53
+ node['target'] = termlookup[target]
54
+ node.children.remove
55
+ node.remove_attribute('defaultref')
56
+ end
57
+
58
+ def replace_automatic_generated_ids_terms
59
+ xmldoc.xpath('//term').each.with_object({}) do |term_node, res|
60
+ normalize_id_and_memorize(term_node, res, './preferred')
61
+ end
62
+ end
63
+
64
+ def normalize_id_and_memorize(term_node, res_table, text_selector)
65
+ term_text = normalize_ref_id(term_node.at(text_selector).text)
66
+ unless AUTOMATIC_GENERATED_ID_REGEXP.match(term_node['id']).nil?
67
+ term_node['id'] = unique_text_id(term_text)
68
+ end
69
+ res_table[term_text] = term_node['id']
70
+ end
71
+
72
+ def normalize_ref_id(text)
73
+ text.downcase.gsub(/[[:space:]]/, '-')
74
+ end
75
+
76
+ def unique_text_id(text)
77
+ return "term-#{text}" if xmldoc.at("//*[@id = 'term-#{text}']").nil?
78
+
79
+ (1..Float::INFINITY).lazy.each do |index|
80
+ if xmldoc.at("//*[@id = 'term-#{text}-#{index}']").nil?
81
+ break("term-#{text}-#{index}")
82
+ end
83
+ end
84
+ end
85
+ end
86
+ end
87
+ end
@@ -24,12 +24,14 @@ module Asciidoctor
24
24
  def isosubgroup_validate(root)
25
25
  root.xpath("//technical-committee/@type").each do |t|
26
26
  unless %w{TC PC JTC JPC}.include? t.text
27
- @log.add("Document Attributes", nil, "invalid technical committee type #{t}")
27
+ @log.add("Document Attributes", nil,
28
+ "invalid technical committee type #{t}")
28
29
  end
29
30
  end
30
31
  root.xpath("//subcommittee/@type").each do |t|
31
32
  unless %w{SC JSC}.include? t.text
32
- @log.add("Document Attributes", nil, "invalid subcommittee type #{t}")
33
+ @log.add("Document Attributes", nil,
34
+ "invalid subcommittee type #{t}")
33
35
  end
34
36
  end
35
37
  end
@@ -39,10 +41,12 @@ module Asciidoctor
39
41
  root.xpath("//xref").each do |t|
40
42
  # does not deal with preceding text marked up
41
43
  preceding = t.at("./preceding-sibling::text()[last()]")
42
- next unless !preceding.nil? && /\b(see| refer to)\s*$/mi.match(preceding)
44
+ next unless !preceding.nil? &&
45
+ /\b(see| refer to)\s*$/mi.match(preceding)
43
46
  (target = root.at("//*[@id = '#{t['target']}']")) || next
44
47
  if target&.at("./ancestor-or-self::*[@obligation = 'normative']")
45
- @log.add("Style", t, "'see #{t['target']}' is pointing to a normative section")
48
+ @log.add("Style", t,
49
+ "'see #{t['target']}' is pointing to a normative section")
46
50
  end
47
51
  end
48
52
  end
@@ -51,14 +55,16 @@ module Asciidoctor
51
55
  def see_erefs_validate(root)
52
56
  root.xpath("//eref").each do |t|
53
57
  preceding = t.at("./preceding-sibling::text()[last()]")
54
- next unless !preceding.nil? && /\b(see|refer to)\s*$/mi.match(preceding)
58
+ next unless !preceding.nil? &&
59
+ /\b(see|refer to)\s*$/mi.match(preceding)
55
60
  unless target = root.at("//*[@id = '#{t['bibitemid']}']")
56
- @log.add("Bibliography", t, "'#{t} is not pointing to a real reference")
61
+ @log.add("Bibliography", t,
62
+ "'#{t} is not pointing to a real reference")
57
63
  next
58
64
  end
59
- if target.at("./ancestor::references"\
60
- "[title = 'Normative References']")
61
- @log.add("Style", t, "'see #{t}' is pointing to a normative reference")
65
+ if target.at("./ancestor::references[@normative = 'true']")
66
+ @log.add("Style", t,
67
+ "'see #{t}' is pointing to a normative reference")
62
68
  end
63
69
  end
64
70
  end
@@ -68,8 +74,9 @@ module Asciidoctor
68
74
  root.xpath("//eref[descendant::locality]").each do |t|
69
75
  if /^(ISO|IEC)/.match t["citeas"]
70
76
  unless /:[ ]?(\d+{4}|–)$/.match t["citeas"]
71
- @log.add("Style", t, "undated reference #{t['citeas']} should not contain "\
72
- "specific elements")
77
+ @log.add("Style", t,
78
+ "undated reference #{t['citeas']} should not contain "\
79
+ "specific elements")
73
80
  end
74
81
  end
75
82
  end
@@ -106,32 +113,37 @@ module Asciidoctor
106
113
  doctype = xmldoc&.at("//bibdata/ext/doctype")&.text
107
114
  %w(international-standard technical-specification technical-report
108
115
  publicly-available-specification international-workshop-agreement
109
- guide).include? doctype or
110
- @log.add("Document Attributes", nil, "#{doctype} is not a recognised document type")
116
+ guide amendment technical-corrigendum).include? doctype or
117
+ @log.add("Document Attributes", nil,
118
+ "#{doctype} is not a recognised document type")
111
119
  end
112
120
 
113
121
  def script_validate(xmldoc)
114
122
  script = xmldoc&.at("//bibdata/script")&.text
115
123
  script == "Latn" or
116
- @log.add("Document Attributes", nil, "#{script} is not a recognised script")
124
+ @log.add("Document Attributes", nil,
125
+ "#{script} is not a recognised script")
117
126
  end
118
127
 
119
128
  def stage_validate(xmldoc)
120
129
  stage = xmldoc&.at("//bibdata/status/stage")&.text
121
130
  %w(00 10 20 30 40 50 60 90 95).include? stage or
122
- @log.add("Document Attributes", nil, "#{stage} is not a recognised stage")
131
+ @log.add("Document Attributes", nil,
132
+ "#{stage} is not a recognised stage")
123
133
  end
124
134
 
125
135
  def substage_validate(xmldoc)
126
136
  substage = xmldoc&.at("//bibdata/status/substage")&.text or return
127
137
  %w(00 20 60 90 92 93 98 99).include? substage or
128
- @log.add("Document Attributes", nil, "#{substage} is not a recognised substage")
138
+ @log.add("Document Attributes", nil,
139
+ "#{substage} is not a recognised substage")
129
140
  end
130
141
 
131
142
  def iteration_validate(xmldoc)
132
143
  iteration = xmldoc&.at("//bibdata/status/iteration")&.text or return
133
144
  /^\d+/.match(iteration) or
134
- @log.add("Document Attributes", nil, "#{iteration} is not a recognised iteration")
145
+ @log.add("Document Attributes", nil,
146
+ "#{iteration} is not a recognised iteration")
135
147
  end
136
148
 
137
149
  def bibdata_validate(doc)
@@ -158,20 +170,24 @@ module Asciidoctor
158
170
 
159
171
  def bibitem_validate(xmldoc)
160
172
  xmldoc.xpath("//bibitem[date/on = '–']").each do |b|
161
- found = false
162
- b.xpath("./note").each do |n|
163
- found = true if /^ISO DATE:/.match n.text
164
- end
165
- found or
166
- @log.add("Style", b, "Reference #{b&.at("./@id")&.text} does not have an "\
167
- "associated footnote indicating unpublished status")
173
+ b.at("./note[@type = 'ISO DATE']") or
174
+ @log.add("Style", b,
175
+ "Reference #{b&.at("./@id")&.text} does not have an "\
176
+ "associated footnote indicating unpublished status")
168
177
  end
169
178
  end
170
179
 
171
180
  def validate(doc)
172
181
  content_validate(doc)
182
+ doctype = doc&.at("//bibdata/ext/doctype")&.text
183
+ schema = case doctype
184
+ when "amendment", "technical-corrigendum" # @amd
185
+ "isostandard-amd.rng"
186
+ else
187
+ "isostandard.rng"
188
+ end
173
189
  schema_validate(formattedstr_strip(doc.dup),
174
- File.join(File.dirname(__FILE__), "isostandard.rng"))
190
+ File.join(File.dirname(__FILE__), schema))
175
191
  end
176
192
  end
177
193
  end