metanorma-standoc 0.0.1

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 (87) hide show
  1. checksums.yaml +7 -0
  2. data/.gitattributes +4 -0
  3. data/.gitignore +11 -0
  4. data/.hound.yml +3 -0
  5. data/.oss-guides.rubocop.yml +1077 -0
  6. data/.rubocop.ribose.yml +66 -0
  7. data/.rubocop.tb.yml +650 -0
  8. data/.rubocop.yml +15 -0
  9. data/.travis.yml +21 -0
  10. data/CODE_OF_CONDUCT.md +46 -0
  11. data/Gemfile +7 -0
  12. data/LICENSE +25 -0
  13. data/Makefile +39 -0
  14. data/README.adoc +9 -0
  15. data/Rakefile +6 -0
  16. data/bin/rspec +18 -0
  17. data/docs/customisation.adoc +178 -0
  18. data/docs/guidance.adoc +436 -0
  19. data/docs/htmloutput.adoc +115 -0
  20. data/docs/quickstart.adoc +375 -0
  21. data/lib/asciidoctor/standoc/base.rb +198 -0
  22. data/lib/asciidoctor/standoc/biblio.rng +836 -0
  23. data/lib/asciidoctor/standoc/blocks.rb +190 -0
  24. data/lib/asciidoctor/standoc/cleanup.rb +247 -0
  25. data/lib/asciidoctor/standoc/cleanup_block.rb +193 -0
  26. data/lib/asciidoctor/standoc/cleanup_footnotes.rb +78 -0
  27. data/lib/asciidoctor/standoc/cleanup_ref.rb +125 -0
  28. data/lib/asciidoctor/standoc/converter.rb +55 -0
  29. data/lib/asciidoctor/standoc/front.rb +121 -0
  30. data/lib/asciidoctor/standoc/inline.rb +134 -0
  31. data/lib/asciidoctor/standoc/isodoc.rng +1059 -0
  32. data/lib/asciidoctor/standoc/lists.rb +87 -0
  33. data/lib/asciidoctor/standoc/macros.rb +95 -0
  34. data/lib/asciidoctor/standoc/ref.rb +187 -0
  35. data/lib/asciidoctor/standoc/section.rb +159 -0
  36. data/lib/asciidoctor/standoc/table.rb +61 -0
  37. data/lib/asciidoctor/standoc/utils.rb +121 -0
  38. data/lib/asciidoctor/standoc/validate.rb +65 -0
  39. data/lib/asciidoctor/standoc/validate_section.rb +42 -0
  40. data/lib/asciidoctor/standoc/version.rb +5 -0
  41. data/lib/metanorma-standoc.rb +9 -0
  42. data/lib/metanorma/standoc.rb +7 -0
  43. data/lib/metanorma/standoc/processor.rb +40 -0
  44. data/metanorma-standoc.gemspec +47 -0
  45. data/spec/asciidoctor-standoc/base_spec.rb +271 -0
  46. data/spec/asciidoctor-standoc/blocks_spec.rb +469 -0
  47. data/spec/asciidoctor-standoc/cleanup_spec.rb +760 -0
  48. data/spec/asciidoctor-standoc/inline_spec.rb +162 -0
  49. data/spec/asciidoctor-standoc/isobib_cache_spec.rb +332 -0
  50. data/spec/asciidoctor-standoc/lists_spec.rb +190 -0
  51. data/spec/asciidoctor-standoc/macros_spec.rb +111 -0
  52. data/spec/asciidoctor-standoc/refs_spec.rb +606 -0
  53. data/spec/asciidoctor-standoc/section_spec.rb +310 -0
  54. data/spec/asciidoctor-standoc/table_spec.rb +307 -0
  55. data/spec/asciidoctor-standoc/validate_spec.rb +133 -0
  56. data/spec/assets/header.html +7 -0
  57. data/spec/assets/html.css +2 -0
  58. data/spec/assets/htmlcover.html +4 -0
  59. data/spec/assets/htmlintro.html +5 -0
  60. data/spec/assets/i18n.yaml +2 -0
  61. data/spec/assets/iso.headless.html +33 -0
  62. data/spec/assets/iso.xml +8 -0
  63. data/spec/assets/rice_image1.png +0 -0
  64. data/spec/assets/scripts.html +3 -0
  65. data/spec/assets/std.css +2 -0
  66. data/spec/assets/word.css +2 -0
  67. data/spec/assets/wordcover.html +3 -0
  68. data/spec/assets/wordintro.html +4 -0
  69. data/spec/examples/103_01_02.html +247 -0
  70. data/spec/examples/english.yaml +69 -0
  71. data/spec/examples/iso_123_.xml +45 -0
  72. data/spec/examples/iso_123_all_parts.xml +45 -0
  73. data/spec/examples/iso_123_no_year_note.xml +46 -0
  74. data/spec/examples/iso_124_.xml +41 -0
  75. data/spec/examples/iso_216_.xml +47 -0
  76. data/spec/examples/iso_iec_12382_.xml +48 -0
  77. data/spec/examples/rice.adoc +715 -0
  78. data/spec/examples/rice.preview.html +1877 -0
  79. data/spec/examples/rice.sh +4 -0
  80. data/spec/examples/rice_images/rice_image1.png +0 -0
  81. data/spec/examples/rice_images/rice_image2.png +0 -0
  82. data/spec/examples/rice_images/rice_image3_1.png +0 -0
  83. data/spec/examples/rice_images/rice_image3_2.png +0 -0
  84. data/spec/examples/rice_images/rice_image3_3.png +0 -0
  85. data/spec/metanorma/processor_spec.rb +70 -0
  86. data/spec/spec_helper.rb +198 -0
  87. metadata +370 -0
