metanorma 1.3.7 → 1.3.10

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: 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