metanorma 1.3.4 → 1.3.8

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.
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative "util"
4
+
3
5
  module Metanorma
4
6
  # Metanorma collection's manifest
5
7
  class CollectionManifest
@@ -15,6 +17,7 @@ module Metanorma
15
17
  @title = title
16
18
  @docref = docref
17
19
  @manifest = manifest
20
+ @disambig = Util::DisambigFiles.new
18
21
  end
19
22
 
20
23
  class << self
@@ -43,9 +46,11 @@ module Metanorma
43
46
  # @return [Hash{String=>String}]
44
47
  def parse_docref(mnf)
45
48
  mnf.xpath("xmlns:docref").map do |dr|
46
- h = { "identifier" => dr.at("identifier").text }
47
- dr[:fileref] and h["fileref"] = dr[:fileref]
48
- h["attachment"] = dr[:attachment] if dr[:attachment]
49
+ h = { "identifier" => dr.at("identifier").children.to_xml }
50
+ %i(fileref attachment sectionsplit index).each do |s|
51
+ h[s.to_s] = dr[s] if dr[s]
52
+ end
53
+ h["presentation-xml"] = dr[:presentationxml] if dr[:presentationxml]
49
54
  h
50
55
  end
51
56
  end
@@ -57,7 +62,7 @@ module Metanorma
57
62
  @manifest.each { |mnf| mnf.collection = col }
58
63
  end
59
64
 
60
- # @param dir [String] path to coolection
65
+ # @param dir [String] path to collection
61
66
  # @return [Hash<String, Metanorma::Document>]
62
67
  def documents(dir = "")
63
68
  docs = @docref.each_with_object({}) do |dr, m|
@@ -65,7 +70,7 @@ module Metanorma
65
70
 
66
71
  m[dr["identifier"]] = Document.parse_file(
67
72
  File.join(dir, dr["fileref"]),
68
- dr["attachment"], dr["identifier"]
73
+ dr["attachment"], dr["identifier"], dr["index"]
69
74
  )
70
75
  m
71
76
  end
@@ -100,14 +105,34 @@ module Metanorma
100
105
 
101
106
  # @param builder [Nokogiri::XML::Builder]
102
107
  def docref_to_xml(builder)
108
+ @disambig = Util::DisambigFiles.new
103
109
  @docref.each do |dr|
104
- drf = builder.docref { |b| b.identifier dr["identifier"] }
105
- drf[:fileref] = Util::source2dest_filename(dr["fileref"])
106
- drf[:attachment] = dr["attachment"] if dr["attachment"]
107
- if collection.directives.include?("documents-inline")
108
- id = collection.documents.find_index { |k, _| k == dr["identifier"] }
109
- drf[:id] = format("doc%<index>09d", index: id)
110
+ drf = builder.docref do |b|
111
+ b.identifier do |i|
112
+ i << dr["identifier"]
113
+ end
114
+ end
115
+ docref_to_xml_attrs(drf, dr)
116
+ end
117
+ end
118
+
119
+ def docref_to_xml_attrs(elem, docref)
120
+ elem[:fileref] = @disambig.source2dest_filename(docref["fileref"])
121
+ %i(attachment sectionsplit).each do |i|
122
+ elem[i] = docref[i.to_s] if docref[i.to_s]
123
+ end
124
+ elem[:index] = docref.has_key?("index") ? docref["index"] : "true"
125
+ elem[:presentationxml] = "true" if docref["presentation-xml"] &&
126
+ [true, "true"].include?(docref["presentation-xml"])
127
+ docref_to_xml_attrs_id(elem, docref)
128
+ end
129
+
130
+ def docref_to_xml_attrs_id(elem, docref)
131
+ if collection.directives.include?("documents-inline")
132
+ id = collection.documents.find_index do |k, _|
133
+ k == docref["identifier"]
110
134
  end
135
+ elem[:id] = format("doc%<index>09d", index: id)
111
136
  end
112
137
  end
113
138
  end
