metanorma-iso 1.10.5 → 2.0.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 (66) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/rake.yml +3 -33
  3. data/.gitignore +26 -0
  4. data/Makefile +1 -1
  5. data/lib/asciidoctor/iso/base.rb +2 -69
  6. data/lib/asciidoctor/iso/cleanup.rb +2 -175
  7. data/lib/asciidoctor/iso/converter.rb +2 -17
  8. data/lib/asciidoctor/iso/deprecated.rb +5 -0
  9. data/lib/asciidoctor/iso/front.rb +2 -169
  10. data/lib/asciidoctor/iso/front_id.rb +2 -224
  11. data/lib/asciidoctor/iso/section.rb +2 -48
  12. data/lib/asciidoctor/iso/validate.rb +2 -171
  13. data/lib/asciidoctor/iso/validate_image.rb +2 -96
  14. data/lib/asciidoctor/iso/validate_requirements.rb +2 -110
  15. data/lib/asciidoctor/iso/validate_section.rb +2 -246
  16. data/lib/asciidoctor/iso/validate_style.rb +2 -169
  17. data/lib/asciidoctor/iso/validate_title.rb +2 -104
  18. data/lib/isodoc/iso/html/style-human.css +19 -14
  19. data/lib/isodoc/iso/html/style-human.scss +8 -2
  20. data/lib/isodoc/iso/html/style-iso.css +21 -15
  21. data/lib/isodoc/iso/html/style-iso.scss +9 -2
  22. data/lib/isodoc/iso/html_convert.rb +6 -4
  23. data/lib/isodoc/iso/iso.amendment.xsl +1449 -1222
  24. data/lib/isodoc/iso/iso.international-standard.xsl +1449 -1222
  25. data/lib/isodoc/iso/word_convert.rb +2 -0
  26. data/lib/metanorma/iso/base.rb +70 -0
  27. data/lib/{asciidoctor → metanorma}/iso/basicdoc.rng +0 -0
  28. data/lib/{asciidoctor → metanorma}/iso/biblio.rng +2 -2
  29. data/lib/{asciidoctor → metanorma}/iso/boilerplate-fr.xml +0 -0
  30. data/lib/{asciidoctor → metanorma}/iso/boilerplate.xml +0 -0
  31. data/lib/metanorma/iso/cleanup.rb +176 -0
  32. data/lib/metanorma/iso/converter.rb +18 -0
  33. data/lib/metanorma/iso/front.rb +170 -0
  34. data/lib/metanorma/iso/front_id.rb +225 -0
  35. data/lib/{asciidoctor → metanorma}/iso/isodoc.rng +98 -1
  36. data/lib/{asciidoctor → metanorma}/iso/isostandard-amd.rng +0 -0
  37. data/lib/{asciidoctor → metanorma}/iso/isostandard.rnc +0 -0
  38. data/lib/{asciidoctor → metanorma}/iso/isostandard.rng +0 -0
  39. data/lib/{asciidoctor → metanorma}/iso/reqt.rng +0 -0
  40. data/lib/metanorma/iso/section.rb +49 -0
  41. data/lib/metanorma/iso/validate.rb +172 -0
  42. data/lib/metanorma/iso/validate_image.rb +97 -0
  43. data/lib/metanorma/iso/validate_requirements.rb +111 -0
  44. data/lib/metanorma/iso/validate_section.rb +247 -0
  45. data/lib/metanorma/iso/validate_style.rb +170 -0
  46. data/lib/metanorma/iso/validate_title.rb +105 -0
  47. data/lib/metanorma/iso/version.rb +1 -1
  48. data/lib/metanorma-iso.rb +1 -1
  49. data/metanorma-iso.gemspec +2 -2
  50. data/spec/isodoc/ref_spec.rb +4 -2
  51. data/spec/isodoc/section_spec.rb +1 -1
  52. data/spec/{asciidoctor → metanorma}/amd_spec.rb +1 -1
  53. data/spec/{asciidoctor → metanorma}/base_spec.rb +141 -130
  54. data/spec/{asciidoctor → metanorma}/blank_spec.rb +1 -1
  55. data/spec/{asciidoctor → metanorma}/blocks_spec.rb +1 -1
  56. data/spec/{asciidoctor → metanorma}/cleanup_spec.rb +1 -1
  57. data/spec/{asciidoctor → metanorma}/inline_spec.rb +1 -1
  58. data/spec/{asciidoctor → metanorma}/lists_spec.rb +1 -1
  59. data/spec/metanorma/processor_spec.rb +1 -1
  60. data/spec/{asciidoctor → metanorma}/refs_spec.rb +1 -1
  61. data/spec/{asciidoctor → metanorma}/section_spec.rb +1 -1
  62. data/spec/{asciidoctor → metanorma}/table_spec.rb +1 -1
  63. data/spec/{asciidoctor → metanorma}/validate_spec.rb +1 -1
  64. data/spec/spec_helper.rb +1 -1
  65. data/spec/vcr_cassettes/docrels.yml +21 -216
  66. metadata +39 -26
