metanorma-iec 1.0.3 → 1.0.8

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 (50) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/macos.yml +8 -7
  3. data/.github/workflows/ubuntu.yml +12 -9
  4. data/.github/workflows/windows.yml +8 -8
  5. data/lib/asciidoctor/iec/biblio.rng +142 -37
  6. data/lib/asciidoctor/iec/converter.rb +22 -130
  7. data/lib/asciidoctor/iec/front.rb +220 -0
  8. data/lib/asciidoctor/iec/isodoc.rng +48 -2
  9. data/lib/asciidoctor/iec/isostandard.rng +17 -1
  10. data/lib/isodoc/iec/base_convert.rb +157 -0
  11. data/lib/isodoc/iec/html/htmlstyle.scss +11 -8
  12. data/lib/isodoc/iec/html/isodoc.scss +15 -9
  13. data/lib/isodoc/iec/html/scripts.html +23 -21
  14. data/lib/isodoc/iec/html/wordstyle.scss +0 -3
  15. data/lib/isodoc/iec/html_convert.rb +8 -0
  16. data/lib/isodoc/iec/i18n-en.yaml +2 -0
  17. data/lib/isodoc/iec/i18n-fr.yaml +2 -0
  18. data/lib/isodoc/iec/iec.international-standard.xsl +4133 -0
  19. data/lib/isodoc/iec/metadata.rb +3 -52
  20. data/lib/isodoc/iec/pdf_convert.rb +31 -0
  21. data/lib/isodoc/iec/word_convert.rb +17 -6
  22. data/lib/metanorma-iec.rb +1 -0
  23. data/lib/metanorma/iec/processor.rb +12 -1
  24. data/lib/metanorma/iec/version.rb +1 -1
  25. data/spec/asciidoctor-iec/base_spec.rb +20 -29
  26. data/spec/asciidoctor-iec/blocks_spec.rb +15 -7
  27. data/spec/asciidoctor-iec/cleanup_spec.rb +13 -7
  28. data/spec/asciidoctor-iec/iev_spec.rb +161 -0
  29. data/spec/asciidoctor-iec/inline_spec.rb +2 -1
  30. data/spec/asciidoctor-iec/section_spec.rb +8 -8
  31. data/spec/assets/iso.xml +65 -2
  32. data/spec/examples/rice.html +5 -5
  33. data/spec/examples/rice_img/rice_image1.png +0 -0
  34. data/spec/examples/rice_img/rice_image2.png +0 -0
  35. data/spec/examples/rice_img/rice_image3_1.png +0 -0
  36. data/spec/examples/rice_img/rice_image3_2.png +0 -0
  37. data/spec/examples/rice_img/rice_image3_3.png +0 -0
  38. data/spec/isodoc/blocks_spec.rb +160 -0
  39. data/spec/isodoc/i18n_spec.rb +15 -22
  40. data/spec/isodoc/iev_spec.rb +360 -0
  41. data/spec/isodoc/inline_spec.rb +2 -2
  42. data/spec/isodoc/iso_spec.rb +2 -19
  43. data/spec/isodoc/metadata_spec.rb +92 -9
  44. data/spec/isodoc/postproc_spec.rb +8 -2
  45. data/spec/isodoc/ref_spec.rb +249 -0
  46. data/spec/isodoc/section_spec.rb +49 -14
  47. data/spec/isodoc/terms_spec.rb +2 -2
  48. data/spec/metanorma/processor_spec.rb +3 -3
  49. data/spec/spec_helper.rb +3 -2
  50. metadata +14 -2
