metanorma-iso 2.4.2 → 2.4.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,102 @@
1
+ require_relative "init"
2
+ require "isodoc"
3
+ require_relative "index"
4
+ require_relative "presentation_xref"
5
+ require_relative "presentation_bibdata"
6
+ require_relative "../../relaton/render/general"
7
+
8
+ module IsoDoc
9
+ module Iso
10
+ class PresentationXMLConvert < IsoDoc::PresentationXMLConvert
11
+ def concept(docxml)
12
+ concept_term(docxml)
13
+ docxml.xpath(ns("//concept")).each do |node|
14
+ concept_render(node, ital: "false", ref: "false",
15
+ linkref: "true", linkmention: "false")
16
+ end
17
+ end
18
+
19
+ def concept_term(docxml)
20
+ docxml.xpath(ns("//term")).each do |f|
21
+ m = {}
22
+ (f.xpath(ns(".//concept")) - f.xpath(ns(".//term//concept")))
23
+ .each { |c| concept_term1(c, m) }
24
+ end
25
+ end
26
+
27
+ def concept_term1(node, seen)
28
+ term = to_xml(node.at(ns("./refterm")))
29
+ if term && seen[term]
30
+ concept_render(node, ital: "false", ref: "false",
31
+ linkref: "true", linkmention: "false")
32
+ else concept_render(node, ital: "true", ref: "true",
33
+ linkref: "true", linkmention: "false")
34
+ end
35
+ seen[term] = true if term
36
+ seen
37
+ end
38
+
39
+ def concept1_ref_content(ref)
40
+ prev = "("
41
+ foll = ")"
42
+ if ref.name == "termref"
43
+ prev, foll = @i18n.term_defined_in.split("%")
44
+ end
45
+ ref.previous = prev
46
+ ref.next = foll
47
+ end
48
+
49
+ def concept1(node)
50
+ node.replace(node&.at(ns("./renderterm"))&.children ||
51
+ node&.at(ns("./refterm"))&.children ||
52
+ node.children)
53
+ end
54
+
55
+ def termdefinition1(elem)
56
+ prefix_domain_to_definition(elem)
57
+ super
58
+ end
59
+
60
+ def prefix_domain_to_definition(elem)
61
+ ((d = elem.at(ns("./domain"))) &&
62
+ (v = elem.at(ns("./definition/verbal-definition"))) &&
63
+ v.elements.first.name == "p") or return
64
+ v.elements.first.children.first.previous =
65
+ "&#x3c;#{to_xml(d.remove.children)}&#x3e; "
66
+ end
67
+
68
+ def insertall_after_here(node, insert, name)
69
+ node.children.each do |n|
70
+ n.name == name or next
71
+ insert.next = n.remove
72
+ insert = n
73
+ end
74
+ insert
75
+ end
76
+
77
+ def termexamples_before_termnotes(node)
78
+ insert = node.at(ns("./definition")) or return
79
+ insert = insertall_after_here(node, insert, "termexample")
80
+ insertall_after_here(node, insert, "termnote")
81
+ end
82
+
83
+ def terms(docxml)
84
+ docxml.xpath(ns("//term[termnote][termexample]")).each do |node|
85
+ termexamples_before_termnotes(node)
86
+ end
87
+ super
88
+ end
89
+
90
+ def related1(node)
91
+ node.remove
92
+ end
93
+
94
+ def termsource_status(status)
95
+ case status
96
+ when "modified", "adapted"
97
+ @i18n.modified
98
+ end
99
+ end
100
+ end
101
+ end
102
+ end
@@ -3,6 +3,7 @@ require "isodoc"
3
3
  require_relative "index"
4
4
  require_relative "presentation_xref"
5
5
  require_relative "presentation_bibdata"
6
+ require_relative "presentation_terms"
6
7
  require_relative "../../relaton/render/general"
7
8
 
8
9
  module IsoDoc
@@ -86,50 +87,6 @@ module IsoDoc
86
87
  end
87
88
  end
88
89
 