@@ -154,11 +154,13 @@ module IsoDoc
154
154
  end
155
155
 
156
156
  def annex_name(_annex, name, div)
157
+ preceding_floating_titles(name, div)
157
158
  return if name.nil?
158
159
 
159
160
  name&.at(ns("./strong"))&.remove # supplied by CSS list numbering
160
161
  div.h1 **{ class: "Annex" } do |t|
161
162
  name.children.each { |c2| parse(c2, t) }
163
+ clause_parse_subtitle(name, t)
162
164
  end
163
165
  end
164
166
 
@@ -0,0 +1,70 @@
1
+ require "date"
2
+ require "nokogiri"
3
+ require "json"
4
+ require "pathname"
5
+ require "open-uri"
6
+ require "isodoc"
7
+ require "fileutils"
8
+
9
+ module Metanorma
10
+ module ISO
11
+ class Converter < Standoc::Converter
12
+ XML_ROOT_TAG = "iso-standard".freeze
13
+ XML_NAMESPACE = "https://www.metanorma.org/ns/iso".freeze
14
+
15
+ def html_converter(node)
16
+ IsoDoc::Iso::HtmlConvert.new(html_extract_attributes(node))
17
+ end
18
+
19
+ def html_converter_alt(node)
20
+ IsoDoc::Iso::HtmlConvert.new(html_extract_attributes(node)
21
+ .merge(alt: true))
22
+ end
23
+
24
+ def doc_converter(node)
25
+ IsoDoc::Iso::WordConvert.new(doc_extract_attributes(node))
26
+ end
27
+
28
+ def pdf_converter(node)
29
+ return nil if node.attr("no-pdf")
30
+
31
+ IsoDoc::Iso::PdfConvert.new(pdf_extract_attributes(node))
32
+ end
33
+
34
+ def sts_converter(node)
35
+ return nil if node.attr("no-pdf")
36
+
37
+ IsoDoc::Iso::StsConvert.new(html_extract_attributes(node))
38
+ end
39
+
40
+ def presentation_xml_converter(node)
41
+ IsoDoc::Iso::PresentationXMLConvert.new(html_extract_attributes(node))
42
+ end
43
+
44
+ def init(node)
45
+ super
46
+ @amd = %w(amendment technical-corrigendum).include? doctype(node)
47
+ @vocab = node.attr("docsubtype") == "vocabulary"
48
+ end
49
+
50
+ def ol_attrs(node)
51
+ attr_code(keep_attrs(node)
52
+ .merge(id: ::Metanorma::Utils::anchor_or_uuid(node)))
53
+ end
54
+
55
+ def outputs(node, ret)
56
+ File.open("#{@filename}.xml", "w:UTF-8") { |f| f.write(ret) }
57
+ presentation_xml_converter(node).convert("#{@filename}.xml")
58
+ html_converter_alt(node).convert("#{@filename}.presentation.xml",
59
+ nil, false, "#{@filename}_alt.html")
60
+ html_converter(node).convert("#{@filename}.presentation.xml",
61
+ nil, false, "#{@filename}.html")
62
+ doc_converter(node).convert("#{@filename}.presentation.xml",
63
+ nil, false, "#{@filename}.doc")
64
+ pdf_converter(node)&.convert("#{@filename}.presentation.xml",
65
+ nil, false, "#{@filename}.pdf")
66
+ # sts_converter(node)&.convert(@filename + ".xml")
67
+ end
68
+ end
69
+ end
70
+ end
File without changes
@@ -401,9 +401,9 @@
401
401
  <choice>