@@ -0,0 +1,220 @@
1
+ module Asciidoctor
2
+ module Iec
3
+ class Converter < ISO::Converter
4
+ def metadata_author(node, xml)
5
+ publishers = node.attr("publisher") || "IEC"
6
+ publishers.split(/,[ ]?/).each do |p|
7
+ xml.contributor do |c|
8
+ c.role **{ type: "author" }
9
+ c.organization { |a| organization(a, p) }
10
+ end
11
+ end
12
+ end
13
+
14
+ def metadata_publisher(node, xml)
15
+ publishers = node.attr("publisher") || "IEC"
16
+ publishers.split(/,[ ]?/).each do |p|
17
+ xml.contributor do |c|
18
+ c.role **{ type: "publisher" }
19
+ c.organization { |a| organization(a, p) }
20
+ end
21
+ end
22
+ end
23
+
24
+ def metadata_copyright(node, xml)
25
+ publishers = node.attr("publisher") || "IEC"
26
+ publishers.split(/,[ ]?/).each do |p|
27
+ xml.copyright do |c|
28
+ c.from (node.attr("copyright-year") || Date.today.year)
29
+ c.owner do |owner|
30
+ owner.organization { |o| organization(o, p) }
31
+ end
32
+ end
33
+ end
34
+ end
35
+
36
+ def iso_id(node, xml)
37
+ return unless node.attr("docnumber")
38
+ part, subpart = node&.attr("partnumber")&.split(/-/)
39
+ dn = add_id_parts(node.attr("docnumber"), part, subpart)
40
+ dn = id_stage_prefix(dn, node, false)
41
+ dn = id_edition_suffix(dn, node)
42
+ xml.docidentifier dn, **attr_code(type: "iso")
43
+ end
44
+
45
+ def id_edition_suffix(dn, node)
46
+ ed = node.attr("edition") || 1
47
+ dn += " ED #{ed}"
48
+ dn
49
+ end
50
+
51
+ STAGE_CODES = {
52
+ "PNW" => "1000",
53
+ "ANW" => "2000",
54
+ "CAN" => "2098",
55
+ "ACD" => "2099",
56
+ "CD" => "3020",
57
+ "BWG" => "3092",
58
+ "A2CD" => "3099",
59
+ "2CD" => "3520",
60
+ "3CD" => "3520",
61
+ "4CD" => "3520",
62
+ "5CD" => "3520",
63
+ "6CD" => "3520",
64
+ "7CD" => "3520",
65
+ "8CD" => "3520",
66
+ "9CD" => "3520",
67
+ "CDM" => "3591",
68
+ "A3CD" => "3592",
69
+ "A4CD" => "3592",
70
+ "A5CD" => "3592",
71
+ "A6CD" => "3592",
72
+ "A7CD" => "3592",
73
+ "A8CD" => "3592",
74
+ "A9CD" => "3592",
75
+ "ACDV" => "3599",
76
+ "CCDV" => "4020",
77
+ "CDVM" => "4091",
78
+ "NCDV" => "4092",
79
+ "NADIS" => "4093",
80
+ "ADIS" => "4099",
81
+ "ADTR" => "4099",
82
+ "ADTS" => "4099",
83
+ "RDISH" => "5000",
84
+ "RFDIS" => "5000",
85
+ "CDISH" => "5020",
86
+ "CDPAS" => "5020",
87
+ "CDTR" => "5020",
88
+ "CDTS" => "5020",
89
+ "CFDIS" => "5020",
90
+ "DTRM" => "5092",
91
+ "DTSM" => "5092",
92
+ "NDTR" => "5092",
93
+ "NDTS" => "5092",
94
+ "NFDIS" => "5092",
95
+ "APUB" => "5099",
96
+ "BPUB" => "6000",
97
+ "PPUB" => "6060",
98
+ "RR" => "9092",
99
+ "AMW" => "9220",
100
+ "WPUB" => "9599",
101
+ "DELPUB" => "9960",
102
+ }.freeze
103
+
104
+ DOC_STAGE = {
105
+ "00": "PWI",
106
+ "10": "NWIP",
107
+ "20": "WD",
108
+ "30": "CD",
109
+ "40": "CDV",
110
+ "50": "FDIS",
111
+ "60": "PPUB",
112
+ "90": "RR",
113
+ "92": "AMW",
114
+ "95": "WPUB",
115
+ "99": "DELPUB",
116
+ }.freeze
117
+
118
+ STAGE_ABBRS = {
119
+ "00" => {"00" => "PWI"},
120
+ "10" => {"00" => "PNW"},
121
+ "20" => {"00" => "ANW", "98" => "CAN", "99" => "ACD"},
122
+ "30" => {"00" => "CD", "20" => "CD", "92" => "BWG", "97" => "MERGED", "98" => "DREJ", "99" => "A2CD"},
123
+ "35" => {"00" => "CD", "20" => "CD", "91" => "CDM", "92" => "ACD", "99" => "ACDV"},
124
+ "40" => {"00" => "CCDV", "20" => "CCDV", "91" => "CDVM", "92" => "NCDV", "93" => "NADIS", "95" => "ADISSB", "99" => "ADIS"},
125
+ "50" => {"00" => "RFDIS", "20" => "CFDIS", "92" => "NFDIS", "95" => "APUBSB", "99" => "APUB"},
126
+ "60" => {"00" => "BPUB", "60" => "PPUB"},
127
+ "90" => {"00" => "RR", "92" => "RR"},
128
+ "92" => {"00" => "AMW", "20" => "AMW"},
129
+ "95" => {"00" => "WPUB", "99" => "WPUB"},
130
+ "99" => {"00" => "DELPUB", "60" => "DELPUB"},
131
+ }.freeze
132
+
133
+ STAGE_NAMES = {
134
+ "00": "Preliminary work item",
135
+ "10": "New work item proposal",
136
+ "20": "Working draft",
137
+ "30": "Committee draft",
138
+ "35": "Committee draft",
139
+ "40": "Committed draft for vote",
140
+ "50": "Final draft international standard",
141
+ "60": "International standard",
142
+ "90": "Review",
143
+ "92": "Review",
144
+ "95": "Withdrawal",
145
+ "99": "Deleted",
146
+ }.freeze
147
+
148
+ def status_abbrev1(stage, substage, iter, doctype, draft)
149
+ return "" unless stage
150
+ abbr = STAGE_ABBRS.dig(stage, substage) || "??"
151
+ if stage == "35" && substage == "92"
152
+ iter = (iter.to_i + 1) % "02"
153
+ end
154
+ case doctype
155
+ when "technical-report"
156
+ stage = "ADTR" if stage == "40" && substage == "99"
157
+ stage = "CDTR" if stage == "50" && substage == "20"
158
+ stage = "DTRM" if stage == "50" && substage == "92"
159
+ when "technical-specification"
160
+ stage = "ADTS" if stage == "40" && substage == "99"
161
+ stage = "CDTS" if stage == "50" && substage == "20"
162
+ stage = "DTSM" if stage == "50" && substage == "92"
163
+ when "interpretation-sheet"
164
+ stage = "RDISH" if stage == "50" && substage == "00"
165
+ stage = "CDISH" if stage == "50" && substage == "20"
166
+ when "publicly-available-specification"
167
+ stage = "CDPAS" if stage == "50" && substage == "20"
168
+ end
169
+ abbr = abbr.sub(/CD$/, "#{iter}CD") if iter
170
+ abbr
171
+ end
172
+
173
+ def stage_abbr(stage, substage)
174
+ return "PPUB" if stage == "60"
175
+ DOC_STAGE[stage.to_sym] || "??"
176
+ end
177
+
178
+ def stage_name(stage, substage, _doctype, _iteration)
179
+ STAGE_NAMES[stage.to_sym]
180
+ end
181
+
182
+ def get_stage(node)
183
+ stage = node.attr("status") || node.attr("docstage") || "60"
184
+ m = /([0-9])CD$/.match(stage) and
185
+ node.set_attr("iteration", m[1])
186
+ STAGE_CODES[stage] and stage = STAGE_CODES[stage][0..1]
187
+ stage
188
+ end
189
+
190
+ def get_substage(node)
191
+ st = node.attr("status") || node.attr("docstage")
192
+ stage = get_stage(node)
193
+ node.attr("docsubstage") ||
194
+ ( stage == "60" ? "60" :
195
+ STAGE_CODES[st] ? STAGE_CODES[st][2..3] :
196
+ "00" )
197
+ end
198
+
199
+ def id_stage_abbr(stage, substage, node)
200
+ return "" if stage == "60"
201
+ abbr = DOC_STAGE[stage.to_sym] || ""
202
+ abbr = node.attr("iteration") + abbr if node.attr("iteration")
203
+ abbr
204
+ end
205
+
206
+ def metadata_status(node, xml)
207
+ stage = get_stage(node)
208
+ substage = get_substage(node)
209
+ xml.status do |s|
210
+ s.stage stage, **attr_code(abbreviation: stage_abbr(stage, substage))
211
+ s.substage substage,
212
+ **attr_code(abbreviation: status_abbrev1(stage, substage,
213
+ node.attr("iteration"),
214
+ doctype(node),node.attr("draft")))
215
+ node.attr("iteration") && (s.iteration node.attr("iteration"))
216
+ end
217
+ end
218
+ end
219
+ end
220
+ end
@@ -53,6 +53,14 @@
53
53
  <optional>
