metanorma 1.3.7 → 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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 16196ab7719ac294eb22120afeb64ebceee75e83469bf0a4ae1abd2221952139
4
- data.tar.gz: d1ed0d591efa82eb1e40b09f6598f98f6d7738435c85b6146e2ec7ada41a3413
3
+ metadata.gz: d8b82f79d4ce3a18564bd84c137faeca4daf763e2284464f390476fb881a0996
4
+ data.tar.gz: f6a33995af907243fd0ae9ebff3676467455f21cd502089da6599783b4ba4e86
5
5
  SHA512:
6
- metadata.gz: 4618e5ebe7f688ae9eec5680d0f17aa2795391e1485e749f975052952378742a0c29be722e46aef10c34432a658294bb06c5eac945c56a27c65c8ab7aedc944b
7
- data.tar.gz: e0b3b3ac8846b3d6ecd1fb75691d525f3763c126d2c1db3469c1192c93a14f9a168ec75f2a851f92260334c514704072cc9a59c360034d8de578ca37a2bebf24
6
+ metadata.gz: 484b71a094f6e23f5e512ffcbc8eac5bed0cd6d5b3fc6e952a28ce05e0e9eef3b64bff995692fd43f36b0c7888814b20318559aeeb0d9dee7900baf0847d95b8
7
+ data.tar.gz: 508757811e5a63b30b91d4353fdc2a983bfe269da85f39b9be50d0c6a904113965ae53c40052cd43fb38ee740c350b9922d114bfd21833383a525782d278f95c
data/lib/metanorma.rb CHANGED
@@ -5,7 +5,6 @@ require "asciidoctor"
5
5
  require "metanorma/util"
6
6
  require "metanorma/config"
7
7
  require "metanorma/input"
8
- require "metanorma/output"
9
8
  require "metanorma/registry"
10
9
  require "metanorma/processor"
11
10
  require "metanorma/asciidoctor_extensions"
@@ -38,28 +38,58 @@ module Metanorma
38
38
  def add_section_split(files)
39
39
  files.keys.each_with_object({}) do |k, m|
40
40
  if files[k][:sectionsplit] == "true" && !files[k]["attachment"]
41
- sectionsplit(files[k][:rel_path]).each_with_index do |f1, i|
42
- m[k + f1[:title]] =
43
- { parentid: k, presentationxml: true, type: "fileref",
44
- rel_path: f1[:url], out_path: File.basename(f1[:url]),
45
- anchors: read_anchors(Nokogiri::XML(File.read(f1[:url]))),
46
- bibdata: files[k][:bibdata], ref: f1[:url] }
47
- m[k + f1[:title]][:bare] = true unless i.zero?
41
+ s, manifest = sectionsplit(files[k][:ref])
42
+ s.each_with_index do |f1, i|
43
+ add_section_split_instance(f1, m, k, i, files)
48
44
  end
45
+ m["#{k}:index.html"] = add_section_split_cover(files, manifest, k)
49
46
  end
50
47
  m[k] = files[k]
51
48
  end
52
49
  end
53
50
 
51
+ def add_section_split_cover(files, manifest, ident)
52
+ cover = section_split_cover(manifest, ident)
53
+ files[ident][:out_path] = cover
54
+ { attachment: true, index: false, out_path: cover,
55
+ ref: File.join(File.dirname(manifest.file), cover) }
56
+ end
57
+
58
+ def section_split_cover(col, ident)
59
+ dir = File.dirname(col.file)
60
+ @compile.collection_setup(nil, dir)
61
+ CollectionRenderer.new(col, dir,
62
+ output_folder: "#{ident}_collection",
63
+ format: %i(html),
64
+ coverpage: File.join(dir, "cover.html")).coverpage
65
+ FileUtils.mv "#{ident}_collection/index.html",
66
+ File.join(dir, "#{ident}_index.html")
67
+ FileUtils.rm_rf "#{ident}_collection"
68
+ "#{ident}_index.html"
69
+ end
70
+
71
+ def add_section_split_instance(file, manifest, key, idx, files)
72
+ dir = File.dirname(files[key][:ref])
73
+ presfile = File.join(dir, File.basename(file[:url]))
74
+ manifest["#{key} #{file[:title]}"] =
75
+ { parentid: key, presentationxml: true, type: "fileref",
76
+ rel_path: file[:url], out_path: File.basename(file[:url]),
77
+ anchors: read_anchors(Nokogiri::XML(File.read(presfile))),
78
+ bibdata: files[key][:bibdata], ref: presfile }
79
+ manifest["#{key} #{file[:title]}"][:bare] = true unless idx.zero?
80
+ end
81
+
54
82
  def sectionsplit(file)