@@ -3,6 +3,7 @@
3
3
  require "isodoc"
4
4
  require_relative "collection_fileprocess"
5
5
  require_relative "fontist_utils"
6
+ require_relative "util"
6
7
 
7
8
  module Metanorma
8
9
  # XML collection renderer
@@ -34,13 +35,18 @@ module Metanorma
34
35
 
35
36
  @outdir = options[:output_folder]
36
37
  @coverpage = options[:coverpage]
37
- @format = options[:format]
38
+ @format = Util.sort_extensions_execution(options[:format])
38
39
  @compile_options = options[:compile] || {}
40
+ @compile_options[:no_install_fonts] = true if options[:no_install_fonts]
39
41
  @log = options[:log]
40
42
  @documents = collection.documents
43
+ @directives = collection.directives
44
+ @disambig = Util::DisambigFiles.new
45
+ @compile = Compile.new
41
46
 
42
47
  # list of files in the collection
43
48
  @files = read_files folder
49
+ isodoc_populate(@isodoc)
44
50
  FileUtils.rm_rf @outdir
45
51
  FileUtils.mkdir_p @outdir
46
52
  end
@@ -48,14 +54,20 @@ module Metanorma
48
54
  # @param col [Metanorma::Collection] XML collection
49
55
  # @param options [Hash]
50
56
  # @option options [String] :coverpage cover page HTML (Liquid template)
51
- # @option options [Array<Synbol>] :format list of formats
57
+ # @option options [Array<Symbol>] :format list of formats
52
58
  # @option options [Strong] :ourput_folder output directory
53
59
  def self.render(col, options = {})
54
60
  folder = File.dirname col.file
61
+ # require "byebug"; byebug
62
+ warn "\n\n\n\n\nRender Init: #{DateTime.now.strftime('%H:%M:%S')}"
55
63
  cr = new(col, folder, options)
64
+ warn "\n\n\n\n\nRender Files: #{DateTime.now.strftime('%H:%M:%S')}"
56
65
  cr.files
66
+ warn "\n\n\n\n\nConcatenate: #{DateTime.now.strftime('%H:%M:%S')}"
57
67
  cr.concatenate(col, options)
68
+ warn "\n\n\n\n\nCoverpage: #{DateTime.now.strftime('%H:%M:%S')}"
58
69
  cr.coverpage if options[:format]&.include?(:html)
70
+ warn "\n\n\n\n\nDone: #{DateTime.now.strftime('%H:%M:%S')}"
59
71
  end
60
72
 
61
73
  def concatenate(col, options)
@@ -66,13 +78,15 @@ module Metanorma
66
78
  ext = e == :presentation ? "presentation.xml" : e.to_s
67
79
  out = col.clone
68
80
  out.directives << "documents-inline"
69
- out.documents.keys.each do |id|
70
- next if @files[id][:attachment]
81
+ out.documents.each_key do |id|
82
+ next if @files[id][:attachment] || @files[id][:outputs].nil?
71
83
 
72
84
  filename = @files[id][:outputs][e]
73
85
  out.documents[id] = Metanorma::Document.raw_file(filename)
74
86
  end
75
- File.open(File.join(@outdir, "collection.#{ext}"), "w:UTF-8") { |f| f.write(out.to_xml) }
87
+ File.open(File.join(@outdir, "collection.#{ext}"), "w:UTF-8") do |f|
88
+ f.write(out.to_xml)
89
+ end
76
90
  end
77
91
  options[:format].include?(:pdf) and
78
92
  pdfconv.convert(File.join(@outdir, "collection.presentation.xml"))
@@ -103,15 +117,21 @@ module Metanorma
103
117
  end
104
118
 
105
119
  # The isodoc class for the metanorma flavour we are using
106
- def isodoc # rubocop:disable Metrics/MethodLength
120
+ def isodoc
107
121
  x = Asciidoctor.load nil, backend: @doctype.to_sym
108
122
  isodoc = x.converter.html_converter(Dummy.new)
