metanorma-ietf 2.2.10 → 2.3.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,3 +1,5 @@
1
+ require "open-uri"
2
+
1
3
  module Asciidoctor
2
4
  module Ietf
3
5
  class Converter < ::Asciidoctor::Standoc::Converter
@@ -10,15 +12,18 @@ module Asciidoctor
10
12
  def image_validate(doc)
11
13
  doc.xpath("//image").each do |i|
12
14
  next if i["mimetype"] == "image/svg+xml"
15
+
13
16
  @log.add("MIME", i, "image #{i['src'][0, 40]} is not SVG!")
14
17
  end
15
18
  end
16
19
 
17
20
  def workgroup_validate(doc)
18
21
  return if @workgroups.empty?
22
+
19
23
  doc.xpath("//bibdata/ext/editorialgroup/workgroup").each do |wg|
20
24
  wg_norm = wg.text.sub(/ (Working|Research) Group$/, "")
21
25
  next if @workgroups.include?(wg_norm)
26
+
22
27
  @log.add("Document Attributes", nil, "IETF: unrecognised working group #{wg.text}")
23
28
  end
24
29
  end
@@ -29,25 +34,29 @@ module Asciidoctor
29
34
  File.join(File.dirname(__FILE__), "ietf.rng"))
30
35
  end
31
36
 
37
+ def wgcache_name
38
+ "#{Dir.home}/.metanorma-ietf-workgroup-cache.json"
39
+ end
40
+
32
41
  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
42
+ node.attr("flush-caches") == "true" and
43
+ FileUtils.rm wgcache_name, force: true
35
44
  wg = []
36
45
  if Pathname.new(wgcache_name).file?
37
46
  begin
38
47
  File.open(wgcache_name, "r") { |f| wg = JSON.parse(f.read) }
39
48
  rescue Exception => e
40
- STDERR.puts "Cache #{wgcache_name} is invalid, drop it"
49
+ warn "Cache #{wgcache_name} is invalid, drop it"
41
50
  end
42
51
  end
43
52
  [wg, wgcache_name]
44
53
  end
45
54
 
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|
55
+ def cache_workgroup_ietf(wg, _b)
56
+ warn "Reading workgroups from https://tools.ietf.org/wg/..."
57
+ URI.open("https://tools.ietf.org/wg/") do |f|
58
+ f.each_line do |l|
59
+ l.scan(%r{<td width="50%" style='padding: 0 1ex'>([^<]+)</td>}) do |w|
51
60
  wg << w[0].gsub(/\s+$/, "").gsub(/ Working Group$/, "")
52
61
  end
53
62
  end
@@ -55,11 +64,11 @@ module Asciidoctor
55
64
  wg
56
65
  end
57
66
 
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|
67
+ def cache_workgroup_irtf(wg, _b)
68
+ warn "Reading workgroups from https://irtf.org/groups..."
69
+ URI.open("https://irtf.org/groups", ssl_verify_mode: OpenSSL::SSL::VERIFY_NONE) do |f|
70
+ f.each_line do |l|
71
+ l.scan(%r{<a title="([^"]+) Research Group"[^>]+>([^<]+)<}) do |w|
63
72
  wg << w[0].gsub(/\s+$/, "")
64
73
  wg << w[1].gsub(/\s+$/, "") # abbrev
65
74
  end
@@ -43,7 +43,7 @@ module IsoDoc::Ietf
43
43
  end
44
44
 
45
45
  def ol_attrs(node)
