metanorma-ietf 1.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 +7 -0
- data/.gitignore +18 -0
- data/.hound.yml +3 -0
- data/.oss-guides.rubocop.yml +1077 -0
- data/.rspec +2 -0
- data/.rubocop.ribose.yml +65 -0
- data/.rubocop.tb.yml +650 -0
- data/.rubocop.yml +15 -0
- data/.travis.yml +23 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/Gemfile +4 -0
- data/Guardfile +22 -0
- data/LICENSE +25 -0
- data/README.adoc +1660 -0
- data/Rakefile +6 -0
- data/bin/asciidoctor-rfc2 +14 -0
- data/bin/asciidoctor-rfc3 +14 -0
- data/bin/console +14 -0
- data/bin/rspec +17 -0
- data/bin/setup +8 -0
- data/docs/installation.md +21 -0
- data/docs/navigation.md +10 -0
- data/docs/overview.md +5 -0
- data/lib/asciidoctor/rfc.rb +8 -0
- data/lib/asciidoctor/rfc/common/base.rb +531 -0
- data/lib/asciidoctor/rfc/common/front.rb +120 -0
- data/lib/asciidoctor/rfc/v2/base.rb +379 -0
- data/lib/asciidoctor/rfc/v2/blocks.rb +261 -0
- data/lib/asciidoctor/rfc/v2/converter.rb +60 -0
- data/lib/asciidoctor/rfc/v2/front.rb +69 -0
- data/lib/asciidoctor/rfc/v2/inline_anchor.rb +111 -0
- data/lib/asciidoctor/rfc/v2/lists.rb +135 -0
- data/lib/asciidoctor/rfc/v2/table.rb +114 -0
- data/lib/asciidoctor/rfc/v2/validate.rb +32 -0
- data/lib/asciidoctor/rfc/v2/validate2.rng +716 -0
- data/lib/asciidoctor/rfc/v3/base.rb +329 -0
- data/lib/asciidoctor/rfc/v3/blocks.rb +246 -0
- data/lib/asciidoctor/rfc/v3/converter.rb +62 -0
- data/lib/asciidoctor/rfc/v3/front.rb +122 -0
- data/lib/asciidoctor/rfc/v3/inline_anchor.rb +89 -0
- data/lib/asciidoctor/rfc/v3/lists.rb +176 -0
- data/lib/asciidoctor/rfc/v3/svg.rng +9081 -0
- data/lib/asciidoctor/rfc/v3/table.rb +65 -0
- data/lib/asciidoctor/rfc/v3/validate.rb +34 -0
- data/lib/asciidoctor/rfc/v3/validate.rng +2143 -0
- data/lib/metanorma-ietf.rb +7 -0
- data/lib/metanorma/ietf.rb +8 -0
- data/lib/metanorma/ietf/processor.rb +89 -0
- data/lib/metanorma/ietf/version.rb +5 -0
- data/metanorma-ietf.gemspec +51 -0
- data/rfc2629-other.ent +61 -0
- data/rfc2629-xhtml.ent +165 -0
- data/rfc2629.dtd +312 -0
- metadata +289 -0
@@ -0,0 +1,62 @@
|
|
1
|
+
require "asciidoctor"
|
2
|
+
|
3
|
+
require_relative "../common/base"
|
4
|
+
require_relative "../common/front"
|
5
|
+
require_relative "base"
|
6
|
+
require_relative "blocks"
|
7
|
+
require_relative "front"
|
8
|
+
require_relative "inline_anchor"
|
9
|
+
require_relative "lists"
|
10
|
+
require_relative "table"
|
11
|
+
require_relative "validate"
|
12
|
+
|
13
|
+
module Asciidoctor
|
14
|
+
module Rfc::V3
|
15
|
+
# A {Converter} implementation that generates RFC XML output, a format used to
|
16
|
+
# format RFC proposals (https://tools.ietf.org/html/rfc7991)
|
17
|
+
#
|
18
|
+
# Features drawn from https://github.com/miekg/mmark/wiki/Syntax and
|
19
|
+
# https://github.com/riboseinc/rfc2md
|
20
|
+
class Converter
|
21
|
+
include ::Asciidoctor::Converter
|
22
|
+
include ::Asciidoctor::Writer
|
23
|
+
|
24
|
+
include ::Asciidoctor::Rfc::Common::Base
|
25
|
+
include ::Asciidoctor::Rfc::Common::Front
|
26
|
+
include ::Asciidoctor::Rfc::V3::Base
|
27
|
+
include ::Asciidoctor::Rfc::V3::Blocks
|
28
|
+
include ::Asciidoctor::Rfc::V3::Front
|
29
|
+
include ::Asciidoctor::Rfc::V3::InlineAnchor
|
30
|
+
include ::Asciidoctor::Rfc::V3::Lists
|
31
|
+
include ::Asciidoctor::Rfc::V3::Table
|
32
|
+
include ::Asciidoctor::Rfc::V3::Validate
|
33
|
+
|
34
|
+
register_for "rfc3"
|
35
|
+
|
36
|
+
$seen_back_matter = false
|
37
|
+
$xreftext = {}
|
38
|
+
|
39
|
+
def initialize(backend, opts)
|
40
|
+
super
|
41
|
+
# enable when Asciidoctor 1.5.7 is released
|
42
|
+
Asciidoctor::Compliance.natural_xrefs = false
|
43
|
+
# basebackend 'html'
|
44
|
+
outfilesuffix ".xml"
|
45
|
+
end
|
46
|
+
|
47
|
+
# alias_method :pass, :content
|
48
|
+
alias_method :embedded, :content
|
49
|
+
alias_method :audio, :skip
|
50
|
+
alias_method :colist, :skip
|
51
|
+
alias_method :page_break, :skip
|
52
|
+
alias_method :thematic_break, :skip
|
53
|
+
alias_method :video, :skip
|
54
|
+
alias_method :inline_button, :skip
|
55
|
+
alias_method :inline_kbd, :skip
|
56
|
+
alias_method :inline_menu, :skip
|
57
|
+
alias_method :inline_image, :skip
|
58
|
+
|
59
|
+
alias_method :inline_callout, :content
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,122 @@
|
|
1
|
+
module Asciidoctor
|
2
|
+
module Rfc::V3
|
3
|
+
module Front
|
4
|
+
# Syntax:
|
5
|
+
# = Title
|
6
|
+
# Author
|
7
|
+
# :METADATA
|
8
|
+
def front(node, xml)
|
9
|
+
xml.front do |xml_front|
|
10
|
+
title node, xml_front
|
11
|
+
series_info node, xml_front
|
12
|
+
author node, xml_front
|
13
|
+
date node, xml_front
|
14
|
+
area node, xml_front
|
15
|
+
workgroup node, xml_front
|
16
|
+
keyword node, xml_front
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def series_info(node, xml)
|
21
|
+
docname = node.attr("name")
|
22
|
+
return if docname.nil? || docname&.empty?
|
23
|
+
is_rfc = docname =~ /^rfc-?/i || node.attr("doctype") == "rfc"
|
24
|
+
|
25
|
+
if is_rfc
|
26
|
+
name = docname.gsub(/^rfc-?/i, "")
|
27
|
+
nameattr = "RFC"
|
28
|
+
else
|
29
|
+
name = docname
|
30
|
+
nameattr = "Internet-Draft"
|
31
|
+
end
|
32
|
+
value = name.gsub(/\.[^\/]+$/, "")
|
33
|
+
|
34
|
+
seriesInfo_attributes = {
|
35
|
+
name: nameattr,
|
36
|
+
status: node.attr("status"),
|
37
|
+
stream: node.attr("submission-type") || "IETF",
|
38
|
+
value: value,
|
39
|
+
}
|
40
|
+
xml.seriesInfo **attr_code(seriesInfo_attributes)
|
41
|
+
|
42
|
+
intendedstatus = node.attr("intended-series")
|
43
|
+
if !is_rfc && !intendedstatus.nil?
|
44
|
+
unless intendedstatus =~ /^(standard|full-standard|bcp|fyi|informational|experimental|historic)$/
|
45
|
+
warn %(asciidoctor: WARNING (#{current_location(node)}): disallowed value for intended-series in document header: #{intendedstatus})
|
46
|
+
end
|
47
|
+
seriesInfo_attributes = {
|
48
|
+
name: "",
|
49
|
+
status: intendedstatus,
|
50
|
+
value: value,
|
51
|
+
}
|
52
|
+
xml.seriesInfo **attr_code(seriesInfo_attributes)
|
53
|
+
end
|
54
|
+
|
55
|
+
rfcstatus = intendedstatus
|
56
|
+
if is_rfc && !rfcstatus.nil?
|
57
|
+
m = /^(\S+) (\d+)$/.match rfcstatus
|
58
|
+
if m.nil?
|
59
|
+
rfcstatus = "exp" if rfcstatus == "experimental"
|
60
|
+
rfcstatus = "info" if rfcstatus == "informational"
|
61
|
+
warn %(asciidoctor: WARNING (#{current_location(node)}): disallowed value for intended-series in document header with no series number: #{rfcstatus}) unless rfcstatus =~ /^(info|exp|historic)$/
|
62
|
+
else
|
63
|
+
rfcstatus = m[1]
|
64
|
+
value = m[2]
|
65
|
+
warn %(asciidoctor: WARNING (#{current_location(node)}): disallowed value for intended-series in document header with series number: #{rfcstatus}) unless rfcstatus =~ /^(standard|full-standard|bcp)$/
|
66
|
+
end
|
67
|
+
seriesInfo_attributes = {
|
68
|
+
name: "",
|
69
|
+
status: rfcstatus,
|
70
|
+
value: value,
|
71
|
+
}
|
72
|
+
xml.seriesInfo **attr_code(seriesInfo_attributes)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def organization(node, suffix, xml)
|
77
|
+
organization = node.attr("organization#{suffix}")
|
78
|
+
xml.organization { |org| org << organization } unless organization.nil?
|
79
|
+
end
|
80
|
+
|
81
|
+
def address(node, suffix, xml)
|
82
|
+
email = node.attr("email#{suffix}")
|
83
|
+
facsimile = node.attr("fax#{suffix}")
|
84
|
+
phone = node.attr("phone#{suffix}")
|
85
|
+
postalline = node.attr("postal-line#{suffix}")
|
86
|
+
street = node.attr("street#{suffix}")
|
87
|
+
uri = node.attr("uri#{suffix}")
|
88
|
+
if [email, facsimile, phone, postalline, street, uri].any?
|
89
|
+
xml.address do |xml_address|
|
90
|
+
address1 node, suffix, xml_address if [postalline, street].any?
|
91
|
+
xml_address.phone { |p| p << phone } unless phone.nil?
|
92
|
+
xml_address.facsimile { |f| f << facsimile } unless facsimile.nil?
|
93
|
+
xml_address.email { |e| e << email } unless email.nil?
|
94
|
+
xml_address.uri { |u| u << uri } unless uri.nil?
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
private
|
100
|
+
|
101
|
+
def address1(node, suffix, xml_address)
|
102
|
+
postalline = node.attr("postal-line#{suffix}")
|
103
|
+
street = node.attr("street#{suffix}")
|
104
|
+
xml_address.postal do |xml_postal|
|
105
|
+
if postalline.nil?
|
106
|
+
city = node.attr("city#{suffix}")
|
107
|
+
code = node.attr("code#{suffix}")
|
108
|
+
country = node.attr("country#{suffix}")
|
109
|
+
region = node.attr("region#{suffix}")
|
110
|
+
street&.split("\\ ")&.each { |st| xml_postal.street { |s| s << st } }
|
111
|
+
xml_postal.city { |c| c << city } unless city.nil?
|
112
|
+
xml_postal.region { |r| r << region } unless region.nil?
|
113
|
+
xml_postal.code { |c| c << code } unless code.nil?
|
114
|
+
xml_postal.country { |c| c << country } unless country.nil?
|
115
|
+
else
|
116
|
+
postalline&.split("\\ ")&.each { |pl| xml_postal.postalLine { |p| p << pl } }
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
@@ -0,0 +1,89 @@
|
|
1
|
+
module Asciidoctor
|
2
|
+
module Rfc::V3
|
3
|
+
module InlineAnchor
|
4
|
+
def inline_anchor(node)
|
5
|
+
case node.type
|
6
|
+
when :xref
|
7
|
+
inline_anchor_xref node
|
8
|
+
when :link
|
9
|
+
inline_anchor_link node
|
10
|
+
when :bibref
|
11
|
+
inline_anchor_bibref node
|
12
|
+
when :ref
|
13
|
+
inline_anchor_ref node
|
14
|
+
else
|
15
|
+
warn %(asciidoctor: WARNING (#{current_location(node)}): unknown anchor type: #{node.type.inspect})
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def inline_anchor_xref(node)
|
22
|
+
text = node.text
|
23
|
+
if text =~ /^\S+ (of|comma|parens|bare)\b/
|
24
|
+
# <<crossreference#fragment,section (of|comma|parens|bare): text>> = relref
|
25
|
+
matched = /(?<section>\S+)\s+(?<format>[a-z]+)(: )?(?<text>.*)$/.match node.text
|
26
|
+
|
27
|
+
relref_contents = matched[:text]
|
28
|
+
|
29
|
+
relref_attributes = {
|
30
|
+
relative: node.attributes["path"].nil? ? nil : node.attributes["fragment"],
|
31
|
+
section: matched[:section],
|
32
|
+
displayFormat: matched[:format],
|
33
|
+
# fragment inserts file suffix, e.g. rfc2911#fragment becomes rfc2911.xml#fragment
|
34
|
+
target: node.target.gsub(/^#/, "").gsub(/(.)(\.xml)?#.*$/, "\\1"),
|
35
|
+
}
|
36
|
+
|
37
|
+
noko do |xml|
|
38
|
+
xml.relref relref_contents, **attr_code(relref_attributes)
|
39
|
+
end.join
|
40
|
+
else
|
41
|
+
xref_contents = node.text
|
42
|
+
matched = /^format=(?<format>counter|title|none|default)(?<text>:\s*.*)?$/.match xref_contents
|
43
|
+
xref_contents = if matched.nil?
|
44
|
+
xref_contents
|
45
|
+
else
|
46
|
+
matched[:text].nil? ? "" : matched[:text].gsub(/^:\s*/, "")
|
47
|
+
end
|
48
|
+
|
49
|
+
warn %(asciidoctor: WARNING (#{current_location(node)}): fragments not supported on crossreferences in v3 without relref: #{node.target} #{node.text}) if node.target =~ /.#/
|
50
|
+
xref_attributes = {
|
51
|
+
format: matched&.[](:format),
|
52
|
+
target: node.target.gsub(/^#/, "").gsub(/(.)(\.xml)?#.*$/, "\\1"),
|
53
|
+
}
|
54
|
+
|
55
|
+
noko do |xml|
|
56
|
+
xml.xref xref_contents, **attr_code(xref_attributes)
|
57
|
+
end.join
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def inline_anchor_link(node)
|
62
|
+
eref_contents = node.target == node.text ? nil : node.text
|
63
|
+
eref_attributes = {
|
64
|
+
target: node.target,
|
65
|
+
}
|
66
|
+
|
67
|
+
noko do |xml|
|
68
|
+
xml.eref eref_contents, **attr_code(eref_attributes)
|
69
|
+
end.join
|
70
|
+
end
|
71
|
+
|
72
|
+
def inline_anchor_bibref(node)
|
73
|
+
unless node.xreftext.nil?
|
74
|
+
x = node.xreftext.gsub(/^\[(.+)\]$/, "\\1")
|
75
|
+
if node.id != x
|
76
|
+
$xreftext[node.id] = x
|
77
|
+
end
|
78
|
+
end
|
79
|
+
# NOTE technically node.text should be node.reftext, but subs have already been applied to text
|
80
|
+
# %(<bibanchor="#{node.id}">) # will convert to anchor attribute upstream
|
81
|
+
nil
|
82
|
+
end
|
83
|
+
|
84
|
+
def inline_anchor_ref(node)
|
85
|
+
warn %(asciidoctor: WARNING (#{current_location(node)}): anchor "#{node.id}" is not in a place where XML RFC will recognise it as an anchor attribute)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
@@ -0,0 +1,176 @@
|
|
1
|
+
module Asciidoctor
|
2
|
+
module Rfc::V3
|
3
|
+
module Lists
|
4
|
+
# Syntax:
|
5
|
+
# * [[[ref1]]] A
|
6
|
+
# * [[[ref2]]] B
|
7
|
+
# * [[[ref3]]] (Referencegroup: no content)
|
8
|
+
# * [[[ref4]]] C
|
9
|
+
# * [[[ref4]]] D
|
10
|
+
# @note ulist repurposed as reference list
|
11
|
+
# def reflist(node)
|
12
|
+
# result = []
|
13
|
+
# if node.context == :ulist
|
14
|
+
# node.items.each do |item|
|
15
|
+
# # we expect the biblio anchor to be right at the start of the reference
|
16
|
+
# if item.blocks?
|
17
|
+
# # we expect any list to be embedded, and only one level of embedding
|
18
|
+
# # we expect no content in the referencegroup line other than the bibliographic anchor
|
19
|
+
# result << "<referencegroup>#{item.text}".gsub(/<referencegroup>\s*\[?<bibanchor="([^"]+)">\]?.*$/, "<referencegroup anchor=\"\\1\">")
|
20
|
+
# item.blocks.each { |b| result << reflist(b) }
|
21
|
+
# result << "</referencegroup>"
|
22
|
+
# else
|
23
|
+
# # quoteTitle = get_header_attribute item, "quoteTitle"
|
24
|
+
# # target = get_header_attribute item, "target"
|
25
|
+
# # annotation = get_header_attribute item, "annotation"
|
26
|
+
# # FIXME: [[[x]]] within embedded list is processed as [<bibref>]
|
27
|
+
# result << "<reference>#{item.text}</refcontent></reference>".gsub(/<reference>\s*\[?<bibanchor="([^"]+)">\]?\s*/, "<reference anchor=\"\\1\"><refcontent>")
|
28
|
+
# end
|
29
|
+
# end
|
30
|
+
# elsif node.context == :pass
|
31
|
+
# # we expect raw xml
|
32
|
+
# node.lines.each do |item|
|
33
|
+
# # undo XML substitution
|
34
|
+
# ref = item.gsub(/\</, "<").gsub(/\>/, ">")
|
35
|
+
# result << ref
|
36
|
+
# end
|
37
|
+
# else
|
38
|
+
# warn %(asciidoctor: WARNING: references are not a ulist or raw XML: #{node.context})
|
39
|
+
# end
|
40
|
+
# result
|
41
|
+
# end
|
42
|
+
|
43
|
+
# Syntax:
|
44
|
+
# [[id]]
|
45
|
+
# [empty=true,spacing=compact|normal] (optional)
|
46
|
+
# * A
|
47
|
+
# * B
|
48
|
+
def ulist(node)
|
49
|
+
result = []
|
50
|
+
|
51
|
+
result << noko do |xml|
|
52
|
+
ul_attributes = {
|
53
|
+
anchor: node.id,
|
54
|
+
empty: node.attr("empty"),
|
55
|
+
spacing: node.attr("spacing"),
|
56
|
+
}
|
57
|
+
|
58
|
+
xml.ul **attr_code(ul_attributes) do |xml_ul|
|
59
|
+
node.items.each do |item|
|
60
|
+
li_attributes = {
|
61
|
+
anchor: item.id,
|
62
|
+
}
|
63
|
+
|
64
|
+
xml_ul.li **attr_code(li_attributes) do |xml_li|
|
65
|
+
if item.blocks?
|
66
|
+
xml_li.t do |t|
|
67
|
+
t << item.text
|
68
|
+
end
|
69
|
+
xml_li << item.content
|
70
|
+
else
|
71
|
+
xml_li << item.text
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
result
|
79
|
+
end
|
80
|
+
|
81
|
+
OLIST_TYPES = Hash.new("1").merge(
|
82
|
+
arabic: "1",
|
83
|
+
# decimal: "1", # not supported
|
84
|
+
loweralpha: "a",
|
85
|
+
# lowergreek: "lower-greek", # not supported
|
86
|
+
lowerroman: "i",
|
87
|
+
upperalpha: "A",
|
88
|
+
upperroman: "I",
|
89
|
+
).freeze
|
90
|
+
|
91
|
+
# Syntax:
|
92
|
+
# [[id]]
|
93
|
+
# [start=n,group=n,spacing=normal|compact] (optional)
|
94
|
+
# . A
|
95
|
+
# . B
|
96
|
+
def olist(node)
|
97
|
+
result = []
|
98
|
+
|
99
|
+
result << noko do |xml|
|
100
|
+
type = OLIST_TYPES[node.style.to_sym]
|
101
|
+
type = node.attr("format") unless node.attr("format").nil?
|
102
|
+
ol_attributes = {
|
103
|
+
anchor: node.id,
|
104
|
+
start: node.attr("start"),
|
105
|
+
group: node.attr("group"),
|
106
|
+
type: type,
|
107
|
+
spacing: ("compact" if node.style == "compact") || node.attr("spacing"),
|
108
|
+
}
|
109
|
+
|
110
|
+
xml.ol **attr_code(ol_attributes) do |xml_ol|
|
111
|
+
node.items.each do |item|
|
112
|
+
li_attributes = {
|
113
|
+
anchor: item.id,
|
114
|
+
}
|
115
|
+
xml_ol.li **attr_code(li_attributes) do |xml_li|
|
116
|
+
if item.blocks?
|
117
|
+
xml_li.t do |t|
|
118
|
+
t << item.text
|
119
|
+
end
|
120
|
+
xml_li << item.content
|
121
|
+
else
|
122
|
+
xml_li << item.text
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
result
|
129
|
+
end
|
130
|
+
|
131
|
+
# Syntax:
|
132
|
+
# [[id]]
|
133
|
+
# [horizontal,compact] (optional)
|
134
|
+
# A:: B
|
135
|
+
# C:: D
|
136
|
+
def dlist(node)
|
137
|
+
result = []
|
138
|
+
|
139
|
+
result << noko do |xml|
|
140
|
+
dl_attributes = {
|
141
|
+
anchor: node.id,
|
142
|
+
hanging: ("true" if node.style == "horizontal"),
|
143
|
+
spacing: ("compact" if node.style == "compact"),
|
144
|
+
}
|
145
|
+
|
146
|
+
xml.dl **attr_code(dl_attributes) do |xml_dl|
|
147
|
+
node.items.each do |terms, dd|
|
148
|
+
terms.each_with_index do |dt, idx|
|
149
|
+
xml_dl.dt { |xml_dt| xml_dt << dt.text }
|
150
|
+
if idx < terms.size - 1
|
151
|
+
xml_dl.dd
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
if dd.nil?
|
156
|
+
xml_dl.dd
|
157
|
+
else
|
158
|
+
xml_dl.dd do |xml_dd|
|
159
|
+
if dd.blocks?
|
160
|
+
if dd.text?
|
161
|
+
xml_dd.t { |t| t << dd.text }
|
162
|
+
end
|
163
|
+
xml_dd << dd.content
|
164
|
+
else
|
165
|
+
xml_dd << dd.text
|
166
|
+
end
|
167
|
+
end
|
168
|
+
end
|
169
|
+
end
|
170
|
+
end
|
171
|
+
end
|
172
|
+
result
|
173
|
+
end
|
174
|
+
end
|
175
|
+
end
|
176
|
+
end
|