metanorma-iso 3.1.3 → 3.1.5
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/iso/html/style-human.css +39 -45
- data/lib/isodoc/iso/html/style-iso.css +40 -46
- data/lib/isodoc/iso/iso.amendment.xsl +632 -170
- data/lib/isodoc/iso/iso.international-standard.xsl +632 -170
- data/lib/isodoc/iso/presentation_section.rb +39 -4
- data/lib/isodoc/iso/word_cleanup.rb +17 -2
- data/lib/metanorma/iso/front.rb +10 -49
- data/lib/metanorma/iso/front_contributor.rb +3 -5
- data/lib/metanorma/iso/isodoc.rng +44 -19
- data/lib/metanorma/iso/validate.rb +18 -126
- data/lib/metanorma/iso/validate_numeric.rb +128 -0
- data/lib/metanorma/iso/validate_style.rb +0 -77
- data/lib/metanorma/iso/validate_xref.rb +130 -0
- data/lib/metanorma/iso/version.rb +1 -1
- metadata +4 -3
- data/lib/metanorma/iso/validate_image.rb +0 -97
@@ -94,17 +94,6 @@ module Metanorma
|
|
94
94
|
style_problem_words(node, text)
|
95
95
|
end
|
96
96
|
|
97
|
-
# https://www.iso.org/ISO-house-style.html#iso-hs-s-text-r-s-quantity
|
98
|
-
def style_subscript(node)
|
99
|
-
warning = "may contain nested subscripts (max 3 levels allowed)"
|
100
|
-
node.xpath(".//sub[.//sub]").each do |x|
|
101
|
-
style_warning(node, warning, x.to_xml)
|
102
|
-
end
|
103
|
-
node.xpath(".//m:msub[.//m:msub]", "m" => MATHML_NS).each do |x|
|
104
|
-
style_warning(node, warning, x.to_xml)
|
105
|
-
end
|
106
|
-
end
|
107
|
-
|
108
97
|
# https://www.iso.org/ISO-house-style.html#iso-hs-s-text-r-s-need
|
109
98
|
# https://www.iso.org/ISO-house-style.html#iso-hs-s-text-r-s-might
|
110
99
|
# https://www.iso.org/ISO-house-style.html#iso-hs-s-text-r-s-family
|
@@ -120,44 +109,6 @@ module Metanorma
|
|
120
109
|
style_regex(/\b(?<num>billions?)\b/i, "ambiguous number", node, text)
|
121
110
|
end
|
122
111
|
|
123
|
-
# ISO/IEC DIR 2, 9.1
|
124
|
-
# ISO/IEC DIR 2, Table B.1
|
125
|
-
# https://www.iso.org/ISO-house-style.html#iso-hs-s-text-r-n-numbers
|
126
|
-
def style_number(node, text)
|
127
|
-
style_number_grouping(node, text)
|
128
|
-
style_regex(/(?:^|\p{Zs})(?<num>[0-9]+\.[0-9]+)(?!\.[0-9])/i,
|
129
|
-
"possible decimal point: mark up numbers with stem:[]", node, text)
|
130
|
-
@lang == "en" and style_regex(/\b(?<num>billions?)\b/i,
|
131
|
-
"ambiguous number", node, text)
|
132
|
-
style_regex(/(?:^|\p{Zs})(?<num>-[0-9][0-9,.]*)/i,
|
133
|
-
"hyphen instead of minus sign U+2212", node, text)
|
134
|
-
@novalid_number = true
|
135
|
-
end
|
136
|
-
|
137
|
-
def style_number_grouping(node, text)
|
138
|
-
if @validate_years
|
139
|
-
style_two_regex_not_prev(
|
140
|
-
node, text, /^(?<num>-?[0-9]{4,}[,0-9]*)\Z/,
|
141
|
-
%r{\b(ISO|IEC|IEEE|(in|January|February|March|April|May|June|August|September|October|November|December)\b)\Z},
|
142
|
-
"number not broken up in threes: mark up numbers with stem:[]"
|
143
|
-
)
|
144
|
-
else
|
145
|
-
style_two_regex_not_prev(
|
146
|
-
node, text, /^(?<num>-?(?:[0-9]{5,}[,0-9]*|[03-9]\d\d\d|1[0-8]\d\d|2[1-9]\d\d|20[5-9]\d))\Z/,
|
147
|
-
%r{\b(ISO|IEC|IEEE|\b)\Z},
|
148
|
-
"number not broken up in threes: mark up numbers with stem:[]"
|
149
|
-
)
|
150
|
-
end
|
151
|
-
end
|
152
|
-
|
153
|
-
# ISO/IEC DIR 2, 9.2.1
|
154
|
-
def style_percent(node, text)
|
155
|
-
style_regex(/\b(?<num>[0-9.,]+%)/,
|
156
|
-
"no space before percent sign", node, text)
|
157
|
-
style_regex(/\b(?<num>[0-9.,]+ \u00b1 [0-9,.]+ %)/,
|
158
|
-
"unbracketed tolerance before percent sign", node, text)
|
159
|
-
end
|
160
|
-
|
161
112
|
# ISO/IEC DIR 2, 8.4
|
162
113
|
# ISO/IEC DIR 2, 9.3
|
163
114
|
def style_abbrev(node, text)
|
@@ -168,34 +119,6 @@ module Metanorma
|
|
168
119
|
"language-specific abbreviation", node, text)
|
169
120
|
end
|
170
121
|
|
171
|
-
# leaving out as problematic: N J K C S T H h d B o E
|
172
|
-
SI_UNIT = "(m|cm|mm|km|μm|nm|g|kg|mgmol|cd|rad|sr|Hz|Hz|MHz|Pa|hPa|kJ|" \
|
173
|
-
"V|kV|W|MW|kW|F|μF|Ω|Wb|°C|lm|lx|Bq|Gy|Sv|kat|l|t|eV|u|Np|Bd|" \
|
174
|
-
"bit|kB|MB|Hart|nat|Sh|var)".freeze
|
175
|
-
|
176
|
-
# ISO/IEC DIR 2, 9.3
|
177
|
-
def style_units(node, text)
|
178
|
-
style_regex(/\b(?<num>[0-9][0-9,]*\p{Zs}+[\u00b0\u2032\u2033])/,
|
179
|
-
"space between number and degrees/minutes/seconds",
|
180
|
-
node, text)
|
181
|
-
style_regex(/\b(?<num>[0-9][0-9,]*#{SI_UNIT})\b/o,
|
182
|
-
"no space between number and SI unit", node, text)
|
183
|
-
style_non_std_units(node, text)
|
184
|
-
end
|
185
|
-
|
186
|
-
NONSTD_UNITS = {
|
187
|
-
sec: "s", mins: "min", hrs: "h", hr: "h", cc: "cm^3",
|
188
|
-
lit: "l", amp: "A", amps: "A", rpm: "r/min"
|
189
|
-
}.freeze
|
190
|
-
|
191
|
-
# ISO/IEC DIR 2, 9.3
|
192
|
-
def style_non_std_units(node, text)
|
193
|
-
NONSTD_UNITS.each do |k, v|
|
194
|
-
style_regex(/\b(?<num>[0-9][0-9,]*\p{Zs}+#{k})\b/,
|
195
|
-
"non-standard unit (should be #{v})", node, text)
|
196
|
-
end
|
197
|
-
end
|
198
|
-
|
199
122
|
# https://www.iso.org/ISO-house-style.html#iso-hs-s-text-r-p-and
|
200
123
|
# https://www.iso.org/ISO-house-style.html#iso-hs-s-text-r-p-andor
|
201
124
|
def style_punct(node, text)
|
@@ -0,0 +1,130 @@
|
|
1
|
+
module Metanorma
|
2
|
+
module Iso
|
3
|
+
class Converter < Standoc::Converter
|
4
|
+
# ISO/IEC DIR 2, 15.5.3, 20.2
|
5
|
+
# does not deal with preceding text marked up
|
6
|
+
def see_xrefs_validate(root)
|
7
|
+
@lang == "en" or return
|
8
|
+
anchors = extract_anchor_norm(root)
|
9
|
+
root.xpath("//xref").each do |t|
|
10
|
+
preceding = t.at("./preceding-sibling::text()[last()]")
|
11
|
+
!preceding.nil? &&
|
12
|
+
/\b(see| refer to)\p{Zs}*\Z/mi.match(preceding) or next
|
13
|
+
anchors[t["target"]] and
|
14
|
+
@log.add("Style", t,
|
15
|
+
"'see #{t['target']}' is pointing to a normative section")
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def extract_anchor_norm(root)
|
20
|
+
nodes = root.xpath("//annex[@obligation = 'normative'] | " \
|
21
|
+
"//references[@obligation = 'normative']")
|
22
|
+
ret = nodes.each_with_object({}) do |n, m|
|
23
|
+
n["anchor"] and m[n["anchor"]] = true
|
24
|
+
end
|
25
|
+
nodes.each do |n|
|
26
|
+
n.xpath(".//*[@anchor]").each { |n1| ret[n1["anchor"]] = true }
|
27
|
+
end
|
28
|
+
ret
|
29
|
+
end
|
30
|
+
|
31
|
+
# ISO/IEC DIR 2, 15.5.3
|
32
|
+
def see_erefs_validate(root)
|
33
|
+
@lang == "en" or return
|
34
|
+
bibitemids = extract_bibitem_anchors(root)
|
35
|
+
root.xpath("//eref").each do |t|
|
36
|
+
prec = t.at("./preceding-sibling::text()[last()]")
|
37
|
+
!prec.nil? && /\b(see|refer to)\p{Zs}*\Z/mi.match(prec) or next
|
38
|
+
unless target = bibitemids[t["bibitemid"]]
|
39
|
+
# unless target = root.at("//bibitem[@anchor = '#{t['bibitemid']}']")
|
40
|
+
@log.add("Bibliography", t,
|
41
|
+
"'#{t} is not pointing to a real reference")
|
42
|
+
next
|
43
|
+
end
|
44
|
+
target[:norm] and
|
45
|
+
@log.add("Style", t,
|
46
|
+
"'see #{t}' is pointing to a normative reference")
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def extract_bibitem_anchors(root)
|
51
|
+
ret = root.xpath("//references[@normative = 'true']//bibitem")
|
52
|
+
.each_with_object({}) do |b, m|
|
53
|
+
m[b["anchor"]] = { bib: b, norm: true }
|
54
|
+
end
|
55
|
+
root.xpath("//references[not(@normative = 'true')]//bibitem")
|
56
|
+
.each do |b|
|
57
|
+
ret[b["anchor"]] = { bib: b, norm: false }
|
58
|
+
end
|
59
|
+
ret
|
60
|
+
end
|
61
|
+
|
62
|
+
# ISO/IEC DIR 2, 10.4
|
63
|
+
def locality_erefs_validate(root)
|
64
|
+
root.xpath("//eref[descendant::locality]").each do |t|
|
65
|
+
if /^(ISO|IEC)/.match?(t["citeas"]) &&
|
66
|
+
!/: ?(\d+{4}|–)$/.match?(t["citeas"])
|
67
|
+
@log.add("Style", t,
|
68
|
+
"undated reference #{t['citeas']} should not contain " \
|
69
|
+
"specific elements")
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
# https://www.iso.org/ISO-house-style.html#iso-hs-s-text-r-r-ref_clause3
|
75
|
+
def term_xrefs_validate(xmldoc)
|
76
|
+
termids = xmldoc
|
77
|
+
.xpath("//sections/terms | //sections/clause[.//terms] | " \
|
78
|
+
"//annex[.//terms]").each_with_object({}) do |t, m|
|
79
|
+
t.xpath(".//*/@anchor").each { |a| m[a.text] = true }
|
80
|
+
t.xpath(".//*/@id").each { |a| m[a.text] = true }
|
81
|
+
t.name == "terms" and m[t["anchor"] || t["id"]] = true
|
82
|
+
end
|
83
|
+
xmldoc.xpath(".//xref").each do |x|
|
84
|
+
term_xrefs_validate1(x, termids)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
def term_xrefs_validate1(xref, termids)
|
89
|
+
closest_id = xref.xpath("./ancestor::*[@id]")&.last or return
|
90
|
+
termids[xref["target"]] && !termids[closest_id["id"]] and
|
91
|
+
@log.add("Style", xref,
|
92
|
+
"only terms clauses can cross-reference terms clause " \
|
93
|
+
"(#{xref['target']})")
|
94
|
+
!termids[xref["target"]] && termids[closest_id["id"]] and
|
95
|
+
@log.add("Style", xref,
|
96
|
+
"non-terms clauses cannot cross-reference terms clause " \
|
97
|
+
"(#{xref['target']})")
|
98
|
+
end
|
99
|
+
|
100
|
+
# require that all assets of a particular type be cross-referenced
|
101
|
+
# within the document
|
102
|
+
def xrefs_mandate_validate(xmldoc)
|
103
|
+
xrefs_mandate_validate1(xmldoc, "//annex", "Annex")
|
104
|
+
xrefs_mandate_validate1(xmldoc, "//table", "Table")
|
105
|
+
xrefs_mandate_validate1(xmldoc, "//figure", "Figure")
|
106
|
+
xrefs_mandate_validate1(xmldoc, "//formula", "Formula")
|
107
|
+
end
|
108
|
+
|
109
|
+
def xrefs_mandate_validate1(xmldoc, xpath, name)
|
110
|
+
exc = %w(table note example figure).map { |x| "//#{x}#{xpath}" }
|
111
|
+
.join(" | ")
|
112
|
+
(xmldoc.xpath(xpath) - xmldoc.xpath(exc)).each do |x|
|
113
|
+
x["unnumbered"] == "true" and next
|
114
|
+
@doc_xrefs[x["anchor"]] or
|
115
|
+
@log.add("Style", x, "#{name} #{x['anchor']} has not been " \
|
116
|
+
"cross-referenced within document",
|
117
|
+
severity: xpath == "//formula" ? 2 : 1)
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
def iso_xref_validate(doc)
|
122
|
+
see_xrefs_validate(doc)
|
123
|
+
term_xrefs_validate(doc)
|
124
|
+
xrefs_mandate_validate(doc)
|
125
|
+
see_erefs_validate(doc)
|
126
|
+
locality_erefs_validate(doc)
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: metanorma-iso
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.1.
|
4
|
+
version: 3.1.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ribose Inc.
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2025-
|
11
|
+
date: 2025-09-15 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: metanorma-standoc
|
@@ -376,12 +376,13 @@ files:
|
|
376
376
|
- lib/metanorma/iso/reqt.rng
|
377
377
|
- lib/metanorma/iso/section.rb
|
378
378
|
- lib/metanorma/iso/validate.rb
|
379
|
-
- lib/metanorma/iso/validate_image.rb
|
380
379
|
- lib/metanorma/iso/validate_list.rb
|
380
|
+
- lib/metanorma/iso/validate_numeric.rb
|
381
381
|
- lib/metanorma/iso/validate_requirements.rb
|
382
382
|
- lib/metanorma/iso/validate_section.rb
|
383
383
|
- lib/metanorma/iso/validate_style.rb
|
384
384
|
- lib/metanorma/iso/validate_title.rb
|
385
|
+
- lib/metanorma/iso/validate_xref.rb
|
385
386
|
- lib/metanorma/iso/version.rb
|
386
387
|
- lib/metanorma/requirements/modspec.rb
|
387
388
|
- lib/metanorma/requirements/requirements.rb
|
@@ -1,97 +0,0 @@
|
|
1
|
-
module Metanorma
|
2
|
-
module Iso
|
3
|
-
class Converter < Standoc::Converter
|
4
|
-
# DRG directives 3.7; but anticipated by standoc
|
5
|
-
def subfigure_validate(xmldoc)
|
6
|
-
elems = { footnote: "fn", note: "note", key: "dl" }
|
7
|
-
xmldoc.xpath("//figure//figure").each do |f|
|
8
|
-
elems.each do |k, v|
|
9
|
-
f.xpath(".//#{v}").each do |n|
|
10
|
-
@log.add("Style", n, "#{k} is not permitted in a subfigure")
|
11
|
-
end
|
12
|
-
end
|
13
|
-
end
|
14
|
-
end
|
15
|
-
|
16
|
-
def image_name_prefix(xmldoc)
|
17
|
-
std = xmldoc.at("//bibdata/ext/structuredidentifier/project-number") or
|
18
|
-
return
|
19
|
-
num = xmldoc.at("//bibdata/docnumber")&.text or return
|
20
|
-
ed = xmldoc.at("//bibdata/edition")&.text || "1"
|
21
|
-
prefix = num
|
22
|
-
std["part"] and prefix += "-#{std['part']}"
|
23
|
-
prefix += "_ed#{ed}"
|
24
|
-
amd = std["amendment"] and prefix += "amd#{amd}"
|
25
|
-
prefix
|
26
|
-
end
|
27
|
-
|
28
|
-
def image_name_suffix(xmldoc)
|
29
|
-
case xmldoc.at("//bibdata/language")&.text
|
30
|
-
when "fr" then "_f"
|
31
|
-
when "de" then "_d"
|
32
|
-
when "ru" then "_r"
|
33
|
-
when "es" then "_s"
|
34
|
-
when "ar" then "_a"
|
35
|
-
# when "en" then "_e"
|
36
|
-
else
|
37
|
-
"_e"
|
38
|
-
end
|
39
|
-
end
|
40
|
-
|
41
|
-
def disjunct_error(img, cond1, cond2, msg1, msg2)
|
42
|
-
cond1 && !cond2 and
|
43
|
-
@log.add("Style", img, "image name #{img['src']} #{msg1}")
|
44
|
-
!cond1 && cond2 and
|
45
|
-
@log.add("Style", img, "image name #{img['src']} #{msg2}")
|
46
|
-
end
|
47
|
-
|
48
|
-
def image_name_parse(img, prefix)
|
49
|
-
m = %r[(SL)?#{prefix}fig(?<tab>Tab)?(?<annex>[A-Z])?(Text)?(?<num>\d+)
|
50
|
-
(?<subfig>[a-z])?(?<key>_key\d+)?(?<lang>_[a-z])?$]x
|
51
|
-
.match(File.basename(img["src"], ".*"))
|
52
|
-
m.nil? and
|
53
|
-
@log.add("Style", img,
|
54
|
-
"image name #{img['src']} does not match DRG requirements")
|
55
|
-
m
|
56
|
-
end
|
57
|
-
|
58
|
-
def image_name_validate1(i, prefix)
|
59
|
-
m = image_name_parse(i, prefix) or return
|
60
|
-
warn i["src"]
|
61
|
-
disjunct_error(i, i.at("./ancestor::table"), !m[:tab].nil?,
|
62
|
-
"is under a table but is not so labelled",
|
63
|
-
"is labelled as under a table but is not")
|
64
|
-
disjunct_error(i, i.at("./ancestor::annex"), !m[:annex].nil?,
|
65
|
-
"is under an annex but is not so labelled",
|
66
|
-
"is labelled as under an annex but is not")
|
67
|
-
disjunct_error(i, i.xpath("./ancestor::figure").size > 1, !m[:subfig].nil?,
|
68
|
-
"does not have a subfigure letter but is a subfigure",
|
69
|
-
"has a subfigure letter but is not a subfigure")
|
70
|
-
lang = image_name_suffix(i.document.root)
|
71
|
-
(m[:lang] || "_e") == lang or
|
72
|
-
@log.add("Style", i,
|
73
|
-
"image name #{i['src']} expected to have suffix #{lang}")
|
74
|
-
end
|
75
|
-
|
76
|
-
# DRG directives 3.2
|
77
|
-
def image_name_validate(xmldoc)
|
78
|
-
prefix = image_name_prefix(xmldoc) or return
|
79
|
-
xmldoc.xpath("//image").each do |i|
|
80
|
-
i["src"].start_with?("data:") and next
|
81
|
-
case File.basename(i["src"])
|
82
|
-
when /^ISO_\d+_/
|
83
|
-
when /^(SL)?#{prefix}fig/ then image_name_validate1(i, prefix)
|
84
|
-
else
|
85
|
-
@log.add("Style", i,
|
86
|
-
"image name #{i['src']} does not match DRG requirements: expect #{prefix}fig")
|
87
|
-
end
|
88
|
-
end
|
89
|
-
end
|
90
|
-
|
91
|
-
def figure_validate(xmldoc)
|
92
|
-
image_name_validate(xmldoc)
|
93
|
-
subfigure_validate(xmldoc)
|
94
|
-
end
|
95
|
-
end
|
96
|
-
end
|
97
|
-
end
|