metanorma-standoc 3.4.8 → 3.4.10

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 (34) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +9 -0
  3. data/Gemfile +6 -1
  4. data/lib/isodoc/html/htmlstyle.css +9 -0
  5. data/lib/metanorma/cleanup/bibdata.rb +11 -3
  6. data/lib/metanorma/cleanup/bibitem.rb +20 -0
  7. data/lib/metanorma/cleanup/cleanup.rb +1 -1
  8. data/lib/metanorma/cleanup/index.rb +6 -3
  9. data/lib/metanorma/cleanup/ref.rb +71 -0
  10. data/lib/metanorma/cleanup/review.rb +5 -0
  11. data/lib/metanorma/cleanup/spans_to_bibitem.rb +3 -1
  12. data/lib/metanorma/cleanup/term_lookup.rb +1 -0
  13. data/lib/metanorma/converter/base.rb +1 -1
  14. data/lib/metanorma/converter/converter.rb +8 -2
  15. data/lib/metanorma/converter/front.rb +6 -1
  16. data/lib/metanorma/converter/init.rb +29 -4
  17. data/lib/metanorma/converter/inline.rb +9 -2
  18. data/lib/metanorma/converter/lists.rb +1 -0
  19. data/lib/metanorma/converter/macros.rb +13 -6
  20. data/lib/metanorma/standoc/version.rb +1 -1
  21. data/lib/metanorma/validate/basicdoc.rng +23 -14
  22. data/lib/metanorma/validate/isodoc.rng +1 -1
  23. data/lib/metanorma/validate/{mathml3-content.rng → mathml4-content.rng} +104 -80
  24. data/lib/metanorma/validate/mathml4-core.rng +1041 -0
  25. data/lib/metanorma/validate/{mathml3-presentation.rng → mathml4-presentation.rng} +184 -1060
  26. data/lib/metanorma/validate/{mathml3-strict-content.rng → mathml4-strict-content.rng} +92 -8
  27. data/lib/metanorma/validate/mathml4.rng +30 -0
  28. data/lib/metanorma/validate/metanorma-mathml.rng +22 -8
  29. data/lib/metanorma/validate/validate.rb +1 -1
  30. data/metanorma-standoc.gemspec +1 -1
  31. metadata +8 -9
  32. data/.hound.yml +0 -5
  33. data/lib/metanorma/validate/mathml3-common.rng +0 -257
  34. data/lib/metanorma/validate/mathml3.rng +0 -23
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8cbc11c6b0e55ec1404d12dd309d0f711c1d4918d079375716d0b0406f6bce2f
4
- data.tar.gz: 016b74cca05a97b06809a7e9af8d48b97b07c39e3d98fe0bd575da362f1bed57
3
+ metadata.gz: b5094a6f74d9378c42e68b279963b6ac50f9c94412e259175c5d689111ddf6e6
4
+ data.tar.gz: 193d1ecb96eaba4fe068290844230558579feb43a911ac55f11d0cac086bb073
5
5
  SHA512:
6
- metadata.gz: 7510bd34addc7e4e2f6d123aa19c89dffe555f1a2f06ff572824136b2269e073721bc7ac8df2f4a94ed09180bd724dbcdb2d5f6d29dc076c71650fe6d5f3c597
7
- data.tar.gz: d575b92f788e95d9754b9d0d2cf6af1f670d82d2f3710d82b165a6e453f8d8ec884fc407926bbf1f86594c61f2992ee3728e9fc3455e0eeb459a2dd4b1f5bcb1
6
+ metadata.gz: 793e4b2daecbde3ff0778cf36373bf9e6fc4ba63705bc7b42b545dc7fa6f52a40f6776325f15d55aaa18ea16e94fafbec88540896ae04f85989d97c67474a021
7
+ data.tar.gz: 90d033cbd1290db48e3a8fd9c33817970c8fb7488c13782b1fbd7ff7519105d4cf5608eeed51e014f9b85645c9d7036dc745a97d6c74a00adf5f92f6ccc173b5
data/.rubocop.yml CHANGED
@@ -2,6 +2,15 @@
2
2
  # See https://github.com/metanorma/cimas
3
3
  inherit_from:
4
4
  - https://raw.githubusercontent.com/riboseinc/oss-guides/main/ci/rubocop.yml
