metanorma-ogc 1.0.3 → 1.0.8

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 (44) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/macos.yml +10 -10
  3. data/.github/workflows/ubuntu.yml +25 -11
  4. data/.github/workflows/windows.yml +11 -12
  5. data/README.adoc +3 -2
  6. data/lib/asciidoctor/ogc/biblio.rng +144 -49
  7. data/lib/asciidoctor/ogc/boilerplate.xml +37 -69
  8. data/lib/asciidoctor/ogc/converter.rb +6 -11
  9. data/lib/asciidoctor/ogc/isodoc.rng +49 -5
  10. data/lib/asciidoctor/ogc/ogc.rng +0 -4
  11. data/lib/isodoc/ogc/base_convert.rb +13 -112
  12. data/lib/isodoc/ogc/biblio.rb +13 -2
  13. data/lib/isodoc/ogc/html/html_ogc_titlepage.html +2 -6
  14. data/lib/isodoc/ogc/html/htmlstyle.scss +11 -1
  15. data/lib/isodoc/ogc/html/scripts.html +14 -27
  16. data/lib/isodoc/ogc/html/word_ogc_titlepage.html +13 -4
  17. data/lib/isodoc/ogc/html_convert.rb +1 -0
  18. data/lib/isodoc/ogc/i18n-en.yaml +3 -0
  19. data/lib/isodoc/ogc/metadata.rb +1 -31
  20. data/lib/isodoc/ogc/ogc.abstract-specification-topic.xsl +3387 -0
  21. data/lib/isodoc/ogc/ogc.best-practice.xsl +3387 -0
  22. data/lib/isodoc/ogc/ogc.change-request-supporting-document.xsl +3387 -0
  23. data/lib/isodoc/ogc/ogc.community-practice.xsl +3387 -0
  24. data/lib/isodoc/ogc/ogc.community-standard.xsl +3387 -0
  25. data/lib/isodoc/ogc/ogc.discussion-paper.xsl +3387 -0
  26. data/lib/isodoc/ogc/ogc.engineering-report.xsl +3387 -0
  27. data/lib/isodoc/ogc/ogc.other.xsl +3387 -0
  28. data/lib/isodoc/ogc/ogc.policy.xsl +3387 -0
  29. data/lib/isodoc/ogc/ogc.reference-model.xsl +3387 -0
  30. data/lib/isodoc/ogc/ogc.release-notes.xsl +3387 -0
  31. data/lib/isodoc/ogc/ogc.standard.xsl +3387 -0
  32. data/lib/isodoc/ogc/ogc.test-suite.xsl +3387 -0
  33. data/lib/isodoc/ogc/ogc.user-guide.xsl +3387 -0
  34. data/lib/isodoc/ogc/ogc.white-paper.xsl +3387 -0
  35. data/lib/isodoc/ogc/pdf_convert.rb +18 -77
  36. data/lib/isodoc/ogc/reqt.rb +74 -114
  37. data/lib/isodoc/ogc/reqt_xref.rb +96 -0
  38. data/lib/isodoc/ogc/sections.rb +111 -0
  39. data/lib/isodoc/ogc/word_convert.rb +17 -11
  40. data/lib/metanorma/ogc/processor.rb +8 -0
  41. data/lib/metanorma/ogc/version.rb +1 -1
  42. data/metanorma-ogc.gemspec +1 -1
  43. metadata +21 -5
  44. data/lib/isodoc/ogc/html/scripts.pdf.html +0 -72
@@ -1,96 +1,37 @@
1
1
  require_relative "base_convert"
2
- require "fileutils"
3
2
  require "isodoc"
4
- require_relative "metadata"
5
3
 
6
4
  module IsoDoc
7
5
  module Ogc
8
6
  # A {Converter} implementation that generates PDF HTML output, and a
9
7
  # document schema encapsulation of the document for validation
10
- class PdfConvert < IsoDoc::PdfConvert
8
+ class PdfConvert < IsoDoc::XslfoPdfConvert
11
9
  def initialize(options)
12
10
  @libdir = File.dirname(__FILE__)
13
11
  super
14
- #FileUtils.cp html_doc_path('logo.jpg'), "logo.jpg"
15
- #@files_to_delete << "logo.jpg"
16
12
  end
17
13
 
