asciidoctor-rfc 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (130) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +5 -0
  3. data/.oss-guides.rubocop.yml +1077 -0
  4. data/.rspec +1 -0
  5. data/.rubocop.yml +19 -1063
  6. data/.travis.yml +3 -2
  7. data/Guardfile +22 -0
  8. data/README.adoc +1151 -0
  9. data/Rakefile +1 -1
  10. data/asciidoctor-rfc.gemspec +20 -3
  11. data/bin/asciidoctor-rfc2 +15 -0
  12. data/bin/asciidoctor-rfc3 +15 -0
  13. data/bin/rspec +0 -1
  14. data/lib/asciidoctor-rfc.rb +4 -0
  15. data/lib/asciidoctor/rfc/common/base.rb +218 -0
  16. data/lib/asciidoctor/rfc/common/front.rb +120 -0
  17. data/lib/asciidoctor/rfc/v2/base.rb +341 -0
  18. data/lib/asciidoctor/rfc/v2/blocks.rb +192 -0
  19. data/lib/asciidoctor/rfc/v2/converter.rb +64 -0
  20. data/lib/asciidoctor/rfc/v2/front.rb +69 -0
  21. data/lib/asciidoctor/rfc/v2/inline_anchor.rb +102 -0
  22. data/lib/asciidoctor/rfc/v2/lists.rb +134 -0
  23. data/lib/asciidoctor/rfc/v2/table.rb +112 -0
  24. data/lib/asciidoctor/rfc/v2/validate.rb +738 -0
  25. data/lib/asciidoctor/rfc/v2/validate2.rng +716 -0
  26. data/lib/asciidoctor/rfc/v3/base.rb +358 -0
  27. data/lib/asciidoctor/rfc/v3/blocks.rb +203 -0
  28. data/lib/asciidoctor/rfc/v3/converter.rb +64 -0
  29. data/lib/asciidoctor/rfc/v3/front.rb +115 -0
  30. data/lib/asciidoctor/rfc/v3/inline_anchor.rb +90 -0
  31. data/lib/asciidoctor/rfc/v3/lists.rb +190 -0
  32. data/lib/asciidoctor/rfc/v3/svg.rng +9081 -0
  33. data/lib/asciidoctor/rfc/v3/table.rb +65 -0
  34. data/lib/asciidoctor/rfc/v3/validate.rb +2168 -0
  35. data/lib/asciidoctor/rfc/v3/validate.rng +2143 -0
  36. data/lib/asciidoctor/rfc/version.rb +2 -2
  37. data/spec/asciidoctor/rfc/v2/appendix_spec.rb +124 -0
  38. data/spec/asciidoctor/rfc/v2/area_spec.rb +60 -0
  39. data/spec/asciidoctor/rfc/v2/author_spec.rb +444 -0
  40. data/spec/asciidoctor/rfc/v2/comments_spec.rb +316 -0
  41. data/spec/asciidoctor/rfc/v2/crossref_spec.rb +205 -0
  42. data/spec/asciidoctor/rfc/v2/date_spec.rb +166 -0
  43. data/spec/asciidoctor/rfc/v2/dlist_spec.rb +108 -0
  44. data/spec/asciidoctor/rfc/v2/document_spec.rb +161 -0
  45. data/spec/asciidoctor/rfc/v2/example_spec.rb +50 -0
  46. data/spec/asciidoctor/rfc/v2/front_spec.rb +75 -0
  47. data/spec/asciidoctor/rfc/v2/image_spec.rb +81 -0
  48. data/spec/asciidoctor/rfc/v2/indexterm_spec.rb +66 -0
  49. data/spec/asciidoctor/rfc/v2/inline_formatting_spec.rb +177 -0
  50. data/spec/asciidoctor/rfc/v2/keyword_spec.rb +63 -0
  51. data/spec/asciidoctor/rfc/v2/listing_spec.rb +59 -0
  52. data/spec/asciidoctor/rfc/v2/literal_spec.rb +53 -0
  53. data/spec/asciidoctor/rfc/v2/olist_spec.rb +147 -0
  54. data/spec/asciidoctor/rfc/v2/paragraph_spec.rb +68 -0
  55. data/spec/asciidoctor/rfc/v2/preamble_spec.rb +140 -0
  56. data/spec/asciidoctor/rfc/v2/quote_spec.rb +24 -0
  57. data/spec/asciidoctor/rfc/v2/references_spec.rb +96 -0
  58. data/spec/asciidoctor/rfc/v2/section_spec.rb +260 -0
  59. data/spec/asciidoctor/rfc/v2/sidebar_spec.rb +32 -0
  60. data/spec/asciidoctor/rfc/v2/table_spec.rb +293 -0
  61. data/spec/asciidoctor/rfc/v2/ulist_spec.rb +96 -0
  62. data/spec/asciidoctor/rfc/v2/workgroup_spec.rb +60 -0
  63. data/spec/asciidoctor/rfc/v3/appendix_spec.rb +130 -0
  64. data/spec/asciidoctor/rfc/v3/area_spec.rb +63 -0
  65. data/spec/asciidoctor/rfc/v3/author_spec.rb +540 -0
  66. data/spec/asciidoctor/rfc/v3/comments_spec.rb +308 -0
  67. data/spec/asciidoctor/rfc/v3/crossref_spec.rb +269 -0
  68. data/spec/asciidoctor/rfc/v3/date_spec.rb +149 -0
  69. data/spec/asciidoctor/rfc/v3/dlist_spec.rb +121 -0
  70. data/spec/asciidoctor/rfc/v3/document_spec.rb +109 -0
  71. data/spec/asciidoctor/rfc/v3/example_spec.rb +34 -0
  72. data/spec/asciidoctor/rfc/v3/front_spec.rb +43 -0
  73. data/spec/asciidoctor/rfc/v3/image_spec.rb +81 -0
  74. data/spec/asciidoctor/rfc/v3/indexterm_spec.rb +69 -0
  75. data/spec/asciidoctor/rfc/v3/inline_formatting_spec.rb +319 -0
  76. data/spec/asciidoctor/rfc/v3/keyword_spec.rb +33 -0
  77. data/spec/asciidoctor/rfc/v3/link_spec.rb +34 -0
  78. data/spec/asciidoctor/rfc/v3/listing_spec.rb +59 -0
  79. data/spec/asciidoctor/rfc/v3/literal_spec.rb +51 -0
  80. data/spec/asciidoctor/rfc/v3/olist_spec.rb +168 -0
  81. data/spec/asciidoctor/rfc/v3/paragraph_spec.rb +73 -0
  82. data/spec/asciidoctor/rfc/v3/preamble_spec.rb +112 -0
  83. data/spec/asciidoctor/rfc/v3/quote_spec.rb +91 -0
  84. data/spec/asciidoctor/rfc/v3/references_spec.rb +147 -0
  85. data/spec/asciidoctor/rfc/v3/section_spec.rb +198 -0
  86. data/spec/asciidoctor/rfc/v3/series_info_spec.rb +151 -0
  87. data/spec/asciidoctor/rfc/v3/sidebar_spec.rb +30 -0
  88. data/spec/asciidoctor/rfc/v3/table_spec.rb +275 -0
  89. data/spec/asciidoctor/rfc/v3/ulist_spec.rb +74 -0
  90. data/spec/asciidoctor/rfc/v3/workgroup_spec.rb +33 -0
  91. data/spec/examples/davies-template-bare-06.adoc +361 -0
  92. data/spec/examples/davies-template-bare-06.xml.orig +426 -0
  93. data/spec/examples/example-v2.adoc +181 -0
  94. data/spec/examples/example-v2.xml +675 -0
  95. data/spec/examples/example-v3.adoc +185 -0
  96. data/spec/examples/example-v3.xml +1009 -0
  97. data/spec/examples/mib-doc-template-xml-06.adoc +596 -0
  98. data/spec/examples/mib-doc-template-xml-06.xml.orig +654 -0
  99. data/spec/examples/rfc1149.md +76 -0
  100. data/spec/examples/rfc1149.md.2.xml +94 -0
  101. data/spec/examples/rfc1149.md.3.xml +93 -0
  102. data/spec/examples/rfc1149.md.adoc +65 -0
  103. data/spec/examples/rfc2100.md +149 -0
  104. data/spec/examples/rfc2100.md.2.xml +169 -0
  105. data/spec/examples/rfc2100.md.3.xml +163 -0
  106. data/spec/examples/rfc2100.md.adoc +136 -0
  107. data/spec/examples/rfc3514.md +203 -0
  108. data/spec/examples/rfc3514.md.2.xml +238 -0
  109. data/spec/examples/rfc3514.md.3.xml +258 -0
  110. data/spec/examples/rfc3514.md.adoc +324 -0
  111. data/spec/examples/rfc5841.md +342 -0
  112. data/spec/examples/rfc5841.md.2.xml +393 -0
  113. data/spec/examples/rfc5841.md.3.xml +449 -0
  114. data/spec/examples/rfc5841.md.adoc +414 -0
  115. data/spec/examples/rfc6350.adoc +3499 -0
  116. data/spec/examples/rfc6350.bib +763 -0
  117. data/spec/examples/rfc748.md +79 -0
  118. data/spec/examples/rfc748.md.2.xml +116 -0
  119. data/spec/examples/rfc748.md.3.xml +109 -0
  120. data/spec/examples/rfc748.md.adoc +80 -0
  121. data/spec/examples/rfc7511.md +257 -0
  122. data/spec/examples/rfc7511.md.2.xml +300 -0
  123. data/spec/examples/rfc7511.md.3.xml +347 -0
  124. data/spec/examples/rfc7511.md.adoc +417 -0
  125. data/spec/spec_helper.rb +115 -5
  126. metadata +274 -9
  127. data/.hound.yml +0 -3
  128. data/README.md +0 -84
  129. data/lib/asciidoctor/rfc.rb +0 -7
  130. data/spec/asciidoctor-rfc/.keep +0 -0