402
402
  <!-- iso191606 TODO -->
403
403
  <group>
404
- <oneOrMore>
404
+ <zeroOrMore>
405
405
  <ref name="street"/>
406
- </oneOrMore>
406
+ </zeroOrMore>
407
407
  <ref name="city"/>
408
408
  <optional>
409
409
  <ref name="state"/>
File without changes
@@ -0,0 +1,176 @@
1
+ require "date"
2
+ require "nokogiri"
3
+ require "htmlentities"
4
+ require "json"
5
+ require "pathname"
6
+
7
+ module Metanorma
8
+ module ISO
9
+ class Converter < Standoc::Converter
10
+ PRE_NORMREF_FOOTNOTES = "//preface//fn | "\
11
+ "//clause[@type = 'scope']//fn".freeze
12
+
13
+ NORMREF_FOOTNOTES =
14
+ "//references[@normative = 'true']//fn".freeze
15
+
16
+ POST_NORMREF_FOOTNOTES =
17
+ "//sections//clause[not(@type = 'scope')]//fn | "\
18
+ "//annex//fn | "\
19
+ "//references[@normative = 'false']//fn".freeze
20
+
21
+ def other_footnote_renumber(xmldoc)
22
+ seen = {}
23
+ i = 0
24
+ [PRE_NORMREF_FOOTNOTES, NORMREF_FOOTNOTES,
25
+ POST_NORMREF_FOOTNOTES].each do |xpath|
26
+ xmldoc.xpath(xpath).each do |fn|
27
+ i, seen = other_footnote_renumber1(fn, i, seen)
28
+ end
29
+ end
30
+ end
31
+
32
+ def id_prefix(prefix, id)
33
+ # we're just inheriting the prefixes from parent doc
34
+ return id.text if @amd
35
+
36
+ prefix.join("/") + (id.text.match?(%{^/}) ? "" : " ") + id.text
37
+ end
38
+
39
+ def get_id_prefix(xmldoc)
40
+ prefix = []
41
+ xmldoc.xpath("//bibdata/contributor[role/@type = 'publisher']"\
42
+ "/organization").each do |x|
43
+ x1 = x.at("abbreviation")&.text || x.at("name")&.text
44
+ (x1 == "ISO" and prefix.unshift("ISO")) or prefix << x1
45
+ end
46
+ prefix
47
+ end
48
+
49
+ # ISO as a prefix goes first
50
+ def docidentifier_cleanup(xmldoc)
51
+ prefix = get_id_prefix(xmldoc)
52
+ id = xmldoc.at("//bibdata/docidentifier[@type = 'ISO']") or return
53
+ id.content = id_prefix(prefix, id)
54
+ id = xmldoc.at("//bibdata/ext/structuredidentifier/project-number") and
55
+ id.content = id_prefix(prefix, id)
56
+ id = xmldoc.at("//bibdata/docidentifier[@type = 'iso-with-lang']") and
57
+ id.content = id_prefix(prefix, id)
58
+ id = xmldoc.at("//bibdata/docidentifier[@type = 'iso-reference']") and
59
+ id.content = id_prefix(prefix, id)
60
+ end
61
+
62
+ def format_ref(ref, type)
63
+ ref = ref.sub(/ \(All Parts\)/i, "")
64
+ super
65
+ end
66
+
67
+ TERM_CLAUSE =
68
+ "//sections//terms | "\
69
+ "//sections//clause[descendant::terms][not(descendant::definitions)]"
70
+ .freeze
71
+
72
+ PUBLISHER = "./contributor[role/@type = 'publisher']/organization".freeze
73
+
74
+ OTHERIDS = "@type = 'DOI' or @type = 'metanorma' or @type = 'ISSN' or "\
75
+ "@type = 'ISBN'".freeze
76
+
77
+ def pub_class(bib)
78
+ return 1 if bib.at("#{PUBLISHER}[abbreviation = 'ISO']")
79
+ return 1 if bib.at("#{PUBLISHER}[name = 'International Organization "\
80
+ "for Standardization']")
81
+ return 2 if bib.at("#{PUBLISHER}[abbreviation = 'IEC']")
82
+ return 2 if bib.at("#{PUBLISHER}[name = 'International "\
83
+ "Electrotechnical Commission']")
84
+ return 3 if bib.at("./docidentifier[@type][not(#{OTHERIDS})]")
85
+
86
+ 4
87
+ end
88
+
89
+ def sort_biblio(bib)
90
+ bib.sort do |a, b|
91
+ sort_biblio_key(a) <=> sort_biblio_key(b)
92
+ end
93
+ end
94
+
95
+ # TODO sort by authors
96
+ # sort by: doc class (ISO, IEC, other standard (not DOI &c), other
97
+ # then standard class (docid class other than DOI &c)
98
+ # then docnumber if present, numeric sort
99
+ # else alphanumeric metanorma id (abbreviation)
100
+ # then doc part number if present, numeric sort
101
+ # then doc id (not DOI &c)
102
+ # then title
103
+ def sort_biblio_key(bib)
104
+ pubclass = pub_class(bib)
105
+ num = bib&.at("./docnumber")&.text
106
+ id = bib&.at("./docidentifier[not(#{OTHERIDS})]")
107
+ metaid = bib&.at("./docidentifier[@type = 'metanorma']")&.text
108
+ abbrid = metaid unless /^\[\d+\]$/.match?(metaid)
109
+ /\d-(?<partid>\d+)/ =~ id&.text
110
+ type = id["type"] if id
111
+ title = bib&.at("./title[@type = 'main']")&.text ||
112
+ bib&.at("./title")&.text || bib&.at("./formattedref")&.text
113
+ "#{pubclass} :: #{type} :: "\
114
+ "#{num.nil? ? abbrid : sprintf('%09d', num.to_i)} :: "\
115
+ "#{sprintf('%09d', partid.to_i)} :: #{id&.text} :: #{title}"
116
+ end
117
+
118
+ def sections_cleanup(xml)
119
+ super
120
+ return unless @amd
121
+
122
+ xml.xpath("//*[@inline-header]").each do |h|
123
+ h.delete("inline-header")
124
+ end
125
+ end
126
+
127
+ def boilerplate_file(_xmldoc)
128
+ file = @lang == "fr" ? "boilerplate-fr.xml" : "boilerplate.xml"
129
+ File.join(@libdir, file)
130
+ end
131
+
132
+ def footnote_cleanup(xmldoc)
133
+ unpub_footnotes(xmldoc)
134
+ super
135
+ end
136
+
137
+ def unpub_footnotes(xmldoc)
138
+ xmldoc.xpath("//bibitem/note[@type = 'Unpublished-Status']").each do |n|
139
+ id = n.parent["id"]
140
+ e = xmldoc.at("//eref[@bibitemid = '#{id}']") or next
141
+ fn = n.children.to_xml
142
+ n&.elements&.first&.name == "p" or fn = "<p>#{fn}</p>"
143
+ e.next = "<fn>#{fn}</fn>"
144
+ end
145
+ end
146
+
147
+ def bibitem_cleanup(xmldoc)
148
+ super
149
+ unpublished_note(xmldoc)
150
+ end
151
+
152
+ def unpublished_note(xmldoc)
153
+ xmldoc.xpath("//bibitem[not(note[@type = 'Unpublished-Status'])]")
154
+ .each do |b|
155
+ next if pub_class(b) > 2
156
+ next unless (s = b.at("./status/stage")) && (s.text.to_i < 60)
157
+
158
+ id = b.at("docidentifier").text
159
+ b.at("./language | ./script | ./abstract | ./status")
160
+ .previous = %(<note type="Unpublished-Status">
161
+ <p>#{@i18n.under_preparation.sub(/%/, id)}</p></note>)
162
+ end
163
+ end
164
+
165
+ def termdef_boilerplate_insert(xmldoc, isodoc, once = false)
166
+ once = true
167
+ super
168
+ end
169
+
170
+ def term_defs_boilerplate_cont(src, term, isodoc)
171
+ @vocab and src.empty? and return
172
+ super
173
+ end
174
+ end
175
+ end
176
+ end
@@ -0,0 +1,18 @@
1
+ require "asciidoctor"
2
+ require "metanorma-standoc"
3
+ require "metanorma/iso/version"
4
+ require "metanorma/iso/base"
5
+ require "metanorma/iso/front"
6
+ require "metanorma/iso/section"
7
+ require "metanorma/iso/validate"
8
+ require "metanorma/iso/cleanup"
9
+
10
+ module Metanorma
11
+ module ISO
12
+ # A {Converter} implementation that generates ISO output, and a document
13
+ # schema encapsulation of the document for validation
14
+ class Converter < ::Metanorma::Standoc::Converter
15
+ register_for "iso"
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,170 @@
1
+ require "date"
2
+ require "nokogiri"
3
+ require "htmlentities"
4
+ require "json"
5
+ require "pathname"
6
+ require "open-uri"
7
+ require_relative "front_id"
8
+
9
+ module Metanorma
10
+ module ISO
11
+ class Converter < Standoc::Converter
12
+ def metadata_ext(node, xml)
13
+ super
14
+ structured_id(node, xml)
15
+ xml.stagename stage_name(get_stage(node), get_substage(node),
16
+ doctype(node), node.attr("iteration"))
17
+ @amd && a = node.attr("updates-document-type") and
18
+ xml.updates_document_type a
19
+ end
20
+
21
+ def metadata_subdoctype(node, xml)
22
+ super
23
+ a = node.attr("horizontal") and xml.horizontal a
24
+ end
25
+
26
+ def org_abbrev
27
+ { "International Organization for Standardization" => "ISO",
28
+ "International Electrotechnical Commission" => "IEC" }
29
+ end
30
+
31
+ def metadata_author(node, xml)
32
+ publishers = node.attr("publisher") || "ISO"
33
+ csv_split(publishers).each do |p|
34
+ xml.contributor do |c|
35
+ c.role **{ type: "author" }
36
+ c.organization do |a|
37
+ organization(a, p, false, node, !node.attr("publisher"))
38
+ end
39
+ end
40
+ end
41
+ end
42
+
43
+ def metadata_publisher(node, xml)
44
+ publishers = node.attr("publisher") || "ISO"
45
+ csv_split(publishers).each do |p|
46
+ xml.contributor do |c|
47
+ c.role **{ type: "publisher" }
48
+ c.organization do |a|
49
+ organization(a, p, true, node, !node.attr("publisher"))
50
+ end
51
+ end
52
+ end
53
+ end
54
+
55
+ def metadata_copyright(node, xml)
56
+ publishers = node.attr("copyright-holder") || node.attr("publisher") ||
57
+ "ISO"
58
+ csv_split(publishers).each do |p|
59
+ xml.copyright do |c|
60
+ c.from (node.attr("copyright-year") || Date.today.year)
61
+ c.owner do |owner|
62
+ owner.organization do |o|
63
+ organization(
64
+ o, p, true, node,
65
+ !(node.attr("copyright-holder") || node.attr("publisher"))
66
+ )
67
+ end
68
+ end
69
+ end
70
+ end
71
+ end
72
+
73
+ def metadata_status(node, xml)
74
+ stage = get_stage(node)
75
+ substage = get_substage(node)
76
+ xml.status do |s|
77
+ s.stage stage, **attr_code(abbreviation: cover_stage_abbr(node))
78
+ s.substage substage
79
+ node.attr("iteration") && (s.iteration node.attr("iteration"))
80
+ end
81
+ end
82
+
83
+ def metadata_committee(node, xml)
84
+ xml.editorialgroup do |a|
85
+ committee_component("technical-committee", node, a)
86
+ committee_component("subcommittee", node, a)
87
+ committee_component("workgroup", node, a)
88
+ node.attr("secretariat") && a.secretariat(node.attr("secretariat"))
89
+ end
90
+ end
91
+
92
+ def title_intro(node, xml, lang, at)
93
+ return unless node.attr("title-intro-#{lang}")
94
+
95
+ xml.title(**attr_code(at.merge(type: "title-intro"))) do |t1|
96
+ t1 << Metanorma::Utils::asciidoc_sub(node.attr("title-intro-#{lang}"))
97
+ end
98
+ end
99
+
100
+ def title_main(node, xml, lang, at)
101
+ xml.title **attr_code(at.merge(type: "title-main")) do |t1|
102
+ t1 << Metanorma::Utils::asciidoc_sub(node.attr("title-main-#{lang}"))
103
+ end
104
+ end
105
+
106
+ def title_part(node, xml, lang, at)
107
+ return unless node.attr("title-part-#{lang}")
108
+
109
+ xml.title(**attr_code(at.merge(type: "title-part"))) do |t1|
110
+ t1 << Metanorma::Utils::asciidoc_sub(node.attr("title-part-#{lang}"))
111
+ end
112
+ end
113
+
114
+ def title_amd(node, xml, lang, at)
115
+ return unless node.attr("title-amendment-#{lang}")
116
+
117
+ xml.title(**attr_code(at.merge(type: "title-amd"))) do |t1|
118
+ t1 << Metanorma::Utils::asciidoc_sub(
119
+ node.attr("title-amendment-#{lang}"),
120
+ )
121
+ end
122
+ end
123
+
124
+ def title_full(node, xml, lang, at)
125
+ title = node.attr("title-main-#{lang}")
126
+ intro = node.attr("title-intro-#{lang}")
127
+ part = node.attr("title-part-#{lang}")
128
+ amd = node.attr("title-amendment-#{lang}")
129
+ title = "#{intro} -- #{title}" if intro
130
+ title = "#{title} -- #{part}" if part
131
+ title = "#{title} -- #{amd}" if amd && @amd
132
+ xml.title **attr_code(at.merge(type: "main")) do |t1|
133
+ t1 << Metanorma::Utils::asciidoc_sub(title)
134
+ end
135
+ end
136
+
137
+ def title(node, xml)
138
+ ["en", "fr"].each do |lang|
139
+ at = { language: lang, format: "text/plain" }
140
+ title_full(node, xml, lang, at)
141
+ title_intro(node, xml, lang, at)
142
+ title_main(node, xml, lang, at)
143
+ title_part(node, xml, lang, at)
144
+ title_amd(node, xml, lang, at) if @amd
145
+ end
146
+ end
147
+
148
+ def relaton_relations
149
+ super + %w(obsoletes successor-of manifestation-of related annotation-of)
150
+ end
151
+
152
+ def relaton_relation_descriptions
153
+ super.merge(
154
+ "amends" => "updates", "revises" => "updates",
155
+ "replaces" => "obsoletes",
156
+ "supersedes" => "obsoletes",
157
+ "corrects" => "updates",
158
+ "informatively-cited-in" => "isCitedIn",
159
+ "informatively-cites" => "cites",
160
+ "normatively-cited in" => "isCitedIn",
161
+ "normatively-cites" => "cites",
162
+ "identical-adopted-from" => "adoptedFrom",
163
+ "modified-adopted-from" => "adoptedFrom",
164
+ "related-directive" => "related",
165
+ "related-mandate" => "related",
166
+ )
167
+ end
168
+ end
169
+ end
170
+ end
@@ -0,0 +1,225 @@
1
+ require "date"
2
+ require "nokogiri"
3
+ require "htmlentities"
4
+ require "json"
5
+ require "pathname"
6
+ require "open-uri"
7
+ require "twitter_cldr"
8
+
9
+ module Metanorma
10
+ module ISO
11
+ class Converter < Standoc::Converter
12
+ STAGE_ABBRS = {
13
+ "00": "PWI",
14
+ "10": "NP",
15
+ "20": "WD",
16
+ "30": "CD",
17
+ "40": "DIS",
18
+ "50": "FDIS",
19
+ "60": "IS",
20
+ "90": "(Review)",
21
+ "95": "(Withdrawal)",
22
+ }.freeze
23
+
24
+ STAGE_NAMES = {
25
+ "00": "Preliminary work item",
26
+ "10": "New work item proposal",
27
+ "20": "Working draft",
28
+ "30": "Committee draft",
29
+ "40": "Draft",
30
+ "50": "Final draft",
31
+ "60": "International standard",
32
+ "90": "Review",
33
+ "95": "Withdrawal",
34
+ }.freeze
35
+
36
+ def stage_abbr(stage, substage, doctype)
37
+ return nil if stage.to_i > 60
38
+
39
+ ret = STAGE_ABBRS[stage.to_sym]
40
+ ret = "PRF" if stage == "60" && substage == "00"
41
+ ret = "AWI" if stage == "10" && substage == "99"
42
+ if %w(amendment technical-corrigendum technical-report
43
+ technical-specification).include?(doctype)
44
+ ret = "D" if stage == "40" && doctype == "amendment"
45
+ ret = "FD" if stage == "50" && %w(amendment technical-corrigendum)
46
+ .include?(doctype)
47
+ end
48
+ ret
49
+ end
50
+
51
+ def stage_name(stage, substage, _doctype, iteration = nil)
52
+ return "Proof" if stage == "60" && substage == "00"
53
+
54
+ ret = STAGE_NAMES[stage.to_sym]
55
+ if iteration && %w(20 30).include?(stage)
56
+ prefix = iteration.to_i.localize(@lang.to_sym)
57
+ .to_rbnf_s("SpelloutRules", "spellout-ordinal")
58
+ ret = "#{prefix.capitalize} #{ret.downcase}"
59
+ end
60
+ ret
61
+ end
62
+
63
+ def metadata_id(node, xml)
64
+ iso_id(node, xml)
65
+ node&.attr("tc-docnumber")&.split(/,\s*/)&.each do |n|
66
+ xml.docidentifier(n, **attr_code(type: "iso-tc"))
67
+ end
68
+ xml.docnumber node&.attr("docnumber")
69
+ end
70
+
71
+ def iso_id(node, xml)
72
+ (!@amd && node.attr("docnumber")) || (@amd && node.attr("updates")) or
73
+ return
74
+
75
+ dn = iso_id1(node)
76
+ dn1 = id_stage_prefix(dn, node, false)
77
+ dn2 = id_stage_prefix(dn, node, true)
78
+ xml.docidentifier dn1, **attr_code(type: "ISO")
79
+ xml.docidentifier(id_langsuffix(dn1, node),
80
+ **attr_code(type: "iso-with-lang"))
81
+ xml.docidentifier(id_langsuffix(dn2, node),
82
+ **attr_code(type: "iso-reference"))
83
+ end
84
+
85
+ def iso_id1(node)
86
+ if @amd
87
+ dn = node.attr("updates")
88
+ add_amd_parts(dn, node)
89
+ else
90
+ part, subpart = node&.attr("partnumber")&.split(/-/)
91
+ add_id_parts(node.attr("docnumber"), part, subpart)
92
+ end
93
+ end
94
+
95
+ def add_amd_parts(docnum, node)
96
+ case doctype(node)
97
+ when "amendment"
98
+ "#{docnum}/Amd #{node.attr('amendment-number')}"
99
+ when "technical-corrigendum"
100
+ "#{docnum}/Cor.#{node.attr('corrigendum-number')}"
101
+ end
102
+ end
103
+
104
+ def id_langsuffix(docnum, node)
105
+ lang = node.attr("language") || "en"
106
+ suffix = case lang
107
+ when "en" then "(E)"
108
+ when "fr" then "(F)"
109
+ else
110
+ "(X)"
111
+ end
112
+ "#{docnum}#{suffix}"
113
+ end
114
+
115
+ def structured_id(node, xml)
116
+ return unless node.attr("docnumber")
117
+
118
+ part, subpart = node&.attr("partnumber")&.split(/-/)
119
+ xml.structuredidentifier do |i|
120
+ i.project_number(node.attr("docnumber"), **attr_code(
121
+ part: part, subpart: subpart,
122
+ amendment: node.attr("amendment-number"),
123
+ corrigendum: node.attr("corrigendum-number"),
124
+ origyr: node.attr("created-date")
125
+ ))
126
+ end
127
+ end
128
+
129
+ def add_id_parts(docnum, part, subpart)
130
+ docnum += "-#{part}" if part
131
+ docnum += "-#{subpart}" if subpart
132
+ docnum
133
+ end
134
+
135
+ def id_stage_abbr(stage, substage, node, bare = false)
136
+ ret = id_stage_abbr1(stage, substage, node, bare)
137
+ if %w(amendment technical-corrigendum technical-report
138
+ technical-specification).include?(doctype(node)) &&
139
+ !%w(D FD).include?(ret)
140
+ ret = "#{ret} "
141
+ end
142
+ ret
143
+ end
144
+
145
+ def id_stage_abbr1(stage, substage, node, bare)
146
+ if bare
147
+ IsoDoc::Iso::Metadata.new("en", "Latn", @i18n)
148
+ .status_abbrev(stage_abbr(stage, substage, doctype(node)),
149
+ substage, nil, nil, doctype(node))
150
+ else
151
+ IsoDoc::Iso::Metadata.new("en", "Latn", @i18n)
152
+ .status_abbrev(stage_abbr(stage, substage, doctype(node)),
153
+ substage, node.attr("iteration"),
154
+ node.attr("draft"), doctype(node))
155
+ end
156
+ end
157
+
158
+ def cover_stage_abbr(node)
159
+ stage = get_stage(node)
160
+ abbr = id_stage_abbr(get_stage(node), get_substage(node), node, true)
161
+ typeabbr = get_typeabbr(node, true)
162
+ if stage.to_i > 50 || (stage.to_i == 60 && get_substage(node).to_i < 60)
163
+ typeabbr = ""
164
+ end
165
+ "#{abbr}#{typeabbr}".strip
166
+ end
167
+
168
+ def id_stage_prefix(docnum, node, force_year)
169
+ stage = get_stage(node)
170
+ typeabbr = get_typeabbr(node)
171
+ if stage && (stage.to_i < 60)
172
+ docnum = unpub_stage_prefix(docnum, stage, typeabbr, node)
173
+ elsif typeabbr == "DIR " then docnum = "#{typeabbr}#{docnum}"
174
+ elsif typeabbr && !@amd then docnum = "/#{typeabbr}#{docnum}"
175
+ end
176
+ (force_year || !(stage && (stage.to_i < 60))) and
177
+ docnum = id_add_year(docnum, node)
178
+ docnum
179
+ end
180
+
181
+ def unpub_stage_prefix(docnum, stage, typeabbr, node)
182
+ abbr = id_stage_abbr(stage, get_substage(node), node)
183
+ %w(40 50).include?(stage) && i = node.attr("iteration") and
184
+ itersuffix = ".#{i}"
185
+ return docnum if abbr.nil? || abbr.empty? # prefixes added in cleanup
186
+ return "/#{abbr}#{typeabbr} #{docnum}#{itersuffix}" unless @amd
187
+
188
+ a = docnum.split(%r{/})
189
+ a[-1] = "#{abbr}#{a[-1]}#{itersuffix}"
190
+ a.join("/")
191
+ end
192
+
193
+ def id_add_year(docnum, node)
194
+ year = node.attr("copyright-year")
195
+ @amd and year ||= node.attr("updated-date")&.sub(/-.*$/, "")
196
+ docnum += ":#{year}" if year
197
+ docnum
198
+ end
199
+
200
+ def get_stage(node)
201
+ a = node.attr("status")
202
+ a = node.attr("docstage") if a.nil? || a.empty?
203
+ a = "60" if a.nil? || a.empty?
204
+ a
205
+ end
206
+
207
+ def get_substage(node)
208
+ stage = get_stage(node)
209
+ ret = node.attr("docsubstage")
210
+ ret = (stage == "60" ? "60" : "00") if ret.nil? || ret.empty?
211
+ ret
212
+ end
213
+
214
+ def get_typeabbr(node, amd = false)
215
+ case doctype(node)
216
+ when "directive" then "DIR "
217
+ when "technical-report" then "TR "
218
+ when "technical-specification" then "TS "
219
+ when "amendment" then (amd ? "Amd " : "")
220
+ when "technical-corrigendum" then (amd ? "Cor " : "")
221
+ end
222
+ end
223
+ end
224
+ end
225
+ end