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.
Files changed (54) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/macos.yml +3 -2
  3. data/.github/workflows/ubuntu.yml +3 -2
  4. data/.github/workflows/windows.yml +4 -3
  5. data/README.adoc +9 -0
  6. data/lib/asciidoctor/ietf/basicdoc.rng +1045 -0
  7. data/lib/asciidoctor/ietf/biblio.rng +1142 -0
  8. data/lib/asciidoctor/ietf/blocks.rb +76 -0
  9. data/lib/asciidoctor/ietf/converter.rb +211 -0
  10. data/lib/asciidoctor/ietf/front.rb +143 -0
  11. data/lib/asciidoctor/ietf/ietf.rng +882 -0
  12. data/lib/asciidoctor/ietf/isodoc.rng +514 -0
  13. data/lib/asciidoctor/ietf/isostandard.rng +860 -0
  14. data/lib/asciidoctor/ietf/reqt.rng +171 -0
  15. data/lib/asciidoctor/ietf/validate.rb +84 -0
  16. data/lib/isodoc/ietf/blocks.rb +215 -0
  17. data/lib/isodoc/ietf/cleanup.rb +220 -0
  18. data/lib/isodoc/ietf/footnotes.rb +70 -0
  19. data/lib/isodoc/ietf/front.rb +232 -0
  20. data/lib/isodoc/ietf/inline.rb +136 -0
  21. data/lib/isodoc/ietf/metadata.rb +62 -0
  22. data/lib/isodoc/ietf/references.rb +129 -0
  23. data/lib/isodoc/ietf/reqt.rb +74 -0
  24. data/lib/isodoc/ietf/rfc_convert.rb +60 -0
  25. data/lib/isodoc/ietf/section.rb +162 -0
  26. data/lib/isodoc/ietf/table.rb +43 -0
  27. data/lib/isodoc/ietf/terms.rb +65 -0
  28. data/lib/metanorma-ietf.rb +2 -1
  29. data/lib/metanorma/ietf/processor.rb +16 -37
  30. data/lib/metanorma/ietf/version.rb +1 -1
  31. data/metanorma-ietf.gemspec +3 -3
  32. metadata +36 -36
  33. data/Gemfile.lock +0 -327
  34. data/lib/asciidoctor/rfc.rb +0 -8
  35. data/lib/asciidoctor/rfc/common/base.rb +0 -544
  36. data/lib/asciidoctor/rfc/common/front.rb +0 -120
  37. data/lib/asciidoctor/rfc/common/validate.rb +0 -31
  38. data/lib/asciidoctor/rfc/v2/base.rb +0 -380
  39. data/lib/asciidoctor/rfc/v2/blocks.rb +0 -299
  40. data/lib/asciidoctor/rfc/v2/converter.rb +0 -60
  41. data/lib/asciidoctor/rfc/v2/front.rb +0 -69
  42. data/lib/asciidoctor/rfc/v2/inline_anchor.rb +0 -111
  43. data/lib/asciidoctor/rfc/v2/lists.rb +0 -135
  44. data/lib/asciidoctor/rfc/v2/table.rb +0 -116
  45. data/lib/asciidoctor/rfc/v2/validate.rng +0 -716
  46. data/lib/asciidoctor/rfc/v3/base.rb +0 -330
  47. data/lib/asciidoctor/rfc/v3/blocks.rb +0 -246
  48. data/lib/asciidoctor/rfc/v3/converter.rb +0 -62
  49. data/lib/asciidoctor/rfc/v3/front.rb +0 -122
  50. data/lib/asciidoctor/rfc/v3/inline_anchor.rb +0 -89
  51. data/lib/asciidoctor/rfc/v3/lists.rb +0 -176
  52. data/lib/asciidoctor/rfc/v3/svg.rng +0 -9081
  53. data/lib/asciidoctor/rfc/v3/table.rb +0 -65
  54. data/lib/asciidoctor/rfc/v3/validate.rng +0 -2143
