metanorma-iso 1.7.0 → 1.8.0

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 (67) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/rake.yml +11 -41
  3. data/.gitignore +2 -0
  4. data/.rubocop.yml +6 -2
  5. data/lib/asciidoctor/iso/base.rb +12 -12
  6. data/lib/asciidoctor/iso/biblio.rng +4 -6
  7. data/lib/asciidoctor/iso/cleanup.rb +1 -1
  8. data/lib/asciidoctor/iso/front.rb +1 -1
  9. data/lib/asciidoctor/iso/front_id.rb +30 -25
  10. data/lib/asciidoctor/iso/isodoc.rng +235 -3
  11. data/lib/asciidoctor/iso/isostandard-amd.rng +3 -0
  12. data/lib/asciidoctor/iso/isostandard.rng +17 -97
  13. data/lib/asciidoctor/iso/validate.rb +1 -0
  14. data/lib/asciidoctor/iso/validate_title.rb +21 -13
  15. data/lib/isodoc/iso/base_convert.rb +11 -0
  16. data/lib/isodoc/iso/html/style-human.css +7 -0
  17. data/lib/isodoc/iso/html/style-iso.css +7 -0
  18. data/lib/isodoc/iso/html_convert.rb +0 -1
  19. data/lib/isodoc/iso/i18n-en.yaml +4 -0
  20. data/lib/isodoc/iso/i18n-fr.yaml +4 -0
  21. data/lib/isodoc/iso/i18n-zh-Hans.yaml +4 -0
  22. data/lib/isodoc/iso/index.rb +140 -0
  23. data/lib/isodoc/iso/iso.amendment.xsl +1010 -324
  24. data/lib/isodoc/iso/iso.international-standard.xsl +1010 -324
  25. data/lib/isodoc/iso/presentation_xml_convert.rb +32 -25
  26. data/lib/isodoc/iso/word_convert.rb +0 -1
  27. data/lib/isodoc/iso/xref.rb +13 -5
  28. data/lib/metanorma/iso/version.rb +1 -1
  29. data/metanorma-iso.gemspec +8 -8
  30. data/spec/asciidoctor/amd_spec.rb +696 -0
  31. data/spec/asciidoctor/base_spec.rb +704 -0
  32. data/spec/asciidoctor/blocks_spec.rb +527 -0
  33. data/spec/asciidoctor/cleanup_spec.rb +1134 -0
  34. data/spec/asciidoctor/inline_spec.rb +195 -0
  35. data/spec/asciidoctor/lists_spec.rb +197 -0
  36. data/spec/asciidoctor/refs_spec.rb +375 -0
  37. data/spec/asciidoctor/section_spec.rb +393 -0
  38. data/spec/asciidoctor/table_spec.rb +329 -0
  39. data/spec/asciidoctor/validate_spec.rb +1572 -0
  40. data/spec/isodoc/amd_spec.rb +967 -946
  41. data/spec/isodoc/blocks_spec.rb +530 -507
  42. data/spec/isodoc/i18n_spec.rb +953 -911
  43. data/spec/isodoc/inline_spec.rb +355 -293
  44. data/spec/isodoc/iso_spec.rb +338 -314
  45. data/spec/isodoc/metadata_spec.rb +392 -382
  46. data/spec/isodoc/postproc_spec.rb +837 -657
  47. data/spec/isodoc/ref_spec.rb +374 -331
  48. data/spec/isodoc/section_spec.rb +821 -519
  49. data/spec/isodoc/table_spec.rb +472 -411
  50. data/spec/isodoc/terms_spec.rb +209 -185
  51. data/spec/isodoc/xref_spec.rb +1370 -1236
  52. data/spec/metanorma/processor_spec.rb +28 -26
  53. data/spec/spec_helper.rb +186 -189
  54. metadata +65 -67
  55. data/.rubocop.ribose.yml +0 -66
  56. data/lib/isodoc/iso/html/scripts.html +0 -178
  57. data/spec/asciidoctor-iso/amd_spec.rb +0 -694
  58. data/spec/asciidoctor-iso/base_spec.rb +0 -713
  59. data/spec/asciidoctor-iso/blocks_spec.rb +0 -482
  60. data/spec/asciidoctor-iso/cleanup_spec.rb +0 -1025
  61. data/spec/asciidoctor-iso/inline_spec.rb +0 -170
  62. data/spec/asciidoctor-iso/lists_spec.rb +0 -190
  63. data/spec/asciidoctor-iso/refs_spec.rb +0 -317
  64. data/spec/asciidoctor-iso/section_spec.rb +0 -362
  65. data/spec/asciidoctor-iso/table_spec.rb +0 -313
  66. data/spec/asciidoctor-iso/validate_spec.rb +0 -1619
  67. data/spec/assets/xref_error.adoc +0 -7