54
54
  <attribute name="alt"/>
55
55
  </optional>
56
+ <optional>
57
+ <attribute name="case">
58
+ <choice>
59
+ <value>capital</value>
60
+ <value>lowercase</value>
61
+ </choice>
62
+ </attribute>
63
+ </optional>
56
64
  <text/>
57
65
  </element>
58
66
  </define>
@@ -129,6 +137,9 @@
129
137
  </choice>
130
138
  </attribute>
131
139
  </optional>
140
+ <attribute name="normative">
141
+ <data type="boolean"/>
142
+ </attribute>
132
143
  <optional>
133
144
  <ref name="section-title"/>
134
145
  </optional>
@@ -305,6 +316,21 @@
305
316
  </define>
306
317
  </include>
307
318
  <!-- end overrides -->
319
+ <define name="TextElement" combine="choice">
320
+ <ref name="concept"/>
321
+ </define>
322
+ <define name="concept">
323
+ <element name="concept">
324
+ <optional>
325
+ <attribute name="term"/>
326
+ </optional>
327
+ <choice>
328
+ <ref name="eref"/>
329
+ <ref name="xref"/>
330
+ <ref name="termref"/>
331
+ </choice>
332
+ </element>
333
+ </define>
308
334
  <define name="BasicBlock" combine="choice">
