metanorma 1.3.6 → 1.3.9.1

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: 1858cecb1db05debaa3cb36f970a2bcb76b403508067ea2fa8569720fd294a98
4
- data.tar.gz: 90f6e4bca7bd431a9d40a989c77837e6cfa47a12e436e0934624592bac0707f0
3
+ metadata.gz: 9a9807dfd686937050274493eff01bd863f032f237dad7baff1c027a0fa75561
4
+ data.tar.gz: 901710c9e8e1ac28c417d859ded7bc930da149ff01220319053583eb518751d1
5
5
  SHA512:
6
- metadata.gz: 8aec70e8a44751d4ab8557b793718c0bd02be3d90715a0048864257a8faf4bf23a5f4b60b780cf6d24658179eb2ecb572bf8b870ca9313b5d6f70839d2df03a5
7
- data.tar.gz: 58814116504a8ec8c80961e836adf50b7e50bc049d2a259031e7dc92b9a8f8909ddd8bbc26219197057a6e4a9dfec4ee05cb16144f1b69fdfdc66d46d9408e9b
6
+ metadata.gz: afe50ca043b69ba258442f8061011492cd53b272c42cd1b386da20781df61348dca788147debac44d4477d3381725f44e956881417d38c8a60cfcec7835de756
7
+ data.tar.gz: 0e1696dab391b92724517eadfc307d7cd1392ad533906c23e427bafc31cf88232dd8fc31a47c2d179d8057de42165da285bfc8a990631a58d4b989fb7dda22d9
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"
@@ -28,9 +28,9 @@ module Metanorma
28
28
  files[identifier][:bibdata] = xml.at(ns("//bibdata"))
29
29
  end
30
30
  files[identifier][:bibitem] = files[identifier][:bibdata].dup
31
- files[identifier][:bibitem].name = "bibitem"
32
- files[identifier][:bibitem]["hidden"] = "true"
33
- files[identifier][:bibitem]&.at("./*[local-name() = 'ext']")&.remove
31
+ files[identifier][:bibitem].name = "bibitem"
32
+ files[identifier][:bibitem]["hidden"] = "true"
33
+ files[identifier][:bibitem]&.at("./*[local-name() = 'ext']")&.remove
34
34
  end
35
35
  add_section_split(files)
36
36
  end
@@ -38,30 +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
49
- m[k] = files[k]
50
- else
51
- m[k] = files[k]
45
+ m["#{k}:index.html"] = add_section_split_cover(files, manifest, k)
52
46
  end
47
+ m[k] = files[k]
53
48
  end
54
49
  end
55
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
+
56
82
  def sectionsplit(file)
57
- Compile.new.compile(
83
+ @compile.compile(
58
84
  file, { format: :asciidoc, extension_keys: [:presentation] }
59
85
  .merge(@compile_options)
60
86
  )
61
87
  r = file.sub(/\.xml$/, ".presentation.xml")
62
- @isodoc.sectionsplit(
63
- Nokogiri::XML(File.read(r)), File.basename(r), File.dirname(r)
64
- ).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))]
65
93
  end
66
94
 
67
95
  # rel_path is the source file address, determined relative to the YAML.
@@ -76,8 +104,9 @@ module Metanorma
76
104
  else
77
105
  { type: "id", ref: ref["id"] }
78
106
  end
79
- ret[:attachment] = ref["attachment"] if ref["attachment"]
80
- 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
81
110
  ret[:presentationxml] = ref["presentation-xml"] if ref["presentation-xml"]
82
111
  ret[:bareafterfirst] = ref["bare-after-first"] if ref["bare-after-first"]
83
112
  ret
@@ -133,11 +162,12 @@ module Metanorma
133
162
  # compile and output individual file in collection
134
163
  # warn "metanorma compile -x html #{f.path}"
135
164
  def file_compile(file, filename, identifier)
136
- c = Compile.new
137
- 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 }
138
168
  .merge(compile_options(identifier))