@@ -39,6 +39,9 @@
39
39
  </choice>
40
40
  </attribute>
41
41
  <ref name="bibdata"/>
42
+ <optional>
43
+ <ref name="misccontainer"/>
44
+ </optional>
42
45
  <optional>
43
46
  <ref name="boilerplate"/>
44
47
  </optional>
@@ -79,19 +79,6 @@
79
79
  </choice>
80
80
  </element>
81
81
  </define>
82
- <define name="ul">
83
- <element name="ul">
84
- <attribute name="id">
85
- <data type="ID"/>
86
- </attribute>
87
- <oneOrMore>
88
- <ref name="ul_li"/>
89
- </oneOrMore>
90
- <zeroOrMore>
91
- <ref name="note"/>
92
- </zeroOrMore>
93
- </element>
94
- </define>
95
82
  <define name="sections">
96
83
  <element name="sections">
97
84
  <zeroOrMore>
@@ -192,17 +179,6 @@
192
179
  </zeroOrMore>
193
180
  </element>
194
181
  </define>
195
- <define name="definition">
196
- <element name="definition">
197
- <oneOrMore>
198
- <choice>
199
- <ref name="paragraph"/>
200
- <ref name="figure"/>
201
- <ref name="formula"/>
202
- </choice>
203
- </oneOrMore>
204
- </element>
205
- </define>
206
182
  <define name="annex">
207
183
  <element name="annex">
208
184
  <optional>
@@ -333,6 +309,11 @@
333
309
  <optional>
334
310
  <attribute name="script"/>
335
311
  </optional>
312
+ <optional>
313
+ <attribute name="inline-header">
314
+ <data type="boolean"/>
315
+ </attribute>
316
+ </optional>
336
317
  <optional>
337
318
  <attribute name="obligation">
338
319
  <choice>
@@ -341,6 +322,12 @@
341
322
  </choice>
342
323
  </attribute>
343
324
  </optional>
325
+ <optional>
326
+ <attribute name="number"/>
327
+ </optional>
328
+ <optional>
329
+ <attribute name="type"/>
330
+ </optional>
344
331
  <optional>
345
332
  <ref name="section-title"/>
346
333
  </optional>
@@ -358,57 +345,6 @@
358
345
  </oneOrMore>
359
346
  </choice>
360
347
  </define>
361
- <define name="table">
362
- <element name="table">
363
- <attribute name="id">
364
- <data type="ID"/>
365
- </attribute>
366
- <optional>
367
- <attribute name="width"/>
368
- </optional>
369
- <optional>
370
- <attribute name="unnumbered">
371
- <data type="boolean"/>
372
- </attribute>
373
- </optional>
374
- <optional>
375
- <attribute name="number"/>
376
- </optional>
377
- <optional>
378
- <attribute name="subsequence"/>
379
- </optional>
380
- <optional>
381
- <attribute name="alt"/>
382
- </optional>
383
- <optional>
384
- <attribute name="summary"/>
385
- </optional>
386
- <optional>
387
- <attribute name="uri">
388
- <data type="anyURI"/>
389
- </attribute>
390
- </optional>
391
- <optional>
392
- <ref name="colgroup"/>
393
- </optional>
394
- <optional>
395
- <ref name="tname"/>
396
- </optional>
397
- <optional>
398
- <ref name="thead"/>
399
- </optional>
400
- <ref name="tbody"/>
401
- <optional>
402
- <ref name="tfoot"/>
403
- </optional>
404
- <zeroOrMore>
405
- <ref name="table-note"/>
406
- </zeroOrMore>
407
- <optional>
408
- <ref name="dl"/>
409
- </optional>
410
- </element>
411
- </define>
412
348
  </include>