109
123
  isodoc.i18n_init(@lang, @script) # read in internationalisation
124
+ isodoc.metadata_init(@lang, @script, isodoc.i18n)
125
+ isodoc.info(@xml, nil)
126
+ isodoc
127
+ end
128
+
129
+ def isodoc_populate(isodoc)
110
130
  # create the @meta class of isodoc, with "navigation" set to the index bar
111
131
  # extracted from the manifest
112
132
  nav = indexfile(@xml.at(ns("//manifest")))
113
133
  i18n = isodoc.i18n
114
- i18n.set(:navigation, nav)
134
+ i18n.set("navigation", nav)
115
135
  isodoc.metadata_init(@lang, @script, i18n)
116
136
  # populate the @meta class of isodoc with the various metadata fields
117
137
  # native to the flavour; used to populate Liquid
@@ -159,7 +179,7 @@ module Metanorma
159
179
  # @param elm [Nokogiri::XML::Element]
160
180
  # @param builder [Nokogiri::XML::Builder]
161
181
  def indexfile_docref(elm, builder)
162
- return "" unless elm.at(ns("./docref"))
182
+ return "" unless elm.at(ns("./docref[@index = 'true']"))
163
183
 
164
184
  builder.ul { |b| docrefs(elm, b) }
165
185
  end
@@ -167,12 +187,20 @@ module Metanorma
167
187
  # @param elm [Nokogiri::XML::Element]
168
188
  # @param builder [Nokogiri::XML::Builder]
169
189
  def docrefs(elm, builder)
170
- elm.xpath(ns("./docref")).each do |d|
171
- identifier = d.at(ns("./identifier")).text
172
- link = if d["fileref"] then d["fileref"].sub(/\.xml$/, ".html")
173
- else d["id"] + ".html"
174
- end
175
- builder.li { builder.a identifier, href: link }
190
+ elm.xpath(ns("./docref[@index = 'true']")).each do |d|
191
+ ident = d.at(ns("./identifier")).children.to_xml
192
+ builder.li do |li|
193
+ li.a **{ href: index_link(d, ident) } do |a|
194
+ a << ident
195
+ end
196
+ end
197
+ end
198
+ end
199
+
200
+ def index_link(docref, ident)
201
+ if docref["fileref"]
202
+ @files[ident][:out_path].sub(/\.xml$/, ".html")
203
+ else "#{docref['id']}.html"
176
204
  end
177
205
  end
178
206
 
@@ -198,6 +226,14 @@ module Metanorma
198
226
 
199
227
  private
200
228
 
229
+ def format_sort(formats)
230
+ ret = []
231
+ formats.include?(:xml) and ret << :xml
232
+ formats.include?(:presentation) and ret << :presentation
233
+ a = %i(presentation xml)
234
+ ret + formats.reject { |i| a.include? i }
235
+ end
236
+
201
237
  # @param options [Hash]
202
238
  # @raise [ArgumentError]
203
239
  def check_options(options)
@@ -6,6 +6,8 @@ require "fontist"
6
6
  require "fontist/manifest/install"
7
7
  require_relative "compile_validate"
8
8
  require_relative "fontist_utils"
9
+ require_relative "util"
10
+ require_relative "sectionsplit"
9
11
 
10
12
  module Metanorma
11
13
  class Compile
@@ -15,6 +17,8 @@ module Metanorma
15
17
  def initialize
16
18
  @registry = Metanorma::Registry.instance
17
19
  @errors = []
20
+ @isodoc = IsoDoc::Convert.new({})
21
+ @fontist_installed = false
18
22
  end
19
23
 
20
24
  def compile(filename, options = {})
@@ -26,7 +30,8 @@ module Metanorma
26
30
  (file, isodoc = process_input(filename, options)) or return nil
27
31
  relaton_export(isodoc, options)
28
32
  extract(isodoc, options[:extract], options[:extract_type])
