metanorma 1.7.7 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (58) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +5 -1
  3. data/lib/metanorma/array_monkeypatch.rb +9 -0
  4. data/lib/metanorma/asciidoctor_extensions/glob_include_processor.rb +13 -11
  5. data/lib/metanorma/collection/collection.rb +225 -0
  6. data/lib/metanorma/collection/config/bibdata.rb +12 -0
  7. data/lib/metanorma/collection/config/compile_options.rb +13 -0
  8. data/lib/metanorma/collection/config/config.rb +163 -0
  9. data/lib/metanorma/collection/config/converters.rb +30 -0
  10. data/lib/metanorma/collection/config/directive.rb +10 -0
  11. data/lib/metanorma/collection/config/manifest.rb +88 -0
  12. data/lib/metanorma/collection/document/document.rb +133 -0
  13. data/lib/metanorma/collection/filelookup/filelookup.rb +250 -0
  14. data/lib/metanorma/collection/filelookup/filelookup_sectionsplit.rb +87 -0
  15. data/lib/metanorma/collection/manifest/manifest.rb +237 -0
  16. data/lib/metanorma/collection/renderer/fileparse.rb +247 -0
  17. data/lib/metanorma/collection/renderer/fileprocess.rb +173 -0
  18. data/lib/metanorma/collection/renderer/navigation.rb +133 -0
  19. data/lib/metanorma/collection/renderer/render_word.rb +133 -0
  20. data/lib/metanorma/collection/renderer/renderer.rb +157 -0
  21. data/lib/metanorma/collection/renderer/utils.rb +183 -0
  22. data/lib/metanorma/collection/sectionsplit/sectionsplit.rb +218 -0
  23. data/lib/metanorma/collection/util/disambig_files.rb +37 -0
  24. data/lib/metanorma/collection/util/util.rb +72 -0
  25. data/lib/metanorma/collection/xrefprocess/xrefprocess.rb +222 -0
  26. data/lib/metanorma/{compile.rb → compile/compile.rb} +17 -11
  27. data/lib/metanorma/{compile_options.rb → compile/compile_options.rb} +9 -5
  28. data/lib/metanorma/{compile_validate.rb → compile/compile_validate.rb} +1 -1
  29. data/lib/metanorma/{extract.rb → compile/extract.rb} +2 -2
  30. data/lib/metanorma/{config.rb → config/config.rb} +1 -1
  31. data/lib/metanorma/input/asciidoc.rb +3 -3
  32. data/lib/metanorma/input/base.rb +1 -5
  33. data/lib/metanorma/processor/processor.rb +54 -0
  34. data/lib/metanorma/processor.rb +1 -49
  35. data/lib/metanorma/{registry.rb → registry/registry.rb} +0 -1
  36. data/lib/metanorma/shale_monkeypatch.rb +15 -0
  37. data/lib/metanorma/util/fontist_helper.rb +130 -0
  38. data/lib/metanorma/util/util.rb +45 -0
  39. data/lib/metanorma/util/worker_pool.rb +39 -0
  40. data/lib/metanorma/version.rb +1 -1
  41. data/lib/metanorma.rb +13 -8
  42. data/metanorma.gemspec +2 -1
  43. metadata +50 -24
  44. data/lib/metanorma/collection.rb +0 -244
  45. data/lib/metanorma/collection_fileparse.rb +0 -257
  46. data/lib/metanorma/collection_fileprocess.rb +0 -168
  47. data/lib/metanorma/collection_manifest.rb +0 -168
  48. data/lib/metanorma/collection_render_utils.rb +0 -169
  49. data/lib/metanorma/collection_render_word.rb +0 -131
  50. data/lib/metanorma/collection_renderer.rb +0 -237
  51. data/lib/metanorma/collection_xref_process.rb +0 -217
  52. data/lib/metanorma/document.rb +0 -133
  53. data/lib/metanorma/files_lookup.rb +0 -224
  54. data/lib/metanorma/files_lookup_sectionsplit.rb +0 -84
  55. data/lib/metanorma/fontist_utils.rb +0 -122
  56. data/lib/metanorma/sectionsplit.rb +0 -216
  57. data/lib/metanorma/util.rb +0 -127
  58. data/lib/metanorma/worker_pool.rb +0 -29