55
- Compile.new.compile(
83
+ @compile.compile(
56
84
  file, { format: :asciidoc, extension_keys: [:presentation] }
57
85
  .merge(@compile_options)
58
86
  )
59
87
  r = file.sub(/\.xml$/, ".presentation.xml")
60
- @isodoc.sectionsplit(
61
- Nokogiri::XML(File.read(r)), File.basename(r), File.dirname(r)
62
- ).sort_by { |f| f[:order] }
88
+ xml = Nokogiri::XML(File.read(r))
89
+ s = @compile.sectionsplit(xml, File.basename(r), File.dirname(r))
90
+ .sort_by { |f| f[:order] }
91
+ [s, @compile.collection_manifest(File.basename(r), s, xml, nil,
92
+ File.dirname(r))]
63
93
  end
64
94
 
65
95
  # rel_path is the source file address, determined relative to the YAML.
@@ -74,8 +104,9 @@ module Metanorma
74
104
  else
75
105
  { type: "id", ref: ref["id"] }
76
106
  end
77
- ret[:attachment] = ref["attachment"] if ref["attachment"]
78
- ret[:sectionsplit] = ref["sectionsplit"] if ref["sectionsplit"]
107
+ %i(attachment sectionsplit index).each do |s|
108
+ ret[s] = ref[s.to_s] if ref[s.to_s]
109
+ end
79
110
  ret[:presentationxml] = ref["presentation-xml"] if ref["presentation-xml"]
80
111
  ret[:bareafterfirst] = ref["bare-after-first"] if ref["bare-after-first"]
81
112
  ret
@@ -131,11 +162,12 @@ module Metanorma
131
162
  # compile and output individual file in collection
132
163
  # warn "metanorma compile -x html #{f.path}"
133
164
  def file_compile(file, filename, identifier)
134
- c = Compile.new
135
- c.compile file.path, { format: :asciidoc, extension_keys: @format }
165
+ return if @files[identifier][:sectionsplit] == "true"
166
+
167
+ @compile.compile file.path, { format: :asciidoc, extension_keys: @format }
136
168
  .merge(compile_options(identifier))
137
169
  @files[identifier][:outputs] = {}
138
- file_compile_formats(file, filename, identifier, c)
170
+ file_compile_formats(file, filename, identifier)
139
171
  end
140
172
 
141
173
  def compile_options(identifier)
@@ -150,9 +182,9 @@ module Metanorma
150
182
  ret
151
183
  end
152
184
 
153
- def file_compile_formats(file, filename, identifier, compile)
185
+ def file_compile_formats(file, filename, identifier)
154
186
  @format.each do |e|
155
- ext = compile.processor.output_formats[e]
187
+ ext = @compile.processor.output_formats[e]
156
188
  fn = File.basename(filename).sub(/(?<=\.)[^.]+$/, ext.to_s)
157
189
  if /html$/.match?(ext) && @files[identifier][:sectionsplit]
158
190
  # file_sectionsplit_copy(file, fn, identifier, ext, e)
@@ -182,6 +214,7 @@ module Metanorma
182
214
  # process each file in the collection
183
215
  # files are held in memory, and altered as postprocessing
184
216
  def files # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
217
+ warn "\n\n\n\n\nInternal Refs: #{DateTime.now.strftime('%H:%M:%S')}"
185
218
  internal_refs = locate_internal_refs
186
219
  @files.each_with_index do |(identifier, x), i|
187
220
  i.positive? && Array(@directives).include?("bare-after-first") and
@@ -189,6 +222,7 @@ module Metanorma
189
222
  if x[:attachment] then copy_file_to_dest(x)
190
223
  else
191
224
  file, filename = targetfile(x, read: true)
225
+ warn "\n\n\n\n\nProcess #{filename}: #{DateTime.now.strftime('%H:%M:%S')}"
192
226
  file = update_xrefs(file, identifier, internal_refs)
193
227
  Tempfile.open(["collection", ".xml"], encoding: "utf-8") do |f|
194
228
  f.write(file)
@@ -47,9 +47,9 @@ module Metanorma
47
47
  def parse_docref(mnf)
48
48
  mnf.xpath("xmlns:docref").map do |dr|
49
49
  h = { "identifier" => dr.at("identifier").children.to_xml }
50
- dr[:fileref] and h["fileref"] = dr[:fileref]
51
- h["attachment"] = dr[:attachment] if dr[:attachment]
52
- h["sectionsplit"] = dr[:sectionsplit] if dr[:sectionsplit]
50
+ %i(fileref attachment sectionsplit index).each do |s|
51
+ h[s.to_s] = dr[s] if dr[s]
52
+ end
53
53
  h["presentation-xml"] = dr[:presentationxml] if dr[:presentationxml]
54
54
  h
55
55
  end
@@ -70,7 +70,7 @@ module Metanorma
70
70
 
71
71
  m[dr["identifier"]] = Document.parse_file(
72
72
  File.join(dir, dr["fileref"]),
73
- dr["attachment"], dr["identifier"]
73
+ dr["attachment"], dr["identifier"], dr["index"]
74
74
  )
75
75
  m
76
76
  end
@@ -118,10 +118,16 @@ module Metanorma
118
118
 
119
119
  def docref_to_xml_attrs(elem, docref)
120
120
  elem[:fileref] = @disambig.source2dest_filename(docref["fileref"])
121
- elem[:attachment] = docref["attachment"] if docref["attachment"]
122
- elem[:sectionsplit] = docref["sectionsplit"] if docref["sectionsplit"]
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"
123
125
  elem[:presentationxml] = "true" if docref["presentation-xml"] &&
124
- docref["presentation-xml"] == "true" || docref["presentation-xml"] == true
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)
125
131
  if collection.directives.include?("documents-inline")
