metanorma 1.3.7 → 1.3.10

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: 6d4f9b74f28f5e648c39c900b79ff848bf734e766660a5e5afd1a3cb8ba3a7c5
4
+ data.tar.gz: a17f035b32e2ddf23a4c75d31ae72f943ade4c855120ddda363eab740cd06434
5
5
  SHA512:
6
- metadata.gz: 4618e5ebe7f688ae9eec5680d0f17aa2795391e1485e749f975052952378742a0c29be722e46aef10c34432a658294bb06c5eac945c56a27c65c8ab7aedc944b
7
- data.tar.gz: e0b3b3ac8846b3d6ecd1fb75691d525f3763c126d2c1db3469c1192c93a14f9a168ec75f2a851f92260334c514704072cc9a59c360034d8de578ca37a2bebf24
6
+ metadata.gz: 2217e729035269240af9d942155eea00dc6b817a5bfa6315e4fb0eabefa90ce47de17e65ca4211e03cd2d25b4d0ee68d7f1a76fce831b6a2797081bd8ac46495
7
+ data.tar.gz: 7e7062afc29acec9ffe4a20af4c6b59611f496c522cd2ce788b43647e8c5d330fc76364aadcf08fb0662a642605119778187208da8be46e97fa2c360269faa02
@@ -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, dir_name_cleanse(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"]
@@ -33,14 +33,16 @@ module Metanorma
33
33
  # output processor for flavour
34
34
  @isodoc = isodoc
35
35
 
36
- @outdir = options[:output_folder]
36
+ @outdir = dir_name_cleanse(options[:output_folder])
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
@@ -49,17 +51,27 @@ module Metanorma
49
51
  FileUtils.mkdir_p @outdir
50
52
  end
51
53
 
54
+ def dir_name_cleanse(name)
55
+ name.gsub(/[<>:"|?*]/, "_")
56
+ end
57
+
52
58
  # @param col [Metanorma::Collection] XML collection
53
59
  # @param options [Hash]
54
60
  # @option options [String] :coverpage cover page HTML (Liquid template)
55
- # @option options [Array<Synbol>] :format list of formats
61
+ # @option options [Array<Symbol>] :format list of formats
56
62
  # @option options [Strong] :ourput_folder output directory
57
63
  def self.render(col, options = {})
58
64
  folder = File.dirname col.file
65
+ # require "byebug"; byebug
66
+ warn "\n\n\n\n\nRender Init: #{DateTime.now.strftime('%H:%M:%S')}"
59
67
  cr = new(col, folder, options)
68
+ warn "\n\n\n\n\nRender Files: #{DateTime.now.strftime('%H:%M:%S')}"
60
69
  cr.files
70
+ warn "\n\n\n\n\nConcatenate: #{DateTime.now.strftime('%H:%M:%S')}"
61
71
  cr.concatenate(col, options)
72
+ warn "\n\n\n\n\nCoverpage: #{DateTime.now.strftime('%H:%M:%S')}"
62
73
  cr.coverpage if options[:format]&.include?(:html)
74
+ warn "\n\n\n\n\nDone: #{DateTime.now.strftime('%H:%M:%S')}"
63
75
  end
64
76
 
65
77
  def concatenate(col, options)
@@ -71,7 +83,7 @@ module Metanorma
71
83
  out = col.clone
72
84
  out.directives << "documents-inline"
73
85
  out.documents.each_key do |id|
74
- next if @files[id][:attachment]
86
+ next if @files[id][:attachment] || @files[id][:outputs].nil?
75
87
 
76
88
  filename = @files[id][:outputs][e]
77
89
  out.documents[id] = Metanorma::Document.raw_file(filename)
@@ -171,7 +183,7 @@ module Metanorma
171
183
  # @param elm [Nokogiri::XML::Element]
172
184
  # @param builder [Nokogiri::XML::Builder]
173
185
  def indexfile_docref(elm, builder)
174
- return "" unless elm.at(ns("./docref"))
186
+ return "" unless elm.at(ns("./docref[@index = 'true']"))
175
187
 
176
188
  builder.ul { |b| docrefs(elm, b) }
177
189
  end
@@ -179,7 +191,7 @@ module Metanorma
179
191
  # @param elm [Nokogiri::XML::Element]
180
192
  # @param builder [Nokogiri::XML::Builder]
181
193
  def docrefs(elm, builder)
182
- elm.xpath(ns("./docref")).each do |d|
194
+ elm.xpath(ns("./docref[@index = 'true']")).each do |d|
183
195
  ident = d.at(ns("./identifier")).children.to_xml
184
196
  builder.li do |li|
185
197
  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
 
@@ -48,13 +52,13 @@ module Metanorma
48
52
  def options_extract(filename, options)
49
53
  content = read_file(filename)
50
54
  o = Metanorma::Input::Asciidoc.new.extract_metanorma_options(content)
51
- o = o.merge(xml_options_extract(content))
55
+ .merge(xml_options_extract(content))
52
56
  options[:type] ||= o[:type]&.to_sym
53
57
  t = @registry.alias(options[:type]) and options[:type] = t
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
@@ -121,9 +130,7 @@ module Metanorma
121
130
 
122
131
  def clean_sourcecode(xml)
123
132
  xml.xpath(".//callout | .//annotation | .//xmlns:callout | "\
124
- ".//xmlns:annotation").each do |x|
125
- x.remove
126
- end
133
+ ".//xmlns:annotation").each(&:remove)
127
134
  xml.xpath(".//br | .//xmlns:br").each { |x| x.replace("\n") }
128
135
  HTMLEntities.new.decode(xml.children.to_xml)
129
136
  end
@@ -132,7 +139,7 @@ module Metanorma
132
139
  return unless dirname
133
140
 
134
141
  if extract_types.nil? || extract_types.empty?
135
- extract_types = [:sourcecode, :image, :requirement]
142
+ extract_types = %i[sourcecode image requirement]
136
143
  end
137
144
  FileUtils.rm_rf dirname
138
145
  FileUtils.mkdir_p dirname
@@ -157,7 +164,7 @@ module Metanorma
157
164
  xml.at("//image | //xmlns:image") or return
158
165
  FileUtils.mkdir_p "#{dirname}/image"
159
166
  xml.xpath("//image | //xmlns:image").each_with_index do |s, i|
160
- next unless /^data:image/.match s["src"]
167
+ next unless /^data:image/.match? s["src"]
161
168
 
162
169
  %r{^data:image/(?<imgtype>[^;]+);base64,(?<imgdata>.+)$} =~ s["src"]
163
170
  filename = s["filename"] || sprintf("image-%04d.%s", i, imgtype)
@@ -168,8 +175,8 @@ module Metanorma
168
175
  end
169
176
 
170
177
  REQUIREMENT_XPATH = "//requirement | //xmlns:requirement | "\
171
- "//recommendation | //xmlns:recommendation | //permission | "\
172
- "//xmlns:permission".freeze
178
+ "//recommendation | //xmlns:recommendation | //permission | "\
179
+ "//xmlns:permission".freeze
173
180
 
174
181
  def requirement_export(xml, dirname)
175
182
  xml.at(REQUIREMENT_XPATH) or return
@@ -201,15 +208,20 @@ module Metanorma
201
208
  outfilename = f.sub(/\.[^.]+$/, ".#{file_extension}")
202
209
  isodoc_options = get_isodoc_options(file, options, ext)
203
210
  if ext == :rxl
204
- options[:relaton] = outfilename
205
- relaton_export(isodoc, options)
211
+ relaton_export(isodoc, options.merge(relaton: outfilename))
206
212
  elsif options[:passthrough_presentation_xml] && ext == :presentation
207
213
  FileUtils.cp f, presentationxml_name
214
+ elsif ext == :html && options[:sectionsplit]
215
+ sectionsplit_convert(xml_name, isodoc, outfilename, isodoc_options)
208
216
  else
209
217
  begin
210
- @processor.use_presentation_xml(ext) ?
211
- @processor.output(nil, presentationxml_name, outfilename, ext, isodoc_options) :
212
- @processor.output(isodoc, xml_name, outfilename, ext, isodoc_options)
218
+ if @processor.use_presentation_xml(ext)
219
+ @processor.output(nil, presentationxml_name, outfilename, ext,
220
+ isodoc_options)
221
+ else
222
+ @processor.output(isodoc, xml_name, outfilename, ext,
223
+ 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]
@@ -75,6 +75,7 @@ module Metanorma
75
75
  /\n:(?<hier_assets>hierarchical-assets:[^\n]*)\n/ =~ header
76
76
  /\n:(?<use_xinclude>use-xinclude:[^\n]*)\n/ =~ header
77
77
  /\n:(?<break_up>break-up-urls-in-tables:[^\n]*)\n/ =~ header
78
+ /\n:suppress-asciimath-dup: (?<suppress_asciimath_dup>[^\n]+)\n/ =~ header
78
79
 
79
80
  defined?(hier_assets) and
80
81
  hier_assets = empty_attr(hier_assets, "hierarchical-assets")
@@ -84,6 +85,7 @@ module Metanorma
84
85
  break_up = empty_attr(break_up, "break-up-urls-in-tables")
85
86
  ret.merge(
86
87
  datauriimage: defined?(datauriimage) ? datauriimage != "false" : nil,
88
+ suppressasciimathdup: defined?(suppress_asciimath_dup) ? suppress_asciimath_dup != "false" : nil,
87
89
  hierarchical_assets: defined?(hier_assets) ? hier_assets : nil,
88
90
  use_xinclude: defined?(use_xinclude) ? use_xinclude : nil,
89
91
  break_up_urls_in_tables: defined?(break_up) ? break_up : nil,
@@ -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,254 @@
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><head/>
50
+ <body>
51
+ <h1>{{ doctitle }}</h1>
52
+ <h2>{{ docnumber }}</h2>
53
+ <nav>{{ labels["navigation"] }}</nav>
54
+ </body>
55
+ </html>
56
+ COVER
57
+ end
58
+
59
+ SPLITSECTIONS =
60
+ [["//preface/*", "preface"], ["//sections/*", "sections"],
61
+ ["//annex", nil],
62
+ ["//bibliography/*[not(@hidden = 'true')]", "bibliography"],
63
+ ["//indexsect", nil]].freeze
64
+
65
+ def sectionsplit(xml, filename, dir)
66
+ @key = xref_preprocess(xml)
67
+ @splitdir = dir
68
+ out = emptydoc(xml)
69
+ SPLITSECTIONS.each_with_object([]) do |n, ret|
70
+ xml.xpath(ns(n[0])).each do |s|
71
+ ret << sectionfile(xml, out, "#{filename}.#{ret.size}", s, n[1])
72
+ end
73
+ end
74
+ end
75
+
76
+ def emptydoc(xml)
77
+ out = xml.dup
78
+ out.xpath(
79
+ ns("//preface | //sections | //annex | //bibliography/clause | "\
80
+ "//bibliography/references[not(@hidden = 'true')] | //indexsect"),
81
+ ).each(&:remove)
82
+ out
83
+ end
84
+
85
+ def sectionfile(fulldoc, xml, file, chunk, parentnode)
86
+ fname = create_sectionfile(fulldoc, xml.dup, file, chunk, parentnode)
87
+ { order: chunk["displayorder"].to_i, url: fname,
88
+ title: titlerender(chunk) }
89
+ end
90
+
91
+ def create_sectionfile(xml, out, file, chunk, parentnode)
92
+ ins = out.at(ns("//misccontainer")) || out.at(ns("//bibdata"))
93
+ if parentnode
94
+ ins.next = "<#{parentnode}/>"
95
+ ins.next.add_child(chunk.dup)
96
+ else ins.next = chunk.dup
97
+ end
98
+ xref_process(out, xml, @key)
99
+ outname = "#{file}.xml"
100
+ File.open(File.join(@splitdir, outname), "w:UTF-8") { |f| f.write(out) }
101
+ outname
102
+ end
103
+
104
+ def xref_preprocess(xml)
105
+ svg_preprocess(xml)
106
+ key = (0...8).map { rand(65..90).chr }.join # random string
107
+ xml.root["type"] = key # to force recognition of internal refs
108
+ key
109
+ end
110
+
111
+ def xref_process(section, xml, key)
112
+ refs = eref_to_internal_eref(section, xml, key)
113
+ refs += xref_to_internal_eref(section, key)
114
+ ins = new_hidden_ref(section)
115
+ copied_refs = copy_repo_items_biblio(ins, section, xml)
116
+ insert_indirect_biblio(ins, refs - copied_refs, key)
117
+ end
118
+
119
+ def svg_preprocess(xml)
120
+ xml.xpath("//m:svg", "m" => "http://www.w3.org/2000/svg").each do |s|
121
+ m = svgmap_wrap(s)
122
+ s.xpath(".//m:a", "m" => "http://www.w3.org/2000/svg").each do |a|
123
+ next unless /^#/.match? a["href"]
124
+
125
+ a["href"] = a["href"].sub(/^#/, "")
126
+ m << "<target href='#{a['href']}'>"\
127
+ "<xref target='#{a['href']}'/></target>"
128
+ end
129
+ end
130
+ end
131
+
132
+ def svgmap_wrap(svg)
133
+ ret = svg.at("./ancestor::xmlns:svgmap") and return ret
134
+ ret = svg.at("./ancestor::xmlns:figure")
135
+ ret.wrap("<svgmap/>")
136
+ svg.at("./ancestor::xmlns:svgmap")
137
+ end
138
+
139
+ def make_anchor(anchor)
140
+ "<localityStack><locality type='anchor'><referenceFrom>"\
141
+ "#{anchor}</referenceFrom></locality></localityStack>"
142
+ end
143
+
144
+ def xref_to_internal_eref(xml, key)
145
+ xml.xpath(ns("//xref")).each_with_object({}) do |x, m|
146
+ x["bibitemid"] = "#{key}_#{x['target']}"
147
+ x << make_anchor(x["target"])
148
+ m[x["bibitemid"]] = true
149
+ x.delete("target")
150
+ x["type"] = key
151
+ x.name = "eref"
152
+ end.keys
153
+ end
154
+
155
+ def eref_to_internal_eref(section, xml, key)
156
+ eref_to_internal_eref_select(section, xml).each_with_object([]) do |x, m|
157
+ url = xml.at(ns("//bibitem[@id = '#{x}']/url[@type = 'citation']"))
158
+ section.xpath(("//*[@bibitemid = '#{x}']")).each do |e|
159
+ id = eref_to_internal_eref1(e, key, url)
160
+ id and m << id
161
+ end
162
+ end
163
+ end
164
+
165
+ def eref_to_internal_eref1(elem, key, url)
166
+ if url
167
+ elem.name = "link"
168
+ elem["target"] = url
169
+ nil
170
+ else
171
+ elem["bibitemid"] = "#{key}_#{elem['bibitemid']}"
172
+ elem << make_anchor(elem["bibitemid"])
173
+ elem["type"] = key
174
+ elem["bibitemid"]
175
+ end
176
+ end
177
+
178
+ def eref_to_internal_eref_select(section, xml)
179
+ refs = section.xpath(("//*/@bibitemid")).map { |x| x.text } # rubocop:disable Style/SymbolProc
180
+ refs.uniq.reject do |x|
181
+ xml.at(ns("//bibitem[@id = '#{x}'][@type = 'internal']")) ||
182
+ xml.at(ns("//bibitem[@id = '#{x}']"\
183
+ "[docidentifier/@type = 'repository']"))
184
+ end
185
+ end
186
+
187
+ # from standoc
188
+ def new_hidden_ref(xmldoc)
189
+ ins = xmldoc.at("bibliography") or
190
+ xmldoc.root << "<bibliography/>" and ins = xmldoc.at("bibliography")
191
+ ins.add_child("<references hidden='true' normative='false'/>").first
192
+ end
193
+
194
+ def copy_repo_items_biblio(ins, section, xml)
195
+ xml.xpath(ns("//references/bibitem[docidentifier/@type = 'repository']"))
196
+ .each_with_object([]) do |b, m|
197
+ section.at("//*[@bibitemid = '#{b['id']}']") or next
198
+ ins << b.dup
199
+ m << b["id"]
200
+ end
201
+ end
202
+
203
+ def insert_indirect_biblio(ins, refs, prefix)
204
+ refs.each do |x|
205
+ ins << <<~BIBENTRY
206
+ <bibitem id="#{x}" type="internal">
207
+ <docidentifier type="repository">#{x.sub(/^#{prefix}_/, "#{prefix}/")}</docidentifier>
208
+ </bibitem>
209
+ BIBENTRY
210
+ end
211
+ end
212
+
213
+ def recursive_string_keys(hash)
214
+ case hash
215
+ when Hash then hash.map { |k, v| [k.to_s, recursive_string_keys(v)] }.to_h
216
+ when Enumerable then hash.map { |v| recursive_string_keys(v) }
217
+ else
218
+ hash
219
+ end
220
+ end
221
+
222
+ def titlerender(section)
223
+ title = section.at(ns("./title")) or return "[Untitled]"
224
+ t = title.dup
225
+ t.xpath(ns(".//tab | .//br")).each { |x| x.replace(" ") }
226
+ t.xpath(ns(".//strong")).each { |x| x.replace(x.children) }
227
+ t.children.to_xml
228
+ end
229
+
230
+ def collectionyaml(files, xml)
231
+ ret = {
232
+ directives: ["presentation-xml", "bare-after-first"],
233
+ bibdata: {
234
+ title: {
235
+ type: "title-main", language: @lang,
236
+ content: xml.at(ns("//bibdata/title")).text
237
+ },
238
+ type: "collection",
239
+ docid: {
240
+ type: xml.at(ns("//bibdata/docidentifier/@type")).text,
241
+ id: xml.at(ns("//bibdata/docidentifier")).text,
242
+ },
243
+ },
244
+ manifest: {
245
+ level: "collection", title: "Collection",
246
+ docref: files.sort_by { |f| f[:order] }.each.map do |f|
247
+ { fileref: f[:url], identifier: f[:title] }
248
+ end
249
+ },
250
+ }
251
+ recursive_string_keys(ret).to_yaml
252
+ end
253
+ end
254
+ end
@@ -1,3 +1,3 @@
1
1
  module Metanorma
2
- VERSION = "1.3.7".freeze
2
+ VERSION = "1.3.10".freeze
3
3
  end
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"
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.11"
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.10
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-30 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.11'
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.11'
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,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
-
@@ -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