89
- def concept(docxml)
90
- concept_term(docxml)
91
- docxml.xpath(ns("//concept")).each do |node|
92
- concept_render(node, ital: "false", ref: "false",
93
- linkref: "true", linkmention: "false")
94
- end
95
- end
96
-
97
- def concept_term(docxml)
98
- docxml.xpath(ns("//term")).each do |f|
99
- m = {}
100
- (f.xpath(ns(".//concept")) - f.xpath(ns(".//term//concept")))
101
- .each { |c| concept_term1(c, m) }
102
- end
103
- end
104
-
105
- def concept_term1(node, seen)
106
- term = to_xml(node.at(ns("./refterm")))
107
- if term && seen[term]
108
- concept_render(node, ital: "false", ref: "false",
109
- linkref: "true", linkmention: "false")
110
- else concept_render(node, ital: "true", ref: "true",
111
- linkref: "true", linkmention: "false")
112
- end
113
- seen[term] = true if term
114
- seen
115
- end
116
-
117
- def concept1_ref_content(ref)
118
- prev = "("
119
- foll = ")"
120
- if ref.name == "termref"
121
- prev, foll = @i18n.term_defined_in.split("%")
122
- end
123
- ref.previous = prev
124
- ref.next = foll
125
- end
126
-
127
- def concept1(node)
128
- node.replace(node&.at(ns("./renderterm"))&.children ||
129
- node&.at(ns("./refterm"))&.children ||
130
- node.children)
131
- end
132
-
133
90
  # we're assuming terms and clauses in the right place for display,
134
91
  # to cope with multiple terms sections
135
92
  def display_order(docxml)
@@ -145,41 +102,6 @@ module IsoDoc
145
102
  display_order_xpath(docxml, "//indexsect", i)
146
103
  end
147
104
 
148
- def termdefinition1(elem)
149
- prefix_domain_to_definition(elem)
150
- super
151
- end
152
-
153
- def prefix_domain_to_definition(elem)
154
- ((d = elem.at(ns("./domain"))) &&
155
- (v = elem.at(ns("./definition/verbal-definition"))) &&
156
- v.elements.first.name == "p") or return
157
- v.elements.first.children.first.previous =
158
- "&#x3c;#{to_xml(d.remove.children)}&#x3e; "
159
- end
160
-
161
- def insertall_after_here(node, insert, name)
162
- node.children.each do |n|
163
- n.name == name or next
164
- insert.next = n.remove
165
- insert = n
166
- end
167
- insert
168
- end
169
-
170
- def termexamples_before_termnotes(node)
171
- insert = node.at(ns("./definition")) or return
172
- insert = insertall_after_here(node, insert, "termexample")
173
- insertall_after_here(node, insert, "termnote")
174
- end
175
-
176
- def terms(docxml)
177
- docxml.xpath(ns("//term[termnote][termexample]")).each do |node|
178
- termexamples_before_termnotes(node)
179
- end
180
- super
181
- end
182
-
183
105
  def admonition1(elem)
184
106
  super
185
107
  n = elem.at(ns("./name")) or return
@@ -212,10 +134,6 @@ module IsoDoc
212
134
  type
213
135
  end
214
136
 
215
- def related1(node)
216
- node.remove
217
- end
218
-
219
137
  def note1(elem)
220
138
  elem["type"] == "units" and return
221
139
  super
@@ -237,6 +155,12 @@ module IsoDoc
237
155
  dlist.remove
238
156
  end
239
157
 
158
+ def toc_title(docxml)
159
+ doctype = docxml.at(ns("//bibdata/ext/doctype"))&.text
160
+ %w(amendment technical-corrigendum).include?(doctype) and return
161
+ super
162
+ end
163
+
240
164
  include Init
241
165
  end
242
166
  end
@@ -35,26 +35,26 @@ module IsoDoc
35
35
  amd(isoxml) and @suppressheadingnumbers = true
36
36
  end
37
37
 
38
- def introduction(isoxml, out)
39
- f = isoxml.at(ns("//introduction")) || return
38
+ =begin
39
+ def introduction(clause, out)
40
40
  title_attr = { class: "IntroTitle" }
41
41
  page_break(out)
42
- out.div class: "Section3", id: f["id"] do |div|
43
- clause_name(f, f.at(ns("./title")), div, title_attr)
44
- f.elements.each do |e|
42
+ out.div class: "Section3", id: clause["id"] do |div|
43
+ clause_name(clause, clause.at(ns("./title")), div, title_attr)
44
+ clause.elements.each do |e|
45
45
  parse(e, div) unless e.name == "title"
46
46
  end
47
47
  end
48
48
  end
49
+ =end
49
50
 
50
- def foreword(isoxml, out)
51
- f = isoxml.at(ns("//foreword")) or return
51
+ def foreword(clause, out)
52
52
  @foreword = true
53
53
  page_break(out)