309
335
  <choice>
310
336
  <ref name="requirement"/>
@@ -884,7 +910,15 @@
884
910
  <attribute name="id">
885
911
  <data type="ID"/>
886
912
  </attribute>
887
- <ref name="paragraph"/>
913
+ <oneOrMore>
914
+ <choice>
915
+ <ref name="paragraph"/>
916
+ <ref name="ul"/>
917
+ <ref name="ol"/>
918
+ <ref name="dl"/>
919
+ <ref name="formula"/>
920
+ </choice>
921
+ </oneOrMore>
888
922
  </element>
889
923
  </define>
890
924
  <define name="termexample">
@@ -911,7 +945,10 @@
911
945
  </define>
912
946
  <define name="origin">
913
947
  <element name="origin">
914
- <ref name="erefType"/>
948
+ <choice>
949
+ <ref name="erefType"/>
950
+ <ref name="termref"/>
951
+ </choice>
915
952
  </element>
916
953
  </define>
917
954
  <define name="modification">
@@ -919,6 +956,15 @@
919
956
  <ref name="paragraph"/>
920
957
  </element>
921
958
  </define>
959
+ <define name="termref">
960
+ <element name="termref">
961
+ <attribute name="base"/>
962
+ <attribute name="target"/>
963
+ <optional>
964
+ <text/>
965
+ </optional>
966
+ </element>
967
+ </define>
922
968
  <define name="structuredidentifier">
923
969
  <element name="structuredidentifier">
924
970
  <optional>
@@ -43,6 +43,9 @@
43
43
  <ref name="ics"/>
44
44
  </zeroOrMore>
45
45
  <ref name="structuredidentifier"/>
46
+ <optional>
47
+ <ref name="stagename"/>
48
+ </optional>
46
49
  </define>
