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.
- checksums.yaml +4 -4
- data/.github/workflows/macos.yml +3 -2
- data/.github/workflows/ubuntu.yml +3 -2
- data/.github/workflows/windows.yml +4 -3
- data/README.adoc +9 -0
- data/lib/asciidoctor/ietf/basicdoc.rng +1045 -0
- data/lib/asciidoctor/ietf/biblio.rng +1142 -0
- data/lib/asciidoctor/ietf/blocks.rb +76 -0
- data/lib/asciidoctor/ietf/converter.rb +211 -0
- data/lib/asciidoctor/ietf/front.rb +143 -0
- data/lib/asciidoctor/ietf/ietf.rng +882 -0
- data/lib/asciidoctor/ietf/isodoc.rng +514 -0
- data/lib/asciidoctor/ietf/isostandard.rng +860 -0
- data/lib/asciidoctor/ietf/reqt.rng +171 -0
- data/lib/asciidoctor/ietf/validate.rb +84 -0
- data/lib/isodoc/ietf/blocks.rb +215 -0
- data/lib/isodoc/ietf/cleanup.rb +220 -0
- data/lib/isodoc/ietf/footnotes.rb +70 -0
- data/lib/isodoc/ietf/front.rb +232 -0
- data/lib/isodoc/ietf/inline.rb +136 -0
- data/lib/isodoc/ietf/metadata.rb +62 -0
- data/lib/isodoc/ietf/references.rb +129 -0
- data/lib/isodoc/ietf/reqt.rb +74 -0
- data/lib/isodoc/ietf/rfc_convert.rb +60 -0
- data/lib/isodoc/ietf/section.rb +162 -0
- data/lib/isodoc/ietf/table.rb +43 -0
- data/lib/isodoc/ietf/terms.rb +65 -0
- data/lib/metanorma-ietf.rb +2 -1
- data/lib/metanorma/ietf/processor.rb +16 -37
- data/lib/metanorma/ietf/version.rb +1 -1
- data/metanorma-ietf.gemspec +3 -3
- metadata +36 -36
- data/Gemfile.lock +0 -327
- data/lib/asciidoctor/rfc.rb +0 -8
- data/lib/asciidoctor/rfc/common/base.rb +0 -544
- data/lib/asciidoctor/rfc/common/front.rb +0 -120
- data/lib/asciidoctor/rfc/common/validate.rb +0 -31
- data/lib/asciidoctor/rfc/v2/base.rb +0 -380
- data/lib/asciidoctor/rfc/v2/blocks.rb +0 -299
- data/lib/asciidoctor/rfc/v2/converter.rb +0 -60
- data/lib/asciidoctor/rfc/v2/front.rb +0 -69
- data/lib/asciidoctor/rfc/v2/inline_anchor.rb +0 -111
- data/lib/asciidoctor/rfc/v2/lists.rb +0 -135
- data/lib/asciidoctor/rfc/v2/table.rb +0 -116
- data/lib/asciidoctor/rfc/v2/validate.rng +0 -716
- data/lib/asciidoctor/rfc/v3/base.rb +0 -330
- data/lib/asciidoctor/rfc/v3/blocks.rb +0 -246
- data/lib/asciidoctor/rfc/v3/converter.rb +0 -62
- data/lib/asciidoctor/rfc/v3/front.rb +0 -122
- data/lib/asciidoctor/rfc/v3/inline_anchor.rb +0 -89
- data/lib/asciidoctor/rfc/v3/lists.rb +0 -176
- data/lib/asciidoctor/rfc/v3/svg.rng +0 -9081
- data/lib/asciidoctor/rfc/v3/table.rb +0 -65
- 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 << "<#{@termdomain}> "
|
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<#{callout.text}> "
|
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
|