5
+ # .rubocop_todo.yml MUST be the last entry. inherit_from is last-wins:
6
+ # if listed before oss-guides, the shared config's stricter Metrics/
7
+ # (MethodLength, BlockLength, etc.) rules override the todo's per-file
8
+ # grandfathering, and the todo becomes inert on those cops. Empirically
9
+ # verified on suma 2026-07-06: with todo listed first, 34 Metrics/* offenses
10
+ # remained; moved last, cleared. Every gem in the metanorma-org fleet
11
+ # already ships a `.rubocop_todo.yml` on its live tree (audited 2026-07-06,
12
+ # 54/54 have it), so this reference is safe to emit unconditionally.
13
+ - .rubocop_todo.yml
5
14
 
6
15
  # Rubocop plugins enabled centrally so every metanorma-org gem picks them up
7
16
  # on cimas sync — best practice belongs at the shared-template layer, not
data/Gemfile CHANGED
@@ -6,5 +6,10 @@ git_source(:github) { |repo| "https://github.com/#{repo}" }
6
6
 
7
7
  gemspec
8
8
 
9
- eval_gemfile("Gemfile.devel") rescue nil
9
+ # Stopgap: lutaml 0.11.x removed lib/lutaml/xmi.rb, which metanorma-plugin-lutaml
10
+ # 0.7.x still `require`s. Hold lutaml at 0.10.x until plugin-lutaml follows the
11
+ # file to its new home. Remove once resolved:
12
+ # https://github.com/metanorma/metanorma-plugin-lutaml/issues/292
13
+ gem "lutaml", "< 0.11"
10
14
 
15
+ eval_gemfile("Gemfile.devel") rescue nil
@@ -137,6 +137,10 @@ dl dd {
137
137
  grid-column-start: 2;
138
138
  }
139
139
 
140
+ dl:has(dt .stem) {
141
+ grid-template-columns: fit-content(8em) auto;
142
+ }
143
+
140
144
  b, strong {
141
145
  font-weight: bold;
142
146
  }
@@ -150,6 +154,11 @@ a.FootnoteRef, span.FootnoteRef {
150
154
  vertical-align: super;
151
155
  }
152
156
 
157
+ a.TableFootnoteRef, a.FootnoteRef, a.footnote-number,
158
+ sup a, a:has(> sup) {
159
+ vertical-align: baseline;
160
+ }
161
+
153
162
  .addition {
154
163
  color: blue;
155
164
  }
@@ -198,15 +198,23 @@ module Metanorma
198
198
  XML
199
199
  end
200
200
 
201
- def published_base?(stage, _xmldoc)
201
+ def published_base?(stage, xmldoc)
202
202
  if @stage_published
203
203
  @stage_published == "true"
204
- else published?(stage, _xmldoc)
204
+ else !draft_stage?(stage, xmldoc)
205
205
  end
206
206
  end
207
207
 
208
+ # Is the stage a draft (unpublished) stage? Overridable seam for
209
+ # flavours whose stage repertoires are not the binary
210
+ # published/unpublished; the :docstage-published: document
211
+ # attribute (@stage_published, above) trumps it either way.
212
+ def draft_stage?(stage, xmldoc)
213
+ !published?(stage, xmldoc)
214
+ end
215
+
208
216
  def published?(stage, _xmldoc)
209
- stage.casecmp("published").zero?
217
+ stage.to_s.casecmp("published").zero?
210
218
  end
211
219
 
212
220
  # allows us to deal with doc relation localities,
@@ -34,6 +34,26 @@ module Metanorma
34
34
  bib.children = new.children.to_xml
35
35
  else bib << new.children.to_xml
36
36
  end
37
+ bibitem_reorder_elems(bib)
38
+ end
39
+
40
+ # canonical element order of BibliographicItem per biblio.rnc
41
+ BIBITEM_ELEM_ORDER =
42
+ %w(fetched formattedref title uri docidentifier docnumber date
43
+ contributor edition version note language locale script abstract
44
+ status copyright relation series medium place price extent size
45
+ accesslocation license classification keyword validity depiction)
46
+ .freeze
47
+
48
+ # the spans-derived fragment is appended after any elements already on
49
+ # the bibitem (e.g. formattedref, docnumber, date), which violates the
50
+ # ordered relaton content model; restore grammar order, stably
51
+ def bibitem_reorder_elems(bib)
52
+ bib.element_children
53
+ .sort_by
54
+ .with_index do |e, i|
55
+ [BIBITEM_ELEM_ORDER.index(e.name) || BIBITEM_ELEM_ORDER.size, i]
56
+ end.each { |e| bib << e }
37
57
  end