47
50
  <define name="bdate">
48
51
  <element name="date">
@@ -88,6 +91,12 @@
88
91
  </define>
89
92
  <define name="sections">
90
93
  <element name="sections">
94
+ <zeroOrMore>
95
+ <choice>
96
+ <ref name="note"/>
97
+ <ref name="admonition"/>
98
+ </choice>
99
+ </zeroOrMore>
91
100
  <ref name="clause"/>
92
101
  <optional>
93
102
  <choice>
@@ -260,6 +269,8 @@
260
269
  <value>publicly-available-specification</value>
261
270
  <value>international-workshop-agreement</value>
262
271
  <value>guide</value>
272
+ <value>amendment</value>
273
+ <value>technical-corrigendum</value>
263
274
  </choice>
264
275
  </define>
265
276
  <define name="structuredidentifier">
@@ -507,8 +518,13 @@
507
518
  </attribute>
508
519
  </optional>
509
520
  <oneOrMore>
510
- <ref name="paragraph-with-footnote"/>
521
+ <ref name="BasicBlock"/>
511
522
  </oneOrMore>
512
523
  </element>
513
524
  </define>
525
+ <define name="stagename">
526
+ <element name="stagename">
527
+ <text/>
528
+ </element>
529
+ </define>
514
530
  </grammar>
@@ -72,6 +72,163 @@ module IsoDoc
72
72
  obl = l10n("(#{@norm_annex_lbl})") if clause["obligation"] == "normative"
73
73
  l10n("<b>#{@annex_lbl} #{num}</b><br/><br/>#{obl}")
74
74
  end