@@ -0,0 +1,87 @@
1
+ require "pp"
2
+
3
+ module Asciidoctor
4
+ module Standoc
5
+ module Lists
6
+ def li(xml_ul, item)
7
+ xml_ul.li do |xml_li|
8
+ if item.blocks?
9
+ xml_li.p(**id_attr(item)) { |t| t << item.text }
10
+ xml_li << item.content
11
+ else
12
+ xml_li.p(**id_attr(item)) { |p| p << item.text }
13
+ end
14
+ end
15
+ end
16
+
17
+ def ulist(node)
18
+ return reference(node) if in_norm_ref? || in_biblio?
19
+ noko do |xml|
20
+ xml.ul **id_attr(node) do |xml_ul|
21
+ node.items.each do |item|
22
+ li(xml_ul, item)
23
+ end
24
+ end
25
+ end.join("\n")
26
+ end
27
+
28
+ def olist_style(style)
29
+ return "alphabet" if style == "loweralpha"
30
+ return "roman" if style == "lowerroman"
31
+ return "roman_upper" if style == "upperroman"
32
+ return "alphabet_upper" if style == "upperalpha"
33
+ style
34
+ end
35
+
36
+ def olist(node)
37
+ noko do |xml|
38
+ xml.ol **attr_code(id: Utils::anchor_or_uuid(node),
39
+ type: olist_style(node.style)) do |xml_ol|
40
+ node.items.each { |item| li(xml_ol, item) }
41
+ end
42
+ end.join("\n")
43
+ end
44
+
45
+ def dt(terms, xml_dl)
46
+ terms.each_with_index do |dt, idx|
47
+ xml_dl.dt { |xml_dt| xml_dt << dt.text }
48
+ if idx < terms.size - 1
49
+ xml_dl.dd
50
+ end
51
+ end
52
+ end
53
+
54
+ def dd(dd, xml_dl)
55
+ if dd.nil?
56
+ xml_dl.dd
57
+ return
58
+ end
59
+ xml_dl.dd do |xml_dd|
60
+ xml_dd.p { |t| t << dd.text } if dd.text?
61
+ xml_dd << dd.content if dd.blocks?
62
+ end
63
+ end
64
+
65
+ def dlist(node)
66
+ noko do |xml|
67
+ xml.dl **id_attr(node) do |xml_dl|
68
+ node.items.each do |terms, dd|
69
+ dt(terms, xml_dl)
70
+ dd(dd, xml_dl)
71
+ end
72
+ end
73
+ end.join("\n")
74
+ end
75
+
76
+ def colist(node)
77
+ noko do |xml|
78
+ node.items.each_with_index do |item, i|
79
+ xml.annotation **attr_code(id: i + 1) do |xml_li|
80
+ xml_li.p { |p| p << item.text }
81
+ end
82
+ end
83
+ end.join("\n")
84
+ end
85
+ end
86
+ end
87
+ end
@@ -0,0 +1,95 @@
1
+ require "asciidoctor/extensions"
2
+ module Asciidoctor
3
+ module Standoc
4
+ class AltTermInlineMacro < Asciidoctor::Extensions::InlineMacroProcessor
5
+ use_dsl
6
+ named :alt
7
+ parse_content_as :text
8
+ using_format :short
9
+
10
+ def process(parent, _target, attrs)
11
+ out = Asciidoctor::Inline.new(parent, :quoted, attrs["text"]).convert
12
+ %{<admitted>#{out}</admitted>}
13
+ end
14
+ end
15
+
16
+ class DeprecatedTermInlineMacro <
17
+ Asciidoctor::Extensions::InlineMacroProcessor
18
+ use_dsl
19
+ named :deprecated
20
+ parse_content_as :text
21
+ using_format :short
22
+
23
+ def process(parent, _target, attrs)
24
+ out = Asciidoctor::Inline.new(parent, :quoted, attrs["text"]).convert
25
+ %{<deprecates>#{out}</deprecates>}
26
+ end
27
+ end
28
+
29
+ class DomainTermInlineMacro < Asciidoctor::Extensions::InlineMacroProcessor
30
+ use_dsl
31
+ named :domain
32
+ parse_content_as :text
33
+ using_format :short
34
+
35
+ def process(parent, _target, attrs)
36
+ out = Asciidoctor::Inline.new(parent, :quoted, attrs["text"]).convert
37
+ %{<domain>#{out}</domain>}
38
+ end
39
+ end
40
+
41
+ class PlantUMLBlockMacroBackend
42
+ # https://stackoverflow.com/questions/2108727/which-in-ruby-checking-if-program-exists-in-path-from-ruby
43
+ def self.plantuml_installed?
44
+ cmd = "plantuml"
45
+ exts = ENV['PATHEXT'] ? ENV['PATHEXT'].split(';') : ['']
46
+ ENV['PATH'].split(File::PATH_SEPARATOR).each do |path|
47
+ exts.each do |ext|
48
+ exe = File.join(path, "#{cmd}#{ext}")
49
+ return exe if File.executable?(exe) && !File.directory?(exe)
50
+ end
51
+ end
52
+ nil
53
+ end
54
+
55
+ def self.generate_file parent, reader
56
+ src = reader.source
57
+ reader.lines.first.sub(/\s+$/, "") != "@startuml" or
58
+ src = "@startuml\n#{src}\n@enduml\n"
59
+ filename = parent.document.reader.lineno
60
+ system "mkdir -p plantuml"
61
+ File.open("plantuml/#{filename}.pml", "w") { |f| f.write src }
62
+ system "plantuml plantuml/#{filename}.pml"
63
+ filename
64
+ end
65
+
66
+ def self.generate_attrs attrs
67
+ through_attrs = %w(id align float title role width height alt).
68
+ inject({}) do |memo, key|
69
+ memo[key] = attrs[key] if attrs.has_key? key
70
+ memo
71
+ end
72
+ end
73
+ end
74
+
75
+ class PlantUMLBlockMacro < Asciidoctor::Extensions::BlockProcessor
76
+ use_dsl
77
+ named :plantuml
78
+ on_context :literal
79
+ parse_content_as :raw
80
+
81
+ def process(parent, reader, attrs)
82
+ if PlantUMLBlockMacroBackend.plantuml_installed?
83
+ filename = PlantUMLBlockMacroBackend.generate_file parent, reader
84
+ through_attrs = PlantUMLBlockMacroBackend.generate_attrs attrs
85
+ through_attrs["target"] = "plantuml/#{filename}.png"
86
+ create_image_block parent, through_attrs
87
+ else
88
+ warn "PlantUML not installed"
89
+ # attrs.delete(1) : remove the style attribute
90
+ create_listing_block parent, reader.source, attrs.reject { |k, v| k == 1 }
91
+ end
92
+ end
93
+ end
94
+ end
95
+ end
@@ -0,0 +1,187 @@
1
+ require "pp"
2
+
3
+ module Asciidoctor
4
+ module Standoc
5
+ module Lists
6
+ def iso_publisher(t, code)
7
+ code.sub(/ .*$/, "").split(/\//).each do |abbrev|
8
+ t.contributor do |c|
9
+ c.role **{ type: "publisher" }
10
+ c.organization do |org|
11
+ organization(org, abbrev)
12
+ end
13
+ end
14
+ end
15
+ end
16
+
17
+ def plaintxt
18
+ { format: "text/plain" }
19
+ end
20
+
21
+ def ref_attributes(m)
22
+ { id: m[:anchor], type: "standard" }
23
+ end
24
+
25
+ def set_date_range(date, text)
26
+ matched = /^(?<from>[0-9]+)(-+(?<to>[0-9]+))?$/.match text
27
+ return unless matched[:from]
28
+ if matched[:to]
29
+ date.from matched[:from]
30
+ date.to matched[:to]
31
+ else
32
+ date.on matched[:from]
33
+ end
34
+ end
35
+
36
+ def use_my_anchor(ref, id)
37
+ ref.parent.elements.last["id"] = id
38
+ ref
39
+ end
40
+
41
+ def isorefmatches(xml, m)
42
+ ref = fetch_ref xml, m[:code], m[:year]
43
+ return use_my_anchor(ref, m[:anchor]) if ref
44
+ xml.bibitem **attr_code(ref_attributes(m)) do |t|
45
+ t.title(**plaintxt) { |i| i << ref_normalise(m[:text]) }
46
+ t.docidentifier m[:code]
47
+ m[:year] and t.date **{ type: "published" } do |d|
48
+ set_date_range(d, m[:year])
49
+ end
50
+ iso_publisher(t, m[:code])
51
+ end
52
+ end
53
+
54
+ def isorefmatches2(xml, m)
55
+ ref = fetch_ref xml, m[:code], nil, no_year: true, note: m[:fn]
56
+ return use_my_anchor(ref, m[:anchor]) if ref
57
+ xml.bibitem **attr_code(ref_attributes(m)) do |t|
58
+ t.title(**plaintxt) { |i| i << ref_normalise(m[:text]) }
59
+ t.docidentifier m[:code]
60
+ t.date **{ type: "published" } do |d|
61
+ d.on "--"
62
+ end
63
+ iso_publisher(t, m[:code])
64
+ t.note(**plaintxt) { |p| p << "ISO DATE: #{m[:fn]}" }
65
+ end
66
+ end
67
+
68
+ def isorefmatches3(xml, m)
69
+ hasyr = m.names.include?("year")
70
+ ref = fetch_ref xml, m[:code], hasyr ? m[:year] : nil, all_parts: true
71
+ return use_my_anchor(ref, m[:anchor]) if ref
72
+ xml.bibitem(**attr_code(ref_attributes(m))) do |t|
73
+ t.title(**plaintxt) { |i| i << ref_normalise(m[:text]) }
74
+ t.docidentifier "#{m[:code]}"
75
+ hasyr and
76
+ t.date(**{ type: "published" }) { |d| set_date_range(d, m[:year]) }
77
+ iso_publisher(t, m[:code])
78
+ t.allParts "true"
79
+ end
80
+ end
81
+
82
+ def fetch_ref(xml, code, year, **opts)
83
+ hit = @bibdb&.fetch(code, year, opts)
84
+ return nil if hit.nil?
85
+ xml.parent.add_child(hit.to_xml)
86
+ xml
87
+ rescue Algolia::AlgoliaProtocolError
88
+ nil # Render reference without an Internet connection.
89
+ end
90
+
91
+ def refitem_render(xml, m)
92
+ xml.bibitem **attr_code(id: m[:anchor]) do |t|
93
+ t.formattedref **{ format: "application/x-isodoc+xml" } do |i|
94
+ i << ref_normalise_no_format(m[:text])
95
+ end
96
+ t.docidentifier(/^\d+$/.match(m[:code]) ? "[#{m[:code]}]" : m[:code])
97
+ end
98
+ end
99
+
100
+ # TODO: alternative where only title is available
101
+ def refitem(xml, item, node)
102
+ unless m = NON_ISO_REF.match(item)
103
+ Utils::warning(node, "no anchor on reference", item)
104
+ return
105
+ end
106
+ unless m[:code] && /^\d+$/.match(m[:code])
107
+ ref = fetch_ref xml, m[:code],
108
+ m.names.include?("year") ? m[:year] : nil, {}
109
+ return use_my_anchor(ref, m[:anchor]) if ref
110
+ end
111
+ refitem_render(xml, m)
112
+ end
113
+
114
+ def ref_normalise(ref)
115
+ ref.
116
+ # gsub(/&#8201;&#8212;&#8201;/, " -- ").
117
+ gsub(/&amp;amp;/, "&amp;").
118
+ gsub(%r{^<em>(.*)</em>}, "\\1")
119
+ end
120
+
121
+ def ref_normalise_no_format(ref)
122
+ ref.
123
+ # gsub(/&#8201;&#8212;&#8201;/, " -- ").
124
+ gsub(/&amp;amp;/, "&amp;")
125
+ end
126
+
127
+ ISO_REF = %r{^<ref\sid="(?<anchor>[^"]+)">
128
+ \[(?<code>(ISO|IEC)[^0-9]*\s[0-9-]+|IEV)
129
+ (:(?<year>[0-9][0-9-]+))?\]</ref>,?\s
130
+ (?<text>.*)$}xm
131
+
132
+ ISO_REF_NO_YEAR = %r{^<ref\sid="(?<anchor>[^"]+)">
133
+ \[(?<code>(ISO|IEC)[^0-9]*\s[0-9-]+):--\]</ref>,?\s?
134
+ <fn[^>]*>\s*<p>(?<fn>[^\]]+)</p>\s*</fn>,?\s?(?<text>.*)$}xm
135
+
136
+ ISO_REF_ALL_PARTS = %r{^<ref\sid="(?<anchor>[^"]+)">
137
+ \[(?<code>(ISO|IEC)[^0-9]*\s[0-9]+)(:(?<year>[0-9][0-9-]+))?\s
138
+ \(all\sparts\)\]</ref>,?\s
139
+ (?<text>.*)$}xm
140
+
141
+ NON_ISO_REF = %r{^<ref\sid="(?<anchor>[^"]+)">
142
+ \[(?<code>[^\]]+?)([:-](?<year>(19|20)[0-9][0-9]))?\]</ref>,?\s
143
+ (?<text>.*)$}xm
144
+
145
+ # @param item [String]
146
+ # @return [Array<MatchData>]
147
+ def reference1_matches(item)
148
+ matched = ISO_REF.match item
149
+ matched2 = ISO_REF_NO_YEAR.match item
150
+ matched3 = ISO_REF_ALL_PARTS.match item
151
+ [matched, matched2, matched3]
152
+ end
153
+
154
+ # @param node [Asciidoctor::List]
155
+ # @param item [String]
156
+ # @param xml [Nokogiri::XML::Builder]
157
+ def reference1(node, item, xml)
158
+ matched, matched2, matched3 = reference1_matches(item)
159
+ if matched3.nil? && matched2.nil? && matched.nil?
160
+ refitem(xml, item, node)
161
+ # elsif fetch_ref(matched3 || matched2 || matched, xml)
162
+ elsif !matched.nil? then isorefmatches(xml, matched)
163
+ elsif !matched2.nil? then isorefmatches2(xml, matched2)
164
+ elsif !matched3.nil? then isorefmatches3(xml, matched3)
165
+ end
166
+ end
167
+
168
+ def reference(node)
169
+ noko do |xml|
170
+ node.items.each do |item|
171
+ reference1(node, item.text, xml)
172
+ end
173
+ end.join("\n")
174
+ end
175
+
176
+ def bibliocache_name(global)
177
+ global ? "#{Dir.home}/.relaton-bib.pstore" :
178
+ "#{@filename}.relaton.pstore"
179
+ end
180
+
181
+ def ievcache_name(global)
182
+ global ? "#{Dir.home}/.iev.pstore" :
183
+ "#{@filename}.iev.pstore"
184
+ end
185
+ end
186
+ end
187
+ end
@@ -0,0 +1,159 @@
1
+ require "htmlentities"
2
+ require "uri"
3
+
4
+ module Asciidoctor
5
+ module Standoc
6
+ module Section
7
+ @biblio = false
8
+ @term_def = false
9
+ @norm_ref = false
10
+
11
+ def in_biblio?
12
+ @biblio
13
+ end
14
+
15
+ def in_terms?
16
+ @term_def
17
+ end
18
+
19
+ def in_norm_ref?
20
+ @norm_ref
21
+ end
22
+
23
+ def sectiontype(node)
24
+ node&.attr("heading")&.downcase || node.title.downcase
25
+ end
26
+
27
+ def section(node)
28
+ a = { id: Utils::anchor_or_uuid(node) }
29
+ noko do |xml|
30
+ case sectiontype(node)
31
+ when "introduction" then
32
+ if node.level == 1 then introduction_parse(a, xml, node)
33
+ else
34
+ clause_parse(a, xml, node)
35
+ end
36
+ when "normative references" then norm_ref_parse(a, xml, node)
37
+ when "terms and definitions",
38
+ "terms, definitions, symbols and abbreviated terms",
39
+ "terms, definitions, symbols and abbreviations",
40
+ "terms, definitions and symbols",
41
+ "terms, definitions and abbreviations",
42
+ "terms, definitions and abbreviated terms"
43
+ @term_def = true
44
+ term_def_parse(a, xml, node, true)
45
+ @term_def = false
46
+ when "symbols and abbreviated terms"
47
+ symbols_parse(a, xml, node)
48
+ when "bibliography" then bibliography_parse(a, xml, node)
49
+ else
50
+ if @term_def then term_def_subclause_parse(a, xml, node)
51
+ elsif @biblio then bibliography_parse(a, xml, node)
52
+ elsif node.attr("style") == "bibliography" && node.level == 1
53
+ bibliography_parse(a, xml, node)
54
+ elsif node.attr("style") == "appendix" && node.level == 1
55
+ annex_parse(a, xml, node)
56
+ else
57
+ clause_parse(a, xml, node)
58
+ end
59
+ end
60
+ end.join("\n")
61
+ end
62
+
63
+ def set_obligation(attrs, node)
64
+ attrs[:obligation] = if node.attributes.has_key?("obligation")
65
+ node.attr("obligation")
66
+ elsif node.parent.attributes.has_key?("obligation")
67
+ node.parent.attr("obligation")
68
+ else
69
+ "normative"
70
+ end
71
+ end
72
+
73
+ def clause_parse(attrs, xml, node)
74
+ attrs["inline-header".to_sym] = node.option? "inline-header"
75
+ attrs[:level] = node.attr("level")
76
+ set_obligation(attrs, node)
77
+ xml.send "clause", **attr_code(attrs) do |xml_section|
78
+ xml_section.title { |n| n << node.title } unless node.title.nil?
79
+ xml_section << node.content
80
+ end
81
+ end
82
+
83
+ def annex_parse(attrs, xml, node)
84
+ attrs["inline-header".to_sym] = node.option? "inline-header"
85
+ set_obligation(attrs, node)
86
+ xml.annex **attr_code(attrs) do |xml_section|
87
+ xml_section.title { |name| name << node.title }
88
+ xml_section << node.content
89
+ end
90
+ end
91
+
92
+ def bibliography_parse(attrs, xml, node)
93
+ node.attr("style") == "bibliography" or
94
+ warn "Section not marked up as [bibliography]!"
95
+ @biblio = true
96
+ xml.references **attr_code(attrs) do |xml_section|
97
+ title = node.level == 1 ? "Bibliography" : node.title
98
+ xml_section.title { |t| t << title }
99
+ xml_section << node.content
100
+ end
101
+ @biblio = false
102
+ end
103
+
104
+ def symbols_parse(attrs, xml, node)
105
+ xml.definitions **attr_code(attrs) do |xml_section|
106
+ xml_section << node.content
107
+ end
108
+ end
109
+
110
+ # subclause contains subclauses
111
+ def term_def_subclause_parse(attrs, xml, node)
112
+ sub = node.find_by(context: :section) { |s| s.level == node.level + 1 }
113
+ sub.empty? || (return term_def_parse(attrs, xml, node, false))
114
+ node.title.casecmp("symbols and abbreviated terms").zero? &&
115
+ (return symbols_parse(attrs, xml, node))
116
+ xml.term **attr_code(attrs) do |xml_section|
117
+ xml_section.preferred { |name| name << node.title }
118
+ xml_section << node.content
119
+ end
120
+ end
121
+
122
+ def term_def_title(toplevel, node)
123
+ return node.title unless toplevel
124
+ sub = node.find_by(context: :section) do |s|
125
+ s.title.casecmp("symbols and abbreviated terms").zero?
126
+ end
127
+ return "Terms and definitions" if sub.empty?
128
+ "Terms, definitions, symbols and abbreviated terms"
129
+ end
130
+
131
+ def term_def_parse(attrs, xml, node, toplevel)
132
+ xml.terms **attr_code(attrs) do |section|
133
+ section.title { |t| t << term_def_title(toplevel, node) }
134
+ (s = node.attr("source")) && s.split(/,/).each do |s1|
135
+ section.termdocsource(nil, **attr_code(bibitemid: s1, type: "inline"))
136
+ end
137
+ section << node.content
138
+ end
139
+ end
140
+
141
+ def norm_ref_parse(attrs, xml, node)
142
+ @norm_ref = true
143
+ xml.references **attr_code(attrs) do |xml_section|
144
+ xml_section.title { |t| t << "Normative References" }
145
+ xml_section << node.content
146
+ end
147
+ @norm_ref = false
148
+ end
149
+
150
+ def introduction_parse(attrs, xml, node)
151
+ xml.introduction **attr_code(attrs) do |xml_section|
152
+ xml_section.title = "Introduction"
153
+ content = node.content
154
+ xml_section << content
155
+ end
156
+ end
157
+ end
158
+ end
159
+ end