54
- out.div **attr_code(id: f["id"]) do |s|
55
- clause_name(nil, f.at(ns("./title")) || @i18n.foreword, s,
54
+ out.div **attr_code(id: clause["id"]) do |s|
55
+ clause_name(nil, clause.at(ns("./title")) || @i18n.foreword, s,
56
56
  { class: "ForewordTitle" })
57
- f.elements.each { |e| parse(e, s) unless e.name == "title" }
57
+ clause.elements.each { |e| parse(e, s) unless e.name == "title" }
58
58
  end
59
59
  @foreword = false
60
60
  end
@@ -142,6 +142,9 @@ module IsoDoc
142
142
  # supply missing annex title
143
143
  def make_WordToC(docxml, level)
144
144
  toc = ""
145
+ if source = docxml.at("//div[@class = 'TOC']")
146
+ toc = to_xml(source.children)
147
+ end
145
148
  xpath = (1..level).each.map { |i| "//h#{i}" }.join (" | ")
146
149
  docxml.xpath(xpath).each do |h|
147
150
  x = ""
@@ -54,6 +54,7 @@ module Metanorma
54
54
  super
55
55
  @amd = %w(amendment technical-corrigendum).include? doctype(node)
56
56
  @vocab = node.attr("docsubtype") == "vocabulary"
57
+ @validate_years = node.attr("validate-years")
57
58
  end
58
59
 
59
60
  def toc_default
@@ -17,6 +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.2 -->
20
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">
21
22
  <include href="reqt.rng"/>
22
23
  <include href="basicdoc.rng">
@@ -210,6 +211,9 @@
210
211
  <data type="boolean"/>
211
212
  </attribute>
212
213
  </optional>
214
+ <optional>
215
+ <attribute name="style"/>
216
+ </optional>
213
217
  <ref name="CitationType"/>
214
218
  <oneOrMore>
215
219
  <ref name="PureTextElement"/>
@@ -1349,15 +1353,19 @@
1349
1353
  </choice>
1350
1354
  </element>
1351
1355
  </define>
1356
+ <define name="Root-Attributes">
1357
+ <attribute name="version"/>
1358
+ <attribute name="schema-version"/>
1359
+ <attribute name="type">
1360
+ <choice>
1361
+ <value>semantic</value>
1362
+ <value>presentation</value>
1363
+ </choice>
1364
+ </attribute>
1365
+ </define>
1352
1366
  <define name="standard-document">
1353
1367
  <element name="standard-document">
1354
- <attribute name="version"/>
1355
- <attribute name="type">
1356
- <choice>
1357
- <value>semantic</value>
1358
- <value>presentation</value>
1359
- </choice>
1360
- </attribute>
1368
+ <ref name="Root-Attributes"/>
1361
1369
  <ref name="bibdata"/>
1362
1370
  <optional>
1363
1371
  <ref name="misccontainer"/>
@@ -2131,6 +2139,7 @@
2131
2139
  <choice>
2132
2140
  <value>identical</value>
2133
2141
  <value>modified</value>
2142
+ <value>adapted</value>
2134
2143
  <value>restyled</value>
2135
2144
  <value>context-added</value>
2136
2145
  <value>generalisation</value>
@@ -1,6 +1,9 @@
1
1
  <?xml version="1.0" encoding="UTF-8"?>
2
2
  <grammar ns="https://www.metanorma.org/ns/iso" xmlns="http://relaxng.org/ns/structure/1.0">
3
- <!-- default namespace isostandard = "https://www.metanorma.com/ns/iso" -->
3
+ <!--
4
+ VERSION v1.2.1
5
+ default namespace isostandard = "https://www.metanorma.com/ns/iso"
6
+ -->
4
7
  <include href="relaton-iso.rng"/>
5
8
  <include href="isostandard.rng">
6
9
  <start>
@@ -32,13 +35,7 @@
32
35
  </define>
33
36
  <define name="iso-standard">
34
37
  <element name="iso-standard">
35
- <attribute name="version"/>
36
- <attribute name="type">
37
- <choice>
38
- <value>semantic</value>
39
- <value>presentation</value>
40
- </choice>
41
- </attribute>
38
+ <ref name="Root-Attributes"/>
42
39
  <ref name="bibdata"/>
43
40
  <optional>
44
41
  <ref name="misccontainer"/>
@@ -1,6 +1,9 @@
1
1
  <?xml version="1.0" encoding="UTF-8"?>
2
2
  <grammar xmlns="http://relaxng.org/ns/structure/1.0" datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes">
3
- <!-- default namespace isostandard = "https://www.metanorma.com/ns/iso" -->
3
+ <!--
4
+ VERSION v1.2.1
5
+ default namespace isostandard = "https://www.metanorma.com/ns/iso"
6
+ -->
4
7
  <include href="isodoc.rng">
5
8
  <start>
6
9
  <ref name="iso-standard"/>
@@ -240,13 +243,7 @@
240
243
  -->
241
244
  <define name="iso-standard">
242
245
  <element name="iso-standard">
243
- <attribute name="version"/>
244
- <attribute name="type">
245
- <choice>
246
- <value>semantic</value>
247
- <value>presentation</value>
248
- </choice>
249
- </attribute>
246
+ <ref name="Root-Attributes"/>
250
247
  <ref name="bibdata"/>
251
248
  <zeroOrMore>
252
249
  <ref name="termdocsource"/>
@@ -30,6 +30,7 @@ module Metanorma
30
30
  # ISO/IEC DIR 2, 15.5.3, 20.2
31
31
  # does not deal with preceding text marked up
32
32
  def see_xrefs_validate(root)
33
+ @lang == "en" or return
33
34
  root.xpath("//xref").each do |t|
34
35
  preceding = t.at("./preceding-sibling::text()[last()]")
35
36
  next unless !preceding.nil? &&
@@ -45,6 +46,7 @@ module Metanorma
45
46
 
46
47
  # ISO/IEC DIR 2, 15.5.3
47
48
  def see_erefs_validate(root)
49
+ @lang == "en" or return
48
50
  root.xpath("//eref").each do |t|
49
51
  prec = t.at("./preceding-sibling::text()[last()]")
50
52
  next unless !prec.nil? && /\b(see|refer to)\s*\Z/mi.match(prec)
@@ -3,8 +3,9 @@ module Metanorma
3
3
  class Converter < Standoc::Converter
4
4
  # DRG directives 3.7; but anticipated by standoc
5
5
  def subfigure_validate(xmldoc)
6
+ elems = { footnote: "fn", note: "note", key: "dl" }
6
7
  xmldoc.xpath("//figure//figure").each do |f|
7
- { footnote: "fn", note: "note", key: "dl" }.each do |k, v|
8
+ elems.each do |k, v|
8
9
  f.xpath(".//#{v}").each do |n|
9
10
  @log.add("Style", n, "#{k} is not permitted in a subfigure")
10
11
  end
@@ -13,10 +14,10 @@ module Metanorma
13
14
  end
14
15
 
15
16
  def image_name_prefix(xmldoc)
16
- std = xmldoc&.at("//bibdata/ext/structuredidentifier/project-number") or
17
+ std = xmldoc.at("//bibdata/ext/structuredidentifier/project-number") or
17
18
  return
18
- num = xmldoc&.at("//bibdata/docnumber")&.text or return
19
- ed = xmldoc&.at("//bibdata/edition")&.text || "1"
19
+ num = xmldoc.at("//bibdata/docnumber")&.text or return
20
+ ed = xmldoc.at("//bibdata/edition")&.text || "1"
20
21
  prefix = num
21
22
  std["part"] and prefix += "-#{std['part']}"
22
23
  prefix += "_ed#{ed}"
@@ -25,7 +26,7 @@ module Metanorma
25
26
  end
26
27
 
27
28
  def image_name_suffix(xmldoc)
28
- case xmldoc&.at("//bibdata/language")&.text
29
+ case xmldoc.at("//bibdata/language")&.text
29
30
  when "fr" then "_f"
30
31
  when "de" then "_d"
31
32
  when "ru" then "_r"
@@ -60,7 +60,7 @@ module Metanorma
60
60
  case prectext.strip[-1]
61
61
  when ":", "" then list_after_colon_punctuation(list, entries)
62
62
  when "." then entries.each { |li| list_full_sentence(li) }
63
- else style_warning(list, "All lists must be preceded by "\
63
+ else style_warning(list, "All lists must be preceded by " \
64
64
  "colon or full stop", prectext)
65
65
  end
66
66
  end
@@ -80,7 +80,7 @@ module Metanorma
80
80
  def list_semicolon_phrase(elem, last)
81
81
  text = elem.text.strip
82
82
  starts_lowercase?(text) or
83
- style_warning(elem, "List entry of broken up sentence must start "\
83
+ style_warning(elem, "List entry of broken up sentence must start " \
84
84
  "with lowercase letter", text)
85
85
  list_semicolon_phrase_punct(elem, text, last)
86
86
  end
@@ -89,11 +89,11 @@ module Metanorma
89
89
  punct = text.strip.sub(/^.*?(\S)$/m, "\\1")
90
90
  if last
91
91
  punct == "." or
92
- style_warning(elem, "Final list entry of broken up "\
92
+ style_warning(elem, "Final list entry of broken up " \
93
93
  "sentence must end with full stop", text)
94
94
  else
95
95
  punct == ";" or
96
- style_warning(elem, "List entry of broken up sentence must "\
96
+ style_warning(elem, "List entry of broken up sentence must " \
97
97
  "end with semicolon", text)
98
98
  end
99
99
  end
@@ -102,11 +102,11 @@ module Metanorma
102
102
  %w(Cyrl Latn Grek).include?(@script) or return
103
103
  text = elem.text.strip
104
104
  starts_uppercase?(text) or
105
- style_warning(elem, "List entry of separate sentences must start "\
105
+ style_warning(elem, "List entry of separate sentences must start " \
106
106
  "with uppercase letter", text)
107
107
  punct = text.strip.sub(/^.*?(\S)$/m, "\\1")
108
108
  punct == "." or
109
- style_warning(elem, "List entry of separate sentences must "\
109
+ style_warning(elem, "List entry of separate sentences must " \
110
110
  "end with full stop", text)
111
111
  end
112
112
 
@@ -24,6 +24,7 @@ module Metanorma
24
24
  end
25
25
 
26
26
  def requirement_check(text)
27
+ @lang == "en" or return
27
28
  text.split(/\.\s+/).each do |t|
28
29
  return t if requirement_re.match t
29
30
  end
@@ -44,6 +45,7 @@ module Metanorma
44
45
  end
45
46
 
46
47
  def recommendation_check(text)
48
+ @lang == "en" or return
47
49
  text.split(/\.\s+/).each do |t|
48
50
  return t if recommendation_re.match t
49
51
  end
@@ -60,6 +62,7 @@ module Metanorma
60
62
  REGEXP
61
63
 
62
64
  def permission_re
65
+ @lang == "en" or return
63
66
  Regexp.new(self.class::PERMISSION_RE_STR.gsub(/\s/, "")
64
67
  .gsub(/_/, "\\s"), Regexp::IGNORECASE)
65
68
  end
@@ -82,6 +85,7 @@ module Metanorma
82
85
  REGEXP
83
86
 
84
87
  def possibility_re
88
+ @lang == "en" or return
85
89
  Regexp.new(self.class::POSSIBILITY_RE_STR.gsub(/\s/, "")
86
90
  .gsub(/_/, "\\s"), Regexp::IGNORECASE)
87
91
  end
@@ -98,6 +102,26 @@ module Metanorma
98
102
  nil
99
103
  end
100
104
 
105
+ AMBIG_WORDS_RE_STR = <<~REGEXP.freeze
106
+ \\b
107
+ need_to | needs_to | might | could
108
+ \\b
109
+ REGEXP
110
+
111
+ def ambig_words_re
112
+ @lang == "en" or return
113
+ Regexp.new(self.class::AMBIG_WORDS_RE_STR.gsub(/\s/, "")
114
+ .gsub(/_/, "\\s"), Regexp::IGNORECASE)
115
+ end
116
+
117
+ def ambig_words_check(text)
118
+ @lang == "en" or return
119
+ text.split(/\.\s+/).each do |t|
120
+ return t if ambig_words_re.match t
121
+ end
122
+ nil
123
+ end
124
+
101
125
  def style_no_guidance(node, text, docpart)
102
126
  @lang == "en" or return
103
127
  r = requirement_check(text)
@@ -90,32 +90,63 @@ module Metanorma
90
90
  end
91
91
 
92
92
  def style(node, text)
93
- return if @novalid
94
-
93
+ @novalid and return
95
94
  style_number(node, text)
96
95
  style_percent(node, text)
97
96
  style_abbrev(node, text)
98
97
  style_units(node, text)
99
98
  style_punct(node, text)
99
+ style_subscript(node)
100
+ style_ambig_words(node, text)
101
+ end
102
+
103
+ # https://www.iso.org/ISO-house-style.html#iso-hs-s-text-r-s-quantity
104
+ def style_subscript(node)
105
+ warning = "may contain nested subscripts (max 3 levels allowed)"
106
+ node.xpath(".//sub[.//sub]").each do |x|
107
+ style_warning(node, warning, x.to_xml)
108
+ end
109
+ node.xpath(".//m:msub[.//m:msub]", "m" => MATHML_NS).each do |x|
110
+ style_warning(node, warning, x.to_xml)
111
+ end
112
+ end
113
+
114
+ # https://www.iso.org/ISO-house-style.html#iso-hs-s-text-r-s-need
115
+ # https://www.iso.org/ISO-house-style.html#iso-hs-s-text-r-s-might
116
+ def style_ambig_words(node, text)
117
+ r = ambig_words_check(text) and
118
+ style_warning(node, "may contain ambiguous provision", r)
100
119
  end
101
120
 
102
121
  # ISO/IEC DIR 2, 9.1
103
122
  # ISO/IEC DIR 2, Table B.1
104
123
  # https://www.iso.org/ISO-house-style.html#iso-hs-s-text-r-n-numbers
105
124
  def style_number(node, text)
106
- style_two_regex_not_prev(
107
- node, text, /^(?<num>-?[0-9]{4,}[,0-9]*)\Z/,
108
- %r{\b(ISO|IEC|IEEE/|(in|January|February|March|April|May|June|August|September|October|November|December)\b)\Z},
109
- "number not broken up in threes"
110
- )
125
+ style_number_grouping(node, text)
111
126
  style_regex(/\b(?<num>[0-9]+\.[0-9]+)/i,
112
127
  "possible decimal point", node, text)
113
128
  @lang == "en" and style_regex(/\b(?<num>billions?)\b/i,
114
129
  "ambiguous number", node, text)
115
- style_regex(/(^|\s)(?<num>-[0-9][0-9,.]*)/i,
130
+ style_regex(/(?:^|\s)(?<num>-[0-9][0-9,.]*)/i,
116
131
  "hyphen instead of minus sign U+2212", node, text)
117
132
  end
118
133
 
134
+ def style_number_grouping(node, text)
135
+ if @validate_years
136
+ style_two_regex_not_prev(
137
+ node, text, /^(?<num>-?[0-9]{4,}[,0-9]*)\Z/,
138
+ %r{\b(ISO|IEC|IEEE|(in|January|February|March|April|May|June|August|September|October|November|December)\b)\Z},
139
+ "number not broken up in threes"
140
+ )
141
+ else
142
+ style_two_regex_not_prev(
143
+ 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/,
144
+ %r{\b(ISO|IEC|IEEE|\b)\Z},
145
+ "number not broken up in threes"
146
+ )
147
+ end
148
+ end
149
+
119
150
  # ISO/IEC DIR 2, 9.2.1
120
151
  def style_percent(node, text)
121
152
  style_regex(/\b(?<num>[0-9.,]+%)/,
@@ -169,6 +200,16 @@ module Metanorma
169
200
  "Use 'either x or y, or both'", node, text)
170
201
  style_regex(/\s(?<num>&)\s/i,
171
202
  "Avoid ampersand in ordinary text'", node, text)
203
+ eref_style_punct(node)
204
+ end
205
+
206
+ # https://www.iso.org/ISO-house-style.html#iso-hs-s-text-r-r-ref_unnumbered
207
+ def eref_style_punct(node)
208
+ node.xpath(".//eref[@type='footnote']").each do |e|
209
+ /^\p{P}/.match?(e.next&.text) or next
210
+ style_warning(node, "superscript cross-reference followed by punctuation",
211
+ node.to_xml)
212
+ end
172
213
  end
173
214
 
174
215
  def style_warning(node, msg, text = nil)
@@ -1,5 +1,5 @@
1
1
  module Metanorma
2
2
  module ISO
3
- VERSION = "2.4.2".freeze
3
+ VERSION = "2.4.4".freeze
4
4
  end
5
5
  end
@@ -32,7 +32,7 @@ Gem::Specification.new do |spec|
32
32
  spec.test_files = `git ls-files -- {spec}/*`.split("\n")
33
33
  spec.required_ruby_version = Gem::Requirement.new(">= 2.7.0")
34
34
 
35
- spec.add_dependency "metanorma-standoc", "~> 2.4.2"
35
+ spec.add_dependency "metanorma-standoc", "~> 2.4.3"
36
36
  spec.add_dependency "mnconvert", "~> 1.14"
37
37
  spec.add_dependency "pubid-iso", "~> 0.5.0"
38
38
  spec.add_dependency "ruby-jing"