126
132
  id = collection.documents.find_index do |k, _|
127
133
  k == docref["identifier"]
@@ -37,10 +37,12 @@ module Metanorma
37
37
  @coverpage = options[:coverpage]
38
38
  @format = Util.sort_extensions_execution(options[:format])
39
39
  @compile_options = options[:compile] || {}
40
+ @compile_options[:no_install_fonts] = true if options[:no_install_fonts]
40
41
  @log = options[:log]
41
42
  @documents = collection.documents
42
43
  @directives = collection.directives
43
44
  @disambig = Util::DisambigFiles.new
45
+ @compile = Compile.new
44
46
 
45
47
  # list of files in the collection
46
48
  @files = read_files folder
@@ -52,14 +54,20 @@ module Metanorma
52
54
  # @param col [Metanorma::Collection] XML collection
53
55
  # @param options [Hash]
54
56
  # @option options [String] :coverpage cover page HTML (Liquid template)
55
- # @option options [Array<Synbol>] :format list of formats
57
+ # @option options [Array<Symbol>] :format list of formats
56
58
  # @option options [Strong] :ourput_folder output directory
57
59
  def self.render(col, options = {})
58
60
  folder = File.dirname col.file
61
+ # require "byebug"; byebug
62
+ warn "\n\n\n\n\nRender Init: #{DateTime.now.strftime('%H:%M:%S')}"
59
63
  cr = new(col, folder, options)
64
+ warn "\n\n\n\n\nRender Files: #{DateTime.now.strftime('%H:%M:%S')}"
60
65
  cr.files
66
+ warn "\n\n\n\n\nConcatenate: #{DateTime.now.strftime('%H:%M:%S')}"
61
67
  cr.concatenate(col, options)
68
+ warn "\n\n\n\n\nCoverpage: #{DateTime.now.strftime('%H:%M:%S')}"
62
69
  cr.coverpage if options[:format]&.include?(:html)
70
+ warn "\n\n\n\n\nDone: #{DateTime.now.strftime('%H:%M:%S')}"
63
71
  end
64
72
 
65
73
  def concatenate(col, options)
@@ -71,7 +79,7 @@ module Metanorma
71
79
  out = col.clone
72
80
  out.directives << "documents-inline"
73
81
  out.documents.each_key do |id|
74
- next if @files[id][:attachment]
82
+ next if @files[id][:attachment] || @files[id][:outputs].nil?
75
83
 
76
84
  filename = @files[id][:outputs][e]
77
85
  out.documents[id] = Metanorma::Document.raw_file(filename)
@@ -171,7 +179,7 @@ module Metanorma
171
179
  # @param elm [Nokogiri::XML::Element]
172
180
  # @param builder [Nokogiri::XML::Builder]
173
181
  def indexfile_docref(elm, builder)
174
- return "" unless elm.at(ns("./docref"))
182
+ return "" unless elm.at(ns("./docref[@index = 'true']"))
175
183
 
176
184
  builder.ul { |b| docrefs(elm, b) }
177
185
  end
@@ -179,7 +187,7 @@ module Metanorma
179
187
  # @param elm [Nokogiri::XML::Element]
180
188
  # @param builder [Nokogiri::XML::Builder]
181
189
  def docrefs(elm, builder)
182
- elm.xpath(ns("./docref")).each do |d|
190
+ elm.xpath(ns("./docref[@index = 'true']")).each do |d|
183
191
  ident = d.at(ns("./identifier")).children.to_xml
184
192
  builder.li do |li|
185
193
  li.a **{ href: index_link(d, ident) } do |a|
@@ -7,6 +7,7 @@ require "fontist/manifest/install"
7
7
  require_relative "compile_validate"
8
8
  require_relative "fontist_utils"
9
9
  require_relative "util"
10
+ require_relative "sectionsplit"
10
11
 
11
12
  module Metanorma
12
13
  class Compile
@@ -16,6 +17,8 @@ module Metanorma
16
17
  def initialize
17
18
  @registry = Metanorma::Registry.instance
18
19
  @errors = []
20
+ @isodoc = IsoDoc::Convert.new({})
21
+ @fontist_installed = false
19
22
  end
20
23
 
21
24
  def compile(filename, options = {})
@@ -27,7 +30,8 @@ module Metanorma
27
30
  (file, isodoc = process_input(filename, options)) or return nil
28
31
  relaton_export(isodoc, options)
29
32
  extract(isodoc, options[:extract], options[:extract_type])
30
- FontistUtils.install_fonts(@processor, options)
33
+ FontistUtils.install_fonts(@processor, options) unless @fontist_installed
34
+ @fontist_installed = true
31
35
  process_extensions(extensions, file, isodoc, options)
