metanorma-ietf 1.0.10 → 2.0.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 (54) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/macos.yml +3 -2
  3. data/.github/workflows/ubuntu.yml +3 -2
  4. data/.github/workflows/windows.yml +4 -3
  5. data/README.adoc +9 -0
  6. data/lib/asciidoctor/ietf/basicdoc.rng +1045 -0
  7. data/lib/asciidoctor/ietf/biblio.rng +1142 -0
  8. data/lib/asciidoctor/ietf/blocks.rb +76 -0
  9. data/lib/asciidoctor/ietf/converter.rb +211 -0
  10. data/lib/asciidoctor/ietf/front.rb +143 -0
  11. data/lib/asciidoctor/ietf/ietf.rng +882 -0
  12. data/lib/asciidoctor/ietf/isodoc.rng +514 -0
  13. data/lib/asciidoctor/ietf/isostandard.rng +860 -0
  14. data/lib/asciidoctor/ietf/reqt.rng +171 -0
  15. data/lib/asciidoctor/ietf/validate.rb +84 -0
  16. data/lib/isodoc/ietf/blocks.rb +215 -0
  17. data/lib/isodoc/ietf/cleanup.rb +220 -0
  18. data/lib/isodoc/ietf/footnotes.rb +70 -0
  19. data/lib/isodoc/ietf/front.rb +232 -0
  20. data/lib/isodoc/ietf/inline.rb +136 -0
  21. data/lib/isodoc/ietf/metadata.rb +62 -0
  22. data/lib/isodoc/ietf/references.rb +129 -0
  23. data/lib/isodoc/ietf/reqt.rb +74 -0
  24. data/lib/isodoc/ietf/rfc_convert.rb +60 -0
  25. data/lib/isodoc/ietf/section.rb +162 -0
  26. data/lib/isodoc/ietf/table.rb +43 -0
  27. data/lib/isodoc/ietf/terms.rb +65 -0
  28. data/lib/metanorma-ietf.rb +2 -1
  29. data/lib/metanorma/ietf/processor.rb +16 -37
  30. data/lib/metanorma/ietf/version.rb +1 -1
  31. data/metanorma-ietf.gemspec +3 -3
  32. metadata +36 -36
  33. data/Gemfile.lock +0 -327
  34. data/lib/asciidoctor/rfc.rb +0 -8
  35. data/lib/asciidoctor/rfc/common/base.rb +0 -544
  36. data/lib/asciidoctor/rfc/common/front.rb +0 -120
  37. data/lib/asciidoctor/rfc/common/validate.rb +0 -31
  38. data/lib/asciidoctor/rfc/v2/base.rb +0 -380
  39. data/lib/asciidoctor/rfc/v2/blocks.rb +0 -299
  40. data/lib/asciidoctor/rfc/v2/converter.rb +0 -60
  41. data/lib/asciidoctor/rfc/v2/front.rb +0 -69
  42. data/lib/asciidoctor/rfc/v2/inline_anchor.rb +0 -111
  43. data/lib/asciidoctor/rfc/v2/lists.rb +0 -135
  44. data/lib/asciidoctor/rfc/v2/table.rb +0 -116
  45. data/lib/asciidoctor/rfc/v2/validate.rng +0 -716
  46. data/lib/asciidoctor/rfc/v3/base.rb +0 -330
  47. data/lib/asciidoctor/rfc/v3/blocks.rb +0 -246
  48. data/lib/asciidoctor/rfc/v3/converter.rb +0 -62
  49. data/lib/asciidoctor/rfc/v3/front.rb +0 -122
  50. data/lib/asciidoctor/rfc/v3/inline_anchor.rb +0 -89
  51. data/lib/asciidoctor/rfc/v3/lists.rb +0 -176
  52. data/lib/asciidoctor/rfc/v3/svg.rng +0 -9081
  53. data/lib/asciidoctor/rfc/v3/table.rb +0 -65
  54. data/lib/asciidoctor/rfc/v3/validate.rng +0 -2143