29
- FontistUtils.install_fonts(@processor, options)
33
+ FontistUtils.install_fonts(@processor, options) unless @fontist_installed
34
+ @fontist_installed = true
30
35
  process_extensions(extensions, file, isodoc, options)
31
36
  end
32
37
 
@@ -35,7 +40,7 @@ module Metanorma
35
40
  end
36
41
 
37
42
  def xml_options_extract(file)
38
- xml = Nokogiri::XML(file)
43
+ xml = Nokogiri::XML(file) { |config| config.huge }
39
44
  if xml.root
40
45
  @registry.root_tags.each do |k, v|
41
46
  return { type: k } if v == xml.root.name
@@ -53,7 +58,7 @@ module Metanorma
53
58
  dir = filename.sub(%r(/[^/]+$), "/")
54
59
  options[:relaton] ||= "#{dir}/#{o[:relaton]}" if o[:relaton]
55
60
  options[:sourcecode] ||= "#{dir}/#{o[:sourcecode]}" if o[:sourcecode]
56
- options[:extension_keys] ||= o[:extensions]&.split(/,[ ]*/)&.map(&:to_sym)
61
+ options[:extension_keys] ||= o[:extensions]&.split(/, */)&.map(&:to_sym)
57
62
  options[:extension_keys] = nil if options[:extension_keys] == [:all]
58
63
  options[:format] ||= :asciidoc
59
64
  options[:filename] = filename
@@ -61,12 +66,10 @@ module Metanorma
61
66
  end
62
67
 
63
68
  def get_extensions(options)
64
- options[:extension_keys] ||= @processor.output_formats.reduce([]) do |memo, (k, _)|
65
- memo << k
66
- end
69
+ options[:extension_keys] ||=
70
+ @processor.output_formats.reduce([]) { |memo, (k, _)| memo << k }
67
71
  extensions = options[:extension_keys].reduce([]) do |memo, e|
68
- if @processor.output_formats[e]
69
- memo << e
72
+ if @processor.output_formats[e] then memo << e
70
73
  else
71
74
  message = "[metanorma] Error: #{e} format is not supported for this standard."
72
75
  @errors << message
@@ -74,7 +77,9 @@ module Metanorma
74
77
  memo
75
78
  end
76
79
  end
77
- if !extensions.include?(:presentation) and extensions.any? { |e| @processor.use_presentation_xml(e) }
80
+ if !extensions.include?(:presentation) && extensions.any? do |e|
81
+ @processor.use_presentation_xml(e)
82
+ end
78
83
  extensions << :presentation
79
84
  end
80
85
  extensions
@@ -82,41 +87,50 @@ module Metanorma
82
87
 
83
88
  def process_input(filename, options)
84
89
  case extname = File.extname(filename)
85
- when ".adoc"
86
- Util.log("[metanorma] Processing: AsciiDoc input.", :info)
87
- file = read_file(filename)
88
- options[:asciimath] and
89
- file.sub!(/^(=[^\n]+\n)/, "\\1:mn-keep-asciimath:\n")
90
- dir = File.dirname(filename)
91
- dir != '.' and
92
- file.gsub!(/^include::/, "include::#{dir}/")
93
- [file, @processor.input_to_isodoc(file, filename, options)]
94
- when ".xml"
95
- Util.log("[metanorma] Processing: Metanorma XML input.", :info)
96
- # TODO NN: this is a hack -- we should provide/bridge the
97
- # document attributes in Metanorma XML
98
- ["", read_file(filename)]
90
+ when ".adoc" then process_input_adoc(filename, options)
91
+ when ".xml" then process_input_xml(filename, options)
99
92
  else
100
- Util.log("[metanorma] Error: file extension #{extname} is not supported.", :error)
93
+ Util.log("[metanorma] Error: file extension #{extname} "\
94
+ "is not supported.", :error)
101
95
  nil
102
96
  end
103
97
  end
104
98
 