46
- { anchor: node["id"],
46
+ { anchor: node["id"],
47
47
  spacing: node["spacing"],
48
48
  type: ol_style(node["type"]),
49
49
  group: node["group"],
@@ -73,7 +73,9 @@ module IsoDoc::Ietf
73
73
 
74
74
  def note_label(node)
75
75
  n = @xrefs.get[node["id"]]
76
- return l10n("#{@i18n.note}: ") if n.nil? || n[:label].nil? || n[:label].empty?
76
+ return l10n("#{@i18n.note}: ") if n.nil? || n[:label].nil? ||
77
+ n[:label].empty?
78
+
77
79
  l10n("#{@i18n.note} #{n[:label]}: ")
78
80
  end
79
81
 
@@ -98,7 +100,7 @@ module IsoDoc::Ietf
98
100
  def example_label(node, div, name)
99
101
  n = @xrefs.get[node["id"]]
100
102
  div.t **attr_code(anchor: node["id"], keepWithNext: "true") do |p|
101
- lbl = (n.nil? || n[:label].nil? || n[:label].empty?) ? @i18n.example :
103
+ lbl = n.nil? || n[:label].nil? || n[:label].empty? ? @i18n.example :
102
104
  l10n("#{@i18n.example} #{n[:label]}")
103
105
  p << lbl
104
106
  name and !lbl.nil? and p << ": "
@@ -107,15 +109,11 @@ module IsoDoc::Ietf
107
109
  end
108
110
 
109
111
  def sourcecode_parse(node, out)
110
- out.figure **attr_code(anchor: node["id"]) do |div|
111
- name = node&.at(ns("./name"))&.remove and div.name do |n|
112
- name.children.each { |nn| parse(nn, n) }
113
- end
114
- div.sourcecode **attr_code(type: node["lang"], name: node["filename"],
115
- markers: node["markers"],
116
- src: node["src"]) do |s|
117
- node.children.each { |x| parse(x, s) unless x.name == "name" }
118
- end
112
+ out.sourcecode **attr_code(
113
+ anchor: node["id"], type: node["lang"], name: node["filename"],
114
+ markers: node["markers"], src: node["src"]
115
+ ) do |s|
116
+ node.children.each { |x| parse(x, s) unless x.name == "name" }
119
117
  end
120
118
  end
121
119
 
@@ -139,6 +137,7 @@ module IsoDoc::Ietf
139
137
 
140
138
  def formula_where(dl, out)
141
139
  return unless dl
140
+
142
141
  out.t { |p| p << @i18n.where }
143
142
  parse(dl, out)
144
143
  end
@@ -146,7 +145,7 @@ module IsoDoc::Ietf
146
145
  def formula_parse1(node, out)
147
146
  out.t **attr_code(anchor: node["id"]) do |p|
148
147
  parse(node.at(ns("./stem")), p)
149
- lbl = @xrefs.anchor(node['id'], :label, false)
148
+ lbl = @xrefs.anchor(node["id"], :label, false)
150
149
  lbl.nil? or
151
150
  p << " (#{lbl})"
152
151
  end
@@ -157,6 +156,7 @@ module IsoDoc::Ietf
157
156
  formula_where(node.at(ns("./dl")), out)
158
157
  node.children.each do |n|
159
158
  next if %w(stem dl).include? n.name
159
+
160
160
  parse(n, out)
161
161
  end
162
162
  end
@@ -176,7 +176,7 @@ module IsoDoc::Ietf
176
176
  end
177
177
 
178
178
  def admonition_name_parse(_node, div, name)
179
- div.t **{keepWithNext: "true" } do |p|
179
+ div.t **{ keepWithNext: "true" } do |p|
180
180
  name.children.each { |n| parse(n, p) }
181
181
  end
182
182
  end
@@ -200,8 +200,9 @@ module IsoDoc::Ietf
200
200
  end
201
201
  end
202
202
 
203
- def figure_name_parse(node, div, name)
203
+ def figure_name_parse(_node, div, name)
204
204
  return if name.nil?
205
+
205
206
  div.name do |n|
206
207
  name.children.each { |n| parse(n, div) }
207
208
  end
@@ -214,6 +215,7 @@ module IsoDoc::Ietf
214
215
  def figure_parse(node, out)
215
216
  return pseudocode_parse(node, out) if node["class"] == "pseudocode" ||
216
217
  node["type"] == "pseudocode"
218
+
217
219
  @in_figure = true
218
220
  out.figure **attr_code(anchor: node["id"]) do |div|
219
221
  figure_name_parse(node, div, node.at(ns("./name")))
@@ -15,14 +15,14 @@ module IsoDoc::Ietf
15
15
  end
16
16
 
17
17
  # TODO: insert <u>
18
-
18
+
19
19
  def front_cleanup(xmldoc)
20
- xmldoc.xpath("//title").each { |s| s.children = s.text }
21
- xmldoc.xpath("//reference/front[not(author)]").each do |f|
22
- insert = f.at("./seriesInfo[last()]") || f.at("./title")
23
- insert.next = "<author surname='Unknown'/>"
24
- end
20
+ xmldoc.xpath("//title").each { |s| s.children = s.text }
21
+ xmldoc.xpath("//reference/front[not(author)]").each do |f|
22
+ insert = f.at("./seriesInfo[last()]") || f.at("./title")
23
+ insert.next = "<author surname='Unknown'/>"
25
24
  end
25
+ end
26
26
 
27
27
  def table_footnote_cleanup(docxml)
28
28
  docxml.xpath("//table[descendant::fn]").each do |t|
@@ -48,15 +48,28 @@ module IsoDoc::Ietf
48
48
  figure_postamble(docxml)
49
49
  figure_unnest(docxml)
50
50
  figure_footnote_cleanup(docxml)
51
+ figure_data_uri(docxml)
52
+ end
53
+
54
+ def figure_data_uri(docxml)
55
+ docxml.xpath("//artwork").each do |a|
56
+ next unless %r{^data:image/svg\+xml;base64}.match?(a["src"])
57
+
58
+ f = Metanorma::Utils::save_dataimage(a["src"])
59
+ a.delete("src")
60
+ a.children = File.read(f).sub(%r{<\?.+\?>}, "")
61
+ end
51
62
  end
52
63
 
53
64
  def figure_unnest(docxml)
54
65
  docxml.xpath("//figure[descendant::figure]").each do |f|
55
66
  insert = f
56
67
  f.xpath(".//figure").each do |a|
68
+ title = f.at("./name") and a.children.first.previous = title.remove
57
69
  insert.next = a.remove
58
70
  insert = insert.next_element
59
71
  end
72
+ f.remove
60
73
  end
61
74
  end
62
75
 
@@ -126,10 +139,12 @@ module IsoDoc::Ietf
126
139
 
127
140
  def make_endnotes(docxml)
128
141
  return unless docxml.at("//fn")
129
- endnotes = docxml.at("//back") or
130
- docxml << "<back/>" and endnotes = docxml.at("//back")
142
+
143
+ unless endnotes = docxml.at("//back")
144
+ docxml << "<back/>" and endnotes = docxml.at("//back")
145
+ end
131
146
  endnotes << "<section><name>Endnotes</name></section>"
132
- endnotes = docxml.at("//back/section[last()]")
147
+ docxml.at("//back/section[last()]")
133
148
  end
134
149
 
135
150
  def image_cleanup(docxml)
@@ -138,7 +153,7 @@ module IsoDoc::Ietf
138
153
  t.xpath(".//artwork").each_with_index do |a, i|
139
154
  insert.next = a.dup
140
155
  insert = insert.next
141
- a.replace("[IMAGE #{i+1}]")
156
+ a.replace("[IMAGE #{i + 1}]")
142
157
  end
143
158
  end
144
159
  end
@@ -146,20 +161,22 @@ module IsoDoc::Ietf
146
161
  # for markup in pseudocode
147
162
  def sourcecode_cleanup(docxml)
148
163
  docxml.xpath("//sourcecode").each do |s|
149
- s.children = s.children.to_xml.gsub(%r{<br/>\n}, "\n").
150
- gsub(%r{\s+(<t[ >])}, "\\1").gsub(%r{</t>\s+}, "</t>")
164
+ s.children = s.children.to_xml.gsub(%r{<br/>\n}, "\n")
165
+ .gsub(%r{\s+(<t[ >])}, "\\1").gsub(%r{</t>\s+}, "</t>")
151
166
  sourcecode_remove_markup(s)
152
- text = HTMLEntities.new.decode(s.children.to_xml.sub(/\A\n+/, ""))
153
- s.children = "<![CDATA[#{text}]]>"
167
+ s.children = "<![CDATA[#{HTMLEntities.new.decode(s
168
+ .children.to_xml.sub(/\A\n+/, ''))}]]>"
154
169
  end