38
58
 
39
59
  def merge_bibitem_from_formattedref_span_attrs(bib, new)
@@ -61,7 +61,7 @@ module Metanorma
61
61
  boilerplateauthority embed_hdr embed_id erefstyle originstyle
62
62
  xrefstyle blockunnumbered keepasciimath numberfmt_formula
63
63
  numberfmt_prof sort_biblio reqt_models default_requirement_model
64
- document_scheme
64
+ document_scheme publisher_sort_config
65
65
  ]
66
66
  end
67
67
 
@@ -1,10 +1,13 @@
1
1
  module Metanorma
2
2
  module Standoc
3
3
  module Index
4
+ # normalize-space(.) rather than normalize-space(text()): index terms
5
+ # wrapped entirely in formatting (<em>a priori</em>, stem) have no
6
+ # direct text nodes but are not empty
4
7
  EMPTY_INDEX_XPATH =
5
- "//index[not(.//primary[normalize-space(text())]) " \
6
- "or .//secondary[. and not(normalize-space(text()))] " \
7
- "or .//tertiary[. and not(normalize-space(text()))]]".freeze
8
+ "//index[not(.//primary[normalize-space(.)]) " \
9
+ "or .//secondary[. and not(normalize-space(.))] " \
10
+ "or .//tertiary[. and not(normalize-space(.))]]".freeze
8
11
 
9
12
  def index_cleanup(xmldoc)
10
13
  para_index_cleanup(xmldoc)
@@ -34,6 +34,77 @@ module Metanorma
34
34
  bib
35
35
  end
36
36
 
37
+ BIBLIO_PUBLISHER_ORG =
38
+ "./contributor[role/@type = 'publisher']/organization".freeze
39
+
40
+ # Configurable publisher sort ranking, shared by every flavour's
41
+ # bibliography sort. `table` is the flavour's default ordering, an array
42
+ # of { abbrev:, name:, rank: }. A per-document / metanorma-taste override
43
+ # (:sort-biblio-<abbrev>: <rank>: <name> attributes, captured into
44
+ # @publisher_sort_config) REPLACES the flavour default when present.
45
+ #
46
+ # A matched publisher gets its configured rank; an unmatched standards
47
+ # reference sorts immediately after the ranked publishers, and a
48
+ # non-standard reference last. With no override and the flavour's own
49
+ # default table, this reproduces the flavour's historical hardcoded ranks.
50
+ def publisher_sort_rank(bib, table)
51
+ table = publisher_sort_table(table)
52
+ if (entry = publisher_sort_match(bib, table))
53
+ return entry[:rank]
54
+ end
55
+
56
+ maxrank = table.map { |e| e[:rank] }.max || 0
57
+ biblio_standards_ref?(bib) ? maxrank + 1 : maxrank + 2
58
+ end
59
+
60
+ # Secondary sort token: the co-publisher(s) other than the matched
61
+ # primary. Deterministic when several co-publishers exist (returns the
62
+ # smallest token), which reproduces e.g. JIS's "JIS+IEC before
63
+ # JIS+ISO, JIS+IEC+ISO alongside JIS+IEC" ordering.
64
+ def publisher_sort_second(bib, table)
65
+ entry = publisher_sort_match(bib, publisher_sort_table(table))
66
+ entry or return ""
67
+ bib.xpath(BIBLIO_PUBLISHER_ORG)
68
+ .reject { |o| publisher_org_match?(o, entry) }
69
+ .map { |o| (o.at("./abbreviation") || o.at("./name"))&.text&.strip }
70
+ .compact.reject(&:empty?).min || ""
71
+ end
72
+
73
+ def publisher_sort_table(default_table)
74
+ cfg = @publisher_sort_config
75
+ cfg && !cfg.empty? ? cfg : default_table
76
+ end
77
+
78
+ # lowest-ranked table entry whose publisher appears on the bibitem
79
+ def publisher_sort_match(bib, table)
80
+ orgs = bib.xpath(BIBLIO_PUBLISHER_ORG)
81
+ table.sort_by { |e| e[:rank] }.find do |e|
82
+ orgs.any? { |o| publisher_org_match?(o, e) }
83
+ end
84
+ end
85
+
86
+ # A table entry matches a publisher organization on its abbreviation
87
+ # (case-insensitive, since AsciiDoc lowercases attribute-derived abbrevs)
88
+ # or on any of its names (`name` may be a single string or an array; the
89
+ # latter lets a flavour list, e.g., a Japanese and an English publisher
90
+ # name for the same rank).
91
+ def publisher_org_match?(org, entry)
92
+ abbr = org.at("./abbreviation")&.text&.strip
93
+ name = org.at("./name")&.text&.strip
94
+ names = Array(entry[:name]).map { |n| n.to_s.strip }.reject(&:empty?)
95
+ (!entry[:abbrev].to_s.empty? && abbr&.casecmp?(entry[:abbrev])) ||
96
+ (!name.to_s.empty? && names.include?(name))
97
+ end
98
+
99
+ # Whether a bibitem is a standards reference (sorts after the ranked
100
+ # publishers, before non-standard references). Base definition: it has a
101
+ # typed, non-DOI/ISSN/ISBN docidentifier. Flavours may widen this (ISO
102
+ # also treats an untyped docidentifier as a standards reference).
103
+ def biblio_standards_ref?(bib)
104
+ !!bib.at("./docidentifier[@type][not(#{@conv.skip_docid} or " \
105
+ "@type = 'metanorma')]")
106
+ end
107
+
37
108
  # default presuppose that all citations in biblio numbered