99
+ def process_input_adoc(filename, options)
100
+ Util.log("[metanorma] Processing: AsciiDoc input.", :info)
101
+ file = read_file(filename)
102
+ options[:asciimath] and
103
+ file.sub!(/^(=[^\n]+\n)/, "\\1:mn-keep-asciimath:\n")
104
+ dir = File.dirname(filename)
105
+ dir != "." and
106
+ file.gsub!(/^include::/, "include::#{dir}/")
107
+ [file, @processor.input_to_isodoc(file, filename, options)]
108
+ end
109
+
110
+ def process_input_xml(filename, _options)
111
+ Util.log("[metanorma] Processing: Metanorma XML input.", :info)
112
+ # TODO NN: this is a hack -- we should provide/bridge the
113
+ # document attributes in Metanorma XML
114
+ ["", read_file(filename)]
115
+ end
116
+
105
117
  def read_file(filename)
106
118
  File.read(filename, encoding: "utf-8").gsub("\r\n", "\n")
107
119
  end
108
120
 
109
121
  def relaton_export(isodoc, options)
110
122
  return unless options[:relaton]
111
- xml = Nokogiri::XML(isodoc)
123
+
124
+ xml = Nokogiri::XML(isodoc) { |config| config.huge }
112
125
  bibdata = xml.at("//bibdata") || xml.at("//xmlns:bibdata")
113
- #docid = bibdata&.at("./xmlns:docidentifier")&.text || options[:filename]
114
- #outname = docid.sub(/^\s+/, "").sub(/\s+$/, "").gsub(/\s+/, "-") + ".xml"
126
+ # docid = bibdata&.at("./xmlns:docidentifier")&.text || options[:filename]
127
+ # outname = docid.sub(/^\s+/, "").sub(/\s+$/, "").gsub(/\s+/, "-") + ".xml"
115
128
  File.open(options[:relaton], "w:UTF-8") { |f| f.write bibdata.to_xml }
116
129
  end
117
130
 
118
131
  def clean_sourcecode(xml)
119
- xml.xpath(".//callout | .//annotation | .//xmlns:callout | .//xmlns:annotation").each do |x|
132
+ xml.xpath(".//callout | .//annotation | .//xmlns:callout | "\
133
+ ".//xmlns:annotation").each do |x|
120
134
  x.remove
121
135
  end
122
136
  xml.xpath(".//br | .//xmlns:br").each { |x| x.replace("\n") }
@@ -125,12 +139,13 @@ module Metanorma
125
139
 
126
140
  def extract(isodoc, dirname, extract_types)
127
141
  return unless dirname
142
+
128
143
  if extract_types.nil? || extract_types.empty?
129
- extract_types = [:sourcecode, :image, :requirement]
144
+ extract_types = %i[sourcecode image requirement]
130
145
  end
131
146
  FileUtils.rm_rf dirname
132
147
  FileUtils.mkdir_p dirname
133
- xml = Nokogiri::XML(isodoc)
148
+ xml = Nokogiri::XML(isodoc) { |config| config.huge }
134
149
  sourcecode_export(xml, dirname) if extract_types.include? :sourcecode
135
150
  image_export(xml, dirname) if extract_types.include? :image
136
151
  requirement_export(xml, dirname) if extract_types.include? :requirement
@@ -151,7 +166,7 @@ module Metanorma
151
166
  xml.at("//image | //xmlns:image") or return
152
167
  FileUtils.mkdir_p "#{dirname}/image"
153
168
  xml.xpath("//image | //xmlns:image").each_with_index do |s, i|
154
- next unless /^data:image/.match s["src"]
169
+ next unless /^data:image/.match? s["src"]
155
170
 
156
171
  %r{^data:image/(?<imgtype>[^;]+);base64,(?<imgdata>.+)$} =~ s["src"]
157
172
  filename = s["filename"] || sprintf("image-%04d.%s", i, imgtype)
@@ -176,17 +191,6 @@ module Metanorma
176
191
  end
177
192
  end
178
193
 
