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.
Files changed (54) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +18 -0
  3. data/.hound.yml +3 -0
  4. data/.oss-guides.rubocop.yml +1077 -0
  5. data/.rspec +2 -0
  6. data/.rubocop.ribose.yml +65 -0
  7. data/.rubocop.tb.yml +650 -0
  8. data/.rubocop.yml +15 -0
  9. data/.travis.yml +23 -0
  10. data/CODE_OF_CONDUCT.md +74 -0
  11. data/Gemfile +4 -0
  12. data/Guardfile +22 -0
  13. data/LICENSE +25 -0
  14. data/README.adoc +1660 -0
  15. data/Rakefile +6 -0
  16. data/bin/asciidoctor-rfc2 +14 -0
  17. data/bin/asciidoctor-rfc3 +14 -0
  18. data/bin/console +14 -0
  19. data/bin/rspec +17 -0
  20. data/bin/setup +8 -0
  21. data/docs/installation.md +21 -0
  22. data/docs/navigation.md +10 -0
  23. data/docs/overview.md +5 -0
  24. data/lib/asciidoctor/rfc.rb +8 -0
  25. data/lib/asciidoctor/rfc/common/base.rb +531 -0
  26. data/lib/asciidoctor/rfc/common/front.rb +120 -0
  27. data/lib/asciidoctor/rfc/v2/base.rb +379 -0
  28. data/lib/asciidoctor/rfc/v2/blocks.rb +261 -0
  29. data/lib/asciidoctor/rfc/v2/converter.rb +60 -0
  30. data/lib/asciidoctor/rfc/v2/front.rb +69 -0
  31. data/lib/asciidoctor/rfc/v2/inline_anchor.rb +111 -0
  32. data/lib/asciidoctor/rfc/v2/lists.rb +135 -0
  33. data/lib/asciidoctor/rfc/v2/table.rb +114 -0
  34. data/lib/asciidoctor/rfc/v2/validate.rb +32 -0
  35. data/lib/asciidoctor/rfc/v2/validate2.rng +716 -0
  36. data/lib/asciidoctor/rfc/v3/base.rb +329 -0
  37. data/lib/asciidoctor/rfc/v3/blocks.rb +246 -0
  38. data/lib/asciidoctor/rfc/v3/converter.rb +62 -0
  39. data/lib/asciidoctor/rfc/v3/front.rb +122 -0
  40. data/lib/asciidoctor/rfc/v3/inline_anchor.rb +89 -0
  41. data/lib/asciidoctor/rfc/v3/lists.rb +176 -0
  42. data/lib/asciidoctor/rfc/v3/svg.rng +9081 -0
  43. data/lib/asciidoctor/rfc/v3/table.rb +65 -0
  44. data/lib/asciidoctor/rfc/v3/validate.rb +34 -0
  45. data/lib/asciidoctor/rfc/v3/validate.rng +2143 -0
  46. data/lib/metanorma-ietf.rb +7 -0
  47. data/lib/metanorma/ietf.rb +8 -0
  48. data/lib/metanorma/ietf/processor.rb +89 -0
  49. data/lib/metanorma/ietf/version.rb +5 -0
  50. data/metanorma-ietf.gemspec +51 -0
  51. data/rfc2629-other.ent +61 -0
  52. data/rfc2629-xhtml.ent +165 -0
  53. data/rfc2629.dtd +312 -0
  54. 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(/\&lt;/, "<").gsub(/\&gt;/, ">")
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