metanorma 2.3.0 → 2.3.2

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 (33) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +14 -0
  3. data/lib/metanorma/collection/collection.rb +46 -105
  4. data/lib/metanorma/collection/config/config.rb +11 -0
  5. data/lib/metanorma/collection/config/converters.rb +1 -0
  6. data/lib/metanorma/collection/config/manifest.rb +23 -0
  7. data/lib/metanorma/collection/document/document.rb +32 -10
  8. data/lib/metanorma/collection/filelookup/base.rb +43 -0
  9. data/lib/metanorma/collection/filelookup/filelookup.rb +168 -69
  10. data/lib/metanorma/collection/filelookup/filelookup_sectionsplit.rb +49 -10
  11. data/lib/metanorma/collection/filelookup/utils.rb +93 -0
  12. data/lib/metanorma/collection/helpers.rb +82 -0
  13. data/lib/metanorma/collection/manifest/manifest.rb +14 -3
  14. data/lib/metanorma/collection/multilingual/multilingual.rb +1 -1
  15. data/lib/metanorma/collection/renderer/filelocation.rb +162 -0
  16. data/lib/metanorma/collection/renderer/fileparse.rb +9 -6
  17. data/lib/metanorma/collection/renderer/fileprocess.rb +56 -42
  18. data/lib/metanorma/collection/renderer/navigation.rb +15 -1
  19. data/lib/metanorma/collection/renderer/render_word.rb +8 -4
  20. data/lib/metanorma/collection/renderer/renderer.rb +104 -10
  21. data/lib/metanorma/collection/renderer/svg.rb +54 -7
  22. data/lib/metanorma/collection/renderer/utils.rb +58 -22
  23. data/lib/metanorma/collection/sectionsplit/collection.rb +14 -5
  24. data/lib/metanorma/collection/sectionsplit/sectionsplit.rb +20 -7
  25. data/lib/metanorma/collection/util/disambig_files.rb +4 -5
  26. data/lib/metanorma/collection/util/util.rb +106 -6
  27. data/lib/metanorma/collection/xrefprocess/xrefprocess.rb +2 -2
  28. data/lib/metanorma/compile/compile_options.rb +3 -2
  29. data/lib/metanorma/compile/flavor.rb +11 -4
  30. data/lib/metanorma/compile/render.rb +1 -0
  31. data/lib/metanorma/version.rb +1 -1
  32. data/metanorma.gemspec +6 -16
  33. metadata +30 -152
@@ -1,6 +1,7 @@
1
1
  module Metanorma
2
2
  class Collection
3
3
  class Renderer
4
+ # Converts SVG images to data URIs for inline embedding
4
5
  def svg_datauri(docxml, docid)
5
6
  rel = @files.get(docid, :rel_path)
6
7
  parent = @files.get(docid, :parentid) and
@@ -10,16 +11,39 @@ module Metanorma
10
11
  datauri_encode(docxml, dir)
11
12
  end
12
13
 
14
+ # Resolves SVG map references and processes SVG ID disambiguation.
15
+ #
16
+ # Delegates SVG manipulation to Vectory gem, which handles:
17
+ # 1. Document-level suffixing for cross-document ID disambiguation
18
+ # 2. Index-based suffixing for multiple svgmaps within one document
19
+ # 3. Link remapping and SVG extraction
20
+ #
21
+ # Metanorma's role: State requirements and coordinate the workflow.
22
+ # Vectory's role: Handle all SVG ID manipulation internally.
23
+ #
24
+ # @param docxml [Nokogiri::XML::Document] The document XML to process
25
+ # @param docid [String] Document identifier for retrieving suffix
26
+ # @param presxml [Boolean, nil] Whether this is presentation XML
13
27
  def svgmap_resolve(docxml, docid, presxml)
14
28
  ids, docxml, isodoc, tag = svgmap_resolve_prep(docxml, docid, presxml)