@@ -0,0 +1,136 @@
1
+ require "mathml2asciimath"
2
+
3
+ module IsoDoc::Ietf
4
+ class RfcConvert < ::IsoDoc::Convert
5
+ def em_parse(node, out)
6
+ out.em do |e|
7
+ node.children.each { |n| parse(n, e) }
8
+ end
9
+ end
10
+
11
+ def sup_parse(node, out)
12
+ out.sup do |e|
13
+ node.children.each { |n| parse(n, e) }
14
+ end
15
+ end
16
+
17
+ def sub_parse(node, out)
18
+ out.sub do |e|
19
+ node.children.each { |n| parse(n, e) }
20
+ end
21
+ end
22
+
23
+ def tt_parse(node, out)
24
+ out.tt do |e|
25
+ node.children.each { |n| parse(n, e) }
26
+ end
27
+ end
28
+
29
+ def strong_parse(node, out)
30
+ out.strong do |e|
31
+ node.children.each { |n| parse(n, e) }
32
+ end
33
+ end
34
+
35
+ def bcp14_parse(node, out)
36
+ out.bcp14 do |e|
37
+ node.children.each { |n| parse(n, e) }
38
+ end
39
+ end
40
+
41
+ def strike_parse(node, out)
42
+ node.children.each { |n| parse(n, out) }
43
+ end
44
+
45
+ def smallcap_parse(node, out)
46
+ node.children.each { |n| parse(n, out) }
47
+ end
48
+
49
+ def keyword_parse(node, out)
50
+ node.children.each { |n| parse(n, out) }
51
+ end
52
+
53
+ def text_parse(node, out)
54
+ return if node.nil? || node.text.nil?
55
+ text = node.to_s
56
+ out << text
57
+ end
58
+
59
+ def stem_parse(node, out)
60
+ stem = case node["type"]
61
+ when "MathML" then MathML2AsciiMath.m2a(node.children.to_xml)
62
+ else
63
+ HTMLEntities.new.encode(node.text)
64
+ end
65
+ out << "#{@openmathdelim} #{stem} #{@closemathdelim}"
66
+ end
67
+
68
+ def page_break(_out)
69
+ end
70
+
71
+ def br_parse(node, out)
72
+ if @sourcecode
73
+ out.br
74
+ end
75
+ end
76
+
77
+ def hr_parse(node, out)
78
+ end
79
+
80
+ def link_parse(node, out)
81
+ out.eref **attr_code(target: node["target"]) do |l|
82
+ node.children.each { |n| parse(n, l) }
83
+ end
84
+ end
85
+
86
+ def image_parse(node, out, caption)
87
+ attrs = { src: node["src"], title: node["title"],
88
+ align: node["align"], name: node["filename"],
89
+ anchor: node["id"], type: "svg",
90
+ alt: node["alt"] }
91
+ out.artwork **attr_code(attrs)
92
+ image_title_parse(out, caption)
93
+ end
94
+
95
+ def image_title_parse(out, caption)
96
+ unless caption.nil?
97
+ out.t **{ align: "center", keepWithPrevious: "true" } do |p|
98
+ p << caption.to_s
99
+ end
100
+ end
101
+ end
102
+
103
+ def xref_parse(node, out)
104
+ out.xref **attr_code(target: node["target"], format: node["format"],
105
+ relative: node["relative"]) do |l|
106
+ l << get_linkend(node)
107
+ end
108
+ end
109
+
110
+ def eref_parse(node, out)
111
+ linkend = node.children.select { |c| c.name != "locality" }
112
+ section = eref_clause(node.xpath(ns("./locality")), nil) || ""
113
+ out.relref **attr_code(target: node["bibitemid"], section: section,
114
+ displayFormat: node["displayFormat"]) do |l|
115
+ linkend.each { |n| parse(n, l) }
116
+ end
117
+ end
118
+
119
+ def eref_clause(refs, target)
120
+ refs.each do |l|
121
+ next unless %w(clause section).include? l["type"]
122
+ return l&.at(ns("./referenceFrom"))&.text
123
+ end
124
+ return nil
125
+ end
126
+
127
+ def index_parse(node, out)
128
+ out.iref nil, **attr_code(item: node["primary"],
129
+ subitem: node["secondary"])
130
+ end
131
+
132
+ def bookmark_parse(node, out)
133
+ out.bookmark nil, **attr_code(anchor: node["id"])
134
+ end
135
+ end
136
+ end
@@ -0,0 +1,62 @@
1
+ require "isodoc"
2
+
3
+ module IsoDoc
4
+ module Ietf
5
+ class Metadata < IsoDoc::Metadata
6
+ TITLE_RFC = "//bibdata//title[@type='main' and @language='en']".freeze
7
+
8
+ def title(isoxml, _out)
9
+ t = isoxml.at(ns(TITLE_RFC)) and
10
+ set(:doctitle, t.text)
11
+ t = isoxml.at(ns(TITLE_RFC.sub(/main/, "abbrev"))) and
12
+ set(:docabbrev, t.text)
13
+ t = isoxml.at(ns(TITLE_RFC.sub(/main/, "ascii"))) and
14
+ set(:docascii, t.text)
15
+ end
16
+
17
+ def relaton_relations
18
+ %w(included-in described-by derived-from equivalent)
19
+ # = item describedby convertedfrom alternate
20
+ end
21
+
22
+ def keywords(isoxml, _out)
23
+ ret = []
24
+ isoxml.xpath(ns("//bibdata/keyword")).each do |kw|
25
+ ret << kw.text
26
+ end
27
+ set(:keywords, ret)
28
+ end
29
+
30
+ def areas(isoxml, _out)
31
+ ret = []
32
+ isoxml.xpath(ns("//bibdata/ext/area")).each do |kw|
33
+ ret << kw.text
34
+ end
35
+ set(:areas, ret)
36
+ end
37
+
38
+ def docid(isoxml, _out)
39
+ dn = isoxml.at(ns("//bibdata/docnumber"))
40
+ set(:docnumber, dn&.text&.sub(/^rfc-/, "")&.sub(/\.[a-z0-9]+$/i, ""))
41
+ end
42
+
43
+ def author(xml, _out)
44
+ super
45
+ wg(xml)
46
+ end
47
+
48
+ def wg(xml)
49
+ workgroups = []
50
+ xml.xpath(ns("//bibdata/ext/editorialgroup/workgroup")).each do |wg|
51
+ workgroups << wg.text
52
+ end
53
+ set(:wg, workgroups)
54
+ end
55
+
56
+ def doctype(isoxml, _out)
57
+ super
58
+ set(:doctype, "Rfc") if get[:doctype].nil?
59
+ end
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,129 @@
1
+ module IsoDoc::Ietf
2
+ class RfcConvert < ::IsoDoc::Convert
3
+ # TODO displayreference will be implemented as combination of autofetch and user-provided citations
4
+
5
+ def bibliography(isoxml, out)
6
+ isoxml.xpath(ns("//references")).each do |f|
7
+ out.references **attr_code(anchor: f["id"]) do |div|
8
+ title = f.at(ns("./title")) and div.name do |name|
9
+ title.children.each { |n| parse(n, name) }
10
+ end
11
+ f.elements.reject do |e|
12
+ %w(reference title bibitem note).include? e.name
13
+ end.each { |e| parse(e, div) }
14
+ biblio_list(f, div, true)
15
+ end
16
+ end
17
+ end
18
+
19
+ def biblio_list(f, div, biblio)
20
+ i = 0
21
+ f.xpath(ns("./bibitem | ./note")).each do |b|
22
+ next if implicit_reference(b)
23
+ i += 1 if b.name == "bibitem"
24
+ if b.name == "note" then note_parse(b, div)
25
+ elsif(is_ietf(b)) then ietf_bibitem_entry(div, b, i)
26
+ else
27
+ nonstd_bibitem(div, b, i, biblio)
28
+ end
29
+ end
30
+ end
31
+
32
+ def nonstd_bibitem(list, b, ordinal, bibliography)
33
+ uris = b.xpath(ns("./uri"))
34
+ list.reference **attr_code(target: uris.empty? ? nil : uris[0]&.text,
35
+ anchor: b["id"]) do |r|
36
+ r.front do |f|
37
+ relaton_to_title(b, f)
38
+ relaton_to_author(b, f)
39
+ relaton_to_date(b, f)
40
+ relaton_to_keyword(b, f)
41
+ relaton_to_abstract(b, f)
42
+ end
43
+ uris[1..-1]&.each do |u|
44
+ r.format nil, **attr_code(target: u.text, type: u["type"])
45
+ end
46
+ end
47
+ end
48
+
49
+ def relaton_to_title(b, f)
50
+ id = bibitem_ref_code(b)
51
+ identifier = render_identifier(id)
52
+ title = b&.at(ns("./title")) || b&.at(ns("./formattedref")) or return
53
+ f.title do |t|
54
+ t << "#{identifier}, "
55
+ title.children.each { |n| parse(n, t) }
56
+ end
57
+ end
58
+
59
+ def relaton_to_author(b, f)
60
+ auths = b.xpath(ns("./contributor[xmlns:role/@type = 'author' or "\
61
+ "xmlns:role/@type = 'editor']"))
62
+ auths.empty? and auths = b.xpath(ns("./contributor[xmlns:role/@type = "\
63
+ "'publisher']"))
64
+ auths.each do |a|
65
+ role = a.at(ns("./role[@type = 'editor']")) ? "editor" : nil
66
+ p = a&.at(ns("./person/name")) and
67
+ relaton_person_to_author(p, role, f) or
68
+ relaton_org_to_author(a&.at(ns("./organization")), role, f)
69
+ end
70
+ end
71
+
72
+ def relaton_person_to_author(p, role, f)
73
+ fullname = p&.at(ns("./completename"))&.text
74
+ surname = p&.at(ns("./surname"))&.text
75
+ initials = p&.xpath(ns("./initial"))&.map { |i| i.text }&.join(" ") ||
76
+ p&.xpath(ns("./forename"))&.map { |i| i.text[0] }&.join(" ")
77
+ initials = nil if initials.empty?
78
+ f.author nil,
79
+ **attr_code(fullname: fullname, asciiFullname: fullname&.transliterate,
80
+ role: role, surname: surname, initials: initials,
81
+ asciiSurname: fullname ? surname&.transliterate : nil,
82
+ asciiInitials: fullname ? initials&.transliterate : nil)
83
+ end
84
+
85
+ def relaton_org_to_author(o, role, f)
86
+ name = o&.at(ns("./name"))&.text
87
+ abbrev = o&.at(ns("./abbreviation"))&.text
88
+ f.author do |a|
89
+ f.organization name, **attr_code(ascii: name&.transliterate,
90
+ abbrev: abbrev)
91
+ end
92
+ end
93
+
94
+ def relaton_to_date(b, f)
95
+ date = b.at(ns("./date[@type = 'published']")) ||
96
+ b.at(ns("./date[@type = 'issued']")) ||
97
+ b.at(ns("./date[@type = 'circulated']"))
98
+ return unless date
99
+ attr = date_attr(date&.at(ns("./on | ./from"))&.text) || return
100
+ f.date **attr_code(attr)
101
+ end
102
+
103
+ def relaton_to_keyword(b, f)
104
+ b.xpath(ns("./keyword")).each do |k|
105
+ f.keyword do |keyword|
106
+ k.children.each { |n| parse(n, keyword) }
107
+ end
108
+ end
109
+ end
110
+
111
+ def relaton_to_abstract(b, f)
112
+ b.xpath(ns("./abstract")).each do |k|
113
+ f.abstract do |abstract|
114
+ k.children.each { |n| parse(n, abstract) }
115
+ end
116
+ end
117
+ end
118
+
119
+ def ietf_bibitem_entry(div, b, i)
120
+ url = b&.at(ns("./uri[@type = 'xml']"))&.text
121
+ div << "<xi:include href='#{url}'/>"
122
+ end
123
+
124
+ def is_ietf(b)
125
+ url = b.at(ns("./uri[@type = 'xml']")) or return false
126
+ /xml2rfc\.tools\.ietf\.org/.match(url)
127
+ end
128
+ end
129
+ end
@@ -0,0 +1,74 @@
1
+ module IsoDoc::Ietf
2
+ class RfcConvert < ::IsoDoc::Convert
3
+ def recommendation_name(node, out, type)
4
+ label, title, lbl = recommendation_labels(node)
5
+ out.t **{ keepWithNext: "true" } do |b|
6
+ b << (lbl.nil? ? l10n("#{type}:") : l10n("#{type} #{lbl}:"))
7
+ end
8
+ if label || title
9
+ out.t **{ keepWithNext: "true" } do |b|
10
+ label and label.children.each { |n| parse(n,b) }
11
+ b << "#{clausedelim} " if label && title
12
+ title and title.children.each { |n| parse(n,b) }
13
+ end
14
+ end
15
+ end
16
+
17
+ def recommendation_attributes(node, out)
18
+ ret = recommendation_attributes1(node)
19
+ return if ret.empty?
20
+ out.ul do |p|
21
+ ret.each do |l|
22
+ p.li do |i|
23
+ i.em { |e| i << l }
24
+ end
25
+ end
26
+ end
27
+ end
28
+
29
+ def recommendation_parse(node, out)
30
+ recommendation_name(node, out, @recommendation_lbl)
31
+ recommendation_attributes(node, out)
32
+ node.children.each do |n|
33
+ parse(n, out) unless %w(label title).include? n.name
34
+ end
35
+ end
36
+
37
+ def requirement_parse(node, out)
38
+ recommendation_name(node, out, @requirement_lbl)
39
+ recommendation_attributes(node, out)
40
+ node.children.each do |n|
41
+ parse(n, out) unless %w(label title).include? n.name
42
+ end
43
+ end
44
+
45
+ def permission_parse(node, out)
46
+ recommendation_name(node, out, @permission_lbl)
47
+ recommendation_attributes(node, out)
48
+ node.children.each do |n|
49
+ parse(n, out) unless %w(label title).include? n.name
50
+ end
51
+ end
52
+
53
+ def inline?(node)
54
+ return true if node.first_element_child.nil?
55
+ %w(em link eref xref strong tt sup sub strike keyword smallcap
56
+ br hr bookmark pagebreak stem origin term preferred admitted
57
+ deprecates domain termsource modification).include? node.first_element_child.name
58
+ end
59
+
60
+ def requirement_component_parse(node, out)
61
+ return if node["exclude"] == "true"
62
+ out1 = out
63
+ if inline?(node)
64
+ out.t do |p|
65
+ p << "INHERIT: " if node.name == "inherit"
66
+ node.children.each { |n| parse(n, p) }
67
+ end
68
+ else
69
+ node.children.each { |n| parse(n, out) }
70
+ end
71
+ end
72
+ end
73
+ end
74
+
@@ -0,0 +1,60 @@
1
+ require_relative "./terms"
2
+ require_relative "./blocks"
3
+ require_relative "./metadata"
4
+ require_relative "./front"
5
+ require_relative "./table"
6
+ require_relative "./inline"
7
+ require_relative "./reqt"
8
+ require_relative "./cleanup"
9
+ require_relative "./footnotes"
10
+ require_relative "./references"
11
+ require_relative "./section"
12
+
13
+ module IsoDoc::Ietf
14
+ class RfcConvert < ::IsoDoc::Convert
15
+ def convert1(docxml, filename, dir)
16
+ anchor_names docxml
17
+ info docxml, nil
18
+ xml = noko do |xml|
19
+ xml.rfc **attr_code(rfc_attributes(docxml)) do |html|
20
+ make_link(html, docxml)
21
+ make_front(html, docxml)
22
+ make_middle(html, docxml)
23
+ make_back(html, docxml)
24
+ end
25
+ end.join("\n").sub(/<!DOCTYPE[^>]+>\n/, "")
26
+ set_pis(docxml, Nokogiri::XML(xml))
27
+ end
28
+
29
+ def metadata_init(lang, script, labels)
30
+ @meta = Metadata.new(lang, script, labels)
31
+ end
32
+
33
+ def extract_delims(text)
34
+ @openmathdelim = "$$"
35
+ @closemathdelim = "$$"
36
+ while %r{#{Regexp.escape(@openmathdelim)}}m.match(text) ||
37
+ %r{#{Regexp.escape(@closemathdelim)}}m.match(text)
38
+ @openmathdelim += "$"
39
+ @closemathdelim += "$"
40
+ end
41
+ [@openmathdelim, @closemathdelim]
42
+ end
43
+
44
+ def error_parse(node, out)
45
+ case node.name
46
+ when "bcp14" then bcp14_parse(node, out)
47
+ else
48
+ text = node.to_xml.gsub(/</, "&lt;").gsub(/>/, "&gt;")
49
+ out.t { |p| p << text }
50
+ end
51
+ end
52
+
53
+ def postprocess(result, filename, dir)
54
+ result = from_xhtml(cleanup(to_xhtml(result))).sub(/<!DOCTYPE[^>]+>\n/, "").
55
+ sub(/(<rfc[^<]+? )lang="[^"]+"/, "\\1")
56
+ File.open("#{filename}.rfc.xml", "w:UTF-8") { |f| f.write(result) }
57
+ @files_to_delete.each { |f| FileUtils.rm_rf f }
58
+ end
59
+ end
60
+ end