413
349
  <!-- end overrides -->
414
350
  <!--
@@ -428,6 +364,9 @@
428
364
  <zeroOrMore>
429
365
  <ref name="termdocsource"/>
430
366
  </zeroOrMore>
367
+ <optional>
368
+ <ref name="misccontainer"/>
369
+ </optional>
431
370
  <optional>
432
371
  <ref name="boilerplate"/>
433
372
  </optional>
@@ -439,6 +378,9 @@
439
378
  <ref name="annex"/>
440
379
  </zeroOrMore>
441
380
  <ref name="bibliography"/>
381
+ <zeroOrMore>
382
+ <ref name="indexsect"/>
383
+ </zeroOrMore>
442
384
  </element>
443
385
  </define>
444
386
  <define name="horizontal">
@@ -527,28 +469,6 @@
527
469
  <ref name="Clause-Section"/>
528
470
  </element>
529
471
  </define>
530
- <define name="ul_li">
531
- <element name="li">
532
- <optional>
533
- <attribute name="id">
534
- <data type="ID"/>
535
- </attribute>
536
- </optional>
537
- <optional>
538
- <attribute name="uncheckedcheckbox">
539
- <data type="boolean"/>
540
- </attribute>
541
- </optional>
542
- <optional>
543
- <attribute name="checkedcheckbox">
544
- <data type="boolean"/>
545
- </attribute>
546
- </optional>
547
- <oneOrMore>
548
- <ref name="BasicBlock"/>
549
- </oneOrMore>
550
- </element>
551
- </define>
552
472
  <define name="stagename">
553
473
  <element name="stagename">
554
474
  <text/>
@@ -209,6 +209,7 @@ module Asciidoctor
209
209
  def image_name_validate(xmldoc)
210
210
  prefix = image_name_prefix(xmldoc) or return
211
211
  xmldoc.xpath("//image").each do |i|
212
+ next if i["src"].start_with?("data:")
212
213
  if /^ISO_\d+_/.match(File.basename(i["src"]))
213
214
  elsif /^(SL)?#{prefix}fig/.match(File.basename(i["src"]))
214
215
  image_name_validate1(i, prefix)
@@ -3,9 +3,13 @@ require "metanorma-standoc"
3
3
  module Asciidoctor
4
4
  module ISO
5
5
  class Converter < Standoc::Converter
6
+ def title_lang_part(doc, part, lang)
7
+ doc.at("//bibdata/title[@type='title-#{part}' and @language='#{lang}']")
8
+ end
9
+
6
10
  def title_intro_validate(root)
7
- title_intro_en = root.at("//title[@type='title-intro' and @language='en']")
8
- title_intro_fr = root.at("//title[@type='title-intro' and @language='fr']")
11
+ title_intro_en = title_lang_part(root, "intro", "en")
12
+ title_intro_fr = title_lang_part(root, "intro", "fr")
9
13
  if title_intro_en.nil? && !title_intro_fr.nil?
10
14
  @log.add("Style", title_intro_fr, "No English Title Intro!")
11
15
  end
@@ -15,8 +19,8 @@ module Asciidoctor
15
19
  end
16
20
 
17
21
  def title_main_validate(root)
18
- title_main_en = root.at("//title[@type='title-main' and @language='en']")
19
- title_main_fr = root.at("//title[@type='title-main' and @language='fr']")
22
+ title_main_en = title_lang_part(root, "main", "en")
23
+ title_main_fr = title_lang_part(root, "main", "fr")
20
24
  if title_main_en.nil? && !title_main_fr.nil?
21
25
  @log.add("Style", title_main_fr, "No English Title!")
22
26
  end
@@ -26,8 +30,8 @@ module Asciidoctor
26
30
  end
27
31
 
28
32
  def title_part_validate(root)
29
- title_part_en = root.at("//title[@type='title-part' and @language='en']")
30
- title_part_fr = root.at("//title[@type='title-part' and @language='fr']")
33
+ title_part_en = title_lang_part(root, "part", "en")
34
+ title_part_fr = title_lang_part(root, "part", "fr")
31
35
  (title_part_en.nil? && !title_part_fr.nil?) &&
32
36
  @log.add("Style", title_part_fr, "No English Title Part!")