155
170
  end
156
171
 
157
- def sourcecode_remove_markup(s)
158
- s.traverse do |n|
172
+ def sourcecode_remove_markup(node)
173
+ node.traverse do |n|
159
174
  next if n.text?
160
175
  next if %w(name callout annotation note sourcecode).include? n.name
161
- if n.name == "br" then n.replace("\n")
162
- elsif n.name == "t" then n.replace("\n\n#{n.children}")
176
+
177
+ case n.name
178
+ when "br" then n.replace("\n")
179
+ when "t" then n.replace("\n\n#{n.children}")
163
180
  else
164
181
  n.replace(n.children)
165
182
  end
@@ -169,6 +186,7 @@ module IsoDoc::Ietf
169
186
  def annotation_cleanup(docxml)
170
187
  docxml.xpath("//reference").each do |r|
171
188
  next unless r&.next_element&.name == "aside"
189
+
172
190
  aside = r.next_element
173
191
  aside.name = "annotation"
174
192
  aside.traverse do |n|
@@ -176,7 +194,7 @@ module IsoDoc::Ietf
176
194
  end
177
195
  r << aside
178
196
  end
179
- docxml.xpath("//references/aside").each { |r| r.remove }
197
+ docxml.xpath("//references/aside").each(&:remove)
180
198
  end