data/Rakefile CHANGED
@@ -3,4 +3,4 @@ require "rspec/core/rake_task"
3
3
 
4
4
  RSpec::Core::RakeTask.new(:spec)
5
5
 
6
- task :default => :spec
6
+ task default: :spec
@@ -1,14 +1,19 @@
1
1
  # coding: utf-8
2
+
2
3
  lib = File.expand_path("../lib", __FILE__)
3
4
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
5
  require "asciidoctor/rfc/version"
5
6
 
6
7
  Gem::Specification.new do |spec|
7
8
  spec.name = "asciidoctor-rfc"
8
- spec.version = Asciidoctor::Rfc::VERSION
9
+ spec.version = Asciidoctor::RFC::VERSION
9
10
  spec.authors = ["Ribose Inc."]
10
11
  spec.email = ["open.source@ribose.com"]
11
- spec.summary = %q{todo: AsciiDoctorRFC description.}
12
+
13
+ spec.summary = "todo: AsciiDoctorRFC summary."
14
+ spec.description = <<~DESCRIPTION
15
+ DESCRIPTION
16
+
12
17
  spec.homepage = "https://github.com/riboseinc/asciidoctor-rfc"
13
18
  spec.license = "MIT"
14
19
 
@@ -16,9 +21,21 @@ Gem::Specification.new do |spec|
16
21
  spec.require_paths = ["lib"]
