metanorma-standoc 2.4.8 → 2.5.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.
- checksums.yaml +4 -4
- data/lib/isodoc/html/htmlstyle.css +13 -9
- data/lib/isodoc/html/htmlstyle.scss +6 -6
- data/lib/metanorma/standoc/blocks.rb +1 -1
- data/lib/metanorma/standoc/cleanup.rb +21 -19
- data/lib/metanorma/standoc/cleanup_block.rb +1 -0
- data/lib/metanorma/standoc/cleanup_inline.rb +18 -4
- data/lib/metanorma/standoc/cleanup_maths.rb +34 -21
- data/lib/metanorma/standoc/cleanup_symbols.rb +3 -20
- data/lib/metanorma/standoc/cleanup_terms.rb +1 -0
- data/lib/metanorma/standoc/cleanup_terms_designations.rb +20 -5
- data/lib/metanorma/standoc/cleanup_text.rb +0 -1
- data/lib/metanorma/standoc/converter.rb +2 -2
- data/lib/metanorma/standoc/inline.rb +21 -12
- data/lib/metanorma/standoc/isodoc.rng +26 -4
- data/lib/metanorma/standoc/macros.rb +0 -2
- data/lib/metanorma/standoc/ref_sect.rb +4 -3
- data/lib/metanorma/standoc/term_lookup_cleanup.rb +117 -60
- data/lib/metanorma/standoc/utils.rb +23 -4
- data/lib/metanorma/standoc/validate.rb +32 -67
- data/lib/metanorma/standoc/validate_term.rb +89 -0
- data/lib/metanorma/standoc/version.rb +1 -1
- data/metanorma-standoc.gemspec +1 -1
- metadata +5 -5
- data/lib/metanorma/standoc/validate_xref.rb +0 -32
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1d6a56b88b9f58482764ff6aede297e389577151d0d112a215b2215d5cfb41cf
|
4
|
+
data.tar.gz: cb0a1a1d73930e89169a27185bcce3d19130f1150a22fd7345da61a73dbd759f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 158547c563e269b769f39123cbd03f749a4891f7e4c772e9462ea40a9221ee4b58839991b2580fc40d9a24007387866d2741867ee6a8f5f39770fa3d38a57138
|
7
|
+
data.tar.gz: ba7b26ed9ebfae0f92dedc50750aad4e31c53b5e5b16defe3e2a2ea6583049fab738f07449846ac62aa74af06944d725389fed9d54357bf9ff9c33b3196cac2f
|
@@ -98,7 +98,7 @@ h1, h2, h3, h4, h5, h6 {
|
|
98
98
|
|
99
99
|
blockquote, q {
|
100
100
|
quotes: none; }
|
101
|
-
blockquote
|
101
|
+
blockquote::before, blockquote::after, q::before, q::after {
|
102
102
|
content: '';
|
103
103
|
content: none; }
|
104
104
|
|
@@ -121,14 +121,18 @@ b, strong {
|
|
121
121
|
div.document-stage-band, div.document-type-band {
|
122
122
|
background-color: #333333; }
|
123
123
|
|
124
|
-
a.FootnoteRef + a.FootnoteRef
|
124
|
+
a.FootnoteRef + a.FootnoteRef::before {
|
125
125
|
content: ", ";
|
126
126
|
vertical-align: super; }
|
127
127
|
|
128
|
-
a.TableFootnoteRef + a.TableFootnoteRef
|
128
|
+
a.TableFootnoteRef + a.TableFootnoteRef::before {
|
129
129
|
content: ", ";
|
130
130
|
vertical-align: super; }
|
131
131
|
|
132
|
+
a.TableFootnoteRef, span.TableFootnoteRef,
|
133
|
+
a.FootnoteRef, span.FootnoteRef {
|
134
|
+
vertical-align: super; }
|
135
|
+
|
132
136
|
.addition {
|
133
137
|
color: blue; }
|
134
138
|
|
@@ -594,7 +598,7 @@ ul, ol {
|
|
594
598
|
ul li {
|
595
599
|
list-style: none; }
|
596
600
|
|
597
|
-
ul li
|
601
|
+
ul li::before {
|
598
602
|
content: "—";
|
599
603
|
display: inline-block;
|
600
604
|
width: 1em;
|
@@ -612,7 +616,7 @@ ul li:first-child {
|
|
612
616
|
#toc-list li {
|
613
617
|
list-style-type: none; }
|
614
618
|
|
615
|
-
#toc li
|
619
|
+
#toc li::before {
|
616
620
|
content: " ";
|
617
621
|
display: none; }
|
618
622
|
|
@@ -633,13 +637,13 @@ ol[class="alphabet"] > li {
|
|
633
637
|
ol[class="alphabet"] ol[class="alphabet"] > li {
|
634
638
|
list-style: inherit; }
|
635
639
|
|
636
|
-
ol[class="alphabet"] > li
|
640
|
+
ol[class="alphabet"] > li::before {
|
637
641
|
counter-increment: alphabet;
|
638
642
|
content: counter(alphabet, lower-alpha) ") ";
|
639
643
|
position: absolute;
|
640
644
|
left: -1.4em; }
|
641
645
|
|
642
|
-
ol[class="alphabet"] ol[class="alphabet"] > li
|
646
|
+
ol[class="alphabet"] ol[class="alphabet"] > li::before {
|
643
647
|
counter-increment: none;
|
644
648
|
content: initial; }
|
645
649
|
|
@@ -653,13 +657,13 @@ ol[class="roman"] > li {
|
|
653
657
|
ol[class="roman"] ol[class="roman"] > li {
|
654
658
|
list-style: inherit; }
|
655
659
|
|
656
|
-
ol[class="roman"] > li
|
660
|
+
ol[class="roman"] > li::before {
|
657
661
|
counter-increment: roman;
|
658
662
|
content: "(" counter(roman, lower-roman) ") ";
|
659
663
|
position: absolute;
|
660
664
|
left: -2.0em; }
|
661
665
|
|
662
|
-
ol[class="roman"] ol[class="roman"] > li
|
666
|
+
ol[class="roman"] ol[class="roman"] > li::before {
|
663
667
|
counter-increment: none;
|
664
668
|
content: initial; }
|
665
669
|
|
@@ -230,7 +230,7 @@ ul li {
|
|
230
230
|
list-style: none;
|
231
231
|
}
|
232
232
|
|
233
|
-
ul li
|
233
|
+
ul li::before {
|
234
234
|
content: "—";
|
235
235
|
display: inline-block; width: 1em;
|
236
236
|
margin-left: -1.2em;
|
@@ -252,7 +252,7 @@ ul li:first-child {
|
|
252
252
|
list-style-type: none;
|
253
253
|
}
|
254
254
|
|
255
|
-
#toc li
|
255
|
+
#toc li::before {
|
256
256
|
content: " ";
|
257
257
|
display: none;
|
258
258
|
}
|
@@ -275,13 +275,13 @@ ol[class="alphabet"] > li {
|
|
275
275
|
ol[class="alphabet"] ol[class="alphabet"] > li {
|
276
276
|
list-style: inherit;
|
277
277
|
}
|
278
|
-
ol[class="alphabet"] > li
|
278
|
+
ol[class="alphabet"] > li::before {
|
279
279
|
counter-increment: alphabet;
|
280
280
|
content: counter(alphabet, lower-alpha)") ";
|
281
281
|
position: absolute;
|
282
282
|
left: -1.4em;
|
283
283
|
}
|
284
|
-
ol[class="alphabet"] ol[class="alphabet"] > li
|
284
|
+
ol[class="alphabet"] ol[class="alphabet"] > li::before {
|
285
285
|
counter-increment: none;
|
286
286
|
content: initial;
|
287
287
|
}
|
@@ -295,13 +295,13 @@ ol[class="roman"] > li {
|
|
295
295
|
ol[class="roman"] ol[class="roman"] > li {
|
296
296
|
list-style: inherit;
|
297
297
|
}
|
298
|
-
ol[class="roman"] > li
|
298
|
+
ol[class="roman"] > li::before {
|
299
299
|
counter-increment: roman;
|
300
300
|
content: "("counter(roman, lower-roman)") ";
|
301
301
|
position: absolute;
|
302
302
|
left: -2.0em;
|
303
303
|
}
|
304
|
-
ol[class="roman"] ol[class="roman"] > li
|
304
|
+
ol[class="roman"] ol[class="roman"] > li::before {
|
305
305
|
counter-increment: none;
|
306
306
|
content: initial;
|
307
307
|
}
|
@@ -1,24 +1,24 @@
|
|
1
1
|
require "nokogiri"
|
2
2
|
require "pathname"
|
3
3
|
require "html2doc"
|
4
|
-
require_relative "
|
5
|
-
require_relative "
|
6
|
-
require_relative "
|
7
|
-
require_relative "
|
8
|
-
require_relative "
|
9
|
-
require_relative "
|
10
|
-
require_relative "
|
11
|
-
require_relative "
|
12
|
-
require_relative "
|
13
|
-
require_relative "
|
14
|
-
require_relative "
|
15
|
-
require_relative "
|
16
|
-
require_relative "
|
17
|
-
require_relative "
|
18
|
-
require_relative "
|
19
|
-
require_relative "
|
20
|
-
require_relative "
|
21
|
-
require_relative "
|
4
|
+
require_relative "cleanup_block"
|
5
|
+
require_relative "cleanup_table"
|
6
|
+
require_relative "cleanup_footnotes"
|
7
|
+
require_relative "cleanup_ref"
|
8
|
+
require_relative "cleanup_asciibib"
|
9
|
+
require_relative "cleanup_boilerplate"
|
10
|
+
require_relative "cleanup_bibdata"
|
11
|
+
require_relative "cleanup_section"
|
12
|
+
require_relative "cleanup_terms"
|
13
|
+
require_relative "cleanup_symbols"
|
14
|
+
require_relative "cleanup_xref"
|
15
|
+
require_relative "cleanup_inline"
|
16
|
+
require_relative "cleanup_amend"
|
17
|
+
require_relative "cleanup_maths"
|
18
|
+
require_relative "cleanup_image"
|
19
|
+
require_relative "cleanup_reqt"
|
20
|
+
require_relative "cleanup_text"
|
21
|
+
require_relative "cleanup_toc"
|
22
22
|
require "relaton_iev"
|
23
23
|
|
24
24
|
module Metanorma
|
@@ -51,6 +51,7 @@ module Metanorma
|
|
51
51
|
normref_cleanup(xmldoc)
|
52
52
|
biblio_cleanup(xmldoc)
|
53
53
|
reference_names(xmldoc)
|
54
|
+
asciimath_cleanup(xmldoc) # feeds: mathml_cleanup, termdef_cleanup, symbols_cleanup
|
54
55
|
symbols_cleanup(xmldoc) # feeds: termdef_cleanup
|
55
56
|
xref_cleanup(xmldoc) # feeds: concept_cleanup, origin_cleanup
|
56
57
|
concept_cleanup(xmldoc) # feeds: related_cleanup, termdef_cleanup
|
@@ -79,6 +80,7 @@ module Metanorma
|
|
79
80
|
empty_element_cleanup(xmldoc)
|
80
81
|
img_cleanup(xmldoc)
|
81
82
|
anchor_cleanup(xmldoc)
|
83
|
+
link_cleanup(xmldoc)
|
82
84
|
xmldoc
|
83
85
|
end
|
84
86
|
|
@@ -107,7 +109,7 @@ module Metanorma
|
|
107
109
|
end
|
108
110
|
|
109
111
|
def element_name_cleanup(xmldoc)
|
110
|
-
xmldoc.traverse { |n| n.name = n.name.gsub(
|
112
|
+
xmldoc.traverse { |n| n.name = n.name.gsub("_", "-") }
|
111
113
|
end
|
112
114
|
|
113
115
|
# allows us to deal with doc relation localities,
|
@@ -78,7 +78,7 @@ module Metanorma
|
|
78
78
|
def concept_cleanup1(elem)
|
79
79
|
elem.children.remove if elem&.children&.text&.strip&.empty?
|
80
80
|
key_extract_locality(elem)
|
81
|
-
if
|
81
|
+
if elem["key"].include?(":") then concept_termbase_cleanup(elem)
|
82
82
|
elsif refid? elem["key"] then concept_eref_cleanup(elem)
|
83
83
|
else concept_xref_cleanup(elem)
|
84
84
|
end
|
@@ -95,15 +95,14 @@ module Metanorma
|
|
95
95
|
end
|
96
96
|
|
97
97
|
def key_extract_locality(elem)
|
98
|
-
|
99
|
-
|
98
|
+
elem["key"].include?(",") or return
|
100
99
|
elem.add_child("<locality>#{elem['key'].sub(/^[^,]+,/, '')}</locality>")
|
101
100
|
elem["key"] = elem["key"].sub(/,.*$/, "")
|
102
101
|
end
|
103
102
|
|
104
103
|
def concept_termbase_cleanup(elem)
|
105
104
|
t = elem&.at("./xrefrender")&.remove&.children
|
106
|
-
termbase, key = elem["key"].split(
|
105
|
+
termbase, key = elem["key"].split(":", 2)
|
107
106
|
elem.add_child(%(<termref base="#{termbase}" target="#{key}">) +
|
108
107
|
"#{t&.to_xml}</termref>")
|
109
108
|
end
|
@@ -207,6 +206,21 @@ module Metanorma
|
|
207
206
|
end
|
208
207
|
end
|
209
208
|
|
209
|
+
def link_cleanup(xmldoc)
|
210
|
+
xmldoc.xpath("//link[@target]").each do |l|
|
211
|
+
l["target"] = URI.parse(l["target"]).to_s
|
212
|
+
rescue StandardError
|
213
|
+
err = "Malformed URI: #{l['target']}"
|
214
|
+
@log.add("Anchors", l, err)
|
215
|
+
@fatalerror << err
|
216
|
+
warn err
|
217
|
+
end
|
218
|
+
end
|
219
|
+
|
220
|
+
def uri_component_encode(comp)
|
221
|
+
CGI.escape(comp).gsub("+", "%20")
|
222
|
+
end
|
223
|
+
|
210
224
|
private
|
211
225
|
|
212
226
|
# skip ZWNJ inserted to prevent regexes operating in asciidoctor
|
@@ -3,17 +3,28 @@ require "asciimath2unitsml"
|
|
3
3
|
module Metanorma
|
4
4
|
module Standoc
|
5
5
|
module Cleanup
|
6
|
-
def
|
7
|
-
|
8
|
-
|
6
|
+
def asciimath_cleanup(xml)
|
7
|
+
!@keepasciimath and asciimath2mathml(xml)
|
8
|
+
end
|
9
|
+
|
10
|
+
def asciimath2mathml(xml)
|
11
|
+
xpath = xml.xpath("//stem[@type = 'AsciiMath']")
|
12
|
+
xpath.each_with_index do |x, i|
|
13
|
+
progress_conv(i, 500, xpath.size, 1000, "AsciiMath")
|
14
|
+
asciimath2mathml_indiv(x)
|
9
15
|
end
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
16
|
+
asciimath2mathml_wrap(xml)
|
17
|
+
end
|
18
|
+
|
19
|
+
def asciimath2mathml_indiv(elem)
|
20
|
+
elem["type"] = "MathML"
|
21
|
+
expr = @c.decode(elem.text)
|
22
|
+
ret = Plurimath::Math.parse(expr, "asciimath")
|
23
|
+
.to_mathml(display_style: elem["block"])
|
24
|
+
ret += "<asciimath>#{@c.encode(@c.decode(expr), :basic)}</asciimath>"
|
25
|
+
elem.children = ret
|
14
26
|
rescue StandardError => e
|
15
|
-
asciimath2mathml_err(
|
16
|
-
text
|
27
|
+
asciimath2mathml_err(elem.to_xml, e)
|
17
28
|
end
|
18
29
|
|
19
30
|
def asciimath2mathml_err(text, expr)
|
@@ -23,25 +34,27 @@ module Metanorma
|
|
23
34
|
warn err
|
24
35
|
end
|
25
36
|
|
26
|
-
def asciimath2mathml_wrap(
|
27
|
-
|
28
|
-
x.xpath("//*[local-name() = 'math'][@display]").each do |y|
|
37
|
+
def asciimath2mathml_wrap(xml)
|
38
|
+
xml.xpath("//*[local-name() = 'math'][@display]").each do |y|
|
29
39
|
y.delete("display")
|
30
40
|
end
|
31
|
-
x.xpath("
|
32
|
-
|
33
|
-
end
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
41
|
+
# x.xpath("//stem").each do |y|
|
42
|
+
# y.next_element&.name == "asciimath" and y << y.next_element
|
43
|
+
# end
|
44
|
+
xml
|
45
|
+
end
|
46
|
+
|
47
|
+
def progress_conv(idx, step, total, threshold, msg)
|
48
|
+
return unless (idx % step).zero? && total > threshold && idx.positive?
|
49
|
+
|
50
|
+
warn "#{msg} #{idx} of #{total}"
|
38
51
|
end
|
39
52
|
|
40
53
|
def xml_unescape_mathml(xml)
|
41
54
|
return if xml.children.any?(&:element?)
|
42
55
|
|
43
|
-
math = xml.text.gsub(
|
44
|
-
.gsub(
|
56
|
+
math = xml.text.gsub("<", "<").gsub(">", ">")
|
57
|
+
.gsub(""", '"').gsub("'", "'").gsub("&", "&")
|
45
58
|
.gsub(/<[^: \r\n\t\/]+:/, "<").gsub(/<\/[^ \r\n\t:]+:/, "</")
|
46
59
|
xml.children = math
|
47
60
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
require "metanorma/standoc/utils"
|
2
|
+
|
1
3
|
module Metanorma
|
2
4
|
module Standoc
|
3
5
|
module Cleanup
|
@@ -8,31 +10,12 @@ module Metanorma
|
|
8
10
|
def symbol_key(sym)
|
9
11
|
@c.decode(asciimath_key(sym).text)
|
10
12
|
.gsub(/[\[\]{}<>()]/, "").gsub(/\s/m, "")
|
11
|
-
.gsub(/[[:punct:]]|[_^]/, ":\\0").gsub(
|
13
|
+
.gsub(/[[:punct:]]|[_^]/, ":\\0").gsub("`", "")
|
12
14
|
.gsub(/[0-9]+/, "þ\\0")
|
13
15
|
.tr("AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz",
|
14
16
|
"ABCFEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz")
|
15
17
|
end
|
16
18
|
|
17
|
-
def asciimath_key(sym)
|
18
|
-
key = sym.dup
|
19
|
-
key.traverse do |n|
|
20
|
-
if n.name == "stem" && a = n.at(".//asciimath")
|
21
|
-
n.children = @c.encode(
|
22
|
-
@c.decode(grkletters(a.text)), :basic
|
23
|
-
)
|
24
|
-
end
|
25
|
-
end
|
26
|
-
key.xpath(".//asciimath").each(&:remove)
|
27
|
-
Nokogiri::XML(key.to_xml)
|
28
|
-
end
|
29
|
-
|
30
|
-
def grkletters(text)
|
31
|
-
text.gsub(/\b(alpha|beta|gamma|delta|epsilon|zeta|eta|theta|iota|kappa|
|
32
|
-
lambda|mu|nu|xi|omicron|pi|rho|sigma|tau|upsilon|phi|chi|
|
33
|
-
psi|omega)\b/xi, "&\\1;")
|
34
|
-
end
|
35
|
-
|
36
19
|
def extract_symbols_list(dlist)
|
37
20
|
dl_out = []
|
38
21
|
dlist.xpath("./dt | ./dd").each do |dtd|
|
@@ -111,6 +111,7 @@ module Metanorma
|
|
111
111
|
term_dl_to_metadata(xmldoc)
|
112
112
|
term_termsource_to_designation(xmldoc)
|
113
113
|
term_designation_reorder(xmldoc)
|
114
|
+
term_designation_redundant(xmldoc)
|
114
115
|
termdef_from_termbase(xmldoc)
|
115
116
|
termdomain_cleanup(xmldoc)
|
116
117
|
termdef_stem_cleanup(xmldoc)
|
@@ -101,7 +101,7 @@ module Metanorma
|
|
101
101
|
|
102
102
|
def term_dl_to_designation_category(prev, category)
|
103
103
|
cat = prev.at(".//expression/grammar/#{category}")
|
104
|
-
|
104
|
+
cat&.text&.include?(",") and
|
105
105
|
cat.replace(cat.text.split(/,\s*/)
|
106
106
|
.map { |x| "<#{category}>#{x}</#{category}>" }.join)
|
107
107
|
end
|
@@ -148,13 +148,15 @@ module Metanorma
|
|
148
148
|
end
|
149
149
|
end
|
150
150
|
|
151
|
+
DESIGNATOR = %w(preferred admitted deprecates related).freeze
|
152
|
+
|
151
153
|
def term_termsource_to_designation(xmldoc)
|
152
154
|
xmldoc.xpath("//term/termsource").each do |t|
|
153
155
|
p = t.previous_element
|
154
156
|
while %w(domain subject).include? p&.name
|
155
157
|
p = p.previous_element
|
156
158
|
end
|
157
|
-
|
159
|
+
DESIGNATOR.include?(p&.name) or
|
158
160
|
next
|
159
161
|
related2pref(p) << t.remove
|
160
162
|
end
|
@@ -162,8 +164,7 @@ module Metanorma
|
|
162
164
|
|
163
165
|
def term_designation_reorder(xmldoc)
|
164
166
|
xmldoc.xpath("//term").each do |t|
|
165
|
-
des =
|
166
|
-
.each_with_object([]) do |tag, m|
|
167
|
+
des = DESIGNATOR.each_with_object([]) do |tag, m|
|
167
168
|
t.xpath("./#{tag}").each { |x| m << x.remove }
|
168
169
|
end.reverse
|
169
170
|
t << " "
|
@@ -174,7 +175,21 @@ module Metanorma
|
|
174
175
|
end
|
175
176
|
|
176
177
|
def related2pref(elem)
|
177
|
-
elem&.name == "related" ? elem
|
178
|
+
elem&.name == "related" ? elem.at("./preferred") : elem
|
179
|
+
end
|
180
|
+
|
181
|
+
def term_designation_redundant(xmldoc)
|
182
|
+
xmldoc.xpath("//term").each do |t|
|
183
|
+
DESIGNATOR.each do |n|
|
184
|
+
t.xpath("./#{n}/expression/name").each_with_object([]) do |d, m|
|
185
|
+
if m.include?(d.text)
|
186
|
+
@log.add("Terms", t, "Removed duplicate designation #{d.text}")
|
187
|
+
d.parent.parent.remove
|
188
|
+
end
|
189
|
+
m << d.text
|
190
|
+
end
|
191
|
+
end
|
192
|
+
end
|
178
193
|
end
|
179
194
|
end
|
180
195
|
end
|
@@ -3,7 +3,6 @@ module Metanorma
|
|
3
3
|
module Cleanup
|
4
4
|
def textcleanup(result)
|
5
5
|
text = result.flatten.map { |l| l.sub(/\s*\Z/, "") } * "\n"
|
6
|
-
!@keepasciimath and text = asciimath2mathml(text)
|
7
6
|
text = text.gsub(/\s+<fn /, "<fn ")
|
8
7
|
%w(passthrough passthrough-inline).each do |v|
|
9
8
|
text.gsub!(%r{<#{v}\s+formats="metanorma">([^<]*)
|
@@ -20,6 +20,8 @@ module Metanorma
|
|
20
20
|
# schema encapsulation of the document for validation
|
21
21
|
class Converter
|
22
22
|
Asciidoctor::Extensions.register do
|
23
|
+
preprocessor Metanorma::Standoc::EmbedIncludeProcessor
|
24
|
+
preprocessor Metanorma::Standoc::NamedEscapePreprocessor
|
23
25
|
preprocessor Metanorma::Standoc::Datamodel::AttributesTablePreprocessor
|
24
26
|
preprocessor Metanorma::Standoc::Datamodel::DiagramPreprocessor
|
25
27
|
preprocessor Metanorma::Plugin::Datastruct::Json2TextPreprocessor
|
@@ -60,8 +62,6 @@ module Metanorma
|
|
60
62
|
treeprocessor Metanorma::Standoc::ToDoInlineAdmonitionBlock
|
61
63
|
block Metanorma::Standoc::PlantUMLBlockMacro
|
62
64
|
block Metanorma::Standoc::PseudocodeBlockMacro
|
63
|
-
preprocessor Metanorma::Standoc::EmbedIncludeProcessor
|
64
|
-
preprocessor Metanorma::Standoc::NamedEscapePreprocessor
|
65
65
|
end
|
66
66
|
|
67
67
|
include ::Asciidoctor::Converter
|
@@ -138,9 +138,10 @@ module Metanorma
|
|
138
138
|
noko { |xml| xml.hr }.join
|
139
139
|
end
|
140
140
|
|
141
|
-
def latex_parse1(text)
|
141
|
+
def latex_parse1(text, block)
|
142
142
|
lxm_input = Unicode2LaTeX.unicode2latex(@c.decode(text))
|
143
|
-
results = Plurimath::Math.parse(lxm_input, "latex")
|
143
|
+
results = Plurimath::Math.parse(lxm_input, "latex")
|
144
|
+
.to_mathml(display_style: block)
|
144
145
|
if results.nil?
|
145
146
|
@log.add("Math", nil,
|
146
147
|
"latexmlmath failed to process equation:\n#{lxm_input}")
|
@@ -149,22 +150,23 @@ module Metanorma
|
|
149
150
|
results.sub(%r{<math ([^>]+ )?display="block"}, "<math \\1")
|
150
151
|
end
|
151
152
|
|
152
|
-
def stem_parse(text, xml, style)
|
153
|
+
def stem_parse(text, xml, style, block)
|
153
154
|
if /<([^:>&]+:)?math(\s+[^>&]+)?> |
|
154
155
|
<([^:>&]+:)?math(\s+[^>&]+)?>/x.match? text
|
155
156
|
math = xml_encode(text)
|
156
|
-
xml.stem type: "MathML" do |s|
|
157
|
+
xml.stem type: "MathML", block: block do |s|
|
157
158
|
s << math
|
158
159
|
end
|
159
|
-
elsif style == :latexmath then latex_parse(text, xml)
|
160
|
+
elsif style == :latexmath then latex_parse(text, xml, block)
|
160
161
|
else
|
161
|
-
xml.stem text&.gsub(
|
162
|
+
xml.stem text&.gsub("&#", "&#"), type: "AsciiMath", block: block
|
162
163
|
end
|
163
164
|
end
|
164
165
|
|
165
|
-
def latex_parse(text, xml)
|
166
|
-
latex = latex_parse1(text) or
|
167
|
-
|
166
|
+
def latex_parse(text, xml, block)
|
167
|
+
latex = latex_parse1(text, block) or
|
168
|
+
return xml.stem type: "MathML", block: block
|
169
|
+
xml.stem type: "MathML", block: block do |s|
|
168
170
|
math = Nokogiri::XML.fragment(latex.sub(/<\?[^>]+>/, ""))
|
169
171
|
.elements[0]
|
170
172
|
math.delete("alttext")
|
@@ -187,8 +189,8 @@ module Metanorma
|
|
187
189
|
when :single then xml << "'#{node.text}'"
|
188
190
|
when :superscript then xml.sup { |s| s << node.text }
|
189
191
|
when :subscript then xml.sub { |s| s << node.text }
|
190
|
-
when :asciimath then stem_parse(node.text, xml, :asciimath)
|
191
|
-
when :latexmath then stem_parse(node.text, xml, :latexmath)
|
192
|
+
when :asciimath then stem_parse(node.text, xml, :asciimath, false)
|
193
|
+
when :latexmath then stem_parse(node.text, xml, :latexmath, false)
|
192
194
|
when :mark then highlight_parse(node.text, xml)
|
193
195
|
else
|
194
196
|
case node.role
|
@@ -215,7 +217,14 @@ module Metanorma
|
|
215
217
|
end
|
216
218
|
|
217
219
|
def image_attributes(node)
|
218
|
-
|
220
|
+
nodetarget = node.attr("target") || node.target
|
221
|
+
if Gem.win_platform? && /^[a-zA-Z]:/.match?(nodetarget)
|
222
|
+
nodetarget.prepend("/")
|
223
|
+
end
|
224
|
+
uri = node.image_uri (nodetarget)
|
225
|
+
if Gem.win_platform? && /^\/[a-zA-Z]:/.match?(uri)
|
226
|
+
uri = uri[1..-1]
|
227
|
+
end
|
219
228
|
types = if /^data:/.match?(uri) then Metanorma::Utils::datauri2mime(uri)
|
220
229
|
else MIME::Types.type_for(uri)
|
221
230
|
end
|
@@ -17,7 +17,7 @@
|
|
17
17
|
these elements; we just want one namespace for any child grammars
|
18
18
|
of this.
|
19
19
|
-->
|
20
|
-
<!-- VERSION v1.2.
|
20
|
+
<!-- VERSION v1.2.3 -->
|
21
21
|
<grammar xmlns:a="http://relaxng.org/ns/compatibility/annotations/1.0" xmlns="http://relaxng.org/ns/structure/1.0" datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes">
|
22
22
|
<include href="reqt.rng"/>
|
23
23
|
<include href="basicdoc.rng">
|
@@ -192,9 +192,11 @@
|
|
192
192
|
</attribute>
|
193
193
|
</optional>
|
194
194
|
<attribute name="citeas"/>
|
195
|
-
<
|
196
|
-
<
|
197
|
-
|
195
|
+
<optional>
|
196
|
+
<attribute name="type">
|
197
|
+
<ref name="ReferenceFormat"/>
|
198
|
+
</attribute>
|
199
|
+
</optional>
|
198
200
|
<optional>
|
199
201
|
<attribute name="alt"/>
|
200
202
|
</optional>
|
@@ -836,6 +838,26 @@
|
|
836
838
|
<ref name="paragraph"/>
|
837
839
|
</element>
|
838
840
|
</define>
|
841
|
+
<define name="stem">
|
842
|
+
<element name="stem">
|
843
|
+
<attribute name="type">
|
844
|
+
<choice>
|
845
|
+
<value>MathML</value>
|
846
|
+
<value>AsciiMath</value>
|
847
|
+
<value>LatexMath</value>
|
848
|
+
</choice>
|
849
|
+
</attribute>
|
850
|
+
<attribute name="block">
|
851
|
+
<data type="boolean"/>
|
852
|
+
</attribute>
|
853
|
+
<oneOrMore>
|
854
|
+
<choice>
|
855
|
+
<text/>
|
856
|
+
<ref name="AnyElement"/>
|
857
|
+
</choice>
|
858
|
+
</oneOrMore>
|
859
|
+
</element>
|
860
|
+
</define>
|
839
861
|
<define name="em">
|
840
862
|
<element name="em">
|
841
863
|
<zeroOrMore>
|
@@ -85,13 +85,14 @@ module Metanorma
|
|
85
85
|
end
|
86
86
|
end
|
87
87
|
|
88
|
-
def
|
89
|
-
ref[:code].nil? || ref[:code].empty? || ref[:no_year] ||
|
88
|
+
def unfetchable_ref_code?(ref)
|
89
|
+
ref[:code].nil? || ref[:code].empty? || ref[:no_year] ||
|
90
|
+
/^\(.+\)$/.match?(ref[:code]) ||
|
90
91
|
(@bibdb.nil? && !ref[:localfile])
|
91
92
|
end
|
92
93
|
|
93
94
|
def fetch_ref_async(ref, idx, res)
|
94
|
-
if
|
95
|
+
if unfetchable_ref_code?(ref)
|
95
96
|
res << [ref, idx, nil]
|
96
97
|
elsif ref[:localfile]
|
97
98
|
res << [ref, idx, @local_bibdb.get(ref[:code], ref[:localfile])]
|
@@ -1,11 +1,10 @@
|
|
1
|
-
# frozen_string_literal: true.
|
2
1
|
require "metanorma/standoc/utils"
|
3
2
|
|
4
3
|
module Metanorma
|
5
4
|
module Standoc
|
6
5
|
# Intelligent term lookup xml modifier
|
7
6
|
class TermLookupCleanup
|
8
|
-
|
7
|
+
AUTO_GEN_ID_REGEXP = /\A_/.freeze
|
9
8
|
EXISTING_TERM_REGEXP = /\Aterm-/.freeze
|
10
9
|
EXISTING_SYMBOL_REGEXP = /\Asymbol-/.freeze
|
11
10
|
|
@@ -16,6 +15,8 @@ module Metanorma
|
|
16
15
|
@log = log
|
17
16
|
@termlookup = { term: {}, symbol: {}, secondary2primary: {} }
|
18
17
|
@idhash = {}
|
18
|
+
@unique_designs = {}
|
19
|
+
@c = HTMLEntities.new
|
19
20
|
@terms_tags = xmldoc.xpath("//terms").each_with_object({}) do |t, m|
|
20
21
|
m[t["id"]] = true
|
21
22
|
end
|
@@ -23,63 +24,102 @@ module Metanorma
|
|
23
24
|
|
24
25
|
def call
|
25
26
|
@idhash = populate_idhash
|
27
|
+
@unique_designs = unique_designators
|
26
28
|
@termlookup = replace_automatic_generated_ids_terms
|
27
29
|
set_termxref_tags_target
|
28
30
|
concept_cleanup
|
29
31
|
related_cleanup
|
32
|
+
remove_missing_refs
|
33
|
+
concept_cleanup2
|
30
34
|
end
|
31
35
|
|
32
36
|
private
|
33
37
|
|
38
|
+
def unique_designators
|
39
|
+
ret = xmldoc
|
40
|
+
.xpath("//preferred/expression/name | //admitted/expression/name | " \
|
41
|
+
"//deprecated/expression/name").each_with_object({}) do |n, m|
|
42
|
+
m[n.text] ||= 0
|
43
|
+
m[n.text] += 1
|
44
|
+
end
|
45
|
+
ret.each { |k, v| v == 1 or ret.delete(k) }
|
46
|
+
ret
|
47
|
+
end
|
48
|
+
|
34
49
|
def concept_cleanup
|
35
50
|
xmldoc.xpath("//concept").each do |n|
|
36
|
-
n.delete("type")
|
37
51
|
refterm = n.at("./refterm") or next
|
38
|
-
|
39
|
-
|
52
|
+
lookup = normalize_ref_id_text(refterm.text.strip)
|
53
|
+
p = @termlookup[:secondary2primary][lookup] and
|
54
|
+
refterm.children = @c.encode(p)
|
40
55
|
end
|
41
56
|
end
|
42
57
|
|
58
|
+
def concept_cleanup2
|
59
|
+
xmldoc.xpath("//concept").each { |n| n.delete("type") }
|
60
|
+
end
|
61
|
+
|
43
62
|
def related_cleanup
|
44
63
|
xmldoc.xpath("//related").each do |n|
|
45
64
|
refterm = n.at("./refterm") or next
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
65
|
+
lookup = normalize_ref_id_text(refterm.text.strip)
|
66
|
+
p = @termlookup[:secondary2primary][lookup] and
|
67
|
+
refterm.children = @c.encode(p)
|
68
|
+
p || @termlookup[:term][lookup] and
|
69
|
+
refterm.replace("<preferred><expression>" \
|
70
|
+
"<name>#{refterm.children.to_xml}" \
|
71
|
+
"</name></expression></preferred>")
|
51
72
|
end
|
52
73
|
end
|
53
74
|
|
54
75
|
def populate_idhash
|
55
76
|
xmldoc.xpath("//*[@id]").each_with_object({}) do |n, mem|
|
56
|
-
|
57
|
-
|
77
|
+
/^(term|symbol)-/.match?(n["id"]) or next
|
58
78
|
mem[n["id"]] = true
|
59
79
|
end
|
60
80
|
end
|
61
81
|
|
62
82
|
def set_termxref_tags_target
|
63
83
|
xmldoc.xpath("//termxref").each do |node|
|
64
|
-
target =
|
65
|
-
if termlookup[:term][target].nil? && termlookup[:symbol][target].nil?
|
66
|
-
remove_missing_ref(node, target)
|
67
|
-
next
|
68
|
-
end
|
84
|
+
target = normalize_ref_id1(node)
|
69
85
|
x = node.at("../xrefrender") and modify_ref_node(x, target)
|
70
86
|
node.name = "refterm"
|
71
87
|
end
|
72
88
|
end
|
73
89
|
|
90
|
+
def remove_missing_refs
|
91
|
+
xmldoc.xpath("//refterm").each do |node|
|
92
|
+
remove_missing_ref?(node) or next
|
93
|
+
lookup_refterm(node)
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
def remove_missing_ref?(node)
|
98
|
+
node.at("../eref | ../termref") and return false
|
99
|
+
xref = node.at("../xref") or return true
|
100
|
+
xref["target"] && !xref["target"]&.empty? and return false
|
101
|
+
xref.remove # if xref supplied by user, we won't delete
|
102
|
+
true
|
103
|
+
end
|
104
|
+
|
105
|
+
def lookup_refterm(node)
|
106
|
+
target = normalize_ref_id1(node)
|
107
|
+
if termlookup[:term][target].nil? && termlookup[:symbol][target].nil?
|
108
|
+
remove_missing_ref(node, target)
|
109
|
+
else
|
110
|
+
x = node.at("../xrefrender") and x.name = "xref"
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
74
114
|
def remove_missing_ref(node, target)
|
75
115
|
if node.at("./parent::concept[@type = 'symbol']")
|
76
116
|
log.add("AsciiDoc Input", node,
|
77
117
|
remove_missing_ref_msg(node, target, :symbol))
|
78
|
-
|
118
|
+
remove_missing_ref_term(node, target, "symbol")
|
79
119
|
else
|
80
120
|
log.add("AsciiDoc Input", node,
|
81
121
|
remove_missing_ref_msg(node, target, :term))
|
82
|
-
remove_missing_ref_term(node, target)
|
122
|
+
remove_missing_ref_term(node, target, "term")
|
83
123
|
end
|
84
124
|
end
|
85
125
|
|
@@ -94,7 +134,7 @@ module Metanorma
|
|
94
134
|
end
|
95
135
|
|
96
136
|
def remove_missing_ref_msg1(_node, target, ret)
|
97
|
-
target2 = "_#{target.downcase.gsub(
|
137
|
+
target2 = "_#{target.downcase.gsub('-', '_')}"
|
98
138
|
if @terms_tags[target] || @terms_tags[target2]
|
99
139
|
ret.strip!
|
100
140
|
ret += ". Did you mean to point to a subterm?"
|
@@ -102,23 +142,13 @@ module Metanorma
|
|
102
142
|
ret
|
103
143
|
end
|
104
144
|
|
105
|
-
def remove_missing_ref_term(node, target)
|
106
|
-
node.name = "strong"
|
107
|
-
node.at("../xrefrender")&.remove
|
108
|
-
display = node.at("../renderterm")&.remove&.children
|
109
|
-
display = [] if display.nil? || display.to_xml == node.text
|
110
|
-
d = display.empty? ? "" : ", display <tt>#{display.to_xml}</tt>"
|
111
|
-
node.children = "term <tt>#{node.text}</tt>#{d} " \
|
112
|
-
"not resolved via ID <tt>#{target}</tt>"
|
113
|
-
end
|
114
|
-
|
115
|
-
def remove_missing_ref_symbol(node, target)
|
145
|
+
def remove_missing_ref_term(node, target, type)
|
116
146
|
node.name = "strong"
|
117
|
-
node.
|
147
|
+
node.xpath("../xrefrender | ../xref").each(&:remove)
|
118
148
|
display = node.at("../renderterm")&.remove&.children
|
119
149
|
display = [] if display.nil? || display.to_xml == node.text
|
120
150
|
d = display.empty? ? "" : ", display <tt>#{display.to_xml}</tt>"
|
121
|
-
node.children = "
|
151
|
+
node.children = "#{type} <tt>#{@c.encode(node.text)}</tt>#{d} " \
|
122
152
|
"not resolved via ID <tt>#{target}</tt>"
|
123
153
|
end
|
124
154
|
|
@@ -137,35 +167,50 @@ module Metanorma
|
|
137
167
|
|
138
168
|
def replace_automatic_generated_ids_terms
|
139
169
|
r = xmldoc.xpath("//term").each.with_object({}) do |n, res|
|
140
|
-
|
141
|
-
|
170
|
+
norm_id_memorize(n, res, "./preferred//name", "term", true)
|
171
|
+
norm_id_memorize(n, res, "./admitted//name", "term", true)
|
142
172
|
end
|
143
173
|
s = xmldoc.xpath("//definitions//dt").each.with_object({}) do |n, res|
|
144
|
-
|
174
|
+
norm_id_memorize(n, res, ".", "symbol", false)
|
145
175
|
end
|
146
176
|
{ term: r, symbol: s, secondary2primary: pref_secondary2primary }
|
147
177
|
end
|
148
178
|
|
149
179
|
def pref_secondary2primary
|
150
|
-
term = ""
|
151
180
|
xmldoc.xpath("//term").each.with_object({}) do |n, res|
|
152
|
-
n.
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
181
|
+
primary = domain_prefix(n, n.at("./preferred//name")&.text)
|
182
|
+
pref_secondary2primary_preferred(n, res, primary)
|
183
|
+
pref_secondary2primary_admitted(n, res, primary)
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
def pref_secondary2primary_preferred(term, res, primary)
|
188
|
+
term.xpath("./preferred//name").each_with_index do |p, i|
|
189
|
+
t = p.text.strip
|
190
|
+
i.positive? and
|
191
|
+
res[normalize_ref_id_text(domain_prefix(term, t))] = primary
|
192
|
+
@unique_designs[t] && term.at(".//domain") and
|
193
|
+
res[normalize_ref_id_text(t)] = primary
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
197
|
+
def pref_secondary2primary_admitted(term, res, primary)
|
198
|
+
term.xpath("./admitted//name").each do |p|
|
199
|
+
t = p.text.strip
|
200
|
+
res[normalize_ref_id_text(domain_prefix(term, t))] = primary
|
201
|
+
@unique_designs[t] && term.at(".//domain") and
|
202
|
+
res[normalize_ref_id_text(t)] = primary
|
157
203
|
end
|
158
204
|
end
|
159
205
|
|
160
|
-
def
|
161
|
-
|
162
|
-
memorize_other_pref_terms(node, res_table,
|
206
|
+
def norm_id_memorize(node, res_table, selector, prefix, use_domain)
|
207
|
+
norm_id_memorize_init(node, res_table, selector, prefix, use_domain)
|
208
|
+
memorize_other_pref_terms(node, res_table, selector, use_domain)
|
163
209
|
end
|
164
210
|
|
165
|
-
def
|
166
|
-
term_text = normalize_ref_id(node
|
167
|
-
unless
|
168
|
-
!node["id"].nil?
|
211
|
+
def norm_id_memorize_init(node, res_table, selector, prefix, use_domain)
|
212
|
+
term_text = normalize_ref_id(node, selector, use_domain) or return
|
213
|
+
unless AUTO_GEN_ID_REGEXP.match(node["id"]).nil? && !node["id"].nil?
|
169
214
|
id = unique_text_id(term_text, prefix)
|
170
215
|
node["id"] = id
|
171
216
|
@idhash[id] = true
|
@@ -173,34 +218,46 @@ module Metanorma
|
|
173
218
|
res_table[term_text] = node["id"]
|
174
219
|
end
|
175
220
|
|
176
|
-
def memorize_other_pref_terms(node, res_table, text_selector)
|
221
|
+
def memorize_other_pref_terms(node, res_table, text_selector, use_domain)
|
177
222
|
node.xpath(text_selector).each_with_index do |p, i|
|
178
|
-
|
179
|
-
|
180
|
-
res_table[normalize_ref_id(p)] = node["id"]
|
223
|
+
i.positive? or next
|
224
|
+
res_table[normalize_ref_id1(p, use_domain ? node : nil)] = node["id"]
|
181
225
|
end
|
182
226
|
end
|
183
227
|
|
184
|
-
def
|
185
|
-
|
228
|
+
def domain_prefix(node, term)
|
229
|
+
d = node&.at(".//domain") or return term
|
230
|
+
"<#{d.text}> #{term}"
|
231
|
+
end
|
232
|
+
|
233
|
+
def normalize_ref_id(node, selector, use_domain)
|
234
|
+
term = node.at(selector) or return nil
|
235
|
+
normalize_ref_id1(term, use_domain ? node : nil)
|
236
|
+
end
|
186
237
|
|
238
|
+
def normalize_ref_id1(term, node = nil)
|
187
239
|
t = term.dup
|
188
240
|
t.xpath(".//index").map(&:remove)
|
189
|
-
|
190
|
-
|
241
|
+
ret = asciimath_key(t).text.strip
|
242
|
+
node and ret = domain_prefix(node, ret)
|
243
|
+
normalize_ref_id_text(ret)
|
244
|
+
end
|
245
|
+
|
246
|
+
def normalize_ref_id_text(text)
|
247
|
+
Metanorma::Utils::to_ncname(text.gsub(/[[:space:]]+/, "-"))
|
191
248
|
end
|
192
249
|
|
193
250
|
def unique_text_id(text, prefix)
|
194
|
-
|
251
|
+
@idhash["#{prefix}-#{text}"] or
|
195
252
|
return "#{prefix}-#{text}"
|
196
|
-
end
|
197
|
-
|
198
253
|
(1..Float::INFINITY).lazy.each do |index|
|
199
254
|
unless @idhash["#{prefix}-#{text}-#{index}"]
|
200
255
|
break("#{prefix}-#{text}-#{index}")
|
201
256
|
end
|
202
257
|
end
|
203
258
|
end
|
259
|
+
|
260
|
+
include ::Metanorma::Standoc::Utils
|
204
261
|
end
|
205
262
|
end
|
206
263
|
end
|
@@ -70,10 +70,10 @@ module Metanorma
|
|
70
70
|
|
71
71
|
def xml_encode(text)
|
72
72
|
@c.encode(text, :basic, :hexadecimal)
|
73
|
-
.gsub(
|
74
|
-
.gsub(
|
75
|
-
.gsub(
|
76
|
-
.gsub(
|
73
|
+
.gsub("&gt;", ">").gsub("&lt;", "<").gsub("&amp;", "&")
|
74
|
+
.gsub(">", ">").gsub("<", "<").gsub("&", "&")
|
75
|
+
.gsub(""", '"').gsub("
", "\n").gsub("&#", "&#")
|
76
|
+
.gsub("'", "'")
|
77
77
|
end
|
78
78
|
|
79
79
|
# wrapped in <sections>
|
@@ -85,6 +85,25 @@ module Metanorma
|
|
85
85
|
Nokogiri::XML(c).at("//xmlns:sections")
|
86
86
|
end
|
87
87
|
|
88
|
+
def asciimath_key(sym)
|
89
|
+
key = sym.dup
|
90
|
+
key.traverse do |n|
|
91
|
+
if n.name == "stem" && a = n.at(".//asciimath")
|
92
|
+
n.children = @c.encode(
|
93
|
+
@c.decode(grkletters(a.text)), :basic
|
94
|
+
)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
key.xpath(".//asciimath").each(&:remove)
|
98
|
+
Nokogiri::XML(key.to_xml)
|
99
|
+
end
|
100
|
+
|
101
|
+
def grkletters(text)
|
102
|
+
text.gsub(/\b(alpha|beta|gamma|delta|epsilon|zeta|eta|theta|iota|kappa|
|
103
|
+
lambda|mu|nu|xi|omicron|pi|rho|sigma|tau|upsilon|phi|chi|
|
104
|
+
psi|omega)\b/xi, "&\\1;")
|
105
|
+
end
|
106
|
+
|
88
107
|
module_function :adoc2xml
|
89
108
|
|
90
109
|
class EmptyAttr
|
@@ -1,7 +1,7 @@
|
|
1
1
|
require "metanorma/standoc/utils"
|
2
|
-
require_relative "
|
3
|
-
require_relative "
|
4
|
-
require_relative "
|
2
|
+
require_relative "validate_section"
|
3
|
+
require_relative "validate_table"
|
4
|
+
require_relative "validate_term"
|
5
5
|
require "nokogiri"
|
6
6
|
require "jing"
|
7
7
|
require "iev"
|
@@ -10,38 +10,6 @@ require "pngcheck"
|
|
10
10
|
module Metanorma
|
11
11
|
module Standoc
|
12
12
|
module Validate
|
13
|
-
SOURCELOCALITY = "./origin//locality[@type = 'clause']/" \
|
14
|
-
"referenceFrom".freeze
|
15
|
-
|
16
|
-
def init_iev
|
17
|
-
@no_isobib and return nil
|
18
|
-
@iev and return @iev
|
19
|
-
@iev = Iev::Db.new(@iev_globalname, @iev_localname) unless @no_isobib
|
20
|
-
@iev
|
21
|
-
end
|
22
|
-
|
23
|
-
def iev_validate(xmldoc)
|
24
|
-
@iev = init_iev or return
|
25
|
-
xmldoc.xpath("//term").each do |t|
|
26
|
-
t.xpath(".//termsource").each do |src|
|
27
|
-
(/^IEC[ ]60050-/.match(src.at("./origin/@citeas")&.text) &&
|
28
|
-
loc = src.xpath(SOURCELOCALITY)&.text) or next
|
29
|
-
iev_validate1(t, loc, xmldoc)
|
30
|
-
end
|
31
|
-
end
|
32
|
-
end
|
33
|
-
|
34
|
-
def iev_validate1(term, loc, xmldoc)
|
35
|
-
iev = @iev.fetch(loc,
|
36
|
-
xmldoc.at("//language")&.text || "en") or return
|
37
|
-
pref = term.xpath("./preferred//name").inject([]) do |m, x|
|
38
|
-
m << x.text&.downcase
|
39
|
-
end
|
40
|
-
pref.include?(iev.downcase) or
|
41
|
-
@log.add("Bibliography", term, %(Term "#{pref[0]}" does not match ) +
|
42
|
-
%(IEV #{loc} "#{iev}"))
|
43
|
-
end
|
44
|
-
|
45
13
|
def content_validate(doc)
|
46
14
|
repeat_id_validate(doc.root) # feeds xref_validate
|
47
15
|
xref_validate(doc) # feeds nested_asset_validate
|
@@ -51,6 +19,7 @@ module Metanorma
|
|
51
19
|
iev_validate(doc.root)
|
52
20
|
concept_validate(doc, "concept", "refterm")
|
53
21
|
concept_validate(doc, "related", "preferred//name")
|
22
|
+
preferred_validate(doc)
|
54
23
|
table_validate(doc)
|
55
24
|
@fatalerror += requirement_validate(doc)
|
56
25
|
image_validate(doc)
|
@@ -73,7 +42,7 @@ module Metanorma
|
|
73
42
|
def mathml_sanitise(math)
|
74
43
|
math.to_xml(encoding: "US-ASCII").gsub(/ xmlns=["'][^"']+["']/, "")
|
75
44
|
.gsub(%r{<[^:/>]+:}, "<").gsub(%r{</[^:/>]+:}, "</")
|
76
|
-
|
45
|
+
# .gsub(/&#([^;]+);/) { |x| "&#x#{$1.to_i.to_s(16)};" }
|
77
46
|
end
|
78
47
|
|
79
48
|
def math_validate_error(math, elem, error)
|
@@ -125,37 +94,6 @@ module Metanorma
|
|
125
94
|
# @fatalerror << err2
|
126
95
|
end
|
127
96
|
|
128
|
-
def concept_validate(doc, tag, refterm)
|
129
|
-
found = false
|
130
|
-
concept_validate_ids(doc)
|
131
|
-
doc.xpath("//#{tag}/xref").each do |x|
|
132
|
-
@concept_ids[x["target"]] and next
|
133
|
-
@log.add("Anchors", x, concept_validate_msg(doc, tag, refterm, x))
|
134
|
-
found = true
|
135
|
-
end
|
136
|
-
found and @fatalerror << "#{tag.capitalize} not cross-referencing " \
|
137
|
-
"term or symbol"
|
138
|
-
end
|
139
|
-
|
140
|
-
def concept_validate_ids(doc)
|
141
|
-
@concept_ids ||= doc.xpath("//term | //definitions//dt")
|
142
|
-
.each_with_object({}) { |x, m| m[x["id"]] = true }
|
143
|
-
@concept_terms_tags ||= doc.xpath("//terms")
|
144
|
-
.each_with_object({}) { |t, m| m[t["id"]] = true }
|
145
|
-
nil
|
146
|
-
end
|
147
|
-
|
148
|
-
def concept_validate_msg(_doc, tag, refterm, xref)
|
149
|
-
ret = <<~LOG
|
150
|
-
#{tag.capitalize} #{xref.at("../#{refterm}")&.text} is pointing to #{xref['target']}, which is not a term or symbol
|
151
|
-
LOG
|
152
|
-
if @concept_terms_tags[xref["target"]]
|
153
|
-
ret = ret.strip
|
154
|
-
ret += ". Did you mean to point to a subterm?"
|
155
|
-
end
|
156
|
-
ret
|
157
|
-
end
|
158
|
-
|
159
97
|
def schema_validate(doc, schema)
|
160
98
|
Tempfile.open(["tmp", ".xml"], encoding: "UTF-8") do |f|
|
161
99
|
schema_validate1(f, doc, schema)
|
@@ -247,6 +185,33 @@ module Metanorma
|
|
247
185
|
schema_validate(formattedstr_strip(doc.dup),
|
248
186
|
File.join(File.dirname(__FILE__), "isodoc-compile.rng"))
|
249
187
|
end
|
188
|
+
|
189
|
+
def repeat_id_validate1(elem)
|
190
|
+
if @doc_ids[elem["id"]]
|
191
|
+
@log.add("Anchors", elem, "Anchor #{elem['id']} has already been " \
|
192
|
+
"used at line #{@doc_ids[elem['id']]}")
|
193
|
+
@fatalerror << "Multiple instances of same ID: #{elem['id']}"
|
194
|
+
end
|
195
|
+
@doc_ids[elem["id"]] = elem.line
|
196
|
+
end
|
197
|
+
|
198
|
+
def repeat_id_validate(doc)
|
199
|
+
@doc_ids = {}
|
200
|
+
doc.xpath("//*[@id]").each do |x|
|
201
|
+
repeat_id_validate1(x)
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
# manually check for xref/@target, xref/@to integrity
|
206
|
+
def xref_validate(doc)
|
207
|
+
@doc_xrefs = doc.xpath("//xref/@target | //xref/@to")
|
208
|
+
.each_with_object({}) do |x, m|
|
209
|
+
m[x.text] = x
|
210
|
+
@doc_ids[x.text] and next
|
211
|
+
@log.add("Anchors", x.parent,
|
212
|
+
"Crossreference target #{x} is undefined")
|
213
|
+
end
|
214
|
+
end
|
250
215
|
end
|
251
216
|
end
|
252
217
|
end
|
@@ -0,0 +1,89 @@
|
|
1
|
+
module Metanorma
|
2
|
+
module Standoc
|
3
|
+
module Validate
|
4
|
+
SOURCELOCALITY = "./origin//locality[@type = 'clause']/" \
|
5
|
+
"referenceFrom".freeze
|
6
|
+
|
7
|
+
def init_iev
|
8
|
+
@no_isobib and return nil
|
9
|
+
@iev and return @iev
|
10
|
+
@iev = Iev::Db.new(@iev_globalname, @iev_localname) unless @no_isobib
|
11
|
+
@iev
|
12
|
+
end
|
13
|
+
|
14
|
+
def iev_validate(xmldoc)
|
15
|
+
@iev = init_iev or return
|
16
|
+
xmldoc.xpath("//term").each do |t|
|
17
|
+
t.xpath(".//termsource").each do |src|
|
18
|
+
(/^IEC[ ]60050-/.match(src.at("./origin/@citeas")&.text) &&
|
19
|
+
loc = src.xpath(SOURCELOCALITY)&.text) or next
|
20
|
+
iev_validate1(t, loc, xmldoc)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def iev_validate1(term, loc, xmldoc)
|
26
|
+
iev = @iev.fetch(loc,
|
27
|
+
xmldoc.at("//language")&.text || "en") or return
|
28
|
+
pref = term.xpath("./preferred//name").inject([]) do |m, x|
|
29
|
+
m << x.text&.downcase
|
30
|
+
end
|
31
|
+
pref.include?(iev.downcase) or
|
32
|
+
@log.add("Bibliography", term, %(Term "#{pref[0]}" does not match ) +
|
33
|
+
%(IEV #{loc} "#{iev}"))
|
34
|
+
end
|
35
|
+
|
36
|
+
def concept_validate(doc, tag, refterm)
|
37
|
+
found = false
|
38
|
+
concept_validate_ids(doc)
|
39
|
+
doc.xpath("//#{tag}/xref").each do |x|
|
40
|
+
@concept_ids[x["target"]] and next
|
41
|
+
@log.add("Anchors", x, concept_validate_msg(doc, tag, refterm, x))
|
42
|
+
found = true
|
43
|
+
end
|
44
|
+
found and @fatalerror << "#{tag.capitalize} not cross-referencing " \
|
45
|
+
"term or symbol"
|
46
|
+
end
|
47
|
+
|
48
|
+
def concept_validate_ids(doc)
|
49
|
+
@concept_ids ||= doc.xpath("//term | //definitions//dt")
|
50
|
+
.each_with_object({}) { |x, m| m[x["id"]] = true }
|
51
|
+
@concept_terms_tags ||= doc.xpath("//terms")
|
52
|
+
.each_with_object({}) { |t, m| m[t["id"]] = true }
|
53
|
+
nil
|
54
|
+
end
|
55
|
+
|
56
|
+
def concept_validate_msg(_doc, tag, refterm, xref)
|
57
|
+
ret = <<~LOG
|
58
|
+
#{tag.capitalize} #{xref.at("../#{refterm}")&.text} is pointing to #{xref['target']}, which is not a term or symbol
|
59
|
+
LOG
|
60
|
+
if @concept_terms_tags[xref["target"]]
|
61
|
+
ret = ret.strip
|
62
|
+
ret += ". Did you mean to point to a subterm?"
|
63
|
+
end
|
64
|
+
ret
|
65
|
+
end
|
66
|
+
|
67
|
+
def preferred_validate(doc)
|
68
|
+
out = []
|
69
|
+
ret = doc.xpath("//term").each_with_object({}) do |t, m|
|
70
|
+
prefix = t.at("./domain")&.text
|
71
|
+
t.xpath("./preferred//name").each do |n|
|
72
|
+
ret = n.text
|
73
|
+
prefix and ret = "<#{prefix}> #{ret}"
|
74
|
+
(m[ret] and out << ret) or m[ret] = t
|
75
|
+
end
|
76
|
+
end
|
77
|
+
preferred_validate_report(out, ret)
|
78
|
+
end
|
79
|
+
|
80
|
+
def preferred_validate_report(terms, locations)
|
81
|
+
terms.each do |e|
|
82
|
+
err = "Term #{e} occurs twice as preferred designation"
|
83
|
+
@log.add("Terms", locations[e], err)
|
84
|
+
@fatalerror << err
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
data/metanorma-standoc.gemspec
CHANGED
@@ -30,7 +30,7 @@ Gem::Specification.new do |spec|
|
|
30
30
|
|
31
31
|
spec.add_dependency "asciidoctor", "~> 2.0.0"
|
32
32
|
spec.add_dependency "iev", "~> 0.3.0"
|
33
|
-
spec.add_dependency "isodoc", "~> 2.
|
33
|
+
spec.add_dependency "isodoc", "~> 2.6.0"
|
34
34
|
spec.add_dependency "metanorma", ">= 1.5.0"
|
35
35
|
spec.add_dependency "metanorma-plugin-datastruct", "~> 0.2.0"
|
36
36
|
spec.add_dependency "metanorma-plugin-glossarist", "~> 0.1.1"
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: metanorma-standoc
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ribose Inc.
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-07
|
11
|
+
date: 2023-08-07 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: asciidoctor
|
@@ -44,14 +44,14 @@ dependencies:
|
|
44
44
|
requirements:
|
45
45
|
- - "~>"
|
46
46
|
- !ruby/object:Gem::Version
|
47
|
-
version: 2.
|
47
|
+
version: 2.6.0
|
48
48
|
type: :runtime
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
52
|
- - "~>"
|
53
53
|
- !ruby/object:Gem::Version
|
54
|
-
version: 2.
|
54
|
+
version: 2.6.0
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
56
|
name: metanorma
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
@@ -529,7 +529,7 @@ files:
|
|
529
529
|
- lib/metanorma/standoc/validate.rb
|
530
530
|
- lib/metanorma/standoc/validate_section.rb
|
531
531
|
- lib/metanorma/standoc/validate_table.rb
|
532
|
-
- lib/metanorma/standoc/
|
532
|
+
- lib/metanorma/standoc/validate_term.rb
|
533
533
|
- lib/metanorma/standoc/version.rb
|
534
534
|
- lib/metanorma/standoc/views/datamodel/model_representation.adoc.erb
|
535
535
|
- lib/metanorma/standoc/views/datamodel/plantuml_representation.adoc.erb
|
@@ -1,32 +0,0 @@
|
|
1
|
-
module Metanorma
|
2
|
-
module Standoc
|
3
|
-
module Validate
|
4
|
-
def repeat_id_validate1(elem)
|
5
|
-
if @doc_ids[elem["id"]]
|
6
|
-
@log.add("Anchors", elem, "Anchor #{elem['id']} has already been " \
|
7
|
-
"used at line #{@doc_ids[elem['id']]}")
|
8
|
-
@fatalerror << "Multiple instances of same ID: #{elem['id']}"
|
9
|
-
end
|
10
|
-
@doc_ids[elem["id"]] = elem.line
|
11
|
-
end
|
12
|
-
|
13
|
-
def repeat_id_validate(doc)
|
14
|
-
@doc_ids = {}
|
15
|
-
doc.xpath("//*[@id]").each do |x|
|
16
|
-
repeat_id_validate1(x)
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
|
-
# manually check for xref/@target, xref/@to integrity
|
21
|
-
def xref_validate(doc)
|
22
|
-
@doc_xrefs = doc.xpath("//xref/@target | //xref/@to")
|
23
|
-
.each_with_object({}) do |x, m|
|
24
|
-
m[x.text] = x
|
25
|
-
@doc_ids[x.text] and next
|
26
|
-
@log.add("Anchors", x.parent,
|
27
|
-
"Crossreference target #{x} is undefined")
|
28
|
-
end
|
29
|
-
end
|
30
|
-
end
|
31
|
-
end
|
32
|
-
end
|