75
+
76
+ def convert1(docxml, filename, dir)
77
+ id = docxml&.at(ns("//bibdata/docnumber"))&.text
78
+ @is_iev = id == "60050"
79
+ id = docxml&.at(ns("//bibdata/docidentifier[@type = 'iso']"))&.text
80
+ m = /60050-(\d+)/.match(id) and @iev_part = m[1]
81
+ super
82
+ end
83
+
84
+ def introduction(isoxml, out)
85
+ return super unless @is_iev
86
+ f = isoxml.at(ns("//introduction")) || return
87
+ title_attr = { class: "IntroTitle" }
88
+ page_break(out)
89
+ out.div **{ class: "Section3", id: f["id"] } do |div|
90
+ clause_name(nil, @labels["introduction_iev"], div, title_attr)
91
+ f.elements.each do |e|
92
+ parse(e, div) unless e.name == "title"
93
+ end
94
+ end
95
+ end
96
+
97
+ def introduction_names(clause)
98
+ return super unless @is_iev
99
+ end
100
+
101
+ def bibliography(isoxml, out)
102
+ return super unless @is_iev
103
+ end
104
+
105
+ def biblio_list(f, div, biblio)
106
+ return super unless @is_iev
107
+ i = 0
108
+ f.children.each do |b|
109
+ parse(b, div) unless %w(title bibitem).include? b.name
110
+ end
111
+ end
112
+
113
+ def terms_parse(node, out)
114
+ return super unless @is_iev
115
+ page_break(out)
116
+ out.div **attr_code(id: node["id"]) do |div|
117
+ out.p(**{ class: "zzSTDTitle2" }) do |p|
118
+ p.b do |b|
119
+ b << "#{anchor(node['id'], :label)} "
120
+ node&.at(ns("./title"))&.children&.each { |c2| parse(c2, b) }
121
+ end
122
+ end
123
+ node.children.reject { |c1| c1.name == "title" }.each do |c1|
124
+ parse(c1, div)
125
+ end
126
+ end
127
+ end
128
+
129
+ def initial_anchor_names(d)
130
+ super
131
+ return unless @is_iev
132
+ terms_iev_names(d)
133
+ middle_section_asset_names(d)
134
+ termnote_anchor_names(d)
135
+ termexample_anchor_names(d)
136
+ end
137
+
138
+ def terms_iev_names(d)
139
+ d.xpath(ns("//sections/clause/terms")).each_with_index do |t, i|
140
+ num = "#{@iev_part}-%02d" % [i+1]
141
+ @anchors[t["id"]] =
142
+ { label: num, xref: l10n("#{@labels["section_iev"]}-#{num}"), level: 2,
143
+ type: "clause" }
144
+ t.xpath(ns("./term")).each_with_index do |c, i|
145
+ num2 = "%02d" % [i+1]
146
+ section_names1(c, "#{num}-#{num2}", 3)
147
+ end
148
+ end
149
+ end
150
+
151
+ def termref_cleanup(docxml)
152
+ return super unless @is_iev
153
+ docxml.
154
+ gsub(%r{\s*\[/TERMREF\]\s*</p>\s*<p>\s*\[TERMREF\]}, "; ").
155
+ gsub(/\[TERMREF\]\s*/, l10n("#{@source_lbl}: ")).
156
+ gsub(/\s*\[MODIFICATION\]\s*\[\/TERMREF\]/, l10n(", #{@modified_lbl} [/TERMREF]")).
157
+ gsub(/\s*\[\/TERMREF\]\s*/, l10n("")).
158
+ gsub(/\s*\[MODIFICATION\]/, l10n(", #{@modified_lbl} &mdash; "))
159
+ end
160
+
161
+ def set_termdomain(termdomain)
162
+ return super unless @is_iev
163
+ end
164
+
165
+ def term_suffix(node, out)
166
+ return unless @is_iev
167
+ domain = node&.at(ns("../domain"))&.text
168
+ return unless domain
169
+ out << ", &lt;#{domain}&gt;"
170
+ end
171
+
172
+ def deprecated_term_parse(node, out)
173
+ out.p **{ class: "DeprecatedTerms", style:"text-align:left;" } do |p|
174
+ p << l10n("#{@deprecated_lbl}: ")
175
+ node.children.each { |c| parse(c, p) }
176
+ term_suffix(node, p)
177
+ end
178
+ end
179
+
180
+ def admitted_term_parse(node, out)
181
+ out.p **{ class: "AltTerms", style:"text-align:left;" } do |p|
182
+ node.children.each { |c| parse(c, p) }
183
+ term_suffix(node, p)
184
+ end
185
+ end
186
+
187
+ def term_parse(node, out)
188
+ return super unless @is_iev
189
+ out.p **{ class: "Terms", style:"text-align:left;" } do |p|
190
+ node.children.each { |c| parse(c, p) }
191
+ term_suffix(node, p)
192
+ end
193
+ end
194
+
195
+ def admonition_parse(node, out)
196
+ type = node["type"]
197
+ name = admonition_name(node, type)
198
+ out.div **{ id: node["id"], class: admonition_class(node) } do |div|
199
+ node.first_element_child.name == "p" ?
200
+ admonition_p_parse(node, div, name) : admonition_parse1(node, div, name)
201
+ end
202
+ end
203
+
204
+ def admonition_parse1(node, div, name)
205
+ div.p do |p|
206
+ admonition_name_parse(node, p, name) if name
207
+ end
208
+ node.children.each { |n| parse(n, div) unless n.name == "name" }
209
+ end
210
+
211
+ def admonition_p_parse(node, div, name)
212
+ div.p do |p|
213
+ admonition_name_parse(node, p, name) if name
214
+ node.first_element_child.children.each { |n| parse(n, p) }
215
+ end
216
+ node.element_children[1..-1].each { |n| parse(n, div) }
217
+ end
218
+
219
+ def admonition_name_parse(_node, div, name)
220
+ name.children.each { |n| parse(n, div) }
221
+ div << " &mdash; "
222
+ end
223
+
224
+ def clause_parse_title(node, div, c1, out)
225
+ IsoDoc::Common.instance_method(:clause_parse_title).bind(self).call(node, div, c1, out)
226
+ end
227
+
228
+ def biblio_list(f, div, biblio)
229
+ biblio = false
230
+ super
231
+ end
75
232
  end
76
233
  end
77
234
  end