metanorma 1.7.6 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile +5 -1
- data/lib/metanorma/array_monkeypatch.rb +9 -0
- data/lib/metanorma/asciidoctor_extensions/glob_include_processor.rb +13 -11
- data/lib/metanorma/collection/collection.rb +225 -0
- data/lib/metanorma/collection/config/bibdata.rb +12 -0
- data/lib/metanorma/collection/config/compile_options.rb +13 -0
- data/lib/metanorma/collection/config/config.rb +163 -0
- data/lib/metanorma/collection/config/converters.rb +30 -0
- data/lib/metanorma/collection/config/directive.rb +10 -0
- data/lib/metanorma/collection/config/manifest.rb +88 -0
- data/lib/metanorma/collection/document/document.rb +133 -0
- data/lib/metanorma/collection/filelookup/filelookup.rb +250 -0
- data/lib/metanorma/collection/filelookup/filelookup_sectionsplit.rb +87 -0
- data/lib/metanorma/collection/manifest/manifest.rb +237 -0
- data/lib/metanorma/collection/renderer/fileparse.rb +247 -0
- data/lib/metanorma/collection/renderer/fileprocess.rb +173 -0
- data/lib/metanorma/collection/renderer/navigation.rb +133 -0
- data/lib/metanorma/collection/renderer/render_word.rb +133 -0
- data/lib/metanorma/collection/renderer/renderer.rb +157 -0
- data/lib/metanorma/collection/renderer/utils.rb +183 -0
- data/lib/metanorma/collection/sectionsplit/sectionsplit.rb +218 -0
- data/lib/metanorma/collection/util/disambig_files.rb +37 -0
- data/lib/metanorma/collection/util/util.rb +72 -0
- data/lib/metanorma/collection/xrefprocess/xrefprocess.rb +222 -0
- data/lib/metanorma/{compile.rb → compile/compile.rb} +17 -11
- data/lib/metanorma/{compile_options.rb → compile/compile_options.rb} +9 -5
- data/lib/metanorma/{compile_validate.rb → compile/compile_validate.rb} +1 -1
- data/lib/metanorma/{extract.rb → compile/extract.rb} +2 -2
- data/lib/metanorma/{config.rb → config/config.rb} +1 -1
- data/lib/metanorma/input/asciidoc.rb +3 -3
- data/lib/metanorma/input/base.rb +1 -5
- data/lib/metanorma/processor/processor.rb +54 -0
- data/lib/metanorma/processor.rb +1 -49
- data/lib/metanorma/{registry.rb → registry/registry.rb} +0 -1
- data/lib/metanorma/shale_monkeypatch.rb +15 -0
- data/lib/metanorma/util/fontist_helper.rb +130 -0
- data/lib/metanorma/util/util.rb +45 -0
- data/lib/metanorma/util/worker_pool.rb +39 -0
- data/lib/metanorma/version.rb +1 -1
- data/lib/metanorma.rb +13 -8
- data/metanorma.gemspec +2 -1
- metadata +51 -26
- data/Gemfile.devel +0 -2
- data/lib/metanorma/collection.rb +0 -243
- data/lib/metanorma/collection_fileparse.rb +0 -254
- data/lib/metanorma/collection_fileprocess.rb +0 -157
- data/lib/metanorma/collection_manifest.rb +0 -139
- data/lib/metanorma/collection_render_utils.rb +0 -169
- data/lib/metanorma/collection_render_word.rb +0 -131
- data/lib/metanorma/collection_renderer.rb +0 -230
- data/lib/metanorma/document.rb +0 -133
- data/lib/metanorma/files_lookup.rb +0 -208
- data/lib/metanorma/files_lookup_sectionsplit.rb +0 -84
- data/lib/metanorma/fontist_utils.rb +0 -122
- data/lib/metanorma/sectionsplit.rb +0 -216
- data/lib/metanorma/sectionsplit_links.rb +0 -189
- data/lib/metanorma/util.rb +0 -127
- 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
|