17
22
  spec.files = `git ls-files`.split("\n")
18
23
  spec.test_files = `git ls-files -- {spec}/*`.split("\n")
19
- spec.required_ruby_version = Gem::Requirement.new(">= 2.1.9")
24
+ spec.required_ruby_version = Gem::Requirement.new(">= 2.3.0")
25
+
26
+ spec.add_dependency "asciidoctor", "~> 1.5.6"
27
+ spec.add_dependency "htmlentities", "~> 4.3.4"
28
+ spec.add_dependency "nokogiri", "~> 1.8.1"
29
+ spec.add_dependency "thread_safe"
20
30
 
21
31
  spec.add_development_dependency "bundler", "~> 1.15"
22
32
  spec.add_development_dependency "rake", "~> 12.0"
23
33
  spec.add_development_dependency "rspec", "~> 3.6"
34
+ spec.add_development_dependency "simplecov", "~> 0.15"
35
+ spec.add_development_dependency "byebug", "~> 9.1"
36
+ spec.add_development_dependency "guard", "~> 2.14"
37
+ spec.add_development_dependency "guard-rspec", "~> 4.7"
38
+ spec.add_development_dependency "timecop", "~> 0.9"
39
+ spec.add_development_dependency "equivalent-xml", "~> 0.6"
40
+ spec.add_development_dependency "rubocop", "~> 0.50"
24
41
  end
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "asciidoctor/cli"
4
+ require "asciidoctor/rfc/v2/converter"
5
+ # require "asciidoctor-bibliography"
6
+
7
+ options = Asciidoctor::Cli::Options.new backend: "rfc2", header_footer: true
8
+ # FIXME This is a really bizarre API. Please make me simpler.
9
+
10
+ exit 0 if options.parse!(ARGV) == 0
11
+
12
+ invoker = Asciidoctor::Cli::Invoker.new options
13
+ GC.start
14
+ invoker.invoke!
15
+ exit invoker.code
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "asciidoctor/cli"
4
+ require "asciidoctor/rfc/v3/converter"
5
+ # require "asciidoctor-bibliography"
6
+
7
+ options = Asciidoctor::Cli::Options.new backend: "rfc3", header_footer: true
8
+ # FIXME This is a really bizarre API. Please make me simpler.
9
+
10
+ exit 0 if options.parse!(ARGV) == 0
11
+
12
+ invoker = Asciidoctor::Cli::Invoker.new options
13
+ GC.start
14
+ invoker.invoke!
15
+ exit invoker.code
data/bin/rspec CHANGED
@@ -1,5 +1,4 @@
1
1
  #!/usr/bin/env ruby
2
- # frozen_string_literal: true
3
2
 
4
3
  # This file was generated by Bundler.
5
4
  #