32
36
  end
33
37
 
@@ -54,7 +58,7 @@ module Metanorma
54
58
  dir = filename.sub(%r(/[^/]+$), "/")
55
59
  options[:relaton] ||= "#{dir}/#{o[:relaton]}" if o[:relaton]
56
60
  options[:sourcecode] ||= "#{dir}/#{o[:sourcecode]}" if o[:sourcecode]
57
- options[:extension_keys] ||= o[:extensions]&.split(/,[ ]*/)&.map(&:to_sym)
61
+ options[:extension_keys] ||= o[:extensions]&.split(/, */)&.map(&:to_sym)
58
62
  options[:extension_keys] = nil if options[:extension_keys] == [:all]
59
63
  options[:format] ||= :asciidoc
60
64
  options[:filename] = filename
@@ -62,12 +66,10 @@ module Metanorma
62
66
  end
63
67
 
64
68
  def get_extensions(options)
65
- options[:extension_keys] ||= @processor.output_formats.reduce([]) do |memo, (k, _)|
66
- memo << k
67
- end
69
+ options[:extension_keys] ||=
70
+ @processor.output_formats.reduce([]) { |memo, (k, _)| memo << k }
68
71
  extensions = options[:extension_keys].reduce([]) do |memo, e|
69
- if @processor.output_formats[e]
70
- memo << e
72
+ if @processor.output_formats[e] then memo << e
71
73
  else
72
74
  message = "[metanorma] Error: #{e} format is not supported for this standard."
73
75
  @errors << message
@@ -85,26 +87,33 @@ module Metanorma
85
87
 
86
88
  def process_input(filename, options)
87
89
  case extname = File.extname(filename)
88
- when ".adoc"
89
- Util.log("[metanorma] Processing: AsciiDoc input.", :info)
90
- file = read_file(filename)
91
- options[:asciimath] and
92
- file.sub!(/^(=[^\n]+\n)/, "\\1:mn-keep-asciimath:\n")
93
- dir = File.dirname(filename)
94
- dir != "." and
95
- file.gsub!(/^include::/, "include::#{dir}/")
96
- [file, @processor.input_to_isodoc(file, filename, options)]
97
- when ".xml"
98
- Util.log("[metanorma] Processing: Metanorma XML input.", :info)
99
- # TODO NN: this is a hack -- we should provide/bridge the
100
- # document attributes in Metanorma XML
101
- ["", read_file(filename)]
90
+ when ".adoc" then process_input_adoc(filename, options)
91
+ when ".xml" then process_input_xml(filename, options)
102
92
  else
103
- Util.log("[metanorma] Error: file extension #{extname} is not supported.", :error)
93
+ Util.log("[metanorma] Error: file extension #{extname} "\
94
+ "is not supported.", :error)
104
95
  nil
105
96
  end
106
97
  end
107
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
+
108
117
  def read_file(filename)
109
118
  File.read(filename, encoding: "utf-8").gsub("\r\n", "\n")
110
119
  end
@@ -132,7 +141,7 @@ module Metanorma
132
141
  return unless dirname
133
142
 
134
143
  if extract_types.nil? || extract_types.empty?
135
- extract_types = [:sourcecode, :image, :requirement]
144
+ extract_types = %i[sourcecode image requirement]
136
145
  end
137
146
  FileUtils.rm_rf dirname
138
147
  FileUtils.mkdir_p dirname
@@ -157,7 +166,7 @@ module Metanorma
157
166
  xml.at("//image | //xmlns:image") or return
158
167
  FileUtils.mkdir_p "#{dirname}/image"
159
168
  xml.xpath("//image | //xmlns:image").each_with_index do |s, i|
160
- next unless /^data:image/.match s["src"]
169
+ next unless /^data:image/.match? s["src"]
161
170
 
162
171
  %r{^data:image/(?<imgtype>[^;]+);base64,(?<imgdata>.+)$} =~ s["src"]
163
172
  filename = s["filename"] || sprintf("image-%04d.%s", i, imgtype)
@@ -201,15 +210,18 @@ module Metanorma
201
210
  outfilename = f.sub(/\.[^.]+$/, ".#{file_extension}")
202
211
  isodoc_options = get_isodoc_options(file, options, ext)
203
212
  if ext == :rxl
204
- options[:relaton] = outfilename
205
- relaton_export(isodoc, options)
213
+ relaton_export(isodoc, options.merge(relaton: outfilename))
206
214
  elsif options[:passthrough_presentation_xml] && ext == :presentation
207
215
  FileUtils.cp f, presentationxml_name
216
+ elsif ext == :html && options[:sectionsplit]
217
+ sectionsplit_convert(xml_name, isodoc, outfilename, isodoc_options)
208
218
  else
209
219
  begin
210
- @processor.use_presentation_xml(ext) ?
211
- @processor.output(nil, presentationxml_name, outfilename, ext, isodoc_options) :
220
+ if @processor.use_presentation_xml(ext)
221
+ @processor.output(nil, presentationxml_name, outfilename, ext, isodoc_options)
222
+ else
212
223
  @processor.output(isodoc, xml_name, outfilename, ext, isodoc_options)