33
37
  (!title_part_en.nil? && title_part_fr.nil?) &&
@@ -41,20 +45,22 @@ module Asciidoctor
41
45
  iec = root.at("//bibdata/contributor[role/@type = 'publisher']/"\
42
46
  "organization[abbreviation = 'IEC' or "\
43
47
  "name = 'International Electrotechnical Commission']")
44
- @log.add("Style", docid, "Subpart defined on non-IEC document!") if subpart && !iec
48
+ subpart && !iec and
49
+ @log.add("Style", docid, "Subpart defined on non-IEC document!")
45
50
  end
46
51
 
47
52
  # ISO/IEC DIR 2, 11.5.2
48
53
  def title_names_type_validate(root)
49
54
  doctypes = /International\sStandard | Technical\sSpecification |
50
55
  Publicly\sAvailable\sSpecification | Technical\sReport | Guide /xi
51
- title_main_en = root.at("//title[@type='title-main' and @language='en']")
56
+ title_main_en = title_lang_part(root, "main", "en")
52
57
  if !title_main_en.nil? && doctypes.match(title_main_en.text)
53
58
  @log.add("Style", title_main_en, "Main Title may name document type")
54
59
  end
55
- title_intro_en = root.at("//title[@type='title-intro' and @language='en']")
60
+ title_intro_en = title_lang_part(root, "intro", "en")
56
61
  if !title_intro_en.nil? && doctypes.match(title_intro_en.text)
57
- @log.add("Style", title_intro_en, "Title Intro may name document type")
62
+ @log.add("Style", title_intro_en,
63
+ "Title Intro may name document type")
58
64
  end
59
65
  end
60
66
 
@@ -64,8 +70,9 @@ module Asciidoctor
64
70
  title = s&.at("./title")&.text || s.name
65
71
  s.xpath("./clause | ./terms | ./references").each do |ss|
66
72
  subtitle = ss.at("./title")
67
- !subtitle.nil? && !subtitle&.text&.empty? ||
68
- @log.add("Style", ss, "#{title}: each first-level subclause must have a title")
73
+ !subtitle.nil? && !subtitle&.text&.empty? or
74
+ @log.add("Style", ss,
75
+ "#{title}: each first-level subclause must have a title")
69
76
  end
70
77
  end
71
78
  end
@@ -82,7 +89,8 @@ module Asciidoctor
82
89
  withtitle = withtitle || (subtitle && !subtitle.text.empty?)
83
90
  end
84
91
  notitle && withtitle &&
85
- @log.add("Style", nil, "#{label}: all subclauses must have a title, or none")
92
+ @log.add("Style", nil,
93
+ "#{label}: all subclauses must have a title, or none")
86
94
  end
87
95
 
88
96
  def title_validate(root)
@@ -152,6 +152,17 @@ module IsoDoc
152
152
  name and name.children.each { |n| parse(n, div) }
153
153
  end
154
154
  end
155
+
156
+ def middle(isoxml, out)
157
+ super
158
+ indexsect isoxml, out
159
+ end
160
+
161
+ def indexsect(isoxml, out)
162
+ isoxml.xpath(ns("//indexsect")).each do |i|
163
+ clause_parse(i, out)
164
+ end
165
+ end
155
166
  end
156
167
  end
157
168
  end
@@ -115,6 +115,13 @@ a.FootnoteRef + a.FootnoteRef:before {
115
115
  content: ", ";
116
116
  vertical-align: super; }
117
117
 
118
+ .addition {
119
+ color: blue; }
120
+
121
+ .deletion {
122
+ color: red;
123
+ text-decoration: line-through; }
124
+
118
125
  #standard-band {
119
126
  background-color: #0AC442; }
120
127
 
@@ -115,6 +115,13 @@ a.FootnoteRef + a.FootnoteRef:before {
115
115
  content: ", ";
116
116
  vertical-align: super; }
117
117
 
118
+ .addition {
119
+ color: blue; }
120
+
121
+ .deletion {
122
+ color: red;
123
+ text-decoration: line-through; }
124
+
118
125
  #standard-band {
119
126
  background-color: #0AC442; }
120
127
 
@@ -38,7 +38,6 @@ module IsoDoc
38
38
  html_doc_path("style-iso.scss")),
