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.
- checksums.yaml +4 -4
- data/Gemfile +14 -0
- data/lib/metanorma/collection/collection.rb +46 -105
- data/lib/metanorma/collection/config/config.rb +11 -0
- data/lib/metanorma/collection/config/converters.rb +1 -0
- data/lib/metanorma/collection/config/manifest.rb +23 -0
- data/lib/metanorma/collection/document/document.rb +32 -10
- data/lib/metanorma/collection/filelookup/base.rb +43 -0
- data/lib/metanorma/collection/filelookup/filelookup.rb +168 -69
- data/lib/metanorma/collection/filelookup/filelookup_sectionsplit.rb +49 -10
- data/lib/metanorma/collection/filelookup/utils.rb +93 -0
- data/lib/metanorma/collection/helpers.rb +82 -0
- data/lib/metanorma/collection/manifest/manifest.rb +14 -3
- data/lib/metanorma/collection/multilingual/multilingual.rb +1 -1
- data/lib/metanorma/collection/renderer/filelocation.rb +162 -0
- data/lib/metanorma/collection/renderer/fileparse.rb +9 -6
- data/lib/metanorma/collection/renderer/fileprocess.rb +56 -42
- data/lib/metanorma/collection/renderer/navigation.rb +15 -1
- data/lib/metanorma/collection/renderer/render_word.rb +8 -4
- data/lib/metanorma/collection/renderer/renderer.rb +104 -10
- data/lib/metanorma/collection/renderer/svg.rb +54 -7
- data/lib/metanorma/collection/renderer/utils.rb +58 -22
- data/lib/metanorma/collection/sectionsplit/collection.rb +14 -5
- data/lib/metanorma/collection/sectionsplit/sectionsplit.rb +20 -7
- data/lib/metanorma/collection/util/disambig_files.rb +4 -5
- data/lib/metanorma/collection/util/util.rb +106 -6
- data/lib/metanorma/collection/xrefprocess/xrefprocess.rb +2 -2
- data/lib/metanorma/compile/compile_options.rb +3 -2
- data/lib/metanorma/compile/flavor.rb +11 -4
- data/lib/metanorma/compile/render.rb +1 -0
- data/lib/metanorma/version.rb +1 -1
- data/metanorma.gemspec +6 -16
- 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
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
Vectory
|
|
20
|
-
docxml
|
|
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
|
-
|
|
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)
|
|
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(
|
|
42
|
-
ins =
|
|
43
|
-
|
|
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
|
-
|
|
64
|
-
|
|
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(
|
|
74
|
-
ins = new_hidden_ref(
|
|
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,
|
|
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
|
|
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
|
-
|
|
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{(?<!=/)$}, "/"))
|
|
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
|
|
139
|
-
img.elements.map(&:name).include?("svg")
|
|
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
|
|
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
|
-
|
|
149
|
-
|
|
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,
|
|
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"))
|
|
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"))
|
|
53
|
-
id: xml.at(ns("//bibdata/docidentifier"))
|
|
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
|
-
|
|
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
|
-
|
|
65
|
-
|
|
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
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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[
|
|
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
|
-
|
|
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("//#{
|
|
42
|
-
|
|
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[
|
|
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
|
|
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
|
-
|
|
11
|
-
flavor = stdtype2flavor_gem(
|
|
12
|
-
@registry.supported_backends.include?
|
|
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?
|
|
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
|
data/lib/metanorma/version.rb
CHANGED
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.
|
|
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 "
|
|
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
|