metanorma 1.2.8 → 1.3.4
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/.github/workflows/rake.yml +2 -12
- data/.hound.yml +3 -1
- data/.rubocop.yml +3 -7
- data/Rakefile +1 -1
- data/lib/metanorma/asciidoctor_extensions/glob_include_processor.rb +4 -6
- data/lib/metanorma/collection.rb +32 -16
- data/lib/metanorma/collection_fileparse.rb +220 -0
- data/lib/metanorma/collection_fileprocess.rb +66 -222
- data/lib/metanorma/collection_manifest.rb +9 -6
- data/lib/metanorma/collection_renderer.rb +28 -9
- data/lib/metanorma/compile.rb +32 -158
- data/lib/metanorma/compile_validate.rb +51 -0
- data/lib/metanorma/config.rb +1 -1
- data/lib/metanorma/document.rb +24 -10
- data/lib/metanorma/fontist_utils.rb +108 -0
- data/lib/metanorma/input.rb +0 -1
- data/lib/metanorma/input/asciidoc.rb +38 -75
- data/lib/metanorma/output.rb +0 -2
- data/lib/metanorma/output/utils.rb +2 -1
- data/lib/metanorma/util.rb +4 -0
- data/lib/metanorma/version.rb +1 -1
- data/metanorma.gemspec +21 -22
- metadata +47 -44
@@ -44,7 +44,8 @@ module Metanorma
|
|
44
44
|
def parse_docref(mnf)
|
45
45
|
mnf.xpath("xmlns:docref").map do |dr|
|
46
46
|
h = { "identifier" => dr.at("identifier").text }
|
47
|
-
|
47
|
+
dr[:fileref] and h["fileref"] = dr[:fileref]
|
48
|
+
h["attachment"] = dr[:attachment] if dr[:attachment]
|
48
49
|
h
|
49
50
|
end
|
50
51
|
end
|
@@ -62,12 +63,13 @@ module Metanorma
|
|
62
63
|
docs = @docref.each_with_object({}) do |dr, m|
|
63
64
|
next m unless dr["fileref"]
|
64
65
|
|
65
|
-
m[dr["identifier"]] = Document.parse_file
|
66
|
+
m[dr["identifier"]] = Document.parse_file(
|
67
|
+
File.join(dir, dr["fileref"]),
|
68
|
+
dr["attachment"], dr["identifier"]
|
69
|
+
)
|
66
70
|
m
|
67
71
|
end
|
68
|
-
@manifest.reduce(docs)
|
69
|
-
mem.merge mnf.documents(dir)
|
70
|
-
end
|
72
|
+
@manifest.reduce(docs) { |mem, mnf| mem.merge mnf.documents(dir) }
|
71
73
|
end
|
72
74
|
|
73
75
|
# @param builder [Nokogiri::XML::Builder]
|
@@ -100,7 +102,8 @@ module Metanorma
|
|
100
102
|
def docref_to_xml(builder)
|
101
103
|
@docref.each do |dr|
|
102
104
|
drf = builder.docref { |b| b.identifier dr["identifier"] }
|
103
|
-
drf[:fileref] = dr["fileref"]
|
105
|
+
drf[:fileref] = Util::source2dest_filename(dr["fileref"])
|
106
|
+
drf[:attachment] = dr["attachment"] if dr["attachment"]
|
104
107
|
if collection.directives.include?("documents-inline")
|
105
108
|
id = collection.documents.find_index { |k, _| k == dr["identifier"] }
|
106
109
|
drf[:id] = format("doc%<index>09d", index: id)
|
@@ -1,7 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "isodoc"
|
4
|
-
require_relative "
|
4
|
+
require_relative "collection_fileprocess"
|
5
|
+
require_relative "fontist_utils"
|
5
6
|
|
6
7
|
module Metanorma
|
7
8
|
# XML collection renderer
|
@@ -20,9 +21,9 @@ module Metanorma
|
|
20
21
|
# the collection, and that the flavour gem can sensibly process it. We may
|
21
22
|
# need to enhance metadata in the flavour gems isodoc/metadata.rb with
|
22
23
|
# collection metadata
|
23
|
-
def initialize(
|
24
|
+
def initialize(collection, folder, options = {}) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
|
24
25
|
check_options options
|
25
|
-
@xml = Nokogiri::XML
|
26
|
+
@xml = Nokogiri::XML collection.to_xml # @xml is the collection manifest
|
26
27
|
@lang = @xml&.at(ns("//bibdata/language"))&.text || "en"
|
27
28
|
@script = @xml&.at(ns("//bibdata/script"))&.text || "Latn"
|
28
29
|
@doctype = doctype
|
@@ -36,6 +37,7 @@ module Metanorma
|
|
36
37
|
@format = options[:format]
|
37
38
|
@compile_options = options[:compile] || {}
|
38
39
|
@log = options[:log]
|
40
|
+
@documents = collection.documents
|
39
41
|
|
40
42
|
# list of files in the collection
|
41
43
|
@files = read_files folder
|
@@ -50,7 +52,7 @@ module Metanorma
|
|
50
52
|
# @option options [Strong] :ourput_folder output directory
|
51
53
|
def self.render(col, options = {})
|
52
54
|
folder = File.dirname col.file
|
53
|
-
cr = new(col
|
55
|
+
cr = new(col, folder, options)
|
54
56
|
cr.files
|
55
57
|
cr.concatenate(col, options)
|
56
58
|
cr.coverpage if options[:format]&.include?(:html)
|
@@ -60,10 +62,13 @@ module Metanorma
|
|
60
62
|
options[:format] << :presentation if options[:format].include?(:pdf)
|
61
63
|
options[:format].uniq.each do |e|
|
62
64
|
next unless %i(presentation xml).include?(e)
|
65
|
+
|
63
66
|
ext = e == :presentation ? "presentation.xml" : e.to_s
|
64
67
|
out = col.clone
|
65
68
|
out.directives << "documents-inline"
|
66
69
|
out.documents.keys.each do |id|
|
70
|
+
next if @files[id][:attachment]
|
71
|
+
|
67
72
|
filename = @files[id][:outputs][e]
|
68
73
|
out.documents[id] = Metanorma::Document.raw_file(filename)
|
69
74
|
end
|
@@ -74,13 +79,27 @@ module Metanorma
|
|
74
79
|
end
|
75
80
|
|
76
81
|
def pdfconv
|
77
|
-
|
78
|
-
x.
|
82
|
+
doctype = @doctype.to_sym
|
83
|
+
x = Asciidoctor.load nil, backend: doctype
|
84
|
+
x.converter.pdf_converter(PdfOptionsNode.new(doctype, @compile_options))
|
85
|
+
end
|
86
|
+
|
87
|
+
class PdfOptionsNode
|
88
|
+
def initialize(doctype, options)
|
89
|
+
doc_proc = Metanorma::Registry.instance.find_processor(doctype)
|
90
|
+
@font_locations = FontistUtils.fontist_font_locations(doc_proc, options)
|
91
|
+
end
|
92
|
+
|
93
|
+
def attr(key)
|
94
|
+
if key == "mn2pdf-font-manifest-file" && @font_locations
|
95
|
+
@font_locations.path
|
96
|
+
end
|
97
|
+
end
|
79
98
|
end
|
80
99
|
|
81
100
|
# Dummy class
|
82
101
|
class Dummy
|
83
|
-
def attr(
|
102
|
+
def attr(_key); end
|
84
103
|
end
|
85
104
|
|
86
105
|
# The isodoc class for the metanorma flavour we are using
|
@@ -119,6 +138,8 @@ module Metanorma
|
|
119
138
|
# populate liquid template of ARGV[1] with metadata extracted from
|
120
139
|
# collection manifest
|
121
140
|
def coverpage
|
141
|
+
return unless @coverpage
|
142
|
+
|
122
143
|
File.open(File.join(@outdir, "index.html"), "w:UTF-8") do |f|
|
123
144
|
f.write @isodoc.populate_template(File.read(@coverpage))
|
124
145
|
end
|
@@ -183,8 +204,6 @@ module Metanorma
|
|
183
204
|
unless options[:format].is_a?(Array) && (FORMATS & options[:format]).any?
|
184
205
|
raise ArgumentError, "Need to specify formats (xml,html,pdf,doc)"
|
185
206
|
end
|
186
|
-
return if !options[:format].include?(:html) || options[:coverpage]
|
187
|
-
raise ArgumentError, "Need to specify a coverpage to render HTML"
|
188
207
|
end
|
189
208
|
end
|
190
209
|
end
|
data/lib/metanorma/compile.rb
CHANGED
@@ -2,9 +2,10 @@ require "fileutils"
|
|
2
2
|
require "nokogiri"
|
3
3
|
require "htmlentities"
|
4
4
|
require "yaml"
|
5
|
-
|
6
5
|
require "fontist"
|
7
6
|
require "fontist/manifest/install"
|
7
|
+
require_relative "compile_validate"
|
8
|
+
require_relative "fontist_utils"
|
8
9
|
|
9
10
|
module Metanorma
|
10
11
|
class Compile
|
@@ -19,29 +20,25 @@ module Metanorma
|
|
19
20
|
def compile(filename, options = {})
|
20
21
|
require_libraries(options)
|
21
22
|
options = options_extract(filename, options)
|
22
|
-
|
23
|
+
validate_options(options)
|
23
24
|
@processor = @registry.find_processor(options[:type].to_sym)
|
24
25
|
extensions = get_extensions(options) or return nil
|
25
26
|
(file, isodoc = process_input(filename, options)) or return nil
|
26
27
|
relaton_export(isodoc, options)
|
27
28
|
extract(isodoc, options[:extract], options[:extract_type])
|
28
|
-
install_fonts(options)
|
29
|
+
FontistUtils.install_fonts(@processor, options)
|
29
30
|
process_extensions(extensions, file, isodoc, options)
|
30
31
|
end
|
31
32
|
|
32
33
|
def require_libraries(options)
|
33
|
-
|
34
|
-
options[:require].each do |r|
|
35
|
-
require r
|
36
|
-
end
|
37
|
-
end
|
34
|
+
options&.dig(:require)&.each { |r| require r }
|
38
35
|
end
|
39
36
|
|
40
37
|
def xml_options_extract(file)
|
41
38
|
xml = Nokogiri::XML(file)
|
42
39
|
if xml.root
|
43
40
|
@registry.root_tags.each do |k, v|
|
44
|
-
return { type: k }
|
41
|
+
return { type: k } if v == xml.root.name
|
45
42
|
end
|
46
43
|
end
|
47
44
|
{}
|
@@ -63,48 +60,6 @@ module Metanorma
|
|
63
60
|
options
|
64
61
|
end
|
65
62
|
|
66
|
-
def validate_type(options)
|
67
|
-
unless options[:type]
|
68
|
-
Util.log("[metanorma] Error: Please specify a standard type: #{@registry.supported_backends}.", :error)
|
69
|
-
return nil
|
70
|
-
end
|
71
|
-
|
72
|
-
stdtype = options[:type].to_sym
|
73
|
-
metanorma_flavor = "metanorma-#{stdtype}"
|
74
|
-
|
75
|
-
unless @registry.supported_backends.include? stdtype
|
76
|
-
Util.log("[metanorma] Info: Loading `#{metanorma_flavor}` gem for standard type `#{stdtype}`.", :info)
|
77
|
-
end
|
78
|
-
|
79
|
-
begin
|
80
|
-
require "metanorma-#{stdtype}"
|
81
|
-
Util.log("[metanorma] Info: gem `#{metanorma_flavor}` loaded.", :info)
|
82
|
-
|
83
|
-
rescue Gem::ConflictError
|
84
|
-
Util.log("[metanorma] Error: Couldn't resolve dependencies for `metanorma-#{stdtype}`, Please add it to your Gemfile and run bundle install first", :error)
|
85
|
-
return false
|
86
|
-
|
87
|
-
rescue LoadError
|
88
|
-
Util.log("[metanorma] Error: loading gem `#{metanorma_flavor}` failed. Exiting.", :error)
|
89
|
-
return false
|
90
|
-
end
|
91
|
-
|
92
|
-
unless @registry.supported_backends.include? stdtype
|
93
|
-
Util.log("[metanorma] Error: The `#{metanorma_flavor}` gem still doesn't support `#{stdtype}`. Exiting.", :error)
|
94
|
-
return false
|
95
|
-
end
|
96
|
-
|
97
|
-
true
|
98
|
-
end
|
99
|
-
|
100
|
-
def validate_format(options)
|
101
|
-
unless options[:format] == :asciidoc
|
102
|
-
Util.log("[metanorma] Error: Only source file format currently supported is 'asciidoc'.", :error)
|
103
|
-
return false
|
104
|
-
end
|
105
|
-
true
|
106
|
-
end
|
107
|
-
|
108
63
|
def get_extensions(options)
|
109
64
|
options[:extension_keys] ||= @processor.output_formats.reduce([]) do |memo, (k, _)|
|
110
65
|
memo << k
|
@@ -121,7 +76,7 @@ module Metanorma
|
|
121
76
|
end
|
122
77
|
if !extensions.include?(:presentation) and extensions.any? { |e| @processor.use_presentation_xml(e) }
|
123
78
|
extensions << :presentation
|
124
|
-
|
79
|
+
end
|
125
80
|
extensions
|
126
81
|
end
|
127
82
|
|
@@ -187,7 +142,7 @@ module Metanorma
|
|
187
142
|
xml.xpath("//sourcecode | //xmlns:sourcecode").each_with_index do |s, i|
|
188
143
|
filename = s["filename"] || sprintf("sourcecode-%04d.txt", i)
|
189
144
|
File.open("#{dirname}/sourcecode/#{filename}", "w:UTF-8") do |f|
|
190
|
-
f.write clean_sourcecode(s.dup)
|
145
|
+
f.write clean_sourcecode(s.dup)
|
191
146
|
end
|
192
147
|
end
|
193
148
|
end
|
@@ -197,6 +152,7 @@ module Metanorma
|
|
197
152
|
FileUtils.mkdir_p "#{dirname}/image"
|
198
153
|
xml.xpath("//image | //xmlns:image").each_with_index do |s, i|
|
199
154
|
next unless /^data:image/.match s["src"]
|
155
|
+
|
200
156
|
%r{^data:image/(?<imgtype>[^;]+);base64,(?<imgdata>.+)$} =~ s["src"]
|
201
157
|
filename = s["filename"] || sprintf("image-%04d.%s", i, imgtype)
|
202
158
|
File.open("#{dirname}/image/#{filename}", "wb") do |f|
|
@@ -222,22 +178,22 @@ module Metanorma
|
|
222
178
|
|
223
179
|
# dependency ordering
|
224
180
|
def sort_extensions_execution(ext)
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
181
|
+
case ext
|
182
|
+
when :xml then 0
|
183
|
+
when :rxl then 1
|
184
|
+
when :presentation then 2
|
185
|
+
else
|
186
|
+
99
|
187
|
+
end
|
232
188
|
end
|
233
189
|
|
234
190
|
def wrap_html(options, file_extension, outfilename)
|
235
|
-
if options[:wrapper]
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
191
|
+
if options[:wrapper] && /html$/.match(file_extension)
|
192
|
+
outfilename = outfilename.sub(/\.html$/, "")
|
193
|
+
FileUtils.mkdir_p outfilename
|
194
|
+
FileUtils.mv "#{outfilename}.html", outfilename
|
195
|
+
FileUtils.mv "#{outfilename}_images", outfilename, force: true
|
196
|
+
end
|
241
197
|
end
|
242
198
|
|
243
199
|
# isodoc is Raw Metanorma XML
|
@@ -250,11 +206,13 @@ module Metanorma
|
|
250
206
|
end.each do |ext|
|
251
207
|
isodoc_options = @processor.extract_options(file)
|
252
208
|
isodoc_options[:datauriimage] = true if options[:datauriimage]
|
209
|
+
isodoc_options[:sourcefilename] = options[:filename]
|
253
210
|
file_extension = @processor.output_formats[ext]
|
254
211
|
outfilename = f.sub(/\.[^.]+$/, ".#{file_extension}")
|
255
212
|
if ext == :pdf
|
256
|
-
font_locations = fontist_font_locations(options)
|
257
|
-
|
213
|
+
font_locations = FontistUtils.fontist_font_locations(@processor, options)
|
214
|
+
font_locations and
|
215
|
+
isodoc_options[:mn2pdf] = { font_manifest_file: font_locations.path }
|
258
216
|
end
|
259
217
|
if ext == :rxl
|
260
218
|
options[:relaton] = outfilename
|
@@ -265,104 +223,20 @@ module Metanorma
|
|
265
223
|
@processor.output(nil, presentationxml_name, outfilename, ext, isodoc_options) :
|
266
224
|
@processor.output(isodoc, xml_name, outfilename, ext, isodoc_options)
|
267
225
|
rescue StandardError => e
|
268
|
-
|
269
|
-
|
226
|
+
if e.message.include? "Fatal:"
|
227
|
+
@errors << e.message
|
228
|
+
else
|
229
|
+
puts e.message
|
230
|
+
puts e.backtrace.join("\n")
|
231
|
+
end
|
270
232
|
end
|
271
233
|
end
|
272
|
-
if ext == :pdf
|
273
|
-
# font_locations.unlink
|
274
|
-
end
|
275
234
|
wrap_html(options, file_extension, outfilename)
|
276
235
|
end
|
277
236
|
end
|
278
237
|
|
279
|
-
def install_fonts(options)
|
280
|
-
if options[:no_install_fonts]
|
281
|
-
Util.log("[fontist] Skip font installation because" \
|
282
|
-
" --no-install-fonts argument passed", :debug)
|
283
|
-
return
|
284
|
-
end
|
285
|
-
|
286
|
-
if missing_fontist_manifest?
|
287
|
-
Util.log("[fontist] Skip font installation because font_manifest is missing", :debug)
|
288
|
-
return
|
289
|
-
end
|
290
|
-
|
291
|
-
@updated_formulas_repo = false
|
292
|
-
|
293
|
-
manifest = @processor.fonts_manifest
|
294
|
-
agree_to_terms = options[:agree_to_terms] || false
|
295
|
-
continue_without_fonts = options[:continue_without_fonts] || false
|
296
|
-
no_progress = options[:no_progress] || false
|
297
|
-
|
298
|
-
install_fonts_safe(manifest, agree_to_terms, continue_without_fonts, no_progress)
|
299
|
-
end
|
300
|
-
|
301
238
|
private
|
302
239
|
|
303
|
-
def install_fonts_safe(manifest, agree, continue, no_progress)
|
304
|
-
fontist_install(manifest, agree, no_progress)
|
305
|
-
rescue Fontist::Errors::LicensingError
|
306
|
-
if continue
|
307
|
-
Util.log(
|
308
|
-
"[fontist] Processing will continue without fonts installed",
|
309
|
-
:debug
|
310
|
-
)
|
311
|
-
else
|
312
|
-
Util.log("[fontist] Aborting without proper fonts installed," \
|
313
|
-
" make sure that you have set option --agree-to-terms", :fatal)
|
314
|
-
end
|
315
|
-
rescue Fontist::Errors::FontError => e
|
316
|
-
log_level = continue ? :warning : :fatal
|
317
|
-
Util.log("[fontist] '#{e.font}' font is not supported. " \
|
318
|
-
"Please report this issue at github.com/metanorma/metanorma-"\
|
319
|
-
"#{@processor.short}/issues to report this issue.", log_level)
|
320
|
-
rescue Fontist::Errors::FormulaIndexNotFoundError
|
321
|
-
if @updated_formulas_repo
|
322
|
-
Util.log(
|
323
|
-
"[fontist] Bug: formula index not found after 'fontist update'",
|
324
|
-
:fatal
|
325
|
-
)
|
326
|
-
end
|
327
|
-
Util.log("[fontist] Missing formula index. Fetching it...", :debug)
|
328
|
-
Fontist::Formula.update_formulas_repo
|
329
|
-
@updated_formulas_repo = true
|
330
|
-
install_fonts_safe(manifest, agree, continue, no_progress)
|
331
|
-
end
|
332
|
-
|
333
|
-
def fontist_install(manifest, agree, no_progress)
|
334
|
-
Fontist::Manifest::Install.from_hash(
|
335
|
-
manifest,
|
336
|
-
confirmation: agree ? "yes" : "no",
|
337
|
-
no_progress: no_progress
|
338
|
-
)
|
339
|
-
end
|
340
|
-
|
341
|
-
def fontist_font_locations(options)
|
342
|
-
return nil if missing_fontist_manifest? || options[:no_install_fonts]
|
343
|
-
|
344
|
-
dump_fontist_manifest_locations(@processor.fonts_manifest)
|
345
|
-
rescue Fontist::Errors::FormulaIndexNotFoundError
|
346
|
-
raise unless options[:continue_without_fonts]
|
347
|
-
|
348
|
-
nil
|
349
|
-
end
|
350
|
-
|
351
|
-
def dump_fontist_manifest_locations(manifest)
|
352
|
-
location_manifest = Fontist::Manifest::Locations.from_hash(
|
353
|
-
manifest
|
354
|
-
)
|
355
|
-
location_manifest_file = Tempfile.new(["fontist_locations", ".yml"])
|
356
|
-
location_manifest_file.write location_manifest.to_yaml
|
357
|
-
location_manifest_file.flush
|
358
|
-
|
359
|
-
location_manifest_file
|
360
|
-
end
|
361
|
-
|
362
|
-
def missing_fontist_manifest?
|
363
|
-
!@processor.respond_to?(:fonts_manifest) || @processor.fonts_manifest.nil?
|
364
|
-
end
|
365
|
-
|
366
240
|
# @param options [Hash]
|
367
241
|
# @return [String]
|
368
242
|
def change_output_dir(options)
|
@@ -0,0 +1,51 @@
|
|
1
|
+
module Metanorma
|
2
|
+
class Compile
|
3
|
+
def validate_options(options)
|
4
|
+
validate_type(options)
|
5
|
+
validate_format(options)
|
6
|
+
end
|
7
|
+
|
8
|
+
def validate_type(options)
|
9
|
+
unless options[:type]
|
10
|
+
Util.log("[metanorma] Error: Please specify a standard type: "\
|
11
|
+
"#{@registry.supported_backends}.", :fatal)
|
12
|
+
end
|
13
|
+
stdtype = options[:type].to_sym
|
14
|
+
load_flavor(stdtype)
|
15
|
+
end
|
16
|
+
|
17
|
+
def validate_format(options)
|
18
|
+
unless options[:format] == :asciidoc
|
19
|
+
Util.log("[metanorma] Error: Only source file format currently "\
|
20
|
+
"supported is 'asciidoc'.", :fatal)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def load_flavor(stdtype)
|
27
|
+
flavor = "metanorma-#{stdtype}"
|
28
|
+
unless @registry.supported_backends.include? stdtype
|
29
|
+
Util.log("[metanorma] Info: Loading `#{flavor}` gem "\
|
30
|
+
"for standard type `#{stdtype}`.", :info)
|
31
|
+
end
|
32
|
+
require_flavor(flavor, stdtype)
|
33
|
+
unless @registry.supported_backends.include? stdtype
|
34
|
+
Util.log("[metanorma] Error: The `#{flavor}` gem "\
|
35
|
+
"still doesn't support `#{stdtype}`. Exiting.", :fatal)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def require_flavor(flavor, stdtype)
|
40
|
+
require flavor
|
41
|
+
Util.log("[metanorma] Info: gem `#{flavor}` loaded.", :info)
|
42
|
+
rescue Gem::ConflictError
|
43
|
+
Util.log("[metanorma] Error: Couldn't resolve dependencies for "\
|
44
|
+
"`metanorma-#{stdtype}`, Please add it to your Gemfile "\
|
45
|
+
"and run bundle install first", :fatal)
|
46
|
+
rescue LoadError
|
47
|
+
Util.log("[metanorma] Error: loading gem `#{flavor}` "\
|
48
|
+
"failed. Exiting.", :fatal)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|