38
109
  # consecutively, but that standards codes are preserved as is:
39
110
  # only numeric references are renumbered
@@ -35,6 +35,11 @@ module Metanorma
35
35
  when "ol", "ul" then node.at(".//p | .//name") || node.at("./li")
36
36
  when "dl" then node.at(".//p | .//name") || node.at("./dt | ./dd")
37
37
  when "table" then node.at(".//td[text()] | .//th[text()]")
38
+ # terms and their children have no legal place for a loose
39
+ # paragraph, so the bookmark must land inside existing content
40
+ when "term", "definition", "verbal-definition", "preferred",
41
+ "admitted", "deprecates", "related", "termnote", "termexample"
42
+ node.at(".//p | .//name")
38
43
  end or return nil
39
44
  first_non_stem_text(ret)
40
45
  end
@@ -58,7 +58,9 @@ module Metanorma
58
58
  ret += span_to_docid(s, "classification")
59
59
  end
60
60
  spans[:keyword]&.each do |s|
61
- ret += span_to_docid(s, "keyword")
61
+ # keyword content is structured per the grammar: an uncontrolled
62
+ # keyword is a vocab entry, not bare text
63
+ ret += "<keyword><vocab>#{s[:val]}</vocab></keyword>"
62
64
  end
63
65
  spans[:image]&.each do |s|
64
66
  ret += "<depiction>#{s[:val]}</depiction>"
@@ -48,6 +48,7 @@ module Metanorma
48
48
  def concept_cleanup
49
49
  xmldoc.xpath("//concept").each do |n|
50
50
  refterm = n.at("./refterm") or next
51
+ refterm.xpath(".//index").each(&:remove)
51
52
  lookup = norm_ref_id_text(refterm.text.strip)
52
53
  p = @lookup[:sec2prim][lookup] and refterm.children = @c.encode(p)
53
54
  end
@@ -58,7 +58,7 @@ module Metanorma
58
58
  pronunciation|grammar|term|terms|termnote|termexample|source|
59
59
  origin|termref|modification)>)}x, "\\1\n")
60
60
  .gsub(%r{(<(title|name))}, "\n\\1")