@@ -0,0 +1,4 @@
1
+ require 'asciidoctor' unless defined? Asciidoctor::Converter
2
+ require_relative 'asciidoctor/rfc/v2/converter'
3
+ require_relative 'asciidoctor/rfc/v3/converter'
4
+ require_relative 'asciidoctor/rfc/version'
@@ -0,0 +1,218 @@
1
+ require "date"
2
+ require "nokogiri"
3
+ require "htmlentities"
4
+
5
+ module Asciidoctor
6
+ module RFC::Common
7
+ module Base
8
+ def convert(node, transform = nil, opts = {})
9
+ transform ||= node.node_name
10
+ opts.empty? ? (send transform, node) : (send transform, node, opts)
11
+ end
12
+
13
+ def document_ns_attributes(_doc)
14
+ # ' xmlns="http://projectmallard.org/1.0/" xmlns:its="http://www.w3.org/2005/11/its"'
15
+ nil
16
+ end
17
+
18
+ def content(node)
19
+ node.content
20
+ end
21
+
22
+ def skip(node, name = nil)
23
+ warn %(asciidoctor: WARNING: converter missing for #{name || node.node_name} node in RFC backend)
24
+ nil
25
+ end
26
+
27
+ # Syntax:
28
+ # = Title
29
+ # Author
30
+ # :HEADER
31
+ #
32
+ # ABSTRACT
33
+ #
34
+ # NOTE: note
35
+ #
36
+ # @note (boilerplate is ignored)
37
+ def preamble(node)
38
+ result = []
39
+ $seen_abstract = false
40
+ result << node.content
41
+ if $seen_abstract
42
+ result << "</abstract>"
43
+ end
44
+ result << "</front><middle>"
45
+ result
46
+ end
47
+
48
+ # TODO: dead code? remove.
49
+ # def authorname(node, suffix)
50
+ # noko do |xml|
51
+ # author_attributes = {
52
+ # fullname: node.attr("author#{suffix}") || node.attr("fullname#{suffix}"),
53
+ # surname: node.attr("lastname#{suffix}"),
54
+ # initials: node.attr("forename_initials#{suffix}"),
55
+ # role: node.attr("role#{suffix}"),
56
+ # }.reject { |_, value| value.nil? }
57
+ # xml.author **author_attributes
58
+ # end
59
+ # end
60
+
61
+ # Syntax:
62
+ # = Title
63
+ # Author
64
+ # :area x, y
65
+ def area(node, xml)
66
+ node.attr("area")&.split(/, ?/)&.each do |ar|
67
+ xml.area { |a| a << ar }
68
+ end
69
+ end
70
+
71
+ # Syntax:
72
+ # = Title
73
+ # Author
74
+ # :workgroup x, y
75
+ def workgroup(node, xml)
76
+ node.attr("workgroup")&.split(/, ?/)&.each do |wg|
77
+ xml.workgroup { |w| w << wg }
78
+ end
79
+ end
80
+
81
+ # Syntax:
82
+ # = Title
83
+ # Author
84
+ # :keyword x, y
85
+ def keyword(node, xml)
86
+ node.attr("keyword")&.split(/, ?/)&.each do |kw|
87
+ xml.keyword { |k| k << kw }
88
+ end
89
+ end
90
+
91
+ def paragraph1(node)
92
+ result = []
93
+ result1 = node.content
94
+ if result1 =~ /^(<t>|<dl>|<ol>|<ul>)/
95
+ result = result1
96
+ else
97
+ t_attributes = {
98
+ anchor: node.id,
99
+ }
100
+ result << noko { |xml| xml.t result1, **attr_code(t_attributes) }
101
+ end
102
+ result
103
+ end
104
+
105
+ def inline_indexterm(node)
106
+ # supports only primary and secondary terms
107
+ # primary attribute (highlighted major entry) not supported
108
+ if node.type == :visible
109
+ iref_attributes = {
110
+ item: node.text,
111
+ }
112
+ node.text + noko { |xml| xml.iref **attr_code(iref_attributes) }.join
113
+ else
114
+ terms = node.attr "terms"
115
+ warn %(asciidoctor: WARNING: only primary and secondary index terms supported: #{terms.join(': ')}) if terms.size > 2
116
+ iref_attributes = {
117
+ item: terms[0],
118
+ subitem: (terms.size > 1 ? terms[1] : nil),
119
+ }
120
+ noko { |xml| xml.iref **attr_code(iref_attributes) }.join
121
+ end
122
+ end
123
+
124
+ # ulist repurposed as reference list
125
+ def reflist(node)
126
+ # ++++
127
+ # <xml>
128
+ # ++++
129
+ result = []
130
+ if node.context == :pass
131
+ node.lines.each do |item|
132
+ # undo XML substitution
133
+ ref = item.gsub(/\&lt;/, "<").gsub(/\&gt;/, ">")
134
+ result << ref
135
+ end
136
+ else
137
+ warn %(asciidoctor: WARNING: references are not raw XML: #{node.context})
138
+ end
139
+ result
140
+ end
141
+
142
+ def open(node)
143
+ # open block is a container of multiple blocks, treated as a single block.
144
+ # We append each contained block to its parent
145
+ result = []
146
+ if node.blocks?
147
+ node.blocks.each do |b|
148
+ result << send(b.context, b)
149
+ end
150
+ else
151
+ result << paragraph(node)
152
+ end
153
+ result
154
+ end
155
+
156
+ def dash(camel_cased_word)
157
+ camel_cased_word.gsub(/([a-z])([A-Z])/, '\1-\2').downcase
158
+ end
159
+
160
+ # if node contains blocks, flatten them into a single line
161
+ def flatten(node)
162
+ result = []
163
+ result << node.text if node.respond_to?(:text)
164
+ if node.blocks?
165
+ node.blocks.each { |b| result << flatten(b) }
166
+ else
167
+ result << node.content
168
+ end
169
+ result.reject(&:empty?)
170
+ end
171
+
172
+ # if node contains blocks, flatten them into a single line; and extract only raw text
173
+ def flatten_rawtext(node)
174
+ result = []
175
+ if node.blocks?
176
+ node.blocks.each { |b| result << flatten_rawtext(b) }
177
+ elsif node.respond_to?(:lines)
178
+ node.lines.each do |x|
179
+ result << x.gsub(/</, "&lt;").gsub(/>/, "&gt;")
180
+ end
181
+ elsif node.respond_to?(:text)
182
+ result << node.text.gsub(/<[^>]*>/, "")
183
+ else
184
+ result << node.content.gsub(/<[^>]*>/, "")
185
+ end
186
+ result.reject(&:empty?)
187
+ end
188
+
189
+ def noko(&block)
190
+ # fragment = ::Nokogiri::XML::DocumentFragment.parse("")
191
+ # fragment.doc.create_internal_subset("xml", nil, "xhtml.dtd")
192
+ head = <<HERE
193
+ <!DOCTYPE html SYSTEM
194
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
195
+ <html xmlns="http://www.w3.org/1999/xhtml">
196
+ <head>
197
+ <title></title>
198
+ <meta charset="UTF-8" />
199
+ </head>
200
+ <body>
201
+ </body>
202
+ </html>
203
+ HERE
204
+ doc = ::Nokogiri::XML.parse(head)
205
+ fragment = doc.fragment("")
206
+ ::Nokogiri::XML::Builder.with fragment, &block
207
+ fragment.to_xml(encoding: "US-ASCII").lines.map { |l| l.gsub(/\s*\n/, "") }
208
+ end
209
+
210
+ def attr_code(attributes)
211
+ attributes = attributes.reject { |_, val| val.nil? }.map
212
+ attributes.map do |k, v|
213
+ [k, (v.is_a? String) ? HTMLEntities.new.decode(v) : v]
214
+ end.to_h
215
+ end
216
+ end
217
+ end
218
+ end
@@ -0,0 +1,120 @@
1
+ module Asciidoctor
2
+ module RFC::Common
3
+ module Front
4
+ def title(node, xml)
5
+ title_attributes = {
6
+ abbrev: node.attr("abbrev"),
7
+ }
8
+ xml.title **attr_code(title_attributes) do |t|
9
+ t << node.doctitle
10
+ end
11
+ end
12
+
13
+ # Syntax:
14
+ # = Title
15
+ # Author;Author_2;Author_3
16
+ # :fullname
17
+ # :lastname
18
+ # :organization
19
+ # :email
20
+ # :fullname_2
21
+ # :lastname_2
22
+ # :organization_2
23
+ # :email_2
24
+ # :fullname_3
25
+ # :lastname_3
26
+ # :organization_3
27
+ # :email_3
28
+ # @note recurse: author, author_2, author_3...
29
+ def author(node, xml)
30
+ author1(node, "", xml)
31
+ i = 2
32
+ loop do
33
+ suffix = "_#{i}"
34
+ author = node.attr("author#{suffix}")
35
+ fullname = node.attr("fullname#{suffix}")
36
+ break unless [author, fullname].any?
37
+ author1(node, suffix, xml)
38
+ i += 1
39
+ end
40
+ end
41
+
42
+ # Syntax:
43
+ # = Title
44
+ # Author (contains author firstname lastname middlename authorinitials email: Firstname Middlename Lastname <Email>)
45
+ # :fullname
46
+ # :lastname
47
+ # :forename_initials (excludes surname, unlike Asciidoc "initials" attribute)
48
+ # :organization
49
+ # :email
50
+ # :role
51
+ # :fax
52
+ # :uri
53
+ # :phone
54
+ # :postalLine (mutually exclusive with street city etc) (lines broken up by "\ ")
55
+ # :street
56
+ # :city
57
+ # :region
58
+ # :country
59
+ # :code
60
+ def author1(node, suffix, xml)
61
+ role = node.attr("role#{suffix}")
62
+ role = nil if role == "author"
63
+ author_attributes = {
64
+ fullname: node.attr("author#{suffix}") || node.attr("fullname#{suffix}"),
65
+ surname: node.attr("lastname#{suffix}"),
66
+ initials: node.attr("forename_initials#{suffix}"),
67
+ role: role,
68
+ }
69
+
70
+ xml.author **attr_code(author_attributes) do |xml_sub|
71
+ organization node, suffix, xml_sub
72
+ address node, suffix, xml_sub
73
+ end
74
+ end
75
+
76
+ def date1(revdate, xml)
77
+ revdate.gsub!(/T.*$/, "")
78
+ if revdate.length == 4
79
+ date_attributes = {
80
+ year: revdate,
81
+ }
82
+ elsif revdate =~ /^\d\d\d\d-?\d\d$/
83
+ matched = /^(?<year>\d\d\d\d)-(?<month>\d\d)$/.match revdate
84
+ date_attributes = {
85
+ month: Date::MONTHNAMES[(matched[:month]).to_i],
86
+ year: matched[:year],
87
+ }
88
+ else
89
+ d = Date.iso8601 revdate
90
+ date_attributes = {
91
+ day: d.day,
92
+ month: Date::MONTHNAMES[d.month],
93
+ year: d.year,
94
+ }
95
+ end
96
+ xml.date **attr_code(date_attributes)
97
+ end
98
+
99
+ # Syntax:
100
+ # = Title
101
+ # Author
102
+ # :revdate or :date
103
+ def date(node, xml)
104
+ revdate = node.attr("revdate") || node.attr("date")
105
+ if revdate.nil?
106
+ revdate = DateTime.now.iso8601
107
+ warn %(asciidoctor: WARNING: revdate attribute missing from header, provided current date)
108
+ end
109
+ unless revdate.nil?
110
+ begin
111
+ date1(revdate, xml)
112
+ rescue ArgumentError # invalid date
113
+ warn %(asciidoctor: WARNING: invalid date in header, provided current date)
114
+ date1(DateTime.now.iso8601, xml)
115
+ end
116
+ end
117
+ end
118
+ end
119
+ end
120
+ end
@@ -0,0 +1,341 @@
1
+ module Asciidoctor
2
+ module RFC::V2
3
+ module Base
4
+ # Syntax:
5
+ # =Title
6
+ # Author
7
+ # :status
8
+ # :consensus
9
+ # :name
10
+ # :number
11
+ #
12
+ # :ipr
13
+ # :obsoletes
14
+ # :updates
15
+ # :submissionType
16
+ # :indexInclude
17
+ # :ipr-extract
18
+ # :sort-refs
19
+ # :sym-refs
20
+ # :toc-include
21
+ #
22
+ # ABSTRACT
23
+ #
24
+ # NOTEs
25
+ #
26
+ # ==first title
27
+ # CONTENT
28
+ #
29
+ # [bibliography] # start of back matter
30
+ # == Bibliography
31
+ #
32
+ # [appendix] # start of back matter if not already started
33
+ # == Appendix
34
+ def document(node)
35
+ $seen_back_matter = false
36
+ $seen_abstract = false
37
+ $smart_quotes = (node.attr("smart-quotes") != "false")
38
+
39
+ result = []
40
+ result << '<?xml version="1.0" encoding="UTF-8"?>'
41
+
42
+ is_rfc = node.attr("doctype") == "rfc"
43
+
44
+ consensus_value = {
45
+ "false" => "no",
46
+ "true" => "yes",
47
+ }[node.attr("consensus")] || node.attr("consensus")
48
+
49
+ rfc_attributes = {
50
+ ipr: node.attr("ipr"),
51
+ obsoletes: node.attr("obsoletes"),
52
+ updates: node.attr("updates"),
53
+ category: node.attr("status"),
54
+ consensus: consensus_value,
55
+ submissionType: node.attr("submission-type") || "IETF",
56
+ iprExtract: node.attr("ipr-extract"),
57
+ docName: (node.attr("name") unless is_rfc),
58
+ number: (node.attr("name") if is_rfc),
59
+ seriesNo: node.attr("series-no"),
60
+ "xml:lang": node.attr("xml-lang"),
61
+ }
62
+
63
+ rfc_open = noko { |xml| xml.rfc **attr_code(rfc_attributes) }.join.gsub(/\/>$/, ">")
64
+ result << rfc_open
65
+
66
+ result << noko { |xml| front node, xml }
67
+ result.last.last.gsub! /<\/front>$/, "" # FIXME: this is a hack!
68
+ result << "</front><middle1>"
69
+
70
+ result << node.content if node.blocks?
71
+ result << ($seen_back_matter ? "</back>" : "</middle>")
72
+ result << "</rfc>"
73
+
74
+ # <middle> needs to move after preamble
75
+ result = result.flatten
76
+ result = if result.any? { |e| e =~ /<\/front><middle>/ } && result.any? { |e| e =~ /<\/front><middle1>/ }
77
+ result.reject { |e| e =~ /<\/front><middle1>/ }
78
+ else
79
+ result.map { |e| e =~ /<\/front><middle1>/ ? "</front><middle>" : e }
80
+ end
81
+
82
+ ret = result * "\n"
83
+ ret = set_pis(node, Nokogiri::XML(ret)).to_xml
84
+ ret = cleanup(ret)
85
+ Validate::validate(ret)
86
+ ret
87
+ end
88
+
89
+ def inline_break(node)
90
+ noko do |xml|
91
+ xml << node.text
92
+ xml.vspace
93
+ end.join
94
+ end
95
+
96
+ def inline_quoted(node)
97
+ noko do |xml|
98
+ case node.type
99
+ when :emphasis
100
+ xml.spanx node.text, style: "emph"
101
+ when :strong
102
+ xml.spanx node.text, style: "strong"
103
+ when :monospaced
104
+ xml.spanx node.text, style: "verb"
105
+ when :double
106
+ xml << ($smart_quotes ? "“#{node.text}”" : "\"#{node.text}\"")
107
+ when :single
108
+ xml << ($smart_quotes ? "‘#{node.text}’" : "'#{node.text}'")
109
+ when :superscript
110
+ xml << "^#{node.text}^"
111
+ when :subscript
112
+ xml << "_#{node.text}_"
113
+ else
114
+ # [bcp14]#MUST NOT#
115
+ if node.role == "bcp14"
116
+ xml.spanx node.text.upcase, style: "strong"
117
+ else
118
+ xml << node.text
119
+ end
120
+ end
121
+ end.join
122
+ end
123
+
124
+ # Syntax:
125
+ # [[id]]
126
+ # Text
127
+ def paragraph(node)
128
+ result = []
129
+
130
+ if (node.parent.context == :preamble) && !$seen_abstract
131
+ $seen_abstract = true
132
+ result << "<abstract>"
133
+ end
134
+
135
+ t_attributes = {
136
+ anchor: node.id,
137
+ }
138
+
139
+ result << noko do |xml|
140
+ xml.t **attr_code(t_attributes) do |xml_t|
141
+ xml_t << node.content
142
+ end
143
+ end
144
+ result
145
+ end
146
+
147
+ def verse(node)
148
+ result = []
149
+
150
+ if (node.parent.context == :preamble) && !$seen_abstract
151
+ $seen_abstract = true
152
+ result << "<abstract>"
153
+ end
154
+
155
+ t_attributes = {
156
+ anchor: node.id,
157
+ }
158
+
159
+ result << noko do |xml|
160
+ xml.t **attr_code(t_attributes) do |xml_t|
161
+ xml_t << node.content.gsub("\n", "<vspace/>\n")
162
+ end
163
+ end
164
+
165
+ result
166
+ end
167
+
168
+ # Syntax:
169
+ # [[id]]
170
+ # == title
171
+ # Content
172
+ #
173
+ # [bibliography]
174
+ # == Normative|Informative References
175
+ # * [[[ref1]]] Ref [must provide references as list]
176
+ # * [[[ref2]]] Ref
177
+ def section(node)
178
+ result = []
179
+ if node.attr("style") == "bibliography"
180
+ $xreftext = {}
181
+ $processing_reflist = true
182
+
183
+ references_attributes = {
184
+ title: node.title,
185
+ }
186
+
187
+ result << noko do |xml|
188
+ xml.references **attr_code(references_attributes) do |xml_references|
189
+ node.blocks.each { |b| xml_references << reflist(b).join }
190
+ end
191
+ end
192
+
193
+ result = result.unshift("</middle><back>") unless $seen_back_matter
194
+ $processing_reflist = false
195
+ $seen_back_matter = true
196
+ else
197
+ if node.attr("style") == "appendix"
198
+ result << "</middle><back>" unless $seen_back_matter
199
+ $seen_back_matter = true
200
+ end
201
+
202
+ section_attributes = {
203
+ anchor: node.id,
204
+ title: node.title,
205
+ }
206
+
207
+ result << noko do |xml|
208
+ xml.section **attr_code(section_attributes) do |xml_section|
209
+ xml_section << node.content
210
+ end
211
+ end
212
+ end
213
+
214
+ result
215
+ end
216
+
217
+ # Syntax:
218
+ # [[id]]
219
+ # .Name
220
+ # [link=xxx,align=left|center|right,alt=alt_text,type]
221
+ # image::filename[alt_text,width,height]
222
+ # @note ignoring width, height attributes
223
+ def image(node)
224
+ uri = node.image_uri node.attr("target")
225
+ artwork_attributes = {
226
+ align: node.attr("align"),
227
+ alt: node.alt,
228
+ height: node.attr("height"),
229
+ name: node.title,
230
+ src: uri,
231
+ type: node.attr("type"),
232
+ width: node.attr("width"),
233
+ }
234
+
235
+ noko do |xml|
236
+ if node.parent.context != :example
237
+ xml.figure do |xml_figure|
238
+ xml_figure.artwork **attr_code(artwork_attributes)
239
+ end
240
+ else
241
+ xml.artwork **attr_code(artwork_attributes)
242
+ end
243
+ end
244
+ end
245
+
246
+ # clean up XML
247
+ def cleanup(doc)
248
+ xmldoc = Nokogiri::XML(doc) do |config|
249
+ config.noent
250
+ end
251
+ crefs = xmldoc.xpath("//cref")
252
+ # any crefs that are direct children of section should become children of the preceding
253
+ # paragraph, if it exists; otherwise, they need to be wrapped in a paragraph
254
+ crefs.each do |cref|
255
+ if cref.parent.name == "section"
256
+ prev = cref.previous_element
257
+ if !prev.nil? && prev.name == "t"
258
+ cref.parent = prev
259
+ else
260
+ t = Nokogiri::XML::Element.new("t", xmldoc)
261
+ cref.before(t)
262
+ cref.parent = t
263
+ end
264
+ end
265
+ end
266
+ unless $smart_quotes
267
+ xmldoc.traverse do |node|
268
+ if node.text?
269
+ node.content = node.content.tr("\u2019", "'")
270
+ node.content = node.content.gsub(/\&#8217;/, "'")
271
+ node.content = node.content.gsub(/\&#x2019;/, "'")
272
+ elsif node.element?
273
+ node.attributes.each do |k, v|
274
+ node.set_attribute(k, v.content.tr("\u2019", "'"))
275
+ node.set_attribute(k, v.content.gsub(/\&#8217;/, "'"))
276
+ node.set_attribute(k, v.content.gsub(/\&#x2019;/, "'"))
277
+ end
278
+ end
279
+ end
280
+ end
281
+ xmldoc.to_xml(encoding: "US-ASCII")
282
+ end
283
+
284
+ def set_pis(node, doc)
285
+ # Below are generally applicable Processing Instructions (PIs)
286
+ # that most I-Ds might want to use. (Here they are set differently than
287
+ # their defaults in xml2rfc v1.32)
288
+ rfc_pis = {
289
+ # give errors regarding ID-nits and DTD validation
290
+ strict: "yes",
291
+
292
+ # TOC control
293
+ # generate a ToC
294
+ toc: node.attr("toc-include") == "false" ? "no" : "yes",
295
+
296
+ # the number of levels of subsections in ToC. default: 3
297
+ tocdepth: node.attr("toc-depth") || "4",
298
+
299
+ # References control
300
+
301
+ # use symbolic references tags, i.e, [RFC2119] instead of [1]
302
+ symrefs: "yes",
303
+
304
+ # sort the reference entries alphabetically
305
+ sortrefs: "yes",
306
+
307
+ # Vertical whitespace control
308
+ # (using these PIs as follows is recommended by the RFC Editor)
309
+
310
+ # do not start each main section on a new page
311
+ compact: "yes",
312
+
313
+ # keep one blank line between list items
314
+ subcompact: "no",
315
+ }
316
+
317
+ doc.create_internal_subset("rfc", nil, "rfc2629.dtd")
318
+ rfc_pis.each_pair do |k, v|
319
+ pi = Nokogiri::XML::ProcessingInstruction.new(doc,
320
+ "rfc",
321
+ "#{k}=\"#{v}\"")
322
+ doc.root.add_previous_sibling(pi)
323
+ end
324
+
325
+ doc
326
+ end
327
+
328
+ # replace any <t>text</t> instances with <vspace/>text
329
+ def para_to_vspace(doc)
330
+ xmldoc = Nokogiri::XML("<fragment>#{doc}</fragment>")
331
+ paras = xmldoc.xpath("/fragment/t")
332
+ paras.each do |para|
333
+ vspace = Nokogiri::XML::Element.new("vspace", xmldoc.document)
334
+ para.before(vspace)
335
+ para.replace(para.children)
336
+ end
337
+ xmldoc.root.children.to_xml(encoding: "US-ASCII")
338
+ end
339
+ end
340
+ end
341
+ end