181
199
 
182
200
  def deflist_cleanup(docxml)
@@ -203,9 +221,7 @@ module IsoDoc::Ietf
203
221
  end
204
222
 
205
223
  def bookmark_cleanup(docxml)
206
- docxml.xpath("//bookmark").each do |b|
207
- b.remove
208
- end
224
+ docxml.xpath("//bookmark").each(&:remove)
209
225
  end
210
226
 
211
227
  def aside_cleanup(docxml)
@@ -25,10 +25,11 @@ module IsoDoc::Ietf
25
25
 
26
26
  def output_if_translit(text)
27
27
  return nil if text.nil?
28
+
28
29
  text.transliterate != text ? text.transliterate : nil
29
30
  end
30
31
 
31
- def title(isoxml, front)
32
+ def title(_isoxml, front)
32
33
  title = @meta.get[:doctitle] or return
33
34
  front.title title, **attr_code(abbrev: @meta.get[:docabbrev],
34
35
  ascii: (@meta.get[:docascii] ||
@@ -49,18 +50,20 @@ module IsoDoc::Ietf
49
50
  end
50
51
 
51
52
  def rfc_seriesinfo(isoxml, front)
52
- front.seriesInfo **seriesinfo_attr(isoxml).merge({name: "RFC",
53
- asciiName: "RFC"})
53
+ front.seriesInfo **seriesinfo_attr(isoxml).merge({ name: "RFC",
54
+ asciiName: "RFC" })
54
55
  i = isoxml&.at(ns("//bibdata/series[@type = 'intended']")) and
55
56
  front.seriesInfo nil,
56
- **attr_code(name: "", status: i&.at(ns("./title"))&.text,
57
- value: i&.at(ns("./number"))&.text || "")
57
+ **attr_code(name: "",
58
+ status: i&.at(ns("./title"))&.text,
59
+ value: i&.at(ns("./number"))&.text || "")
58
60
  end
59
61
 
60
62
  def id_seriesinfo(isoxml, front)
61
63
  front.seriesInfo nil,
62
- **seriesinfo_attr(isoxml).merge({name: "Internet-Draft",
63
- asciiName: "Internet-Draft"})
64
+ **seriesinfo_attr(isoxml)
65
+ .merge({ name: "Internet-Draft",
66
+ asciiName: "Internet-Draft" })
64
67
  i = isoxml&.at(ns("//bibdata/series[@type = 'intended']/title"))&.text and
65
68
  front.seriesInfo **attr_code(name: "", value: "", status: i)
66
69
  end
@@ -74,44 +77,49 @@ module IsoDoc::Ietf
74
77
  end
75
78
  end
76
79
 
77
- def person_author_attrs(c, role)
78
- return {} if c.nil?
79
- full = c&.at(ns("./completename"))&.text
80
- init = c&.at(ns("./initial"))&.text ||
81
- c&.xpath(ns("./forename")).map { |n| n.text[0] }.join(".")
80
+ def person_author_attrs(contrib, role)
81
+ return {} if contrib.nil?
82
+
83
+ full = contrib&.at(ns("./completename"))&.text
84
+ init = contrib&.at(ns("./initial"))&.text ||
85
+ contrib&.xpath(ns("./forename"))&.map { |n| n.text[0] }&.join(".")
82
86
  init = nil if init.empty?
83
87
  ret = attr_code(role: role, fullname: full, initials: init,
84
- surname: c&.at(ns("./surname"))&.text)
85
- pers_author_attrs1(ret, full, init, c)
86
- end
87
-
88
- def pers_author_attrs1(ret, full, init, c)
89
- full and ret.merge!(attr_code(
90
- asciiFullname: output_if_translit(full),
91
- asciiInitials: output_if_translit(init),
92
- asciiSurname: output_if_translit(c&.at(ns("./surname")))))
88
+ surname: contrib&.at(ns("./surname"))&.text)
89
+ pers_author_attrs1(ret, full, init, contrib)
90
+ end
91
+
92
+ def pers_author_attrs1(ret, full, init, contrib)
93
+ full and ret.merge!(
94
+ attr_code(
95
+ asciiFullname: output_if_translit(full),
96
+ asciiInitials: output_if_translit(init),
97
+ asciiSurname: output_if_translit(contrib&.at(ns("./surname"))),
98
+ ),
99
+ )
93
100
  ret
94
101
  end
95
102
 
96
- def person_author(c, role, front)
97
- front.author **person_author_attrs(c.at(ns("./person/name")), role) do |a|
98
- org = c.at(ns("./person/affiliation/organization")) and
99
- organization(org, a, c.document.at(ns("//showOnFrontPage")))
100
- address(c.xpath(ns(".//address")),
101
- c.at(ns(".//phone[not(@type = 'fax')]")),
102
- c.at(ns(".//phone[@type = 'fax']")),
103
- c.xpath(ns(".//email")), c.xpath(ns(".//uri")), a)
103
+ def person_author(contrib, role, front)
104
+ attrs = person_author_attrs(contrib.at(ns("./person/name")), role)
105
+ front.author **attrs do |a|
106
+ org = contrib.at(ns("./person/affiliation/organization")) and
107
+ organization(org, a, contrib.document.at(ns("//showOnFrontPage")))
108
+ address(contrib.xpath(ns(".//address")),
109
+ contrib.at(ns(".//phone[not(@type = 'fax')]")),
110
+ contrib.at(ns(".//phone[@type = 'fax']")),
111
+ contrib.xpath(ns(".//email")), contrib.xpath(ns(".//uri")), a)
104
112
  end
105
113
  end
106
114
 
107
- def org_author(c, role, front)
115
+ def org_author(contrib, role, front)
108
116
  front.author **attr_code(role: role) do |a|
109
- organization(c.at(ns("./organization")), a,
110
- c.document.at(ns("//showOnFrontPage")))
111
- address(c.at(ns(".//address")),
112
- c.at(ns(".//phone[not(@type = 'fax')]")),
113
- c.at(ns(".//phone[@type = 'fax']")),
114
- c.at(ns(".//email")), c.at(ns(".//uri")), a)
117
+ organization(contrib.at(ns("./organization")), a,
118
+ contrib.document.at(ns("//showOnFrontPage")))
119
+ address(contrib.at(ns(".//address")),
120
+ contrib.at(ns(".//phone[not(@type = 'fax')]")),
121
+ contrib.at(ns(".//phone[@type = 'fax']")),
122
+ contrib.at(ns(".//email")), contrib.at(ns(".//uri")), a)
115
123
  end
116
124
  end
117
125
 
@@ -120,11 +128,13 @@ module IsoDoc::Ietf
120
128
  out.organization name, **attr_code(
121
129
  showOnFrontPage: show&.text, ascii: output_if_translit(name),
122
130
  asciiAbbrev: output_if_translit(org.at(ns("./abbreviation"))),
123
- abbrev: org.at(ns("./abbreviation")))
131
+ abbrev: org.at(ns("./abbreviation"))
132
+ )
124
133
  end