61
- .gsub(%r{(<sourcecode[^<>]*>)\s+(<name[^<>]*>[^<]+</name>)\s+},
61
+ .gsub(%r{(<sourcecode[^<>]*+>)\s++(<name[^<>]*+>(?>.*?</name>))\s++}m,
62
62
  "\\1\\2")
63
63
  end
64
64
 
@@ -54,6 +54,12 @@ module Metanorma
54
54
  preprocessor Metanorma::Standoc::NamedEscapePreprocessor
55
55
  inline_macro Metanorma::Standoc::PreferredTermInlineMacro
56
56
  inline_macro Metanorma::Standoc::DateInlineMacro
57
+ # PassFormat must run before Span (and the other bracketed inline macros
58
+ # below) so that a nested pass/pass-format passthrough is resolved to a
59
+ # bracket-free placeholder before Span delimits its own [...]; otherwise
60
+ # Span stops at the inner passthrough's ] and over-captures. See
61
+ # metanorma-standoc#1221.
62
+ inline_macro Metanorma::Standoc::PassFormatInlineMacro
57
63
  inline_macro Metanorma::Standoc::SpanInlineMacro
58
64
  inline_macro Metanorma::Standoc::AltTermInlineMacro
59
65
  inline_macro Metanorma::Standoc::AdmittedTermInlineMacro
@@ -79,7 +85,6 @@ module Metanorma
79
85
  inline_macro Metanorma::Standoc::FormSelectMacro
80
86
  inline_macro Metanorma::Standoc::FormOptionMacro
81
87
  inline_macro Metanorma::Standoc::ToCInlineMacro
82
- inline_macro Metanorma::Standoc::PassFormatInlineMacro
83
88
  inline_macro Metanorma::Standoc::StdLinkInlineMacro
84
89
  inline_macro Metanorma::Standoc::NumberInlineMacro
85
90
  inline_macro Metanorma::Standoc::TrStyleInlineMacro
@@ -111,7 +116,8 @@ module Metanorma
111
116
  $xreftext = {}
112
117
 
113
118
  attr_reader :bibdb, :lang, :script, :locale, :relaton_log, :libdir, :backend,
114
- :novalid, :local_log, :output_dir, :filename, :files_to_delete
119
+ :novalid, :local_log, :output_dir, :filename, :files_to_delete,
120
+ :docstage_valid
115
121
 
116
122
  def initialize(backend, opts)
117
123
  doc = opts&.dig(:document)
@@ -174,7 +174,12 @@ module Metanorma
174
174
  def metadata_keywords(node, xml)
175
175
  node.attr("keywords") or return
176
176
  node.attr("keywords").split(/,\s*/).each do |kw|
177
- add_noko_elem(xml, "keyword", kw)
177
+ kw.empty? and next
178
+ # keyword content is structured per the grammar: an uncontrolled
179
+ # keyword is a vocab entry, not bare text
180
+ xml.keyword do |k|
181
+ add_noko_elem(k, "vocab", kw)
182
+ end
178
183
  end
179
184
  end
180
185
 
@@ -27,6 +27,7 @@ module Metanorma
27
27
  @document_scheme = document_scheme(node)
28
28
  @default_doctype = "standard"
29
29
  @stage_published = node.attr("docstage-published")
30
+ @docstage_valid = node.attr("docstage-valid")&.split(/,\s*/)
30
31
  @metadata_attrs = metadata_attrs(node)
31
32
  end
32
33
 
@@ -116,6 +117,11 @@ module Metanorma
116
117
  end
117
118
 
118
119
  def init_toc(node)
120
+ init_toc_levels(node)
121
+ init_toc_types(node)
122
+ end
123
+
124
+ def init_toc_levels(node)
119
125
  @htmltoclevels = node.attr("toclevels-html") ||
120
126
  node.attr("htmltoclevels") ||
121
127
  node.attr("toclevels") || toc_default[:html_levels]
@@ -125,10 +131,13 @@ module Metanorma
125
131
  @pdftoclevels = node.attr("toclevels-pdf") ||
126
132
  node.attr("toclevels") || toc_default[:pdf_levels]
127
133
  @toclevels = node.attr("toclevels") || toc_default[:html_levels]
128
- @tocfigures = node.attr("toc-figures")
129
- @toctables = node.attr("toc-tables")
130
- @tocrecommendations = node.attr("toc-recommendations")
131
- @tocexamples = node.attr("toc-examples")
134
+ end
135
+
136
+ def init_toc_types(node)
137
+ @tocfigures = node.attr("toc-figures") != "false"
138
+ @toctables = node.attr("toc-tables") != "false"
139
+ @tocrecommendations = node.attr("toc-recommendations") != "false"
140
+ @tocexamples = node.attr("toc-examples") != "false"
132
141
  end
133
142
 
134
143
  def toc_default
@@ -175,6 +184,7 @@ module Metanorma
175
184
  @no_isobib = node.attr("no-isobib")
176
185
  @flush_caches = node.attr("flush-caches")
177
186
  @sort_biblio = node.attr("sort-biblio") != "false"
187
+ @publisher_sort_config = init_publisher_sort_config(node)
178
188
  init_bib_db(node)
179
189
  init_bib_caches(node)
180
190
  init_iev_caches(node)
@@ -182,6 +192,21 @@ module Metanorma
182
192
  @biblio_cutoff = biblio_cutoff(node)
183
193
  end
184
194
 
195
+ # Per-publisher bibliography sort ranks, from
196
+ # :sort-biblio-<abbrev>: <rank>: <name> document attributes (set directly
197
+ # in a document or injected by a metanorma-taste config). AsciiDoc
198
+ # lowercases attribute names, so <abbrev> is matched case-insensitively
199
+ # downstream. Returns [] when none are set (flavours keep their default
200
+ # publisher ordering).
201
+ def init_publisher_sort_config(node)
202
+ node.attributes.each_with_object([]) do |(k, v), acc|
203
+ m = /\Asort-biblio-(?<abbrev>.+)\z/.match(k.to_s) or next
204
+ rank_s, name = v.to_s.split(":", 2)
205
+ rank = Integer(rank_s.to_s.strip, exception: false) or next
206
+ acc << { abbrev: m[:abbrev].strip, name: name&.strip, rank: rank }
207
+ end
208
+ end
209
+
185
210
  def init_bib_db(node)
186
211
  @bibdb = nil
187
212
  @local_bibdb =
@@ -160,12 +160,19 @@ module Metanorma
160
160
  uri
161
161
  end
162
162
 
163
+ # empty-string dimensions (image::x.png["","",""]) must fall back to
164
+ # "auto": ImageSize admits only numbers, percentages, or "auto"
165
+ def image_dim_attr(node, key)
166
+ ret = node.attr(key)
167
+ ret.nil? || ret.empty? ? "auto" : ret
168
+ end
169
+
163
170
  def image_attributes1(node, uri, sourceuri, type, altmedia)
164
171
  /^data:/.match?(sourceuri) and sourceuri = nil
165
172
  attr_code(altmedia_id_attr(node, altmedia)
166
173
  .merge(src: uri, mimetype: type,
167
- height: node.attr("height") || "auto",
168
- width: node.attr("width") || "auto",
174
+ height: image_dim_attr(node, "height"),
175
+ width: image_dim_attr(node, "width"),
169
176
  filename: node.attr("filename") || sourceuri,
170
177
  title: node.attr("titleattr"),
171
178
  media: node.attr("media"), altmedia: altmedia,
@@ -103,6 +103,7 @@ module Metanorma
103
103
  .merge(
104
104
  metadata: node.option?("metadata") ? "true" : nil,
105
105
  key: node.option?("key") ? "true" : nil,
106
+ class: node.attr("class"),
106
107
  )))
107
108
  end
108
109
 
@@ -67,16 +67,23 @@ module Metanorma
67
67
  end.join
68
68
  end
69
69
 
70
- # debugging output of results of all preprocessing,
71
- # including include files concatenation and Lutaml/Liquid processing
70
+ # debugging output of results of all preprocessing, including include
71
+ # files concatenation and Lutaml/Liquid processing.
72
+ #
73
+ # Skipped for docfile-less (string/stdin) input: the target would
74
+ # degenerate to a single CWD-relative "./metanorma.asciidoc.log.txt" that
75
+ # the thousands of collection sub-compiles all truncate-rewrite (so it
76
+ # carries no useful diagnostics anyway). And a diagnostic write must never
77
+ # abort the build, so a write failure degrades to a warning rather than
78
+ # propagating out of the preprocessor. metanorma/metanorma-standoc#1209
72
79
  def log(doc, text)
73
- source = doc.attr("docfile") || "metanorma"
80
+ source = doc.attr("docfile") or return
74
81
  dirname = File.dirname(source)
75
82
  basename = File.basename(source, ".*")
76
83
  fname = File.join(dirname, "#{basename}.asciidoc.log.txt")
77
- File.open(fname, "w:UTF-8") do |f|
78
- f.write(text.join("\n"))
79
- end
84
+ File.open(fname, "w:UTF-8") { |f| f.write(text.join("\n")) }
85
+ rescue SystemCallError => e
86
+ warn "metanorma: could not write preprocessing log #{fname}: #{e.message}"
80
87
  end
81
88
  end
82
89
 
@@ -19,6 +19,6 @@ module Metanorma
19
19
  end
20
20
 
21
21
  module Standoc
22
- VERSION = "3.4.8".freeze
22
+ VERSION = "3.4.10".freeze
23
23
  end
24
24
  end
@@ -1527,12 +1527,16 @@ to indicate that the index range covers a range of locations between the current
1527
1527
  <ref name="index-primary">
1528
1528
  <a:documentation>Primary index term to be recorded at the current location</a:documentation>
1529
1529
  </ref>
1530
- <ref name="index-secondary">
1531
- <a:documentation>Secondary index term to be recorded at the current location</a:documentation>
1532
- </ref>
1533
- <ref name="index-tertiary">
1534
- <a:documentation>Tertiary index term to be recorded at the current </a:documentation>
1535
- </ref>
1530
+ <optional>
1531
+ <ref name="index-secondary">
1532
+ <a:documentation>Secondary index term to be recorded at the current location</a:documentation>
1533
+ </ref>
1534
+ </optional>
1535
+ <optional>
1536
+ <ref name="index-tertiary">
1537
+ <a:documentation>Tertiary index term to be recorded at the current </a:documentation>
1538
+ </ref>
1539
+ </optional>
1536
1540
  </element>
1537
1541
  </define>
1538
1542
  <define name="index-xref">
@@ -1547,12 +1551,16 @@ The text in the inline element is the primary index term to be be cross-referenc
1547
1551
  <ref name="index-primary">
1548
1552
  <a:documentation>The primary index term to be cross-referenced</a:documentation>
1549
1553
  </ref>
1550
- <ref name="index-secondary">
1551
- <a:documentation>The secondary index term to be cross-referenced</a:documentation>
1552
- </ref>
1553
- <ref name="index-tertiary">
1554
- <a:documentation>The tertiary index term to be cross-referenced</a:documentation>
1555
- </ref>
1554
+ <optional>
1555
+ <ref name="index-secondary">
1556
+ <a:documentation>The secondary index term to be cross-referenced</a:documentation>
1557
+ </ref>
1558
+ </optional>
1559
+ <optional>
1560
+ <ref name="index-tertiary">
1561
+ <a:documentation>The tertiary index term to be cross-referenced</a:documentation>
1562
+ </ref>
1563
+ </optional>
1556
1564
  <element name="target">
1557
1565
  <a:documentation>The index term to be cross-referenced to</a:documentation>
1558
1566
  <oneOrMore>
@@ -1931,9 +1939,10 @@ or as the string "auto"</a:documentation>
1931
1939
  </element>
1932
1940
  </define>
1933
1941
  <define name="mathml">
1934
- <a:documentation>Encoding of MathML: the official W3C MathML 3.0 grammar (namespace
1942
+ <a:documentation>Encoding of MathML: the official W3C MathML 4 grammar (namespace
1935
1943
  http://www.w3.org/1998/Math/MathML), via the metanorma wrapper in
1936
- grammars/mathml/. See grammars/mathml/README.adoc and basicdoc-models#35.</a:documentation>
1944
+ grammars/mathml/. See grammars/mathml/README.adoc, basicdoc-models#35,
1945
+ and the MathML 3 -&gt; 4 migration: basicdoc-models#39 / metanorma#585.</a:documentation>
1937
1946
  <externalRef href="metanorma-mathml.rng"/>
1938
1947
  </define>
1939
1948
  <define name="StemAttributes">
@@ -1,6 +1,6 @@
1
1
  <?xml version="1.0" encoding="UTF-8"?>
2
2
  <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">
3
- <!-- VERSION v2.1.6 -->
3
+ <!-- VERSION v2.2.0 -->
4
4
 
5
5
  <!--
6
6
  ALERT: cannot have root comments, because of https://github.com/metanorma/metanorma/issues/437