139
169
  @files[identifier][:outputs] = {}
140
- file_compile_formats(file, filename, identifier, c)
170
+ file_compile_formats(file, filename, identifier)
141
171
  end
142
172
 
143
173
  def compile_options(identifier)
@@ -152,16 +182,16 @@ module Metanorma
152
182
  ret
153
183
  end
154
184
 
155
- def file_compile_formats(file, filename, identifier, compile)
185
+ def file_compile_formats(file, filename, identifier)
156
186
  @format.each do |e|
157
- ext = compile.processor.output_formats[e]
187
+ ext = @compile.processor.output_formats[e]
158
188
  fn = File.basename(filename).sub(/(?<=\.)[^.]+$/, ext.to_s)
159
189
  if /html$/.match?(ext) && @files[identifier][:sectionsplit]
160
190
  # file_sectionsplit_copy(file, fn, identifier, ext, e)
161
191
  else
162
192
  FileUtils.cp file.path.sub(/\.xml$/, ".#{ext}"),
163
- File.join(@outdir, fn)
164
- @files[identifier][:outputs][e] = File.join(@outdir, fn)
193
+ File.join(@outdir, fn)
194
+ @files[identifier][:outputs][e] = File.join(@outdir, fn)
165
195
  end
166
196
  end
167
197
  end
@@ -184,6 +214,7 @@ module Metanorma
184
214
  # process each file in the collection
185
215
  # files are held in memory, and altered as postprocessing
186
216
  def files # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
217
+ warn "\n\n\n\n\nInternal Refs: #{DateTime.now.strftime('%H:%M:%S')}"
187
218
  internal_refs = locate_internal_refs
188
219
  @files.each_with_index do |(identifier, x), i|
189
220
  i.positive? && Array(@directives).include?("bare-after-first") and
@@ -191,6 +222,7 @@ module Metanorma
191
222
  if x[:attachment] then copy_file_to_dest(x)
192
223
  else
193
224
  file, filename = targetfile(x, read: true)
225
+ warn "\n\n\n\n\nProcess #{filename}: #{DateTime.now.strftime('%H:%M:%S')}"
194
226
  file = update_xrefs(file, identifier, internal_refs)
195
227
  Tempfile.open(["collection", ".xml"], encoding: "utf-8") do |f|
196
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,12 +83,14 @@ 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)
78
90
  end
79
- File.open(File.join(@outdir, "collection.#{ext}"), "w:UTF-8") { |f| f.write(out.to_xml) }
91
+ File.open(File.join(@outdir, "collection.#{ext}"), "w:UTF-8") do |f|
92
+ f.write(out.to_xml)
93
+ end
80
94
  end
81
95
  options[:format].include?(:pdf) and
82
96
  pdfconv.convert(File.join(@outdir, "collection.presentation.xml"))
@@ -169,7 +183,7 @@ module Metanorma
169
183
  # @param elm [Nokogiri::XML::Element]
170
184
  # @param builder [Nokogiri::XML::Builder]
171
185
  def indexfile_docref(elm, builder)
172
- return "" unless elm.at(ns("./docref"))
186
+ return "" unless elm.at(ns("./docref[@index = 'true']"))
173
187
 
174
188
  builder.ul { |b| docrefs(elm, b) }
175
189
  end
@@ -177,7 +191,7 @@ module Metanorma
177
191
  # @param elm [Nokogiri::XML::Element]
178
192
  # @param builder [Nokogiri::XML::Builder]
179
193
  def docrefs(elm, builder)
180
- elm.xpath(ns("./docref")).each do |d|
194
+ elm.xpath(ns("./docref[@index = 'true']")).each do |d|
181
195
  ident = d.at(ns("./identifier")).children.to_xml
182
196
  builder.li do |li|
183
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]
@@ -57,9 +57,9 @@ module Metanorma
57
57
  end
58
58
 
