metanorma-ietf 1.0.10 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
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