18
- def default_fonts(options)
19
- {
20
- bodyfont: (options[:script] == "Hans" ? '"SimSun",serif' : '"Overpass",sans-serif'),
21
- headerfont: (options[:script] == "Hans" ? '"SimHei",sans-serif' : '"Overpass",sans-serif'),
22
- monospacefont: '"Space Mono",monospace'
23
- }
14
+ def pdf_stylesheet(docxml)
15
+ doctype = docxml&.at(ns("//bibdata/ext/doctype"))&.text
16
+ doctype = "other" unless %w(abstract-specification-topic best-practice
17
+ change-request-supporting-document community-practice community-standard
18
+ discussion-paper engineering-report policy reference-model release-notes
19
+ standard user-guide test-suite white-paper).include? doctype
20
+ "ogc.#{doctype}.xsl"
24
21
  end
25
22
 
26
- def default_file_locations(_options)
27
- {
28
- htmlstylesheet: html_doc_path("htmlstyle.scss"),
29
- htmlcoverpage: html_doc_path("html_ogc_titlepage.html"),
30
- htmlintropage: html_doc_path("html_ogc_intro.html"),
31
- scripts_pdf: html_doc_path("scripts.pdf.html"),
32
- }
33
- end
34
-
35
- def metadata_init(lang, script, labels)
36
- @meta = Metadata.new(lang, script, labels)
37
- end
38
-
39
- def googlefonts
40
- <<~HEAD.freeze
41
- <link href="https://fonts.googleapis.com/css?family=Open+Sans:300,300i,400,400i,600,600i|Space+Mono:400,700" rel="stylesheet" />
42
- <link href="https://fonts.googleapis.com/css?family=Overpass:300,300i,600,900" rel="stylesheet" />
43
- <link href="https://fonts.googleapis.com/css?family=Teko:300,400,500" rel="stylesheet">
44
- HEAD
45
- end
46
-
47
- def admonition_class(node)
48
- case node["type"]
49
- when "important" then "Admonition.Important"
50
- when "warning" then "Admonition.Warning"
51
- else
52
- "Admonition"
23
+ def convert(filename, file = nil, debug = false)
24
+ file = File.read(filename, encoding: "utf-8") if file.nil?
25
+ docxml, outname_html, dir = convert_init(file, filename, debug)
26
+ /\.xml$/.match(filename) or
27
+ filename = Tempfile.open([outname_html, ".xml"], encoding: "utf-8") do |f|
28
+ f.write file
29
+ f.path
53
30
  end
31
+ FileUtils.rm_rf dir
32
+ ::Metanorma::Output::XslfoPdf.new.convert(
33
+ filename, outname_html + ".pdf", File.join(@libdir, pdf_stylesheet(docxml)))
54
34
  end
55
-
56
- def make_body(xml, docxml)
57
- body_attr = { lang: "EN-US", link: "blue", vlink: "#954F72", "xml:lang": "EN-US", class: "container" }
58
- xml.body **body_attr do |body|
59
- make_body1(body, docxml)
60
- make_body2(body, docxml)
61
- make_body3(body, docxml)
62
- end
63
- end
64
-
65
- def html_toc(docxml)
66
- docxml
67
- end
68
-
69
- def make_body3(body, docxml)
70
- body.div **{ class: "main-section" } do |div3|
71
- @prefacenum = 0
72
- boilerplate docxml, div3
73
- abstract docxml, div3
74
- keywords docxml, div3
75
- foreword docxml, div3
76
- introduction docxml, div3
77
- submittingorgs docxml, div3
78
- submitters docxml, div3
79
- preface docxml, div3
80
- acknowledgements docxml, div3
81
- middle docxml, div3
82
- footnotes div3
83
- comments div3
84
- end
85
- end
86
-
87
- def authority_cleanup(docxml)
88
- authority_cleanup1(docxml, "contact")
89
- super
90
- end
91
-
92
- include BaseConvert
93
35
  end
94
36
  end
95
37
  end
96
-
@@ -1,38 +1,49 @@
1
1
  require "isodoc"
2
- require_relative "metadata"
3
- require "fileutils"
2
+ require_relative "reqt_xref"
4
3
 
5
4
  module IsoDoc
6
5
  module Ogc
7
6
  module BaseConvert
8
7
  def recommend_class(node)
9
8
  return "recommendtest" if node["type"] == "verification"