125
134
 
126
135
  def address(addr, phone, fax, email, uri, out)
127
136
  return unless addr || phone || fax || email || uri
137
+
128
138
  out.address do |a|
129
139
  addr and postal(addr, a)
130
140
  phone and a.phone phone.text
@@ -137,6 +147,7 @@ module IsoDoc::Ietf
137
147
  def postal(addr, out)
138
148
  out.postal do |p|
139
149
  if line = addr.at(ns("./formattedAddress"))
150
+ line.xpath(ns(".//br")).each { |br| br.replace("\n") }
140
151
  line.text.split(/\n/).each do |l|
141
152
  p.postalLine l, **attr_code(ascii: l.transliterate)
142
153
  end
@@ -163,10 +174,10 @@ module IsoDoc::Ietf
163
174
  def email(email, out)
164
175
  ascii = email.text.transliterate
165
176
  out.email email.text,
166
- **attr_code(ascii: ascii == email.text ? nil : ascii )
177
+ **attr_code(ascii: ascii == email.text ? nil : ascii)
167
178
  end
168
179
 
169
- def date(isoxml, front)
180
+ def date(_isoxml, front)
170
181
  date = @meta.get[:publisheddate] || @meta.get[:circulateddate] || return
171
182
  date = date.gsub(/T.*$/, "")