15
- docxml.xpath(ns("//svgmap//#{tag}")).each do |e|
16
- svgmap_resolve_eref(e, isodoc, docxml, ids, presxml)
17
- end
18
- svgmap_fmt_prefix_remove(docxml)
19
- Vectory::SvgMapping.new(docxml, "").call
20
- docxml.xpath(ns("//svgmap")).each { |s| isodoc.svgmap_extract(s) }
29
+
30
+ # Stage 1: Resolve EREF references to their targets
31
+ resolve_svgmap_erefs(docxml, tag, isodoc, ids, presxml)
32
+
33
+ # Stage 2: Normalize prefixes (Vectory expects eref, not fmt-eref)
34
+ normalize_svgmap_prefixes(docxml)
35
+
36
+ # Stage 3: Process with Vectory
37
+ # Pass document suffix to Vectory as id_suffix for proper SVG ID disambiguation.
38
+ # Vectory handles both id_suffix (document-level) and index suffix internally.
39
+ doc_suffix = @files.get(docid, :document_suffix)
40
+ Vectory::SvgMapping.new(docxml, "", id_suffix: doc_suffix).call
41
+
42
+ # Stage 4: Extract processed SVG content
43
+ extract_svgmap_content(docxml, isodoc)
21
44
  end
22
45
 
46
+ # Prepares document and context for svgmap resolution
23
47
  def svgmap_resolve_prep(docxml, docid, presxml)
24
48
  ids = @files.get(docid, :ids)
25
49
  docxml = svg_unnest(svg_datauri(docxml, docid))
@@ -29,7 +53,28 @@ module Metanorma
29
53
  [ids, docxml, isodoc, tag]
30
54
  end
31
55
 
32
- # undo Presentation XML update: Vectory takes eref not fmt-eref
56
+ private
57
+
58
+ # Resolves EREF elements within svgmap to their actual link targets
59
+ def resolve_svgmap_erefs(docxml, tag, isodoc, ids, presxml)
60
+ docxml.xpath(ns("//svgmap//#{tag}")).each do |e|
61
+ svgmap_resolve_eref(e, isodoc, docxml, ids, presxml)
62
+ end
63
+ end
64
+
65
+ # Converts fmt-eref/fmt-link/fmt-xref back to eref/link/xref
66
+ # Vectory expects non-prefixed element names for proper processing
67
+ def normalize_svgmap_prefixes(docxml)
68
+ svgmap_fmt_prefix_remove(docxml)
69
+ end
70
+
71
+ # Extracts processed SVG content from svgmap elements
72
+ def extract_svgmap_content(docxml, isodoc)
73
+ docxml.xpath(ns("//svgmap")).each { |s| isodoc.svgmap_extract(s) }
74
+ end
75
+
76
+ # Converts Presentation XML fmt- prefix back to standard element names
77
+ # Vectory expects eref/link/xref, not fmt-eref/fmt-link/fmt-xref
33
78
  def svgmap_fmt_prefix_remove(docxml)
34
79
  docxml.xpath(ns("//svgmap/target")).each do |t|
35
80
  n = t.at(ns(".//fmt-link | .//fmt-xref | .//fmt-eref")) or next
@@ -38,6 +83,7 @@ module Metanorma
38
83
  end
39
84
  end
40
85
 
86
+ # Removes nested image elements within svgmap, flattening the structure
41
87
  def svg_unnest(docxml)
42
88
  docxml.xpath(ns("//svgmap//image[.//*[name() = 'image']]")).each do |i|
43
89
  s = i.elements.detect { |e| e.name == "svg" } and
@@ -46,6 +92,7 @@ module Metanorma
46
92
  docxml
47
93
  end
48
94
 
95
+ # Resolves a single EREF element to its target link
49
96
  def svgmap_resolve_eref(eref, isodoc, _docxml, ids, presxml)
50
97
  href = isodoc.eref_target(eref) or return
51
98
  href = href[:link]
@@ -1,3 +1,5 @@
1
+ require "marcel"
2
+
1
3
  module Metanorma
2
4
  class Collection
3
5
  class Renderer
@@ -5,8 +7,7 @@ module Metanorma
5
7
  path = Pathname.new(name)