9
+ return "recommendtest" if node["type"] == "abstracttest"
10
10
  return "recommendclass" if node["type"] == "class"
11
+ return "recommendclass" if node["type"] == "conformanceclass"
11
12
  "recommend"
12
13
  end
13
14
 
14
15
  def recommend_table_attr(node)
15
- attr_code(id: node["id"],
16
- class: recommend_class(node),
16
+ attr_code(id: node["id"], class: recommend_class(node),
17
17
  style: "border-collapse:collapse;border-spacing:0;")
18
18
  end
19
19
 
20
20
  REQ_TBL_ATTR =
21
21
  { style: "vertical-align:top;", class: "recommend" }.freeze
22
22
 
23
+ def recommendation_class(node)
24
+ %w(verification abstracttest).include?(node["type"]) ?
25
+ "RecommendationTestTitle" : "RecommendationTitle"
26
+ end
27
+
23
28
  def recommendation_name(node, out, type)
24
29
  label, title, lbl = recommendation_labels(node)
25
- out.p **{ class: node["type"] == "verification" ?
26
- "RecommendationTestTitle" : "RecommendationTitle" } do |b|
27
- lbl = anchor(node['id'], :label, false)
28
- b << (lbl.nil? ? l10n("#{type}:") : l10n("#{type} #{lbl}:"))
29
- if title
30
- b << " "
31
- title.children.each { |n| parse(n,b) }
30
+ out.p **{ class: recommendation_class(node) } do |b|
31
+ if inject_crossreference_reqt?(node, label)
32
+ lbl = anchor(@reqtlabels[label.text], :xref, false)
33
+ b << (lbl.nil? ? l10n("#{type}:") : l10n("#{lbl}:"))
34
+ else
35
+ b << (lbl.nil? ? l10n("#{type}:") : l10n("#{type} #{lbl}:"))
32
36
  end
37
+ recommendation_name1(title, node, label, b)
33
38
  end
34
39
  end
35
40
 
41
+ def recommendation_name1(title, node, label, b)
42
+ return unless title && !inject_crossreference_reqt?(node, label)
43
+ b << " "
44
+ title.children.each { |n| parse(n,b) }
45
+ end
46
+
36
47
  def recommend_title(node, out)
37
48
  label = node.at(ns("./label")) or return
38
49
  out.tr do |tr|
@@ -44,27 +55,52 @@ module IsoDoc
44
55
  end
45
56
  end
46
57
 
58
+ # embedded reqts xref to top level reqts via label lookup
59
+ def inject_crossreference_reqt?(node, label)
60
+ !node.ancestors("requirement, recommendation, permission").empty? &&
61
+ @reqtlabels[label&.text]
62
+ end
63
+
47
64
  def recommendation_attributes1(node)
48
65
  out = []
49
66
  oblig = node["obligation"] and out << ["Obligation", oblig]
50
- subj = node&.at(ns("./subject"))&.text and
51
- out << [node["type"] == "class" ? "Target Type" : "Subject", subj]
52
- node.xpath(ns("./inherit")).each { |i| out << ["Dependency", i.text] }
67
+ subj = node&.at(ns("./subject"))&.text and out << [rec_subj(node), subj]
68
+ node.xpath(ns("./inherit")).each do |i|
69
+ out << recommendation_attr_parse(i, "Dependency")
70
+ end
53
71
  node.xpath(ns("./classification")).each do |c|
54
- tag = c.at(ns("./tag")) or next
55
- value = c.at(ns("./value")) or next
56
- out << [tag.text.capitalize, value.text]
72
+ line = recommendation_attr_keyvalue(c, "tag", "value") and out << line
57
73
  end
58
74
  out
59
75
  end
60
76
 
77
+ def rec_subj(node)
78
+ %w(class conformanceclass).include?(node["type"]) ?
79
+ "Target Type" : "Subject"
80
+ end
81
+
82
+ def recommendation_attr_parse(node, label)
83
+ text = noko do |xml|
84
+ node.children.each { |n| parse(n, xml) }
85
+ end.join
86
+ [label, text]
87
+ end
88
+
89
+ def recommendation_attr_keyvalue(node, key, value)
90
+ tag = node.at(ns("./#{key}")) or return nil
91
+ value = node.at(ns("./#{value}")) or return nil
92
+ [tag.text.capitalize, value.text]
93
+ end
94
+
61
95
  def recommendation_attributes(node, out)
62
- ret = recommendation_attributes1(node)
63
- return if ret.empty?
64
- ret.each do |i|
96
+ recommendation_attributes1(node).each do |i|
65
97
  out.tr do |tr|
66
- tr.td i[0], **REQ_TBL_ATTR
67
- tr.td i[1], **REQ_TBL_ATTR
98
+ tr.td **REQ_TBL_ATTR do |td|
99
+ td << i[0]
100
+ end
101
+ tr.td **REQ_TBL_ATTR do |td|
102
+ td << i[1]
103
+ end
68
104
  end
69
105
  end
70
106
  end
@@ -118,107 +154,31 @@ module IsoDoc
118
154
  end
119
155
 
120
156
  def recommendation_parse(node, out)
121
- label = case node["type"]
122
- when "verification" then @labels["recommendationtest"]
123
- when "class" then @labels["recommendationclass"]
124
- else
125
- @recommendation_lbl
126
- end
127
- recommendation_parse1(node, out, label)
157
+ recommendation_parse0(node, out, "recommendation")
128
158
  end
129
159
 
130
- def requirement_parse(node, out)
131
- label = case node["type"]
132
- when "verification" then @labels["requirementtest"]
133
- when "class" then @labels["requirementclass"]
134
- else
135
- @requirement_lbl
136
- end
137
- recommendation_parse1(node, out, label)
138
- end
139
-
140
- def permission_parse(node, out)
160
+ def recommendation_parse0(node, out, r)
141
161
  label = case node["type"]
142
- when "verification" then @labels["permissiontest"]
143
- when "class" then @labels["permissionclass"]
144
- else
145
- @permission_lbl
162
+ when "verification" then @labels["#{r}test"]
163
+ when "class" then @labels["#{r}class"]
164
+ when "abstracttest" then @labels["abstracttest"]
165
+ when "conformanceclass" then @labels["conformanceclass"]
166
+ else
167
+ case r
168
+ when "recommendation" then @recommendation_lbl
169
+ when "requirement" then @requirement_lbl
170
+ when "permission" then @permission_lbl
171
+ end
146
172
  end
147
173
  recommendation_parse1(node, out, label)
148
174
  end
149
175
 
150
- FIRST_LVL_REQ = IsoDoc::Function::XrefGen::FIRST_LVL_REQ
151
-
152
- def sequential_permission_names(clause, klass, label)
153
- c = ::IsoDoc::Function::XrefGen::Counter.new
154
- clause.xpath(ns(".//#{klass}#{FIRST_LVL_REQ}")).each do |t|
155
- next if t["id"].nil? || t["id"].empty?
156
- id = c.increment(t).print
157
- @anchors[t["id"]] = anchor_struct(id, t, label, klass, t["unnumbered"])
158
- sequential_permission_children(t, id)
159
- end
160
- end
161
-
162
- def sequential_permission_children(t, id)
163
- sequential_permission_names1(t, id, "permission[not(@type = 'verification' or @type = 'class')]", @permission_lbl)
164
- sequential_permission_names1(t, id, "requirement[not(@type = 'verification' or @type = 'class')]", @requirement_lbl)
165
- sequential_permission_names1(t, id, "recommendation[not(@type = 'verification' or @type = 'class')]", @recommendation_lbl)
166
- sequential_permission_names1(t, id, "permission[@type = 'verification']", @labels["permissiontest"])
167
- sequential_permission_names1(t, id, "requirement[@type = 'verification']", @labels["requirementtest"])
168
- sequential_permission_names1(t, id, "recommendation[@type = 'verification']", @labels["recommendationtest"])
169
- sequential_permission_names1(t, id, "permission[@type = 'class']", @labels["permissionclass"])
170
- sequential_permission_names1(t, id, "requirement[@type = 'class']", @labels["requirementclass"])
171
- sequential_permission_names1(t, id, "recommendation[@type = 'class']", @labels["recommendationclass"])
172
- end
173
-
174
- def sequential_permission_names1(block, lbl, klass, label)
175
- c = ::IsoDoc::Function::XrefGen::Counter.new
176
- block.xpath(ns("./#{klass}")).each do |t|
177
- next if t["id"].nil? || t["id"].empty?
178
- id = "#{lbl}#{hierfigsep}#{c.increment(t).print}"
179
- @anchors[t["id"]] = anchor_struct(id, t, label, klass, t["unnumbered"])
180
- sequential_permission_children(t, id)
181
- end
176
+ def requirement_parse(node, out)
177
+ recommendation_parse0(node, out, "requirement")
182
178
  end
183
179
 
184
- def sequential_asset_names(clause)
185
- sequential_table_names(clause)
186
- sequential_figure_names(clause)
187
- sequential_formula_names(clause)
188
- sequential_permission_names(clause, "permission[not(@type = 'verification' or @type = 'class')]", @permission_lbl)
189
- sequential_permission_names(clause, "requirement[not(@type = 'verification' or @type = 'class')]", @requirement_lbl)
190
- sequential_permission_names(clause, "recommendation[not(@type = 'verification' or @type = 'class')]", @recommendation_lbl)
191
- sequential_permission_names(clause, "permission[@type = 'verification']", @labels["permissiontest"])
192
- sequential_permission_names(clause, "requirement[@type = 'verification']", @labels["requirementtest"])
193
- sequential_permission_names(clause, "recommendation[@type = 'verification']", @labels["recommendationtest"])
194
- sequential_permission_names(clause, "permission[@type = 'class']", @labels["permissionclass"])
195
- sequential_permission_names(clause, "requirement[@type = 'class']", @labels["requirementclass"])
196
- sequential_permission_names(clause, "recommendation[@type = 'class']", @labels["recommendationclass"])
197
- end
198
-
199
- def hierarchical_asset_names(clause, num)
200
- hierarchical_table_names(clause, num)
201
- hierarchical_figure_names(clause, num)
202
- hierarchical_formula_names(clause, num)
203
- hierarchical_permission_names(clause, num, "permission[not(@type = 'verification' or @type = 'class')]", @permission_lbl)
204
- hierarchical_permission_names(clause, num, "requirement[not(@type = 'verification' or @type = 'class')]", @requirement_lbl)
205
- hierarchical_permission_names(clause, num, "recommendation[not(@type = 'verification' or @type = 'class')]", @recommendation_lbl)
206
- hierarchical_permission_names(clause, num, "permission[@type = 'verification']", @labels["permissiontest"])
207
- hierarchical_permission_names(clause, num, "requirement[@type = 'verification']", @labels["requirementtest"])
208
- hierarchical_permission_names(clause, num, "recommendation[@type = 'verification']", @labels["recommendationtest"])
209
- hierarchical_permission_names(clause, num, "permission[@type = 'class']", @labels["permissionclass"])
210
- hierarchical_permission_names(clause, num, "requirement[@type = 'class']", @labels["requirementclass"])
211
- hierarchical_permission_names(clause, num, "recommendation[@type = 'class']", @labels["recommendationclass"])
212
- end
213
-
214
- def hierarchical_permission_names(clause, num, klass, label)
215
- c = ::IsoDoc::Function::XrefGen::Counter.new
216
- clause.xpath(ns(".//#{klass}#{FIRST_LVL_REQ}")).each do |t|
217
- next if t["id"].nil? || t["id"].empty?
218
- lbl = "#{num}#{hiersep}#{c.increment(t).print}"
219
- @anchors[t["id"]] = anchor_struct(lbl, t, label, klass, t["unnumbered"])
220
- sequential_permission_children(t, lbl)
221
- end
180
+ def permission_parse(node, out)
181
+ recommendation_parse0(node, out, "permission")
222
182
  end
223
183
  end
224
184
  end
@@ -0,0 +1,96 @@
1
+ module IsoDoc
2
+ module Ogc
3
+ module BaseConvert
4
+ FIRST_LVL_REQ = IsoDoc::Function::XrefGen::FIRST_LVL_REQ
5
+
6
+ def sequential_permission_names(clause, klass, label)
7
+ c = ::IsoDoc::Function::XrefGen::Counter.new
8
+ clause.xpath(ns(".//#{klass}#{FIRST_LVL_REQ}")).each do |t|
9
+ next if t["id"].nil? || t["id"].empty?
10
+ id = c.increment(t).print
11
+ @anchors[t["id"]] = anchor_struct(id, t, label, klass, t["unnumbered"])
12
+ l = t.at(ns("./label"))&.text and @reqtlabels[l] = t["id"]
13
+ sequential_permission_children(t, id)
14
+ end
15
+ end
16
+
17
+ def req_class_paths
18
+ { "class" => "@type = 'class'",
19
+ "test" => "@type = 'verification'",
20
+ "" => "not(@type = 'verification' or @type = 'class' or "\
21
+ "@type = 'abstracttest' or @type = 'conformanceclass')", }
22
+ end
23
+
24
+ def req_class_paths2
25
+ { "abstracttest" => "@type = 'abstracttest'",
26
+ "conformanceclass" => "@type = 'conformanceclass'", }
27
+ end
28
+
29
+ def sequential_permission_children(t, id)
30
+ req_class_paths.each do |k, v|
31
+ %w(permission requirement recommendation).each do |r|
32
+ sequential_permission_names1(t, id, "#{r}[#{v}]", @labels["#{r}#{k}"])
33
+ sequential_permission_names1(t, id, "#{r}[#{v}]", @labels["#{r}#{k}"])
34
+ sequential_permission_names1(t, id, "#{r}[#{v}]", @labels["#{r}#{k}"])
35
+ end
36
+ end
37
+ req_class_paths2.each do |k, v|
38
+ sequential_permission_names1(t, id, "*[#{v}]", @labels[k])
39
+ end
40
+ end
41
+
42
+ def sequential_permission_names1(block, lbl, klass, label)
43
+ c = ::IsoDoc::Function::XrefGen::Counter.new
44
+ block.xpath(ns("./#{klass}")).each do |t|
45
+ next if t["id"].nil? || t["id"].empty?
46
+ id = "#{lbl}#{hierfigsep}#{c.increment(t).print}"
47
+ @anchors[t["id"]] = anchor_struct(id, t, label, klass, t["unnumbered"])
48
+ sequential_permission_children(t, id)
49
+ end
50
+ end
51
+
52
+ def sequential_asset_names(clause)
53
+ sequential_table_names(clause)
54
+ sequential_figure_names(clause)
55
+ sequential_formula_names(clause)
56
+ req_class_paths.each do |k, v|
57
+ %w(permission requirement recommendation).each do |r|
58
+ sequential_permission_names(clause, "#{r}[#{v}]", @labels["#{r}#{k}"])
59
+ sequential_permission_names(clause, "#{r}[#{v}]", @labels["#{r}#{k}"])
60
+ sequential_permission_names(clause, "#{r}[#{v}]", @labels["#{r}#{k}"])
61
+ end
62
+ end
63
+ req_class_paths2.each do |k, v|
64
+ sequential_permission_names(clause, "*[#{v}]", @labels[k])
65
+ end
66
+ end
67
+
68
+ def hierarchical_asset_names(clause, num)
69
+ hierarchical_table_names(clause, num)
70
+ hierarchical_figure_names(clause, num)
71
+ hierarchical_formula_names(clause, num)
72
+ req_class_paths.each do |k, v|
73
+ %w(permission requirement recommendation).each do |r|
74
+ hierarchical_permission_names(clause, num, "#{r}[#{v}]", @labels["#{r}#{k}"])
75
+ hierarchical_permission_names(clause, num, "#{r}[#{v}]", @labels["#{r}#{k}"])
76
+ hierarchical_permission_names(clause, num, "#{r}[#{v}]", @labels["#{r}#{k}"])
77
+ end
78
+ end
79
+ req_class_paths2.each do |k, v|
80
+ hierarchical_permission_names(clause, num, "*[#{v}]", @labels[k])
81
+ end
82
+ end
83
+
84
+ def hierarchical_permission_names(clause, num, klass, label)
85
+ c = ::IsoDoc::Function::XrefGen::Counter.new
86
+ clause.xpath(ns(".//#{klass}#{FIRST_LVL_REQ}")).each do |t|
87
+ next if t["id"].nil? || t["id"].empty?
88
+ lbl = "#{num}#{hiersep}#{c.increment(t).print}"
89
+ @anchors[t["id"]] = anchor_struct(lbl, t, label, klass, t["unnumbered"])
90
+ l = t.at(ns("./label"))&.text and @reqtlabels[l] = t["id"]
91
+ sequential_permission_children(t, lbl)
92
+ end
93
+ end
94
+ end
95
+ end
96
+ end