172
183
  attr = date_attr(date) || return
@@ -175,8 +186,9 @@ module IsoDoc::Ietf
175
186
 
176
187
  def date_attr(date)
177
188
  return nil if date.nil?
189
+
178
190
  if date.length == 4 && date =~ /^\d\d\d\d$/ then { year: date }
179
- elsif date =~ /^\d\d\d\d-?\d\d$/
191
+ elsif /^\d\d\d\d-?\d\d$/.match?(date)
180
192
  m = /^(?<year>\d\d\d\d)-(?<month>\d\d)$/.match date
181
193
  { month: Date::MONTHNAMES[(m[:month]).to_i], year: m[:year] }
182
194
  else
@@ -184,25 +196,25 @@ module IsoDoc::Ietf
184
196
  d = Date.iso8601 date
185
197
  { day: d.day.to_s.gsub(/^0/, ""), year: d.year,
186
198
  month: Date::MONTHNAMES[d.month] }
187
- rescue
199
+ rescue StandardError
188
200
  nil
189
201
  end
190
202
  end
191
203
  end
192
204
 
193
- def area(isoxml, front)
205
+ def area(_isoxml, front)
194
206
  @meta.get[:areas].each do |w|
195
207
  front.area w
196
208
  end
197
209
  end
198
210
 
199
- def workgroup(isoxml, front)
211
+ def workgroup(_isoxml, front)
200
212
  @meta.get[:wg].each do |w|
201
213
  front.workgroup w
202
214
  end
203
215
  end
204
216
 
205
- def keyword(isoxml, front)
217
+ def keyword(_isoxml, front)
206
218
  @meta.get[:keywords].each do |kw|
207
219
  front.keyword kw
208
220
  end
@@ -230,7 +242,6 @@ module IsoDoc::Ietf
230
242
  end
231
243
  end
232
244
 
233
- def boilerplate(isoxml, front)
234
- end
245
+ def boilerplate(isoxml, front); end
235
246
  end
236
247
  end