59
59
  ADOC_OPTIONS = %w(htmlstylesheet htmlcoverpage htmlintropage scripts
60
- scripts-override scripts-pdf wordstylesheet bare i18nyaml
60
+ scripts-override scripts-pdf wordstylesheet i18nyaml
61
61
  standardstylesheet header wordcoverpage wordintropage
62
- ulstyle olstyle htmlstylesheet-override
62
+ ulstyle olstyle htmlstylesheet-override bare
63
63
  htmltoclevels doctoclevels sectionsplit
64
64
  body-font header-font monospace-font title-font
65
65
  wordstylesheet-override).freeze
@@ -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.6".freeze
2
+ VERSION = "1.3.9.1".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.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"
@@ -36,10 +36,11 @@ Gem::Specification.new do |spec|
36
36
 
37
37
  spec.add_development_dependency "byebug", "~> 10.0"
38
38
  spec.add_development_dependency "equivalent-xml", "~> 0.6"
39
- spec.add_development_dependency "metanorma-iso", "~> 1.8.0"
39
+ spec.add_development_dependency "metanorma-iso", "~> 1.9.0"
40
40
  spec.add_development_dependency "rake", "~> 13.0"
41
41
  spec.add_development_dependency "rspec", "~> 3.0"
42
42
  spec.add_development_dependency "rspec-command", "~> 1.0"
43
43
  spec.add_development_dependency "rubocop", "~> 1.5.2"
44
44
  spec.add_development_dependency "sassc", "~> 2.4.0"
45
+ spec.add_development_dependency "mnconvert"
45
46
  end
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.6
4
+ version: 1.3.9.1
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-05 00:00:00.000000000 Z
11
+ date: 2021-08-16 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
@@ -142,14 +142,14 @@ dependencies:
142
142
  requirements:
143
143
  - - "~>"
144
144
  - !ruby/object:Gem::Version
145
- version: 1.8.0
145
+ version: 1.9.0
146
146
  type: :development
147
147
  prerelease: false
148
148
  version_requirements: !ruby/object:Gem::Requirement
149
149
  requirements:
150
150
  - - "~>"
151
151
  - !ruby/object:Gem::Version
152
- version: 1.8.0
152
+ version: 1.9.0
153
153
  - !ruby/object:Gem::Dependency
154
154
  name: rake
155
155
  requirement: !ruby/object:Gem::Requirement
@@ -220,6 +220,20 @@ dependencies:
220
220
  - - "~>"
221
221
  - !ruby/object:Gem::Version
222
222
  version: 2.4.0
223
+ - !ruby/object:Gem::Dependency
224
+ name: mnconvert
225
+ requirement: !ruby/object:Gem::Requirement
226
+ requirements:
227
+ - - ">="
228
+ - !ruby/object:Gem::Version
229
+ version: '0'
230
+ type: :development
231
+ prerelease: false
232
+ version_requirements: !ruby/object:Gem::Requirement
233
+ requirements:
234
+ - - ">="
235
+ - !ruby/object:Gem::Version
236
+ version: '0'
223
237
  description: Library to process any Metanorma standard.
224
238
  email:
225
239
  - open.source@ribose.com
@@ -264,13 +278,9 @@ files:
264
278
  - lib/metanorma/input.rb
265
279
  - lib/metanorma/input/asciidoc.rb
266
280
  - lib/metanorma/input/base.rb
267
- - lib/metanorma/output.rb
268
- - lib/metanorma/output/base.rb
269
- - lib/metanorma/output/pdf.rb
270
- - lib/metanorma/output/utils.rb
271
- - lib/metanorma/output/xslfo.rb
272
281
  - lib/metanorma/processor.rb
273
282
  - lib/metanorma/registry.rb
283
+ - lib/metanorma/sectionsplit.rb
274
284
  - lib/metanorma/util.rb
275
285
  - lib/metanorma/version.rb
276
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
-