179
- # dependency ordering
180
- def sort_extensions_execution(ext)
181
- case ext
182
- when :xml then 0
183
- when :rxl then 1
184
- when :presentation then 2
185
- else
186
- 99
187
- end
188
- end
189
-
190
194
  def wrap_html(options, file_extension, outfilename)
191
195
  if options[:wrapper] && /html$/.match(file_extension)
192
196
  outfilename = outfilename.sub(/\.html$/, "")
@@ -201,34 +205,25 @@ module Metanorma
201
205
  f = change_output_dir options
202
206
  xml_name = f.sub(/\.[^.]+$/, ".xml")
203
207
  presentationxml_name = f.sub(/\.[^.]+$/, ".presentation.xml")
204
- extensions.sort do |a, b|
205
- sort_extensions_execution(a) <=> sort_extensions_execution(b)
206
- end.each do |ext|
207
- isodoc_options = @processor.extract_options(file)
208
- isodoc_options[:datauriimage] = true if options[:datauriimage]
209
- isodoc_options[:sourcefilename] = options[:filename]
208
+ Util.sort_extensions_execution(extensions).each do |ext|
210
209
  file_extension = @processor.output_formats[ext]
211
210
  outfilename = f.sub(/\.[^.]+$/, ".#{file_extension}")
212
- if ext == :pdf
213
- font_locations = FontistUtils.fontist_font_locations(@processor, options)
214
- font_locations and
215
- isodoc_options[:mn2pdf] = { font_manifest_file: font_locations.path }
216
- end
211
+ isodoc_options = get_isodoc_options(file, options, ext)
217
212
  if ext == :rxl
218
- options[:relaton] = outfilename
219
- relaton_export(isodoc, options)
213
+ relaton_export(isodoc, options.merge(relaton: outfilename))
214
+ elsif options[:passthrough_presentation_xml] && ext == :presentation
215
+ FileUtils.cp f, presentationxml_name
216
+ elsif ext == :html && options[:sectionsplit]
217
+ sectionsplit_convert(xml_name, isodoc, outfilename, isodoc_options)
220
218
  else
221
219
  begin
222
- @processor.use_presentation_xml(ext) ?
223
- @processor.output(nil, presentationxml_name, outfilename, ext, isodoc_options) :
224
- @processor.output(isodoc, xml_name, outfilename, ext, isodoc_options)
225
- rescue StandardError => e
226
- if e.message.include? "Fatal:"
227
- @errors << e.message
220
+ if @processor.use_presentation_xml(ext)
221
+ @processor.output(nil, presentationxml_name, outfilename, ext, isodoc_options)
228
222
  else
229
- puts e.message
230
- puts e.backtrace.join("\n")
223
+ @processor.output(isodoc, xml_name, outfilename, ext, isodoc_options)
231
224
  end
225
+ rescue StandardError => e
226
+ isodoc_error_process(e)
232
227
  end
233
228
  end
234
229
  wrap_html(options, file_extension, outfilename)
@@ -237,6 +232,29 @@ module Metanorma
237
232
 
238
233
  private
239
234
 
235
+ def isodoc_error_process(err)
236
+ if err.message.include? "Fatal:"
237
+ @errors << err.message
238
+ else
239
+ puts err.message
240
+ puts err.backtrace.join("\n")
241
+ end
242
+ end
243
+
244
+ def get_isodoc_options(file, options, ext)
245
+ isodoc_options = @processor.extract_options(file)
246
+ isodoc_options[:datauriimage] = true if options[:datauriimage]
247
+ isodoc_options[:sourcefilename] = options[:filename]
248
+ %i(bare sectionsplit no_install_fonts).each do |x|
249
+ isodoc_options[x] ||= options[x]
250
+ end
251
+ if ext == :pdf
252
+ floc = FontistUtils.fontist_font_locations(@processor, options) and
253
+ isodoc_options[:mn2pdf] = { font_manifest_file: floc.path }
254
+ end
255
+ isodoc_options
256
+ end
257
+
240
258
  # @param options [Hash]
241
259
  # @return [String]
242
260
  def change_output_dir(options)