metanorma 1.3.7 → 1.3.8

Sign up to get free protection for your applications and to get access to all the features.
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
-