6
8
  clean_regex = /[<>:"|?*\p{Zs}]/
7
9
  fallback_sym = "_"
8
- return name.gsub(clean_regex, fallback_sym) unless path.absolute?
9
-
10
+ path.absolute? or return name.gsub(clean_regex, fallback_sym)
10
11
  File.join(path.dirname,
11
12
  path.basename.to_s.gsub(clean_regex, fallback_sym))
12
13
  end
@@ -38,9 +39,9 @@ module Metanorma
38
39
  end
39
40
  end
40
41
 
41
- def new_hidden_ref(xmldoc)
42
- ins = xmldoc.at(ns("bibliography")) or
43
- xmldoc.root << "<bibliography/>" and ins = xmldoc.at(ns("bibliography"))
42
+ def new_hidden_ref(xml)
43
+ ins = xml.at(ns("bibliography")) or
44
+ xml.root << "<bibliography/>" and ins = xml.at(ns("bibliography"))
44
45
  ins.at(ns("./references[@hidden = 'true']")) or
45
46
  ins.add_child("<references hidden='true' normative='false'/>").first
46
47
  end
@@ -60,8 +61,8 @@ module Metanorma
60
61
  tag = presxml ? "fmt-eref" : "eref"
61
62
  docxml.xpath(ns("//#{tag}"))
62
63
  .each_with_object({ citeas: {}, bibitemid: {} }) do |i, m|
63
- m[:citeas][i["citeas"]] = true
64
- m[:bibitemid][i["bibitemid"]] = true
64
+ m[:citeas][i["citeas"]] = true
65
+ m[:bibitemid][i["bibitemid"]] = true
65
66
  end
66
67
  end
67
68
 
@@ -70,16 +71,35 @@ module Metanorma
70
71
  "#{val}</docidentifier>"
71
72
  end
72
73
 
73
- def add_hidden_bibliography(xmldoc, refs)
74
- ins = new_hidden_ref(xmldoc)
74
+ def add_hidden_bibliography(xml, refs, current_id = nil)
75
+ ins = new_hidden_ref(xml)
76
+ current_html = if current_id
77
+ @files.get(current_id,
78
+ :outputs)&.dig(:html)
79
+ else
80
+ nil
81
+ end
75
82
  refs.each do |k, v|
76
83
  url = @files.url(v, {})
84
+ url = make_relative_path(current_html, url) if current_html
77
85
  ins << <<~XML
78
86
  <bibitem id="#{k}" anchor="#{k}">#{docid_xml(v)}<uri type='citation'>#{url}</uri></bibitem>
79
87
  XML
80
88
  end
81
89
  end
82
90
 
91
+ def make_relative_path(from_file, to_file)
92
+ return to_file if to_file.nil? || to_file.to_s.empty?
93
+ return to_file if to_file.start_with?("http://", "https://", "#")
94
+
95
+ from_dir = File.dirname(from_file)
96
+ return to_file if from_dir == "."
97
+
98
+ from_path = Pathname.new(from_dir)
99
+ to_path = Pathname.new(to_file)
100
+ to_path.relative_path_from(from_path).to_s
101
+ end
102
+
83
103
  private
84
104
 
85
105
  def docid_prefix(docid)
@@ -106,14 +126,24 @@ module Metanorma
106
126
  # @raise [ArgumentError]
107
127
  def check_options(options)
108
128
  (options[:format].is_a?(Array) && (FORMATS & options[:format]).any?) or
109
- raise ArgumentError, "Need to specify formats (xml,html,pdf,doc)"
129
+ raise ArgumentError,
130
+ "Need to specify formats (xml,html,pdf,pdf-portfolio,doc)"
131
+ end
132
+
133
+ def pdfconv(added_options)
134
+ flavor, taste_opts, x = pdfconv_prep
135
+ fonts = [taste_opts[:fonts], added_options[:fonts]].compact.flatten
136
+ .join(";")
137
+ opts = @compile_options.merge(added_options.merge(taste_opts))
138
+ opts[:fonts] = fonts
139
+ x.converter.pdf_converter(PdfOptionsNode.new(flavor, opts))
110
140
  end
111
141
 
112
- def pdfconv
113
- flavor = @flavor.to_sym
142
+ def pdfconv_prep
143
+ flavor = Util::taste2flavor(@flavor).to_sym
144
+ taste_opts = Util::taste2isodoc_attrs(@flavor, :pdf)
114
145
  x = Asciidoctor.load nil, backend: flavor
115
- x.converter.pdf_converter(PdfOptionsNode.new(flavor,
116
- @compile_options))
146
+ [flavor, taste_opts, x]
117
147
  end
118
148
 
119
149
  def fail_update_bibitem(docid, identifier)
@@ -125,7 +155,7 @@ module Metanorma
125
155
 
126
156
  def datauri_encode(docxml, directory)
127
157
  docxml.xpath(ns("//image")).each do |i|
128
- read_in_if_svg(i, directory.sub(%r{(?<!=/)$}, "/")) and i["src"] = nil
158
+ read_in_if_svg(i, directory.sub(%r{(?<!=/)$}, "/"))
129
159
  end
130
160
  docxml.xpath(ns("//image")).each do |i| # rubocop:disable Style/CombinableLoops
131
161
  i["src"] && !i["src"].empty? or next
@@ -135,34 +165,40 @@ module Metanorma
135
165
  end
136
166
 
137
167
  def read_in_if_svg(img, localdir)
138
- img["src"] or return false
139
- img.elements.map(&:name).include?("svg") and return true
168
+ img["src"] or return
169
+ if img.elements.map(&:name).include?("svg")
170
+ img["src"] = nil
171
+ return
172
+ end
140
173
  path = Vectory::Utils.svgmap_rewrite0_path(img["src"], localdir)
141
- svg = svg_in_path?(path) or return false
174
+ svg = svg_in_path?(path) or return
142
175
  img.children = (Nokogiri::XML(svg).root)
176
+ img["src"] = nil
143
177
  true
144
178
  end
145
179
 
146
180
  def svg_in_path?(path)
147
181
  File.file?(path) or return false
148
- types = MIME::Types.type_for(path) or return false
149
- types.first == "image/svg+xml" or return false
182
+ type = Marcel::MimeType.for(name: path) or return false
183
+ type == "image/svg+xml" or return false
150
184
  svg = File.read(path, encoding: "utf-8") or return false
151
185
  svg
152
186
  end
153
187
 
154
188
  class PdfOptionsNode
155
189
  def initialize(flavor, options)
156
- p = Metanorma::Registry.instance.find_processor(flavor)
190
+ p = Metanorma::Registry.instance.find_processor(Util::taste2flavor(flavor))
157
191
  if ::Metanorma::Util::FontistHelper.has_custom_fonts?(p, options, {})
158
192
  @fonts_manifest =
159
193
  ::Metanorma::Util::FontistHelper.location_manifest(p, options)
160
194
  end
195
+ @options = options
161
196
  end
162
197
 
163
198
  def attr(key)
164
199
  if key == "fonts-manifest" && @fonts_manifest
165
200
  @fonts_manifest
201
+ else @options[key.to_sym]
166
202
  end
167
203
  end
168
204
  end
@@ -194,7 +230,7 @@ module Metanorma
194
230
  end.doc.root.to_html
195
231
  end
196
232
 
197
- def eref2link(docxml, presxml)
233
+ def eref2link(docxml, _presxml)
198
234
  isodoc = IsoDoc::PresentationXMLConvert.new({})
199
235
  isodoc.bibitem_lookup(docxml)
200
236
  isodoc.eref2link(docxml)
@@ -39,24 +39,33 @@ module Metanorma
39
39
  end
40
40
 
41
41
  def collectionyaml(files, xml)
42
- #warn xml.to_xml
43
42
  ret = {
44
43
  directives: ["presentation-xml", "bare-after-first"],
45
44
  bibdata: {
46
45
  title: {
47
46
  type: "title-main", language: @lang,
48
- content: xml.at(ns("//bibdata/title")).text
47
+ content: xml.at(ns("//bibdata/title"))&.text || "[TITLE]"
49
48
  },
50
49
  type: "collection",
51
50
  docid: {
52
- type: xml.at(ns("//bibdata/docidentifier/@type")).text,
53
- id: xml.at(ns("//bibdata/docidentifier")).text,
51
+ type: xml.at(ns("//bibdata/docidentifier/@type"))&.text || "[FLAVOR]",
52
+ id: xml.at(ns("//bibdata/docidentifier"))&.text || "[DOCID]",
54
53
  },
55
54
  },
56
55
  manifest: {
57
56
  level: "collection", title: "Collection",
58
57
  docref: files.sort_by { |f| f[:order] }.each.map do |f|
59
- { fileref: f[:url], identifier: f[:title] }
58
+ # XML files are always stored flat, so fileref is always the basename
59
+ # f[:url] may include directory for HTML output, but XML is basename only
60
+ fileref = File.basename(f[:url])
61
+ entry = { fileref: fileref, identifier: f[:title] }
62
+ # Include sectionsplit_filename and sectionsplit-output when there's a directory structure
63
+ # This tells the renderer to preserve directory structure in HTML output
64
+ if @sectionsplit_filename && File.dirname(@sectionsplit_filename) != "."
65
+ entry[:"sectionsplit-filename"] = @sectionsplit_filename
66
+ entry[:"sectionsplit-output"] = true
67
+ end
68
+ entry
60
69
  end
61
70
  },
62
71
  }
@@ -1,4 +1,5 @@
1
1
  require "yaml"
2
+ require "fileutils"
2
3
  require_relative "../../util/util"
3
4
  require_relative "../xrefprocess/xrefprocess"
4
5
  require_relative "collection"
@@ -21,6 +22,9 @@ module Metanorma
21
22
  @isodoc = opts[:isodoc]
22
23
  @isodoc_presxml = opts[:isodoc_presxml]
23
24
  @document_suffix = opts[:document_suffix]
25
+ @sectionsplit_filename = opts[:sectionsplit_filename] ||
26
+ "{basename_legacy}.{sectionsplit-num}"
27
+ @parent_idx = opts[:parent_idx] || 0
24
28
  end
25
29
 
26
30
  def ns(xpath)
@@ -49,6 +53,7 @@ module Metanorma
49
53
  def sectionsplit1(xml, empty, empty1, idx)
50
54
  ret = SPLITSECTIONS.each_with_object([]) do |n, m|
51
55
  conflate_floatingtitles(xml.xpath(ns(n[0]))).each do |s|
56
+ # require "debug"; binding.b
52
57
  sectionsplit2(xml, idx.zero? ? empty : empty1, s, n[1],
53
58
  { acc: m, idx: idx })
54
59
  idx += 1
@@ -61,8 +66,13 @@ module Metanorma
61
66
 
62
67
  def sectionsplit2(xml, empty, chunks, parentnode, opt)
63
68
  @pool.post do
64
- warn "#{@base}.#{opt[:idx]}"
65
- a = sectionfile(xml, empty, "#{@base}.#{opt[:idx]}", chunks,
69
+ output_filename = @sectionsplit_filename
70
+ &.gsub(/\{document-num\}/, @parent_idx.to_s)
71
+ &.gsub(/\{basename_legacy\}/, @base)
72
+ &.gsub(/\{basename\}/, File.basename(@base, ".*"))
73
+ &.gsub(/\{sectionsplit-num\}/, opt[:idx].to_s)
74
+ warn "Sectionsplit: #{output_filename}"
75
+ a = sectionfile(xml, empty, output_filename, chunks,
66
76
  parentnode)
67
77
  @mutex.synchronize { opt[:acc] << a }
68
78
  end
@@ -154,11 +164,14 @@ module Metanorma
154
164
  sectionfile_fn_filter(sectionfile_annotation_filter(out))
155
165
  Metanorma::Collection::XrefProcess::xref_process(out, xml, @key,
156
166
  @ident, @isodoc, true)
157
- outname = "#{file}.xml"
158
- File.open(File.join(@splitdir, outname), "w:UTF-8") do |f|
159
- f.write(out)
160
- end
161
- outname
167
+ # XML files are always written flat to the splitdir (_files directory)
168
+ # Directory structure from sectionsplit_filename is only used for HTML output
169
+ xml_filename = "#{File.basename(file)}.xml"
170
+ full_path = File.join(@splitdir, xml_filename)
171
+ File.open(full_path, "w:UTF-8") { |f| f.write(out) }
172
+ # Return full file path (with directory) for use in manifest
173
+ # This preserves directory info for HTML rendering without affecting XML storage
174
+ "#{file}.xml"
162
175
  end
163
176
 
164
177
  def sectionfile_insert(ins, chunks, parentnode)
@@ -10,13 +10,12 @@ module Metanorma
10
10
  name.sub(%r{^(\./)?(\.\./)+}, "")
11
11
  end
12
12
 
13
- def source2dest_filename(name, disambig = true)
13
+ def source2dest_filename(name, disambig: true, preserve_dirs: false)
14
14
  n = strip_root(name)
15
- dir = File.dirname(n)
16
- base = File.basename(n)
17
- if disambig && @seen_filenames.include?(base)
15
+ dir = preserve_dirs ? "." : File.dirname(n)
16
+ base = preserve_dirs ? n : File.basename(n)
17
+ disambig && @seen_filenames.include?(base) and
18
18
  base = disambiguate_filename(base)
19
- end
20
19
  @seen_filenames << base
21
20
  dir == "." ? base : File.join(dir, base)
22
21
  end
@@ -1,7 +1,14 @@
1
+ require "marcel"
2
+
1
3
  module Metanorma
2
4
  class Collection
3
5
  module Util
4
6
  class << self
7
+ def mime_file_recognised?(filename)
8
+ mime_type = Marcel::MimeType.for name: filename
9
+ mime_type != "application/octet-stream"
10
+ end
11
+
5
12
  def anchor_id_attributes
6
13
  Metanorma::Utils::anchor_attributes(presxml: true) +
7
14
  [%w(* id), %w(* anchor), %w(link bibitemid), %w(fmt-link bibitemid)]
@@ -9,12 +16,13 @@ module Metanorma
9
16
 
10
17
  def gather_bibitems(xml)
11
18
  xml.xpath("//xmlns:bibitem[@id]").each_with_object({}) do |b, m|
12
- if m[b["id"]]
19
+ id = b["anchor"] || b["id"]
20
+ if m[id]
13
21
  b.remove
14
22
  next
15
23
  # we can't update duplicate bibitem, processing updates wrong one
16
24
  else
17
- m[b["id"]] = b
25
+ m[id] = b
18
26
  end
19
27
  end
20
28
  end
@@ -36,12 +44,14 @@ module Metanorma
36
44
  end
37
45
  end
38
46
 
39
- def add_suffix_to_attrs(doc, suffix, tag_name, attr_name, isodoc)
47
+ # Skip SVGs, they are processed by Vectory::SvgDocument#suffix_ids
48
+ def add_suffix_to_attrs(doc, suffix, tag, attr, isodoc)
40
49
  (suffix.nil? || suffix.empty?) and return
41
- doc.xpath(isodoc.ns("//#{tag_name}[@#{attr_name}]")).each do |elem|
42
- a = elem.attributes[attr_name].value
50
+ doc.xpath(isodoc.ns("//#{tag}[@#{attr}][not(ancestor-or-self::*[local-name()='svg'])]")).each do |elem|
51
+ # doc.xpath(isodoc.ns("//#{tag}[@#{attr}]")).each do |elem|
52
+ a = elem.attributes[attr].value
43
53
  /_#{suffix}$/.match?(a) or
44
- elem.attributes[attr_name].value = "#{a}_#{suffix}"
54
+ elem.attributes[attr].value = "#{a}_#{suffix}"
45
55
  end
46
56
  end
47
57
 
@@ -71,6 +81,81 @@ module Metanorma
71
81
  @c.decode(ident).gsub(/(\p{Zs})+/, " ")
72
82
  end
73
83
 
84
+ def taste2flavor(taste)
85
+ tastes = Metanorma::TasteRegister.instance.aliases
86
+ tastes[taste.to_sym] and taste = tastes[taste.to_sym]
87
+ taste
88
+ end
89
+
90
+ def taste2isodoc_attrs(taste, format)
91
+ tastes = Metanorma::TasteRegister.instance.aliases
92
+ tastes[taste.to_sym] or return {}
93
+ Metanorma::TasteRegister.isodoc_attrs(taste.to_sym, format)
94
+ end
95
+
96
+ def taste2coverpage_pdf_portfolio(taste)
97
+ tastes = Metanorma::TasteRegister.instance.aliases
98
+ tastes[taste.to_sym] or return nil
99
+ taste = Metanorma::TasteRegister.instance.get(taste.to_sym)
100
+ ret = taste.config.base_override&.filename_attributes
101
+ &.coverpage_pdf_portfolio or return
102
+ File.join(taste.directory, ret)
103
+ end
104
+
105
+ SVG_NS = "http://www.w3.org/2000/svg".freeze
106
+
107
+ # update relative URLs, url(#...), in CSS in @style attrs (incl. SVG),
108
+ # and in include SVG url(#..) attrs,
109
+ # not processed already by add_suffix_to_attrs
110
+ def url_in_css_styles(doc, ids, document_suffix)
111
+ update_ids_css(doc.root, ids, document_suffix)
112
+ doc.xpath("//i:svg", "i" => SVG_NS).each do |s|
113
+ svg = Vectory::SvgDocument.new(s.to_xml)
114
+ svg.suffix_ids(document_suffix)
115
+ end
116
+ end
117
+
118
+ # replicates Vectory update_ids_css, but skips over svgs,
119
+ # which are processed separately by Vectory::SvgDocument#suffix_ids
120
+ def update_ids_css(document, ids, suffix)
121
+ suffix = suffix.is_a?(Integer) ? sprintf("%09d", suffix) : suffix
122
+ document.xpath(".//m:style[not(ancestor::i:svg)]",
123
+ "m" => SVG_NS, "i" => SVG_NS).each do |s|
124
+ s.children = update_ids_css_string(s.children.to_xml, ids, suffix)
125
+ end
126
+ document.xpath(".//*[@style][not(ancestor::i:svg)]",
127
+ "i" => SVG_NS).each do |s|
128
+ s["style"] = update_ids_css_string(s["style"], ids, suffix)
129
+ end
130
+ end
131
+
132
+ # Updates ID references in a CSS style string.
133
+ # Replicates Vectory update_ids_css_string
134
+ def update_ids_css_string(style, ids, suffix)
135
+ ids.each do |i|
136
+ style = style.gsub(%r[##{i}\b],
137
+ sprintf("#%<id>s_%<suffix>s", id: i,
138
+ suffix: suffix))
139
+ .gsub(%r(\[id\s*=\s*['"]?#{i}['"]?\]),
140
+ sprintf("[id='%<id>s_%<suffix>s']", id: i,
141
+ suffix: suffix))
142
+ end
143
+ style
144
+ end
145
+
146
+ # doc.xpath("//*[@style]").each do |s|
147
+ # s["style"] = url_in_css_styles1(s["style"], document_suffix)
148
+ # end
149
+ # doc.xpath("//i:svg//i:style", "i" => "http://www.w3.org/2000/svg")
150
+ # .each do |s|
151
+ # s.children = url_in_css_styles1(s.text, document_suffix)
152
+ # end
153
+ #
154
+ # # KILL
155
+ # def url_in_css_styles1(style, document_suffix)
156
+ # style.gsub(%r{url\(#([^()]+)\)}, "url(#\\1_#{document_suffix})")
157
+ # end
158
+
74
159
  class Dummy
75
160
  def attr(_key); end
76
161
  end
@@ -94,6 +179,21 @@ module Metanorma
94
179
  isodoc.info(xml, nil)
95
180
  isodoc
96
181
  end
182
+
183
+ def asciidoc_dummy_header
184
+ <<~DUMMY
185
+ = X
186
+ A
187
+
188
+ DUMMY
189
+ end
190
+
191
+ def nokogiri_to_temp(xml, filename, suffix)
192
+ file = Tempfile.new([filename, suffix])
193
+ file.write(xml.to_xml(indent: 0))
194
+ file.close
195
+ [file, file.path]
196
+ end
97
197
  end
98
198
  end
99
199
  end
@@ -36,7 +36,7 @@ module Metanorma
36
36
  def svg_preprocess(xml, doc_suffix, presxml)
37
37
  suffix = doc_suffix.nil? || doc_suffix.blank? ? "" : "_#{doc_suffix}"
38
38
  xml.xpath("//m:svg", "m" => "http://www.w3.org/2000/svg").each do |s|
39
- m = svgmap_wrap(s)
39
+ m = svgmap_wrap(s) or next
40
40
  svg_xrefs(s, m, suffix, presxml)
41
41
  end
42
42
  xml
@@ -44,7 +44,7 @@ module Metanorma
44
44
 
45
45
  def svgmap_wrap(svg)
46
46
  ret = svg.at("./ancestor::xmlns:svgmap") and return ret
47
- ret = svg.at("./ancestor::xmlns:figure")
47
+ ret = svg.at("./ancestor::xmlns:figure") or return
48
48
  ret.wrap("<svgmap/>")
49
49
  svg.at("./ancestor::xmlns:svgmap")
50
50
  end
@@ -123,8 +123,9 @@ module Metanorma
123
123
  def copy_isodoc_options_attrs(options, ret)
124
124
  ret[:datauriimage] = true if options[:datauriimage]
125
125
  ret[:sourcefilename] = options[:filename]
126
- %i(bare sectionsplit install_fonts baseassetpath aligncrosselements
127
- tocfigures toctables tocrecommendations strict)
126
+ %i(bare sectionsplit sectionsplit_filename install_fonts baseassetpath
127
+ aligncrosselements tocfigures toctables tocrecommendations strict
128
+ fonts)
128
129
  .each { |x| ret[x] ||= options[x] }
129
130
  end
130
131
 
@@ -7,17 +7,24 @@ module Metanorma
7
7
  # @param stdtype [Symbol] the standard type
8
8
  # @return [void]
9
9
  def load_flavor(stdtype)
10
- stdtype = stdtype.to_sym
11
- flavor = stdtype2flavor_gem(stdtype)
12
- @registry.supported_backends.include? stdtype or
10
+ new_stdtype = taste2flavor(stdtype)
11
+ flavor = stdtype2flavor_gem(new_stdtype)
12
+ @registry.supported_backends.include? new_stdtype or
13
13
  Util.log("[metanorma] Info: Loading `#{flavor}` gem "\
14
14
  "for standard type `#{stdtype}`.", :info)
15
15
  require_flavor(flavor)
16
- @registry.supported_backends.include? stdtype or
16
+ @registry.supported_backends.include? new_stdtype or
17
17
  Util.log("[metanorma] Error: The `#{flavor}` gem does not "\
18
18
  "support the standard type #{stdtype}. Exiting.", :fatal)
19
19
  end
20
20
 
21
+ def taste2flavor(stdtype)
22
+ stdtype = stdtype.to_sym
23
+ tastes = Metanorma::TasteRegister.instance.aliases
24
+ tastes[stdtype] and stdtype = tastes[stdtype].to_sym
25
+ stdtype
26
+ end
27
+
21
28
  # Convert the standard type to the flavor gem name
22
29
  # @param stdtype [Symbol] the standard type
23
30
  # @return [String] the flavor gem name
@@ -159,6 +159,7 @@ module Metanorma
159
159
  ::Metanorma::Collection::Sectionsplit.new(
160
160
  input: input_filename, isodoc: @isodoc, xml: presxml,
161
161
  base: File.basename(output_filename || filename),
162
+ sectionsplit_filename: opts[:sectionsplit_filename],
162
163
  output: output_filename || filename, dir: dir, compile_opts: opts
163
164
  ).build_collection
164
165
  end
@@ -1,3 +1,3 @@
1
1
  module Metanorma
2
- VERSION = "2.3.0".freeze
2
+ VERSION = "2.3.2".freeze
3
3
  end
data/metanorma.gemspec CHANGED
@@ -26,27 +26,17 @@ Gem::Specification.new do |spec|
26
26
 
27
27
  spec.add_runtime_dependency "asciidoctor"
28
28
  spec.add_runtime_dependency "concurrent-ruby"
29
- spec.add_runtime_dependency "fontist", ">= 2.0.0"
29
+ spec.add_runtime_dependency "fontist", ">= 2.1.2"
30
30
  spec.add_runtime_dependency "htmlentities"
31
31
  spec.add_runtime_dependency "isodoc", ">= 3.0.0"
32
- spec.add_runtime_dependency "metanorma-taste", "~> 0.1.0"
32
+ spec.add_runtime_dependency "marcel"
33
+ spec.add_runtime_dependency "metanorma-taste", "~> 1.0.0"
33
34
  spec.add_runtime_dependency "mn2pdf", "~> 2"
34
35
  spec.add_runtime_dependency "nokogiri"
36
+ spec.add_development_dependency "canon", "= 0.1.3"
37
+ spec.add_development_dependency "metanorma-iho"
38
+ spec.add_development_dependency "metanorma-iso"
35
39
 
36
40
  # relaton-cli is required by Metanorma::Collection
37
41
  spec.add_dependency "relaton-cli"
38
-
39
- spec.add_development_dependency "debug"
40
- spec.add_development_dependency "equivalent-xml"
41
- spec.add_development_dependency "metanorma-iso", ">= 3.2.0"
42
- spec.add_development_dependency "mnconvert"
43
- spec.add_development_dependency "pry"
44
- spec.add_development_dependency "rake", "~> 13.0"
45
- spec.add_development_dependency "rspec", "~> 3.0"
46
- spec.add_development_dependency "rspec-command", "~> 1.0"
47
- spec.add_development_dependency "rubocop", "~> 1"
48
- spec.add_development_dependency "rubocop-performance"
49
- spec.add_development_dependency "sassc-embedded", "~> 1"
50
- spec.add_development_dependency "simplecov", "~> 0.15"
51
- spec.add_development_dependency "canon", "= 0.1.3"
52
42
  end