39
39
  htmlcoverpage: html_doc_path("html_iso_titlepage.html"),
40
40
  htmlintropage: html_doc_path("html_iso_intro.html"),
41
- scripts: html_doc_path("scripts.html"),
42
41
  }
43
42
  end
44
43
 
@@ -14,3 +14,7 @@ price_based_on: Price based on % pages
14
14
  under_preparation: Under preparation. (Stage at the time of publication %).
15
15
  table_of_contents: Contents
16
16
  date: Date
17
+ index: Index
18
+ see: see
19
+ see_also: see also
20
+
@@ -13,3 +13,7 @@ reference_number: Numéro de référence
13
13
  price_based_on: Prix basé sur % pages
14
14
  under_preparation: En cours d'élaboration. (Stade au moment de la publication %).
15
15
  date: Date
16
+ index: Index
17
+ see: voir
18
+ see_also: voir aussi
19
+
@@ -11,3 +11,7 @@ reference_number: 参考编号
11
11
  price_based_on: 价格基于%页
12
12
  under_preparation: 制定中(出版时最新状态为%)
13
13
  date: 日期
14
+ index: 索引
15
+ see: 见
16
+ see_also: 另见
17
+
@@ -0,0 +1,140 @@
1
+ module IsoDoc
2
+ module Iso
3
+ class PresentationXMLConvert < IsoDoc::PresentationXMLConvert
4
+ def add_id
5
+ %(id="_#{UUIDTools::UUID.random_create}")
6
+ end
7
+
8
+ def index(docxml)
9
+ unless docxml.at(ns("//index"))
10
+ docxml.xpath(ns("//indexsect")).each { |i| i.remove }
11
+ return
12
+ end
13
+ i = docxml.at(ns("//indexsect")) ||
14
+ docxml.root.add_child("<indexsect #{add_id}><title>#{@i18n.index}</title></indexsect>").first
15
+ index = sort_indexterms(docxml.xpath(ns("//index")), docxml.xpath(ns("//index-xref[@also = 'false']")),
16
+ docxml.xpath(ns("//index-xref[@also = 'true']")))
17
+ index1(docxml, i, index)
18
+ end
19
+
20
+ def index1(docxml, i, index)
21
+ c = i.add_child("<ul></ul>").first
22
+ index.keys.sort.each do |k|
23
+ #c = i.add_child "<clause #{add_id}><title>#{k}</title><ul></ul></clause>"
24
+ words = index[k].keys.each_with_object({}) { |w, v| v[sortable(w).downcase] = w }
25
+ words.keys.localize(@lang.to_sym).sort.to_a.each do |w|
26
+ #c.first.at(ns("./ul")).add_child index_entries(words, index[k], w)
27
+ c.add_child index_entries(words, index[k], w)
28
+ end
29
+ end
30
+ docxml.xpath(ns("//indexsect//xref")).each { |x| x.children.remove }
31
+ @xrefs.bookmark_anchor_names(docxml)
32
+ end
33
+
34
+ def sortable(s)
35
+ HTMLEntities.new.decode(Nokogiri::XML.fragment(s).text)
36
+ end
37
+
38
+ def index_entries_opt
39
+ { xref_lbl: ", ", see_lbl: ", #{see_lbl}", also_lbl: ", #{also_lbl}" }
40
+ end
41
+
42
+ def index_entries(words, index, primary)
43
+ ret = index_entries_head(words[primary], index.dig(words[primary], nil, nil), index_entries_opt)
44
+ words2 = index[words[primary]]&.keys&.reject { |k| k.nil?}&.each_with_object({}) { |w, v| v[w.downcase] = w }
45
+ unless words2.empty?
46
+ ret += "<ul>"
47
+ words2.keys.localize(@lang.to_sym).sort.to_a.each do |w|
48
+ ret += index_entries2(words2, index[words[primary]], w)
49
+ end
50
+ ret += "</ul>"
51
+ end
52
+ ret + "</li>"
53
+ end
54
+
55
+ def index_entries2(words, index, secondary)
56
+ ret = index_entries_head(words[secondary], index.dig(words[secondary], nil), index_entries_opt)
57
+ words3 = index[words[secondary]]&.keys&.reject { |k| k.nil?}&.each_with_object({}) { |w, v| v[w.downcase] = w }
58
+ unless words3.empty?
59
+ ret += "<ul>"
60
+ words3.keys.localize(@lang.to_sym).sort.to_a.each do |w|
61
+ ret += (index_entries_head(words3[w], index[words[secondary]][words3[w]], index_entries_opt) + "</li>")
62
+ end
63
+ ret += "</ul>"
64
+ end
65
+ ret + "</li>"
66
+ end
67
+
68
+ def index_entries_head(head, entries, opt)
69
+ ret = "<li>#{head}"
70
+ xref = entries&.dig(:xref)&.join(", ")
71
+ see_sort = entries&.dig(:see)&.each_with_object({}) { |w, v| v[sortable(w).downcase] = w }
72
+ see = see_sort&.keys&.localize(@lang.to_sym)&.sort&.to_a&.map { |k| see_sort[k] }&.join(", ")
73
+ also_sort = entries&.dig(:also)&.each_with_object({}) { |w, v| v[sortable(w).downcase] = w }
74
+ also = also_sort&.keys&.localize(@lang.to_sym)&.sort&.to_a&.map { |k| also_sort[k] }&.join(", ")
75
+ ret += "#{opt[:xref_lbl]} #{xref}" if xref
76
+ ret += "#{opt[:see_lbl]} #{see}" if see
77
+ ret += "#{opt[:also_lbl]} #{also}" if also
78
+ ret
79
+ end
80
+
81
+ def see_lbl
82
+ @lang == "en" ? @i18n.see : "<em>#{@i18n.see}</em>"
83
+ end
84
+
85
+ def also_lbl
86
+ @lang == "en" ? @i18n.see_also : "<em>#{@i18n.see_also}</em>"
87
+ end
88
+
89
+ def sort_indexterms(terms, see, also)
90
+ index = extract_indexterms(terms)
91
+ index = extract_indexsee(index, see, :see)
92
+ index = extract_indexsee(index, also, :also)
93
+ index.keys.sort.each_with_object({}) do |k, v|
94
+ v[sortable(k)[0].upcase.transliterate] ||= {}
95
+ v[sortable(k)[0].upcase.transliterate][k] = index[k]
96
+ end
97
+ end
98
+
99
+ def extract_indexsee(v, terms, label)
100
+ terms.each_with_object(v) do |t, v|
101
+ term = t&.at(ns("./primary"))&.children&.to_xml
102
+ term2 = t&.at(ns("./secondary"))&.children&.to_xml
103
+ term3 = t&.at(ns("./tertiary"))&.children&.to_xml
104
+ v[term] ||= {}
105
+ v[term][term2] ||= {}
106
+ v[term][term2][term3] ||= {}
107
+ v[term][term2][term3][label] ||= []
108
+ v[term][term2][term3][label] << t&.at(ns("./target"))&.children&.to_xml
109
+ t.remove
110
+ end
111
+ end
112
+
113
+ def xml_encode_attr(s)
114
+ HTMLEntities.new.encode(s, :basic, :hexadecimal).gsub(/\&#x([^;]+);/) { |x| "&#x#{$1.upcase};" }
115
+ end
116
+
117
+ # attributes are decoded into UTF-8, elements in extract_indexsee are still in entities
118
+ def extract_indexterms(terms)
119
+ terms.each_with_object({}) do |t, v|
120
+ term = t&.at(ns("./primary"))&.children&.to_xml
121
+ term2 = t&.at(ns("./secondary"))&.children&.to_xml
122
+ term3 = t&.at(ns("./tertiary"))&.children&.to_xml
123
+ index2bookmark(t)
124
+ v[term] ||= {}
125
+ v[term][term2] ||= {}
126
+ v[term][term2][term3] ||= {}
127
+ v[term][term2][term3][:xref] ||= []
128
+ to = t["to"] ? "to='#{t['to']}' " : ""
129
+ v[term][term2][term3][:xref] << "<xref target='#{t['id']}' #{to}pagenumber='true'/>"
130
+ end
131
+ end
132
+
133
+ def index2bookmark(t)
134
+ t.name = "bookmark"
135
+ t.children.each { |x| x.remove }
136
+ t["id"] = "_#{UUIDTools::UUID.random_create}"
137
+ end
138
+ end
139
+ end
140
+ end