224
+ end
213
225
  rescue StandardError => e
214
226
  isodoc_error_process(e)
215
227
  end
@@ -233,8 +245,9 @@ module Metanorma
233
245
  isodoc_options = @processor.extract_options(file)
234
246
  isodoc_options[:datauriimage] = true if options[:datauriimage]
235
247
  isodoc_options[:sourcefilename] = options[:filename]
236
- isodoc_options[:bare] ||= options[:bare]
237
- isodoc_options[:sectionsplit] ||= options[:sectionsplit]
248
+ %i(bare sectionsplit no_install_fonts).each do |x|
249
+ isodoc_options[x] ||= options[x]
250
+ end
238
251
  if ext == :pdf
239
252
  floc = FontistUtils.fontist_font_locations(@processor, options) and
240
253
  isodoc_options[:mn2pdf] = { font_manifest_file: floc.path }
@@ -1,13 +1,15 @@
1
1
  module Metanorma
2
2
  class Document
3
3
  # @return [Strin]
4
- attr_reader :file, :attachment, :bibitem
4
+ attr_reader :file, :attachment, :bibitem, :index
5
5
 
6
6
  # @param bibitem [RelatonBib::BibliographicItem]
7
7
  def initialize(bibitem, file, options = {})
8
8
  @bibitem = bibitem
9
9
  @file = file
10
10
  @attachment = options[:attachment]
11
+ @index = options[:index]
12
+ @index = true if @index.nil?
11
13
  @raw = options[:raw]
12
14
  end
13
15
 
@@ -16,10 +18,11 @@ module Metanorma
16
18
  # @param attachment [Bool] is an attachment
17
19
  # @param identifier [String] is the identifier assigned the file
18
20
  # in the collection file
21
+ # @param index [Bool] is indication on whether to index this file in coverpage
19
22
  # @return [Metanorma::Document]
20
- def parse_file(file, attachment, identifier = nil)
23
+ def parse_file(file, attachment, identifier = nil, index = true)
21
24
  new(bibitem(file, attachment, identifier), file,
22
- { attachment: attachment })
25
+ { attachment: attachment, index: index })
23
26
  end
24
27
 
25
28
  # #param xml [Nokogiri::XML::Document, Nokogiri::XML::Element]
@@ -3,10 +3,7 @@
3
3
 
4
4
  module Metanorma
5
5
  class Processor
6
-
7
- attr_reader :short
8
- attr_reader :input_format
9
- attr_reader :asciidoctor_backend
6
+ attr_reader :short, :input_format, :asciidoctor_backend
10
7
 
11
8
  def initialize
12
9
  raise "This is an abstract class!"
@@ -16,7 +13,7 @@ module Metanorma
16
13
  {
17
14
  xml: "xml",
18
15
  presentation: "presentation.xml",
19
- rxl: "rxl"
16
+ rxl: "rxl",
20
17
  }
21
18
  end
22
19
 
@@ -36,7 +33,7 @@ module Metanorma
36
33
  end
37
34
  end
38
35
 
39
- def output(isodoc_node, inname, outname, format, options={})
36
+ def output(isodoc_node, _inname, outname, _format, _options = {})
40
37
  File.open(outname, "w:UTF-8") { |f| f.write(isodoc_node) }
41
38
  end
42
39
 