@@ -0,0 +1,171 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <grammar xmlns="http://relaxng.org/ns/structure/1.0" datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes">
3
+ <!--
4
+ Presupposes isodoc.rnc, is included in it
5
+ include "isodoc.rnc" { }
6
+ -->
7
+ <define name="requirement">
8
+ <element name="requirement">
9
+ <ref name="RequirementType"/>
10
+ </element>
11
+ </define>
12
+ <define name="recommendation">
13
+ <element name="recommendation">
14
+ <ref name="RequirementType"/>
15
+ </element>
16
+ </define>
17
+ <define name="permission">
18
+ <element name="permission">
19
+ <ref name="RequirementType"/>
20
+ </element>
21
+ </define>
22
+ <define name="RequirementType">
23
+ <optional>
24
+ <attribute name="obligation">
25
+ <ref name="ObligationType"/>
26
+ </attribute>
27
+ </optional>
28
+ <optional>
29
+ <attribute name="unnumbered">
30
+ <data type="boolean"/>
31
+ </attribute>
32
+ </optional>
33
+ <optional>
34
+ <attribute name="subsequence"/>
35
+ </optional>
36
+ <attribute name="id">
37
+ <data type="ID"/>
38
+ </attribute>
39
+ <optional>
40
+ <attribute name="filename"/>
41
+ </optional>
42
+ <optional>
43
+ <attribute name="model"/>
44
+ </optional>
45
+ <optional>
46
+ <attribute name="type"/>
47
+ </optional>
48
+ <optional>
49
+ <ref name="reqtitle"/>
50
+ </optional>
51
+ <optional>
52
+ <ref name="label"/>
53
+ </optional>
54
+ <optional>
55
+ <ref name="subject"/>
56
+ </optional>
57
+ <optional>
58
+ <ref name="reqinherit"/>
59
+ </optional>
60
+ <zeroOrMore>
61
+ <ref name="classification"/>
62
+ </zeroOrMore>
63
+ <zeroOrMore>
64
+ <choice>
65
+ <ref name="measurementtarget"/>
66
+ <ref name="specification"/>
67
+ <ref name="verification"/>
68
+ <ref name="import"/>
69
+ <ref name="description"/>
70
+ </choice>
71
+ </zeroOrMore>
72
+ <optional>
73
+ <ref name="reqt_references"/>
74
+ </optional>
75
+ <zeroOrMore>
76
+ <choice>
77
+ <ref name="requirement"/>
78
+ <ref name="recommendation"/>
79
+ <ref name="permission"/>
80
+ </choice>
81
+ </zeroOrMore>
82
+ </define>
83
+ <define name="reqtitle">
84
+ <element name="title">
85
+ <ref name="FormattedString"/>
86
+ </element>
87
+ </define>
88
+ <define name="label">
89
+ <element name="label">
90
+ <text/>
91
+ </element>
92
+ </define>
93
+ <define name="subject">
94
+ <element name="subject">
95
+ <text/>
96
+ </element>
97
+ </define>
98
+ <define name="reqinherit">
99
+ <element name="inherit">
100
+ <text/>
101
+ </element>
102
+ </define>
103
+ <define name="measurementtarget">
104
+ <element name="measurement-target">
105
+ <ref name="RequirementSubpart"/>
106
+ </element>
107
+ </define>
108
+ <define name="specification">
109
+ <element name="specification">
110
+ <ref name="RequirementSubpart"/>
111
+ </element>
112
+ </define>
113
+ <define name="verification">
114
+ <element name="verification">
115
+ <ref name="RequirementSubpart"/>
116
+ </element>
117
+ </define>
118
+ <define name="import">
119
+ <element name="import">
120
+ <ref name="RequirementSubpart"/>
121
+ </element>
122
+ </define>
123
+ <define name="description">
124
+ <element name="description">
125
+ <ref name="RequirementSubpart"/>
126
+ </element>
127
+ </define>
128
+ <define name="reqt_references">
129
+ <element name="references">
130
+ <oneOrMore>
131
+ <ref name="bibitem"/>
132
+ </oneOrMore>
133
+ </element>
134
+ </define>
135
+ <define name="RequirementSubpart">
136
+ <optional>
137
+ <attribute name="type"/>
138
+ </optional>
139
+ <optional>
140
+ <attribute name="exclude">
141
+ <data type="boolean"/>
142
+ </attribute>
143
+ </optional>
144
+ <oneOrMore>
145
+ <ref name="BasicBlock"/>
146
+ </oneOrMore>
147
+ </define>
148
+ <define name="ObligationType">
149
+ <choice>
150
+ <value>requirement</value>
151
+ <value>recommendation</value>
152
+ <value>permission</value>
153
+ </choice>
154
+ </define>
155
+ <define name="classification">
156
+ <element name="classification">
157
+ <ref name="classification_tag"/>
158
+ <ref name="classification_value"/>
159
+ </element>
160
+ </define>
161
+ <define name="classification_tag">
162
+ <element name="tag">
163
+ <text/>
164
+ </element>
165
+ </define>
166
+ <define name="classification_value">
167
+ <element name="value">
168
+ <text/>
169
+ </element>
170
+ </define>
171
+ </grammar>
@@ -0,0 +1,84 @@
1
+ module Asciidoctor
2
+ module Ietf
3
+ class Converter < ::Asciidoctor::Standoc::Converter
4
+ def content_validate(doc)
5
+ super
6
+ image_validate(doc)
7
+ workgroup_validate(doc)
8
+ end
9
+
10
+ def image_validate(doc)
11
+ doc.xpath("//image").each do |i|
12
+ next if i["mimetype"] == "image/svg+xml"
13
+ warn "image #{i['src'][0, 40]} is not SVG!"
14
+ end
15
+ end
16
+
17
+ def workgroup_validate(doc)
18
+ return if @workgroups.empty?
19
+ doc.xpath("//bibdata/ext/editorialgroup/workgroup").each do |wg|
20
+ wg_norm = wg.text.sub(/ (Working|Research) Group$/, "")
21
+ next if @workgroups.include?(wg_norm)
22
+ warn "IETF: unrecognised working group #{wg.text}"
23
+ end
24
+ end
25
+
26
+ def validate(doc)
27
+ content_validate(doc)
28
+ schema_validate(formattedstr_strip(doc.dup),
29
+ File.join(File.dirname(__FILE__), "ietf.rng"))
30
+ end
31
+
32
+ def open_wg_cache(node)
33
+ wgcache_name = "#{Dir.home}/.metanorma-ietf-workgroup-cache.json"
34
+ node.attr("flush-caches") == "true" and FileUtils.rm wgcache_name, :force => true
35
+ wg = []
36
+ if Pathname.new(wgcache_name).file?
37
+ begin
38
+ File.open(wgcache_name, "r") { |f| wg = JSON.parse(f.read) }
39
+ rescue Exception => e
40
+ STDERR.puts "Cache #{wgcache_name} is invalid, drop it"
41
+ end
42
+ end
43
+ [wg, wgcache_name]
44
+ end
45
+
46
+ def cache_workgroup_ietf(wg, b)
47
+ STDERR.puts "Reading workgroups from https://tools.ietf.org/wg/..."
48
+ Kernel.open("https://tools.ietf.org/wg/") do |f|
49
+ f.each_line do |line|
50
+ line.scan(%r{<td width="50%" style='padding: 0 1ex'>([^<]+)</td>}) do |w|
51
+ wg << w[0].gsub(/\s+$/, "").gsub(/ Working Group$/, "")
52
+ end
53
+ end
54
+ end
55
+ wg
56
+ end
57
+
58
+ def cache_workgroup_irtf(wg, b)
59
+ STDERR.puts "Reading workgroups from https://irtf.org/groups..."
60
+ Kernel.open("https://irtf.org/groups", ssl_verify_mode: OpenSSL::SSL::VERIFY_NONE) do |f|
61
+ f.each_line do |line|
62
+ line.scan(%r{<a title="([^"]+) Research Group"[^>]+>([^<]+)<}) do |w|
63
+ wg << w[0].gsub(/\s+$/, "")
64
+ wg << w[1].gsub(/\s+$/, "") # abbrev
65
+ end
66
+ end
67
+ end
68
+ wg
69
+ end
70
+
71
+ def cache_workgroup(node)
72
+ wg, wgcache_name = open_wg_cache(node)
73
+ if wg.empty?
74
+ File.open(wgcache_name, "w") do |b|
75
+ wg = cache_workgroup_ietf(wg, b)
76
+ wg = cache_workgroup_irtf(wg, b)
77
+ b << wg.to_json
78
+ end
79
+ end
80
+ wg
81
+ end
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,215 @@
1
+ module IsoDoc::Ietf
2
+ class RfcConvert < ::IsoDoc::Convert
3
+ def para_attrs(node)
4
+ { keepWithNext: node["keepWithNext"],
5
+ keepWithPrevious: node["keepWithPrevious"],
6
+ anchor: node["id"] }
7
+ end
8
+
9
+ def para_parse(node, out)
10
+ out.t **attr_code(para_attrs(node)) do |p|
11
+ unless @termdomain.empty?
12
+ p << "&lt;#{@termdomain}&gt; "
13
+ @termdomain = ""
14
+ end
15
+ node.children.each { |n| parse(n, p) }
16
+ end
17
+ end
18
+
19
+ # NOTE ignoring "bare" attribute, which is tantamount to "empty"
20
+ def ul_attrs(node)
21
+ { anchor: node["id"],
22
+ empty: node["nobullet"],
23
+ spacing: node["spacing"] }
24
+ end
25
+
26
+ def ul_parse(node, out)
27
+ out.ul **attr_code(ul_attrs(node)) do |ul|
28
+ node.children.each { |n| parse(n, ul) }
29
+ end
30
+ end
31
+
32
+ OL_STYLE = {
33
+ arabic: "1",
34
+ roman: "i",
35
+ alphabet: "a",
36
+ roman_upper: "I",
37
+ alphabet_upper: "A",
38
+ }.freeze
39
+
40
+ def ol_style(type)
41
+ OL_STYLE[type&.to_sym] || type
42
+ end
43
+
44
+ def ol_attrs(node)
45
+ { anchor: node["id"],
46
+ spacing: node["spacing"],
47
+ type: ol_style(node["type"]),
48
+ group: node["group"],
49
+ start: node["start"] }
50
+ end
51
+
52
+ def ol_parse(node, out)
53
+ out.ol **attr_code(ol_attrs(node)) do |ol|
54
+ node.children.each { |n| parse(n, ol) }
55
+ end
56
+ end
57
+
58
+ def dl_attr(node)
59
+ attr_code(anchor: node["id"],
60
+ newline: node["newline"],
61
+ indent: node["indent"],
62
+ spacing: node["spacing"])
63
+ end
64
+
65
+ def dt_parse(dt, term)
66
+ if dt.elements.empty?
67
+ term << dt.text
68
+ else
69
+ dt.children.each { |n| parse(n, term) }
70
+ end
71
+ end
72
+
73
+ def note_label(node)
74
+ l10n("#{super}: ")
75
+ end
76
+
77
+ def note_parse(node, out)
78
+ first = node.first_element_child
79
+ out.aside **attr_code(anchor: node["id"] || first["id"]) do |a|
80
+ a.t do |p|
81
+ p << note_label(node)
82
+ first.name == "p" and first.children.each { |n| parse(n, p) }
83
+ end
84
+ first.name == "p" and
85
+ node.elements.drop(1).each { |n| parse(n, out) } or
86
+ node.children.each { |n| parse(n, out) }
87
+ end
88
+ end
89
+
90
+ def example_parse(node, out)
91
+ example_label(node, out, node.at(ns("./name")))
92
+ node.elements.each { |n| parse(n, out) unless n.name == "name" }
93
+ end
94
+
95
+ def example_label(node, div, name)
96
+ n = get_anchors[node["id"]]
97
+ div.t **attr_code(anchor: node["id"], keepWithNext: "true") do |p|
98
+ lbl = (n.nil? || n[:label].nil? || n[:label].empty?) ? @example_lbl :
99
+ l10n("#{@example_lbl} #{n[:label]}")
100
+ p << lbl
101
+ name and !lbl.nil? and p << ": "
102
+ name and name.children.each { |n| parse(n, p) }
103
+ end
104
+ end
105
+
106
+ def sourcecode_parse(node, out)
107
+ out.figure **attr_code(anchor: node["id"]) do |div|
108
+ name = node&.at(ns("./name"))&.remove and div.name do |n|
109
+ name.children.each { |nn| parse(nn, n) }
110
+ end
111
+ div.sourcecode **attr_code(type: node["lang"], name: node["filename"],
112
+ markers: node["markers"],
113
+ src: node["src"]) do |s|
114
+ node.children.each { |x| parse(x, s) unless x.name == "name" }
115
+ end
116
+ end
117
+ end
118
+
119
+ def pre_parse(node, out)
120
+ out.artwork **attr_code(anchor: node["id"], align: node["align"],
121
+ alt: node["alt"], type: "ascii-art") do |s|
122
+ s.cdata node.text.sub(/^\n/, "").gsub(/\t/, " ")
123
+ end
124
+ end
125
+
126
+ def annotation_parse(node, out)
127
+ @sourcecode = false
128
+ @annotation = true
129
+ node.at("./preceding-sibling::*[local-name() = 'annotation']") or
130
+ out << "\n\n"
131
+ callout = node.at(ns("//callout[@target='#{node['id']}']"))
132
+ out << "\n&lt;#{callout.text}&gt; "
133
+ out << node&.children&.text&.strip
134
+ @annotation = false
135
+ end
136
+
137
+ def formula_where(dl, out)
138
+ return unless dl
139
+ out.t { |p| p << @where_lbl }
140
+ parse(dl, out)
141
+ end
142
+
143
+ def formula_parse1(node, out)
144
+ out.t **attr_code(anchor: node["id"]) do |p|
145
+ parse(node.at(ns("./stem")), p)
146
+ lbl = anchor(node['id'], :label, false)
147
+ lbl.nil? or
148
+ p << " (#{lbl})"
149
+ end
150
+ end
151
+
152
+ def quote_attribution(node)
153
+ author = node&.at(ns("./author"))&.text
154
+ source = node&.at(ns("./source/@uri"))&.text
155
+ attr_code(quotedFrom: author, cite: source)
156
+ end
157
+
158
+ def quote_parse(node, out)
159
+ out.blockquote **quote_attribution(node) do |p|
160
+ node.children.each do |n|
161
+ parse(n, p) unless ["author", "source"].include? n.name
162
+ end
163
+ end
164
+ end
165
+
166
+ def admonition_name_parse(_node, div, name)
167
+ div.t **{keepWithNext: "true" } do |p|
168
+ name.children.each { |n| parse(n, p) }
169
+ end
170
+ end
171
+
172
+ def admonition_parse(node, out)
173
+ type = node["type"]
174
+ name = admonition_name(node, type)
175
+ out.aside **{ anchor: node["id"] } do |t|
176
+ admonition_name_parse(node, t, name) if name
177
+ node.children.each { |n| parse(n, t) unless n.name == "name" }
178
+ end
179
+ end
180
+
181
+ def review_note_parse(node, out)
182
+ out.cref **attr_code(anchor: node["id"], display: node["display"],
183
+ source: node["reviewer"]) do |c|
184
+ name = node.at(ns("./name")) and c.name do |div|
185
+ name.children.each { |n| parse(n, div) }
186
+ end
187
+ node.children.each { |n| parse(n, c) unless n.name == "name" }
188
+ end
189
+ end
190
+
191
+ def figure_name_parse(node, div, name)
192
+ return if name.nil?
193
+ div.name do |n|
194
+ name.children.each { |n| parse(n, div) }
195
+ end
196
+ end
197
+
198
+ def pseudocode_parse(node, out)
199
+ sourcecode_parse(node, out)
200
+ end
201
+
202
+ def figure_parse(node, out)
203
+ return pseudocode_parse(node, out) if node["class"] == "pseudocode" ||
204
+ node["type"] == "pseudocode"
205
+ @in_figure = true
206
+ out.figure **attr_code(anchor: node["id"]) do |div|
207
+ figure_name_parse(node, div, node.at(ns("./name")))
208
+ node.children.each do |n|
209
+ parse(n, div) unless n.name == "name"
210
+ end
211
+ end
212
+ @in_figure = false
213
+ end
214
+ end
215
+ end