@@ -0,0 +1,133 @@
1
+ module Metanorma
2
+ class Collection
3
+ class Document
4
+ # @return [Strin]
5
+ attr_reader :file, :attachment, :bibitem, :index
6
+
7
+ # @param bibitem [RelatonBib::BibliographicItem]
8
+ def initialize(bibitem, file, options = {})
9
+ @bibitem = bibitem
10
+ @file = file
11
+ @attachment = options[:attachment]
12
+ @index = options[:index]
13
+ @index = true if @index.nil?
14
+ @raw = options[:raw]
15
+ end
16
+
17
+ class << self
18
+ # @param file [String] file path
19
+ # @param attachment [Bool] is an attachment
20
+ # @param identifier [String] is the identifier assigned the file
21
+ # in the collection file
22
+ # @param index [Bool] is indication on whether to index this file in coverpage
23
+ # @return [Metanorma::Document]
24
+ def parse_file(file, attachment, identifier = nil, index = true)
25
+ new(bibitem(file, attachment, identifier), file,
26
+ { attachment: attachment, index: index })
27
+ end
28
+
29
+ # #param xml [Nokogiri::XML::Document, Nokogiri::XML::Element]
30
+ # @return [Metanorma::Document]
31
+ def parse_xml(xml)
32
+ new from_xml(xml)
33
+ end
34
+
35
+ # raw XML file, can be used to put in entire file instead of just bibitem
36
+ def raw_file(filename)
37
+ doc = Nokogiri::XML(File.read(filename, encoding: "UTF-8"), &:huge)
38
+ new(doc, filename, raw: true)
39
+ end
40
+
41
+ def attachment_bibitem(identifier)
42
+ Nokogiri::XML <<~DOCUMENT
43
+ <bibdata><docidentifier>#{identifier}</docidentifier></bibdata>
44
+ DOCUMENT
45
+ end
46
+
47
+ private
48
+
49
+ def mn2relaton_parser(tag)
50
+ case tag.sub(/-standard/, "")
51
+ when "bipm" then RelatonBipm::XMLParser
52
+ when "bsi" then RelatonBsi::XMLParser
53
+ when "ietf" then RelatonIetf::XMLParser
54
+ when "iho" then RelatonIho::XMLParser
55
+ when "itu" then RelatonItu::XMLParser
56
+ when "iec" then RelatonIec::XMLParser
57
+ when "iso" then RelatonIsoBib::XMLParser
58
+ when "nist" then RelatonNist::XMLParser
59
+ when "ogc" then RelatonOgc::XMLParser
60
+ else RelatonBib::XMLParser
61
+ end
62
+ end
63
+
64
+ # #param xml [Nokogiri::XML::Document, Nokogiri::XML::Element]
65
+ # @return [RelatonBib::BibliographicItem,RelatonIso::IsoBibliographicItem]
66
+ def from_xml(xml)
67
+ b = xml.at("//xmlns:bibitem|//xmlns:bibdata")
68
+ r = mn2relaton_parser(xml.root.name)
69
+ r.from_xml(b.to_xml)
70
+ end
71
+
72
+ # @param file [String]
73
+ # @return [Symbol] file type
74
+ def format(file)
75
+ case file
76
+ when /\.xml$/ then :xml
77
+ when /.ya?ml$/ then :yaml
78
+ end
79
+ end
80
+
81
+ # @param file [String]
82
+ # @return [RelatonBib::BibliographicItem,
83
+ # RelatonIso::IsoBibliographicItem]
84
+ def bibitem(file, attachment, identifier)
85
+ if attachment then attachment_bibitem(identifier)
86
+ else
87
+ case format(file)
88
+ when :xml
89
+ from_xml (Nokogiri::XML(File.read(file, encoding: "UTF-8"),
90
+ &:huge))
91
+ when :yaml
92
+ yaml = File.read(file, encoding: "UTF-8")
93
+ Relaton::Cli::YAMLConvertor.convert_single_file(yaml)
94
+ end
95
+ end
96
+ end
97
+ end
98
+
99
+ # @param builder [Nokogiri::XML::Builder, nil]
100
+ # @return [Nokogiri::XML::Builder, String]
101
+ def to_xml(builder = nil)
102
+ if builder
103
+ render_xml builder
104
+ else
105
+ Nokogiri::XML::Builder.new do |b|
106
+ root = render_xml b
107
+ root["xmlns"] = "http://metanorma.org"
108
+ end.to_xml
109
+ end
110
+ end
111
+
112
+ # @return [String]
113
+ def type
114
+ first = @bibitem.docidentifier.first
115
+ @type ||= (first&.type&.downcase ||
116
+ first&.id&.match(/^[^\s]+/)&.to_s)&.downcase ||
117
+ "standoc"
118
+ end
119
+
120
+ private
121
+
122
+ def render_xml(builder)
123
+ if @raw
124
+ builder.parent.add_child(@bibitem.root)
125
+ else
126
+ builder.send("#{type}-standard") do |b|
127
+ b << @bibitem.to_xml(bibdata: true)
128
+ end
129
+ end
130
+ end
131
+ end
132
+ end
133
+ end
@@ -0,0 +1,250 @@
1
+ require "isodoc"
2
+ require "htmlentities"
3
+ require "metanorma-utils"
4
+ require_relative "filelookup_sectionsplit"
5
+
6
+ module Metanorma
7
+ class Collection
8
+ class FileLookup
9
+ attr_accessor :files_to_delete, :parent
10
+
11
+ # hash for each document in collection of document identifier to:
12
+ # document reference (fileref or id), type of document reference,
13
+ # and bibdata entry for that file
14
+ # @param path [String] path to collection
15
+ def initialize(path, parent)
16
+ @c = HTMLEntities.new
17
+ @files = {}
18
+ @parent = parent
19
+ @xml = parent.xml
20
+ @isodoc = parent.isodoc
21
+ @path = path
22
+ @compile = parent.compile
23
+ @documents = parent.documents
24
+ @files_to_delete = []
25
+ @disambig = Util::DisambigFiles.new
26
+ @manifest = parent.manifest
27
+ read_files(@manifest.entry)
28
+ end
29
+
30
+ def read_files(entries)
31
+ Array(entries).each do |e|
32
+ e.file and read_file(e)
33
+ read_files(e.entry)
34
+ end
35
+ end
36
+
37
+ def read_file(manifest)
38
+ i, k = read_file_idents(manifest)
39
+ entry = file_entry(manifest, k) or return
40
+ bibdata_process(entry, i)
41
+ bibitem_process(entry)
42
+ @files[key(i)] = entry
43
+ end
44
+
45
+ def read_file_idents(manifest)
46
+ id = manifest.identifier
47
+ sanitised_id = key(@isodoc.docid_prefix("", manifest.identifier.dup))
48
+ # if manifest.bibdata and # NO, DO NOT FISH FOR THE GENUINE IDENTIFIER IN BIBDATA
49
+ # d = manifest.bibdata.docidentifier.detect { |x| x.primary } ||
50
+ # manifest.bibdata.docidentifier.first
51
+ # k = d.id
52
+ # i = key(@isodoc.docid_prefix(d.type, d.id.dup))
53
+ # end
54
+ [id, sanitised_id]
55
+ end
56
+
57
+ def bibdata_process(entry, ident)
58
+ if entry[:attachment]
59
+ entry[:bibdata] =
60
+ Metanorma::Collection::Document.attachment_bibitem(ident).root
61
+ else
62
+ file, _filename = targetfile(entry, read: true)
63
+ xml = Nokogiri::XML(file, &:huge)
64
+ add_document_suffix(ident, xml)
65
+ entry.merge!(anchors: read_anchors(xml), ids: read_ids(xml),
66
+ bibdata: xml.at(ns("//bibdata")),
67
+ document_suffix: xml.root["document_suffix"])
68
+ end
69
+ end
70
+
71
+ def bibitem_process(entry)
72
+ entry[:bibitem] = entry[:bibdata].dup
73
+ entry[:bibitem].name = "bibitem"
74
+ entry[:bibitem]["hidden"] = "true"
75
+ entry[:bibitem].at("./*[local-name() = 'ext']")&.remove
76
+ end
77
+
78
+ # ref is the absolute source file address
79
+ # rel_path is the relative source file address, relative to the YAML locaton
80
+ # out_path is the destination file address, with any references outside
81
+ # the working directory (../../...) truncated, and based on relative path
82
+ # identifier is the id with only spaces, no nbsp
83
+ def file_entry(ref, identifier)
84
+ ref.file or return
85
+ abs = @documents[Util::key identifier].file
86
+ ret = if ref.file
87
+ { type: "fileref", ref: abs, rel_path: ref.file, url: ref.url,
88
+ out_path: output_file_path(ref) }
89
+ else { type: "id", ref: ref.id }
90
+ end
91
+ file_entry_copy(ref, ret)
92
+ ret.compact
93
+ end
94
+
95
+ # TODO make the output file location reflect source location universally,
96
+ # not just for attachments: no File.basename
97
+ def output_file_path(ref)
98
+ f = File.basename(ref.file)
99
+ ref.attachment and f = ref.file
100
+ @disambig.source2dest_filename(f)
101
+ end
102
+
103
+ def file_entry_copy(ref, ret)
104
+ %w(attachment sectionsplit index presentation-xml url
105
+ bare-after-first).each do |s|
106
+ ref.respond_to?(s.to_sym) and
107
+ ret[s.gsub("-", "").to_sym] = ref.send(s)
108
+ end
109
+ end
110
+
111
+ def add_document_suffix(identifier, doc)
112
+ document_suffix = Metanorma::Utils::to_ncname(identifier)
113
+ Metanorma::Utils::anchor_attributes.each do |(tag_name, attribute_name)|
114
+ Util::add_suffix_to_attributes(doc, document_suffix, tag_name,
115
+ attribute_name, @isodoc)
116
+ end
117
+ url_in_css_styles(doc, document_suffix)
118
+ doc.root["document_suffix"] ||= ""
119
+ doc.root["document_suffix"] += document_suffix
120
+ end
121
+
122
+ # update relative URLs, url(#...), in CSS in @style attrs (including SVG)
123
+ def url_in_css_styles(doc, document_suffix)
124
+ doc.xpath("//*[@style]").each do |s|
125
+ s["style"] = s["style"]
126
+ .gsub(%r{url\(#([^)]+)\)}, "url(#\\1_#{document_suffix})")
127
+ end
128
+ end
129
+
130
+ # return citation url for file
131
+ # @param doc [Boolean] I am a Metanorma document,
132
+ # so my URL should end with html or pdf or whatever
133
+ def url(ident, options)
134
+ data = get(ident)
135
+ data[:url] || targetfile(data, options)[1]
136
+ end
137
+
138
+ # are references to the file to be linked to a file in the collection,
139
+ # or externally? Determines whether file suffix anchors are to be used
140
+ def url?(ident)
141
+ data = get(ident) or return false
142
+ data[:url]
143
+ end
144
+
145
+ # return file contents + output filename for each file in the collection,
146
+ # given a docref entry
147
+ # @param data [Hash] docref entry
148
+ # @param read [Boolean] read the file in and return it
149
+ # @param doc [Boolean] I am a Metanorma document,
150
+ # so my URL should end with html or pdf or whatever
151
+ # @param relative [Boolean] Return output path,
152
+ # formed relative to YAML file, not input path, relative to calling function
153
+ # @return [Array<String, nil>]
154
+ def targetfile(data, options)
155
+ options = { read: false, doc: true, relative: false }.merge(options)
156
+ path = options[:relative] ? data[:rel_path] : data[:ref]
157
+ if data[:type] == "fileref"
158
+ ref_file path, data[:out_path], options[:read], options[:doc]
159
+ else
160
+ xml_file data[:id], options[:read]
161
+ end
162
+ end
163
+
164
+ def targetfile_id(ident, options)
165
+ targetfile(get(ident), options)
166
+ end
167
+
168
+ def ref_file(ref, out, read, doc)
169
+ file = File.read(ref, encoding: "utf-8") if read
170
+ filename = out.dup
171
+ filename.sub!(/\.xml$/, ".html") if doc
172
+ [file, filename]
173
+ end
174
+
175
+ def xml_file(id, read)
176
+ file = @xml.at(ns("//doc-container[@id = '#{id}']")).to_xml if read
177
+ filename = "#{id}.html"
178
+ [file, filename]
179
+ end
180
+
181
+ # map locality type and label (e.g. "clause" "1") to id = anchor for
182
+ # a document
183
+ # Note: will only key clauses, which have unambiguous reference label in
184
+ # locality. Notes, examples etc with containers are just plunked against
185
+ # UUIDs, so that their IDs can at least be registered to be tracked
186
+ # as existing.
187
+ def read_anchors(xml)
188
+ xrefs = @isodoc.xref_init(@lang, @script, @isodoc, @isodoc.i18n,
189
+ { locale: @locale })
190
+ xrefs.parse xml
191
+ xrefs.get.each_with_object({}) do |(k, v), ret|
192
+ read_anchors1(k, v, ret)
193
+ end
194
+ end
195
+
196
+ def read_anchors1(key, val, ret)
197
+ val[:type] ||= "clause"
198
+ ret[val[:type]] ||= {}
199
+ index = if val[:container] || val[:label].nil? || val[:label].empty?
200
+ UUIDTools::UUID.random_create.to_s
201
+ else val[:label]
202
+ end
203
+ ret[val[:type]][index] = key
204
+ ret[val[:type]][val[:value]] = key if val[:value]
205
+ end
206
+
207
+ # Also parse all ids in doc (including ones which won't be xref targets)
208
+ def read_ids(xml)
209
+ ret = {}
210
+ xml.traverse do |x|
211
+ x.text? and next
212
+ /^semantic__/.match?(x.name) and next
213
+ x["id"] and ret[x["id"]] = true
214
+ end
215
+ ret
216
+ end
217
+
218
+ def key(ident)
219
+ @c.decode(ident).gsub(/(\p{Zs})+/, " ").sub(/^metanorma-collection /,
220
+ "")
221
+ end
222
+
223
+ def keys
224
+ @files.keys
225
+ end
226
+
227
+ def get(ident, attr = nil)
228
+ if attr then @files[key(ident)][attr]
229
+ else @files[key(ident)]
230
+ end
231
+ end
232
+
233
+ def set(ident, attr, value)
234
+ @files[key(ident)][attr] = value
235
+ end
236
+
237
+ def each
238
+ @files.each
239
+ end
240
+
241
+ def each_with_index
242
+ @files.each_with_index
243
+ end
244
+
245
+ def ns(xpath)
246
+ @isodoc.ns(xpath)
247
+ end
248
+ end
249
+ end
250
+ end
@@ -0,0 +1,87 @@
1
+ require_relative "../sectionsplit/sectionsplit"
2
+
3
+ module Metanorma
4
+ class Collection
5
+ class FileLookup
6
+ def add_section_split
7
+ ret = @files.keys.each_with_object({}) do |k, m|
8
+ if @files[k][:sectionsplit] && !@files[k][:attachment]
9
+ process_section_split_instance(k, m)
10
+ cleanup_section_split_instance(k, m)
11
+ end
12
+ m[k] = @files[k]
13
+ end
14
+ @files = ret
15
+ end
16
+
17
+ def process_section_split_instance(key, manifest)
18
+ s, sectionsplit_manifest = sectionsplit(key)
19
+ s.each_with_index do |f1, i|
20
+ add_section_split_instance(f1, manifest, key, i)
21
+ end
22
+ manifest["#{key}:index.html"] =
23
+ add_section_split_cover(sectionsplit_manifest, key)
24
+ end
25
+
26
+ def cleanup_section_split_instance(key, manifest)
27
+ @files_to_delete << manifest["#{key}:index.html"][:ref]
28
+ # @files[key].delete(:ids).delete(:anchors)
29
+ @files[key][:indirect_key] = @sectionsplit.key
30
+ end
31
+
32
+ def add_section_split_cover(manifest, ident)
33
+ cover = @sectionsplit
34
+ .section_split_cover(manifest, @parent.dir_name_cleanse(ident),
35
+ one_doc_collection?)
36
+ @files[ident][:out_path] = cover
37
+ { attachment: true, index: false, out_path: cover,
38
+ ref: File.join(File.dirname(manifest.file), cover) }
39
+ end
40
+
41
+ def one_doc_collection?
42
+ return false
43
+ docs = 0
44
+ @files.each_value do |v|
45
+ v[:attachment] and next
46
+ v[:presentationxml] and next
47
+ docs += 1
48
+ end
49
+ docs > 1
50
+ end
51
+
52
+ def add_section_split_instance(file, manifest, key, idx)
53
+ presfile, newkey, xml =
54
+ add_section_split_instance_prep(file, key)
55
+ manifest[newkey] =
56
+ { parentid: key, presentationxml: true, type: "fileref",
57
+ rel_path: file[:url], out_path: File.basename(file[:url]),
58
+ anchors: read_anchors(xml), ids: read_ids(xml),
59
+ sectionsplit_output: true,
60
+ bibdata: @files[key][:bibdata], ref: presfile }
61
+ @files_to_delete << file[:url]
62
+ manifest[newkey][:bare] = true unless idx.zero?
63
+ end
64
+
65
+ def add_section_split_instance_prep(file, key)
66
+ presfile = File.join(File.dirname(@files[key][:ref]),
67
+ File.basename(file[:url]))
68
+ newkey = key("#{key.strip} #{file[:title]}")
69
+ xml = Nokogiri::XML(File.read(presfile), &:huge)
70
+ [presfile, newkey, xml]
71
+ end
72
+
73
+ def sectionsplit(ident)
74
+ file = @files[ident][:ref]
75
+ @sectionsplit = ::Metanorma::Collection::Sectionsplit
76
+ .new(input: file, base: @files[ident][:out_path], dir: File.dirname(file),
77
+ output: @files[ident][:out_path], compile_opts: @parent.compile_options,
78
+ fileslookup: self, ident: ident, isodoc: @isodoc)
79
+ coll = @sectionsplit.sectionsplit.sort_by { |f| f[:order] }
80
+ xml = Nokogiri::XML(File.read(file, encoding: "UTF-8"), &:huge)
81
+ [coll, @sectionsplit
82
+ .collection_manifest(File.basename(file), coll, xml, nil,
83
+ File.dirname(file))]
84
+ end
85
+ end
86
+ end
87
+ end
@@ -0,0 +1,237 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../../util/util"
4
+
5
+ module Metanorma
6
+ class Collection
7
+ class Manifest
8
+ # @return [Metanorma::Collection]
9
+ attr_reader :collection, :config
10
+
11
+ # @param level [String]
12
+ # @param dir [String]
13
+ # @param title [String, nil]
14
+ # @param docref [Array<Hash{String=>String}>]
15
+ # @param manifest [Array<Metanorma::Collection::Manifest>]
16
+ def initialize(config, collection, dir)
17
+ @collection = collection
18
+ @dir = dir
19
+ @disambig = ::Metanorma::Collection::Util::DisambigFiles.new
20
+ @config = manifest_postprocess(config)
21
+ end
22
+
23
+ def manifest_postprocess(config)
24
+ manifest_bibdata(config)
25
+ manifest_expand_yaml(config, @dir)
26
+ manifest_compile_adoc(config)
27
+ manifest_filexist(config)
28
+ manifest_sectionsplit(config)
29
+ manifest_identifier(config)
30
+ config
31
+ end
32
+
33
+ def manifest_bibdata(config)
34
+ b = config.bibdata
35
+ @lang = b&.language&.first || "en"
36
+ @script = b&.script&.first || "Latn"
37
+ end
38
+
39
+ GUID = "[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}"
40
+
41
+ def manifest_identifier(config)
42
+ no_id = populate_id_from_doc(config)
43
+ config.identifier =
44
+ if no_id && config.file # make file name be id
45
+ @collection.class.resolve_identifier(File.basename(config.file))
46
+ else
47
+ @collection.class.resolve_identifier(config.identifier)
48
+ end
49
+ Array(config.entry).each do |f|
50
+ manifest_identifier(f)
51
+ end
52
+ end
53
+
54
+ def populate_id_from_doc(config)
55
+ no_id = /^#{GUID}$/o.match?(config.identifier)
56
+ # GUID assumed to be no identifier supplied
57
+ if no_id && /\.xml$/.match?(config.file) &&
58
+ (i = retrieve_id_from_doc(config.file))
59
+ config.identifier = i
60
+ no_id = false
61
+ end
62
+ no_id
63
+ end
64
+
65
+ def retrieve_id_from_doc(file)
66
+ x = Nokogiri::XML(File.read(File.join(@dir, file)), &:huge)
67
+ i = x.at("//xmlns:bibdata/xmlns:docidentifier[@primary = 'true']") ||
68
+ x.at("//xmlns:bibdata/xmlns:docidentifier")
69
+ i or return nil
70
+ @doctype ||= i["type"]&.downcase || "standoc"
71
+ load_isodoc
72
+ Util::key(@isodoc.docid_prefix(i["type"], i.text))
73
+ end
74
+
75
+ def load_isodoc
76
+ @isodoc and return
77
+ @collection.compile.load_flavor(@doctype)
78
+ @isodoc = Util::load_isodoc(@doctype)
79
+ @isodoc.i18n_init(@lang, @script, nil) # for @i18n.all_parts in docid
80
+ end
81
+
82
+ def manifest_sectionsplit(config)
83
+ if config.sectionsplit && !config.file
84
+ config.sectionsplit = nil
85
+ Array(config.entry).each do |e|
86
+ e.attachment and next
87
+ e.sectionsplit = true
88
+ end
89
+ end
90
+ Array(config.entry).each do |f|
91
+ manifest_sectionsplit(f)
92
+ end
93
+ end
94
+
95
+ def manifest_filexist(config)
96
+ if config.file
97
+ file = @collection.class.resolve_fileref(@dir, config.file)
98
+ @collection.class.check_file_existence(file)
99
+ config.file = Pathname.new(file).relative_path_from(Pathname.new(@dir))
100
+ end
101
+ Array(config.entry).each do |f|
102
+ manifest_filexist(f)
103
+ end
104
+ end
105
+
106
+ def manifest_expand_yaml(config, dir)
107
+ Array(config.entry).each do |e|
108
+ currdir = dir
109
+ /\.ya?ml$/.match?(e.file) and
110
+ currdir = manifest_expand_yaml_entry(e, dir)
111
+ manifest_expand_yaml(e, currdir)
112
+ end
113
+ config
114
+ end
115
+
116
+ def manifest_expand_yaml_entry(entry, dir)
117
+ f = @collection.class.resolve_fileref(dir, entry.file)
118
+ currdir = File.dirname(f)
119
+ @collection.class.check_file_existence(f)
120
+ entry.file = nil
121
+ entry.entry = ::Metanorma::Collection::Config::Config.from_yaml(File.read(f)).manifest
122
+ if currdir != dir
123
+ prefix = Pathname.new(currdir).relative_path_from(Pathname.new(dir))
124
+ update_filepaths(entry.entry, prefix.to_s)
125
+ end
126
+ currdir
127
+ end
128
+
129
+ def update_filepaths(entry, prefix)
130
+ entry.file && !(Pathname.new entry.file).absolute? and
131
+ entry.file = File.join(prefix, entry.file)
132
+ entry.entry.each do |f|
133
+ update_filepaths(f, prefix)
134
+ end
135
+ end
136
+
137
+ def manifest_compile_adoc(config)
138
+ if /\.adoc$/.match?(config.file)
139
+ file = @collection.class.resolve_fileref(@dir, config.file)
140
+ config.file = compile_adoc(file, config.file)
141
+ end
142
+ Array(config.entry).each do |f|
143
+ manifest_compile_adoc(f)
144
+ end
145
+ end
146
+
147
+ def compile_adoc(resolved_filename, rel_filename)
148
+ compile_adoc_file(resolved_filename)
149
+ set_adoc2xml(rel_filename)
150
+ end
151
+
152
+ # @param fileref [String]
153
+ def set_adoc2xml(fileref)
154
+ File.join(
155
+ File.dirname(fileref),
156
+ File.basename(fileref).gsub(/.adoc$/, ".xml"),
157
+ )
158
+ end
159
+
160
+ # param filepath [String]
161
+ # @raise [AdocFileNotFoundException]
162
+ def compile_adoc_file(file)
163
+ f = (Pathname.new file).absolute? ? file : File.join(@dir, file)
164
+ unless File.exist? f
165
+ raise AdocFileNotFoundException.new "#{f} not found!"
166
+ end
167
+
168
+ ::Metanorma::Util.log("[metanorma] Info: Compiling #{f}...", :info)
169
+ ::Metanorma::Compile.new
170
+ .compile(f, agree_to_terms: true, no_install_fonts: true,
171
+ extension_keys: [:xml])
172
+ ::Metanorma::Util.log("[metanorma] Info: Compiling #{f}...done!", :info)
173
+ end
174
+
175
+ def documents(mnf = @config)
176
+ Array(mnf.entry).each_with_object({}) do |dr, m|
177
+ if dr.file
178
+ m[Util::key dr.identifier] = documents_add(dr)
179
+ elsif dr.entry
180
+ m.merge! documents(dr)
181
+ end
182
+ m
183
+ end
184
+ end
185
+
186
+ def documents_add(docref)
187
+ ::Metanorma::Collection::Document.parse_file(
188
+ Util::rel_path_resolve(@dir, docref.file),
189
+ docref.attachment, docref.identifier, docref.index
190
+ )
191
+ end
192
+
193
+ def to_xml(builder = nil)
194
+ clean_manifest(@config)
195
+ if builder
196
+ builder.parent.add_child(@config.to_xml)
197
+ else
198
+ @config.to_xml
199
+ end
200
+ end
201
+
202
+ def clean_manifest_bibdata(mnf)
203
+ if mnf.file && !mnf.attachment && !mnf.sectionsplit && @collection &&
204
+ d = @collection.bibdatas[Util::key mnf.identifier]
205
+ mnf.bibdata = d.bibitem.dup
206
+ end
207
+ end
208
+
209
+ def clean_manifest_id(mnf)
210
+ @collection.directives.detect do |d|
211
+ d.key == "documents-inline"
212
+ end or return
213
+ id = @collection.documents.find_index do |k, _|
214
+ k == mnf.identifier
215
+ end
216
+ id and mnf.id = format("doc%<index>09d", index: id)
217
+ end
218
+
219
+ def clean_manifest(mnf)
220
+ clean_manifest_bibdata(mnf)
221
+ # mnf.file &&= @disambig.strip_root(mnf.file)
222
+ clean_manifest_id(mnf)
223
+ Array(mnf.entry).each { |e| clean_manifest(e) }
224
+ end
225
+
226
+ # @return [Array<Hash{String=>String}>]
227
+ def docrefs
228
+ @config.entry
229
+ end
230
+
231
+ def docref_by_id(docid)
232
+ @config.entry.detect { |k| k.identifier == docid } ||
233
+ @config.entry.detect { |k| /^#{k.identifier}/ =~ docid }
234
+ end
235
+ end
236
+ end
237
+ end