@@ -0,0 +1,270 @@
1
+ require "yaml"
2
+
3
+ module Metanorma
4
+ class Compile
5
+ # assume we pass in Presentation XML, but we want to recover Semantic XML
6
+ def sectionsplit_convert(input_filename, file, output_filename = nil,
7
+ opts = {})
8
+ @isodoc = IsoDoc::Convert.new({})
9
+ input_filename += ".xml" unless input_filename.match?(/\.xml$/)
10
+ File.exist?(input_filename) or
11
+ File.open(input_filename, "w:UTF-8") { |f| f.write(file) }
12
+ presxml = File.read(input_filename, encoding: "utf-8")
13
+ @openmathdelim, @closemathdelim = @isodoc.extract_delims(presxml)
14
+ xml, filename, dir = @isodoc.convert_init(presxml, input_filename, false)
15
+ build_collection(xml, presxml, output_filename || filename, dir, opts)
16
+ end
17
+
18
+ def ns(xpath)
19
+ @isodoc.ns(xpath)
20
+ end
21
+
22
+ def build_collection(xml, presxml, filename, dir, opts = {})
23
+ base = File.basename(filename)
24
+ collection_setup(base, dir)
25
+ files = sectionsplit(xml, base, dir)
26
+ collection_manifest(base, files, xml, presxml, dir).render(
27
+ { format: %i(html), output_folder: "#{filename}_collection",
28
+ coverpage: File.join(dir, "cover.html") }.merge(opts),
29
+ )
30
+ end
31
+
32
+ def collection_manifest(filename, files, origxml, _presxml, dir)
33
+ File.open(File.join(dir, "#{filename}.html.yaml"), "w:UTF-8") do |f|
34
+ f.write(collectionyaml(files, origxml))
35
+ end
36
+ Metanorma::Collection.parse File.join(dir, "#{filename}.html.yaml")
37
+ end
38
+
39
+ def collection_setup(filename, dir)
40
+ FileUtils.mkdir_p "#{filename}_collection" if filename
41
+ FileUtils.mkdir_p dir
42
+ File.open(File.join(dir, "cover.html"), "w:UTF-8") do |f|
43
+ f.write(coll_cover)
44
+ end
45
+ end
46
+
47
+ def coll_cover
48
+ <<~COVER
49
+ <html>
50
+ <head/>
51
+ <body>
52
+ <h1>{{ doctitle }}</h1>
53
+ <h2>{{ docnumber }}</h2>
54
+ <nav>{{ labels["navigation"] }}</nav>
55
+ </body>
56
+ </html>
57
+ COVER
58
+ end
59
+
60
+ SPLITSECTIONS =
61
+ [["//preface/*", "preface"], ["//sections/*", "sections"],
62
+ ["//annex", nil],
63
+ ["//bibliography/*[not(@hidden = 'true')]", "bibliography"],
64
+ ["//indexsect", nil]].freeze
65
+
66
+ def sectionsplit(xml, filename, dir)
67
+ @key = xref_preprocess(xml)
68
+ @splitdir = dir
69
+ out = emptydoc(xml)
70
+ SPLITSECTIONS.each_with_object([]) do |n, ret|
71
+ xml.xpath(ns(n[0])).each do |s|
72
+ ret << sectionfile(xml, out, "#{filename}.#{ret.size}", s, n[1])
73
+ end
74
+ end
75
+ end
76
+
77
+ def emptydoc(xml)
78
+ out = xml.dup
79
+ out.xpath(
80
+ ns("//preface | //sections | //annex | //bibliography/clause | "\
81
+ "//bibliography/references[not(@hidden = 'true')] | //indexsect"),
82
+ ).each(&:remove)
83
+ out
84
+ end
85
+
86
+ def sectionfile(fulldoc, xml, file, chunk, parentnode)
87
+ fname = create_sectionfile(fulldoc, xml.dup, file, chunk, parentnode)
88
+ { order: chunk["displayorder"].to_i, url: fname,
89
+ title: titlerender(chunk) }
90
+ end
91
+
92
+ def create_sectionfile(xml, out, file, chunk, parentnode)
93
+ ins = out.at(ns("//misccontainer")) || out.at(ns("//bibdata"))
94
+ if parentnode
95
+ ins.next = "<#{parentnode}/>"
96
+ ins.next.add_child(chunk.dup)
97
+ else ins.next = chunk.dup
98
+ end
99
+ xref_process(out, xml, @key)
100
+ outname = "#{file}.xml"
101
+ File.open(File.join(@splitdir, outname), "w:UTF-8") { |f| f.write(out) }
102
+ outname
103
+ end
104
+
105
+ # def xref_preprocess(xml)
106
+ # svg_preprocess(xml)
107
+ # key = (0...8).map { rand(65..90).chr }.join # random string
108
+ # xml.root["type"] = key # to force recognition of internal refs
109
+ # refs = eref_to_internal_eref(xml, key)
110
+ # refs += xref_to_internal_eref(xml, key)
111
+ # ins = new_hidden_ref(xml)
112
+ # copy_repo_items_biblio(ins, xml)
113
+ # insert_indirect_biblio(ins, refs, key)
114
+ # end
115
+
116
+ def xref_preprocess(xml)
117
+ svg_preprocess(xml)
118
+ key = (0...8).map { rand(65..90).chr }.join # random string
119
+ xml.root["type"] = key # to force recognition of internal refs
120
+ key
121
+ end
122
+
123
+ def xref_process(section, xml, key)
124
+ refs = eref_to_internal_eref(section, xml, key)
125
+ refs += xref_to_internal_eref(section, key)
126
+ ins = new_hidden_ref(section)
127
+ copied_refs = copy_repo_items_biblio(ins, section, xml)
128
+ insert_indirect_biblio(ins, refs - copied_refs, key)
129
+ end
130
+
131
+ def svg_preprocess(xml)
132
+ xml.xpath("//m:svg", "m" => "http://www.w3.org/2000/svg").each do |s|
133
+ m = svgmap_wrap(s)
134
+ s.xpath(".//m:a", "m" => "http://www.w3.org/2000/svg").each do |a|
135
+ next unless /^#/.match? a["href"]
136
+
137
+ a["href"] = a["href"].sub(/^#/, "")
138
+ m << "<target href='#{a['href']}'>"\
139
+ "<xref target='#{a['href']}'/></target>"
140
+ end
141
+ end
142
+ end
143
+
144
+ def svgmap_wrap(svg)
145
+ ret = svg.at("./ancestor::xmlns:svgmap") and return ret
146
+ ret = svg.at("./ancestor::xmlns:figure")
147
+ ret.wrap("<svgmap/>")
148
+ svg.at("./ancestor::xmlns:svgmap")
149
+ end
150
+
151
+ def make_anchor(anchor)
152
+ "<localityStack><locality type='anchor'><referenceFrom>"\
153
+ "#{anchor}</referenceFrom></locality></localityStack>"
154
+ end
155
+
156
+ def xref_to_internal_eref(xml, key)
157
+ xml.xpath(ns("//xref")).each_with_object({}) do |x, m|
158
+ x["bibitemid"] = "#{key}_#{x['target']}"
159
+ x << make_anchor(x["target"])
160
+ m[x["bibitemid"]] = true
161
+ x.delete("target")
162
+ x["type"] = key
163
+ x.name = "eref"
164
+ end.keys
165
+ end
166
+
167
+ def eref_to_internal_eref(section, xml, key)
168
+ eref_to_internal_eref_select(section, xml).each_with_object([]) do |x, m|
169
+ url = xml.at(ns("//bibitem[@id = '#{x}']/url[@type = 'citation']"))
170
+ section.xpath(("//*[@bibitemid = '#{x}']")).each do |e|
171
+ id = eref_to_internal_eref1(e, key, url)
172
+ id and m << id
173
+ end
174
+ end
175
+ end
176
+
177
+ def eref_to_internal_eref1(elem, key, url)
178
+ if url
179
+ elem.name = "link"
180
+ elem["target"] = url
181
+ nil
182
+ else
183
+ elem["bibitemid"] = "#{key}_#{elem['bibitemid']}"
184
+ elem << make_anchor(elem["bibitemid"])
185
+ elem["type"] = key
186
+ elem["bibitemid"]
187
+ end
188
+ end
189
+
190
+ def eref_to_internal_eref_select(section, xml)
191
+ refs = section.xpath(("//*/@bibitemid")).map { |x| x.text } # rubocop:disable Style/SymbolProc
192
+ refs.uniq.reject do |x|
193
+ xml.at(ns("//bibitem[@id = '#{x}'][@type = 'internal']")) ||
194
+ xml.at(ns("//bibitem[@id = '#{x}']"\
195
+ "[docidentifier/@type = 'repository']"))
196
+ end
197
+ end
198
+
199
+ # from standoc
200
+ def new_hidden_ref(xmldoc)
201
+ ins = xmldoc.at("bibliography") or
202
+ xmldoc.root << "<bibliography/>" and ins = xmldoc.at("bibliography")
203
+ ins.add_child("<references hidden='true' normative='false'/>").first
204
+ end
205
+
206
+ def copy_repo_items_biblio(ins, section, xml)
207
+ xml.xpath(ns("//references/bibitem[docidentifier/@type = 'repository']"))
208
+ .each_with_object([]) do |b, m|
209
+ section.at("//*[@bibitemid = '#{b['id']}']") or next
210
+ ins << b.dup
211
+ m << b["id"]
212
+ end
213
+ end
214
+
215
+ def insert_indirect_biblio(ins, refs, prefix)
216
+ refs.each do |x|
217
+ ins << <<~BIBENTRY
218
+ <bibitem id="#{x}" type="internal">
219
+ <docidentifier type="repository">#{x.sub(/^#{prefix}_/, "#{prefix}/")}</docidentifier>
220
+ </bibitem>
221
+ BIBENTRY
222
+ end
223
+ end
224
+
225
+ def recursive_string_keys(hash)
226
+ case hash
227
+ when Hash then Hash[
228
+ hash.map { |k, v| [k.to_s, recursive_string_keys(v)] }
229
+ ]
230
+ when Enumerable then hash.map { |v| recursive_string_keys(v) }
231
+ else
232
+ hash
233
+ end
234
+ end
235
+
236
+ def titlerender(section)
237
+ title = section.at(ns("./title")) or return "[Untitled]"
238
+ t = title.dup
239
+ t.xpath(ns(".//tab | .//br")).each { |x| x.replace(" ") }
240
+ t.xpath(ns(".//strong")).each { |x| x.replace(x.children) }
241
+ t.children.to_xml
242
+ end
243
+
244
+ def collectionyaml(files, xml)
245
+ ret = {
246
+ directives: ["presentation-xml", "bare-after-first"],
247
+ bibdata: {
248
+ title: {
249
+ type: "title-main",
250
+ language: @lang,
251
+ content: xml.at(ns("//bibdata/title")).text,
252
+ },
253
+ type: "collection",
254
+ docid: {
255
+ type: xml.at(ns("//bibdata/docidentifier/@type")).text,
256
+ id: xml.at(ns("//bibdata/docidentifier")).text,
257
+ },
258
+ },
259
+ manifest: {
260
+ level: "collection",
261
+ title: "Collection",
262
+ docref: files.sort_by { |f| f[:order] }.each.map do |f|
263
+ { fileref: f[:url], identifier: f[:title] }
264
+ end,
265
+ },
266
+ }
267
+ recursive_string_keys(ret).to_yaml
268
+ end
269
+ end
270
+ end
@@ -1,3 +1,3 @@
1
1
  module Metanorma
2
- VERSION = "1.3.7".freeze
2
+ VERSION = "1.3.8".freeze
3
3
  end
data/metanorma.gemspec CHANGED
@@ -23,7 +23,7 @@ Gem::Specification.new do |spec|
23
23
  spec.required_ruby_version = ">= 2.5.0"
24
24
 
25
25
  spec.add_runtime_dependency "asciidoctor"
26
- spec.add_runtime_dependency "fontist", "~> 1.9"
26
+ spec.add_runtime_dependency "fontist", "~> 1.9.0"
27
27
  spec.add_runtime_dependency "htmlentities"
28
28
  spec.add_runtime_dependency "metanorma-utils", "~> 1.2.0"
29
29
  spec.add_runtime_dependency "mn2pdf", "~> 1"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: metanorma
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.3.7
4
+ version: 1.3.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ribose Inc.
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-07-19 00:00:00.000000000 Z
11
+ date: 2021-08-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: asciidoctor
@@ -30,14 +30,14 @@ dependencies:
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: '1.9'
33
+ version: 1.9.0
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: '1.9'
40
+ version: 1.9.0
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: htmlentities
43
43
  requirement: !ruby/object:Gem::Requirement
@@ -278,13 +278,9 @@ files:
278
278
  - lib/metanorma/input.rb
279
279
  - lib/metanorma/input/asciidoc.rb
280
280
  - lib/metanorma/input/base.rb
281
- - lib/metanorma/output.rb
282
- - lib/metanorma/output/base.rb
283
- - lib/metanorma/output/pdf.rb
284
- - lib/metanorma/output/utils.rb
285
- - lib/metanorma/output/xslfo.rb
286
281
  - lib/metanorma/processor.rb
287
282
  - lib/metanorma/registry.rb
283
+ - lib/metanorma/sectionsplit.rb
288
284
  - lib/metanorma/util.rb
289
285
  - lib/metanorma/version.rb
290
286
  - metanorma.gemspec
@@ -1,8 +0,0 @@
1
- require_relative "./output/base"
2
- require_relative "./output/pdf"
3
- require_relative "./output/xslfo"
4
-
5
- module Metanorma
6
- module Output
7
- end
8
- end
@@ -1,13 +0,0 @@
1
-
2
- module Metanorma
3
- module Output
4
-
5
- class Base
6
-
7
- def convert(in_path, out_path)
8
- raise "This is an abstract class"
9
- end
10
-
11
- end
12
- end
13
- end
@@ -1,32 +0,0 @@
1
- require "open3"
2
- require_relative "./utils.rb"
3
- require "pathname"
4
- require "shellwords"
5
-
6
- module Metanorma
7
- module Output
8
- class Pdf < Base
9
-
10
- def convert(url_path, output_path)
11
- file_url = Utils::file_path(url_path)
12
- pdfjs = File.join(File.dirname(__FILE__), "../../../bin/metanorma-pdf.js")
13
-
14
- node_path = ENV["NODE_PATH"] || `npm root --quiet -g`.strip
15
- node_cmd = ["node", pdfjs, file_url, output_path].map { |arg| shellescape(arg) }.join(" ")
16
-
17
- _, error_str, status = Open3.capture3({ "NODE_PATH" => node_path }, node_cmd)
18
- raise error_str unless status.success?
19
- end
20
-
21
- def shellescape(str)
22
- if Gem.win_platform?()
23
- # https://bugs.ruby-lang.org/issues/16741
24
- str.match(" ") ? "\"#{str}\"" : str
25
- else
26
- Shellwords.shellescape(str)
27
- end
28
- end
29
- end
30
- end
31
- end
32
-
@@ -1,17 +0,0 @@
1
- require "pathname"
2
-
3
- module Metanorma
4
- module Output
5
- module Utils
6
- class << self
7
- def file_path(url_path)
8
- file_url = url_path
9
- file_url = "file://#{url_path}" if Pathname.new(file_url).absolute?
10
- %r{^file://}.match?(file_url) or
11
- file_url = "file://#{Dir.pwd}/#{url_path}"
12
- file_url
13
- end
14
- end
15
- end
16
- end
17
- end
@@ -1,21 +0,0 @@
1
- require 'mn2pdf'
2
- require_relative "./utils.rb"
3
-
4
- module Metanorma
5
- module Output
6
- class XslfoPdf < Base
7
- def convert(url_path, output_path, xsl_stylesheet, options = "")
8
- return if url_path.nil? || output_path.nil? || xsl_stylesheet.nil?
9
-
10
- Mn2pdf.convert(quote(url_path), quote(output_path), quote(xsl_stylesheet), options)
11
- end
12
-
13
- def quote(x)
14
- return x if /^'.*'$/.match(x)
15
- return x if /^".*"$/.match(x)
16
- %("#{x}")
17
- end
18
- end
19
- end
20
- end
21
-