metanorma 1.7.6 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +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,157 @@
|
|
1
|
+
require "isodoc"
|
2
|
+
require "htmlentities"
|
3
|
+
require_relative "fileprocess"
|
4
|
+
require_relative "../../util/fontist_helper"
|
5
|
+
require_relative "../../util/util"
|
6
|
+
require_relative "../filelookup/filelookup"
|
7
|
+
require_relative "utils"
|
8
|
+
require_relative "render_word"
|
9
|
+
require_relative "navigation"
|
10
|
+
|
11
|
+
module Metanorma
|
12
|
+
class Collection
|
13
|
+
class Renderer
|
14
|
+
FORMATS = %i[html xml doc pdf].freeze
|
15
|
+
|
16
|
+
attr_accessor :isodoc, :nested
|
17
|
+
attr_reader :xml, :compile, :compile_options, :documents, :outdir,
|
18
|
+
:manifest
|
19
|
+
|
20
|
+
# This is only going to render the HTML collection
|
21
|
+
# @param xml [Metanorma::Collection] input XML collection
|
22
|
+
# @param folder [String] input folder
|
23
|
+
# @param options [Hash]
|
24
|
+
# @option options [String] :coverpage cover page HTML (Liquid template)
|
25
|
+
# @option options [Array<Symbol>] :format list of formats (xml,html,doc,pdf)
|
26
|
+
# @option options [String] :output_folder output directory
|
27
|
+
#
|
28
|
+
# We presuppose that the bibdata of the document is equivalent to that of
|
29
|
+
# the collection, and that the flavour gem can sensibly process it. We may
|
30
|
+
# need to enhance metadata in the flavour gems isodoc/metadata.rb with
|
31
|
+
# collection metadata
|
32
|
+
def initialize(collection, folder, options = {}) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
|
33
|
+
check_options options
|
34
|
+
@xml = Nokogiri::XML collection.to_xml # @xml is the collection manifest
|
35
|
+
@xml.root.default_namespace = "http://metanorma.org"
|
36
|
+
@lang = collection.bibdata.language.first || "en"
|
37
|
+
@script = collection.bibdata.script.first || "Latn"
|
38
|
+
@locale = @xml.at("//xmlns:bibdata/xmlns:locale")&.text
|
39
|
+
@doctype = doctype
|
40
|
+
@compile = Compile.new
|
41
|
+
@compile.load_flavor(@doctype)
|
42
|
+
|
43
|
+
@isodoc = isodoc_create # output processor for flavour
|
44
|
+
@outdir = dir_name_cleanse(options[:output_folder])
|
45
|
+
@coverpage = options[:coverpage] || collection.coverpage
|
46
|
+
@format = ::Metanorma::Util.sort_extensions_execution(options[:format])
|
47
|
+
@compile_options = options[:compile] || {}
|
48
|
+
@compile_options[:install_fonts] = true if options[:install_fonts]
|
49
|
+
@log = options[:log]
|
50
|
+
@bibdata = collection.bibdata
|
51
|
+
@documents = collection.documents
|
52
|
+
@bibdatas = collection.documents
|
53
|
+
@directives = collection.directives
|
54
|
+
@dirname = collection.dirname
|
55
|
+
@manifest = collection.manifest.config
|
56
|
+
@disambig = Util::DisambigFiles.new
|
57
|
+
@prefatory = collection.prefatory
|
58
|
+
@final = collection.final
|
59
|
+
@c = HTMLEntities.new
|
60
|
+
@files_to_delete = []
|
61
|
+
@nested = options[:nested] # if false, this is the root instance of Renderer
|
62
|
+
# if true, then this is not the last time Renderer will be run
|
63
|
+
# (e.g. this is sectionsplit)
|
64
|
+
|
65
|
+
# list of files in the collection
|
66
|
+
@files = Metanorma::Collection::FileLookup.new(folder, self)
|
67
|
+
@files.add_section_split
|
68
|
+
isodoc_populate
|
69
|
+
create_non_existing_directory(@outdir)
|
70
|
+
end
|
71
|
+
|
72
|
+
def flush_files
|
73
|
+
warn "\n\n\n\n\nDone: #{DateTime.now.strftime('%H:%M:%S')}"
|
74
|
+
warn @files.files_to_delete
|
75
|
+
@files.files_to_delete.each { |f| FileUtils.rm_f(f) }
|
76
|
+
@files_to_delete.each { |f| FileUtils.rm_f(f) }
|
77
|
+
end
|
78
|
+
|
79
|
+
# @param col [Metanorma::Collection] XML collection
|
80
|
+
# @param options [Hash]
|
81
|
+
# @option options [String] :coverpage cover page HTML (Liquid template)
|
82
|
+
# @option options [Array<Symbol>] :format list of formats
|
83
|
+
# @option options [Strong] :ourput_folder output directory
|
84
|
+
def self.render(col, options = {})
|
85
|
+
warn "\n\n\n\n\nRender Init: #{DateTime.now.strftime('%H:%M:%S')}"
|
86
|
+
cr = new(col, File.dirname(col.file), options)
|
87
|
+
cr.files
|
88
|
+
cr.concatenate(col, options)
|
89
|
+
options[:format]&.include?(:html) and cr.coverpage
|
90
|
+
cr.flush_files
|
91
|
+
cr
|
92
|
+
end
|
93
|
+
|
94
|
+
def concatenate(col, options)
|
95
|
+
warn "\n\n\n\n\nConcatenate: #{DateTime.now.strftime('%H:%M:%S')}"
|
96
|
+
(options[:format] & %i(pdf doc)).empty? or
|
97
|
+
options[:format] << :presentation
|
98
|
+
concatenate_prep(col, options)
|
99
|
+
concatenate_outputs(options)
|
100
|
+
end
|
101
|
+
|
102
|
+
def concatenate_prep(col, options)
|
103
|
+
%i(xml presentation).each do |e|
|
104
|
+
options[:format].include?(e) or next
|
105
|
+
ext = e == :presentation ? "presentation.xml" : e.to_s
|
106
|
+
File.open(File.join(@outdir, "collection.#{ext}"), "w:UTF-8") do |f|
|
107
|
+
b = concatenate1(col.clone, e).to_xml
|
108
|
+
e == :presentation and
|
109
|
+
b.sub!("<metanorma-collection>", "<metanorma-collection xmlns='http://metanorma.org'>")
|
110
|
+
# TODO BEING FORCED TO DO THAT BECAUSE SHALE IS NOT DEALING WITH DEFAULT NAMESPACES
|
111
|
+
f.write(b)
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
def concatenate_outputs(options)
|
117
|
+
pres = File.join(@outdir, "collection.presentation.xml")
|
118
|
+
options[:format].include?(:pdf) and pdfconv.convert(pres)
|
119
|
+
options[:format].include?(:doc) and docconv_convert(pres)
|
120
|
+
end
|
121
|
+
|
122
|
+
def concatenate1(out, ext)
|
123
|
+
out.directives << ::Metanorma::Collection::Config::Directive.new(key: "documents-inline")
|
124
|
+
out.bibdatas.each_key do |ident|
|
125
|
+
id = @isodoc.docid_prefix(nil, ident.dup)
|
126
|
+
@files.get(id, :attachment) || @files.get(id, :outputs).nil? and next
|
127
|
+
out.documents[Util::key id] =
|
128
|
+
Metanorma::Collection::Document.raw_file(@files.get(id,
|
129
|
+
:outputs)[ext])
|
130
|
+
end
|
131
|
+
out
|
132
|
+
end
|
133
|
+
|
134
|
+
# infer the flavour from the first document identifier; relaton does that
|
135
|
+
def doctype
|
136
|
+
if (docid = @xml.at("//bibdata/docidentifier/@type")&.text)
|
137
|
+
dt = docid.downcase
|
138
|
+
elsif (docid = @xml.at("//bibdata/docidentifier")&.text)
|
139
|
+
dt = docid.sub(/\s.*$/, "").lowercase
|
140
|
+
else return "standoc"
|
141
|
+
end
|
142
|
+
@registry = Metanorma::Registry.instance
|
143
|
+
@registry.alias(dt.to_sym)&.to_s || dt
|
144
|
+
end
|
145
|
+
|
146
|
+
# populate liquid template of ARGV[1] with metadata extracted from
|
147
|
+
# collection manifest
|
148
|
+
def coverpage
|
149
|
+
@coverpage or return
|
150
|
+
warn "\n\n\n\n\nCoverpage: #{DateTime.now.strftime('%H:%M:%S')}"
|
151
|
+
File.open(File.join(@outdir, "index.html"), "w:UTF-8") do |f|
|
152
|
+
f.write @isodoc.populate_template(File.read(@coverpage))
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|
@@ -0,0 +1,183 @@
|
|
1
|
+
module Metanorma
|
2
|
+
class Collection
|
3
|
+
class Renderer
|
4
|
+
def dir_name_cleanse(name)
|
5
|
+
path = Pathname.new(name)
|
6
|
+
clean_regex = /[<>:"|?*]/
|
7
|
+
fallback_sym = "_"
|
8
|
+
return name.gsub(clean_regex, fallback_sym) unless path.absolute?
|
9
|
+
|
10
|
+
File.join(path.dirname,
|
11
|
+
path.basename.to_s.gsub(clean_regex, fallback_sym))
|
12
|
+
end
|
13
|
+
|
14
|
+
def dup_bibitem(docid, bib)
|
15
|
+
newbib = @files.get(docid, :bibdata).dup
|
16
|
+
newbib.name = "bibitem"
|
17
|
+
newbib["hidden"] = "true"
|
18
|
+
newbib&.at("./*[local-name() = 'ext']")&.remove
|
19
|
+
newbib["id"] = bib["id"]
|
20
|
+
newbib
|
21
|
+
end
|
22
|
+
|
23
|
+
def get_bibitem_docid(bib, identifier)
|
24
|
+
docid =
|
25
|
+
bib.at(ns("./docidentifier[@type = 'metanorma-collection']")) ||
|
26
|
+
bib.at(ns("./docidentifier[not(@type)]")) ||
|
27
|
+
bib.at(ns("./docidentifier"))
|
28
|
+
docid &&= docid_prefix(docid)
|
29
|
+
if @files.get(docid) then docid
|
30
|
+
else
|
31
|
+
fail_update_bibitem(docid, identifier)
|
32
|
+
nil
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def hide_refs(docxml)
|
37
|
+
docxml.xpath(ns("//references[bibitem][not(./bibitem[not(@hidden) or " \
|
38
|
+
"@hidden = 'false'])]")).each do |f|
|
39
|
+
f["hidden"] = "true"
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def strip_eref(eref)
|
44
|
+
eref.xpath(ns("./locality | ./localityStack")).each(&:remove)
|
45
|
+
eref.replace(eref.children)
|
46
|
+
end
|
47
|
+
|
48
|
+
def docid_to_citeas(bib)
|
49
|
+
docid = bib.at(ns("./docidentifier[@primary = 'true']")) ||
|
50
|
+
bib.at(ns("./docidentifier")) or return
|
51
|
+
docid_prefix(docid)
|
52
|
+
end
|
53
|
+
|
54
|
+
def collect_erefs(docxml)
|
55
|
+
docxml.xpath(ns("//eref"))
|
56
|
+
.each_with_object({ citeas: {}, bibitemid: {} }) do |i, m|
|
57
|
+
m[:citeas][i["citeas"]] = true
|
58
|
+
m[:bibitemid][i["bibitemid"]] = true
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def docid_xml(val)
|
63
|
+
"<docidentifier type='repository'>current-metanorma-collection/" \
|
64
|
+
"#{val}</docidentifier>"
|
65
|
+
end
|
66
|
+
|
67
|
+
def add_hidden_bibliography(xmldoc, refs)
|
68
|
+
ins = new_hidden_ref(xmldoc)
|
69
|
+
refs.each do |k, v|
|
70
|
+
url = @files.url(v, {})
|
71
|
+
ins << <<~XML
|
72
|
+
<bibitem id="#{k}">#{docid_xml(v)}<uri type='citation'>#{url}</uri></bibitem>
|
73
|
+
XML
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
private
|
78
|
+
|
79
|
+
def docid_prefix(docid)
|
80
|
+
type = docid["type"]
|
81
|
+
type == "metanorma-collection" and type = nil
|
82
|
+
@c.decode(@isodoc
|
83
|
+
.docid_prefix(type, docid.children.to_xml)).gsub(/\s/, " ")
|
84
|
+
end
|
85
|
+
|
86
|
+
def create_non_existing_directory(output_directory)
|
87
|
+
!File.exist?(output_directory) and
|
88
|
+
FileUtils.mkdir_p(output_directory)
|
89
|
+
end
|
90
|
+
|
91
|
+
def format_sort(formats)
|
92
|
+
ret = []
|
93
|
+
formats.include?(:xml) and ret << :xml
|
94
|
+
formats.include?(:presentation) and ret << :presentation
|
95
|
+
a = %i(presentation xml)
|
96
|
+
ret + formats.reject { |i| a.include? i }
|
97
|
+
end
|
98
|
+
|
99
|
+
# @param options [Hash]
|
100
|
+
# @raise [ArgumentError]
|
101
|
+
def check_options(options)
|
102
|
+
(options[:format].is_a?(Array) && (FORMATS & options[:format]).any?) or
|
103
|
+
raise ArgumentError, "Need to specify formats (xml,html,pdf,doc)"
|
104
|
+
end
|
105
|
+
|
106
|
+
def pdfconv
|
107
|
+
doctype = @doctype.to_sym
|
108
|
+
x = Asciidoctor.load nil, backend: doctype
|
109
|
+
x.converter.pdf_converter(PdfOptionsNode.new(doctype,
|
110
|
+
@compile_options))
|
111
|
+
end
|
112
|
+
|
113
|
+
def fail_update_bibitem(docid, identifier)
|
114
|
+
error = "[metanorma] Cannot find crossreference to document #{docid} " \
|
115
|
+
"in document #{identifier}."
|
116
|
+
@log&.add("Cross-References", nil, error)
|
117
|
+
::Metanorma::Util.log(error, :warning)
|
118
|
+
end
|
119
|
+
|
120
|
+
def datauri_encode(docxml, directory)
|
121
|
+
docxml.xpath(ns("//image")).each do |i|
|
122
|
+
i["src"] = Vectory::Utils::datauri(i["src"], directory)
|
123
|
+
end
|
124
|
+
docxml
|
125
|
+
end
|
126
|
+
|
127
|
+
class PdfOptionsNode
|
128
|
+
def initialize(doctype, options)
|
129
|
+
p = Metanorma::Registry.instance.find_processor(doctype)
|
130
|
+
if ::Metanorma::Util::FontistHelper.has_custom_fonts?(p, options, {})
|
131
|
+
@fonts_manifest =
|
132
|
+
::Metanorma::Util::FontistHelper.location_manifest(p, options)
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
def attr(key)
|
137
|
+
if key == "fonts-manifest" && @fonts_manifest
|
138
|
+
@fonts_manifest
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
def isodoc_create
|
144
|
+
isodoc = Util::load_isodoc(@doctype)
|
145
|
+
isodoc.i18n_init(@lang, @script, @locale) # read in internationalisation
|
146
|
+
isodoc.metadata_init(@lang, @script, @locale, isodoc.i18n)
|
147
|
+
isodoc.info(@xml, nil)
|
148
|
+
isodoc
|
149
|
+
end
|
150
|
+
|
151
|
+
# create the @meta class of isodoc, for populating Liquid,
|
152
|
+
# with "navigation" set to the index bar.
|
153
|
+
# extracted from the manifest
|
154
|
+
def isodoc_populate
|
155
|
+
@isodoc.info(@xml, nil)
|
156
|
+
{ navigation: indexfile(@manifest), nav_object: index_object(@manifest),
|
157
|
+
docrefs: liquid_docrefs(@manifest),
|
158
|
+
"prefatory-content": isodoc_builder(@xml.at("//prefatory-content")),
|
159
|
+
"final-content": isodoc_builder(@xml.at("//final-content")),
|
160
|
+
doctitle: @bibdata.title.first.title.content,
|
161
|
+
docnumber: @bibdata.docidentifier.first.id }.each do |k, v|
|
162
|
+
v and @isodoc.meta.set(k, v)
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
def isodoc_builder(node)
|
167
|
+
node or return
|
168
|
+
|
169
|
+
# Kludging namespace back in because of Shale brain damage
|
170
|
+
doc = Nokogiri::XML(node.to_xml.sub(">", " xmlns='http://www.metanorma.org'>"))
|
171
|
+
Nokogiri::HTML::Builder.new(encoding: "UTF-8") do |b|
|
172
|
+
b.div do |div|
|
173
|
+
doc.root.children&.each { |n| @isodoc.parse(n, div) }
|
174
|
+
end
|
175
|
+
end.doc.root.to_html
|
176
|
+
end
|
177
|
+
|
178
|
+
def ns(xpath)
|
179
|
+
@isodoc.ns(xpath)
|
180
|
+
end
|
181
|
+
end
|
182
|
+
end
|
183
|
+
end
|
@@ -0,0 +1,218 @@
|
|
1
|
+
require "yaml"
|
2
|
+
require_relative "../../util/util"
|
3
|
+
require_relative "../xrefprocess/xrefprocess"
|
4
|
+
|
5
|
+
module Metanorma
|
6
|
+
class Collection
|
7
|
+
class Sectionsplit
|
8
|
+
attr_accessor :filecache, :key
|
9
|
+
|
10
|
+
def initialize(opts)
|
11
|
+
@input_filename = opts[:input]
|
12
|
+
@base = opts[:base]
|
13
|
+
@output_filename = opts[:output]
|
14
|
+
@xml = opts[:xml]
|
15
|
+
@dir = opts[:dir]
|
16
|
+
@compile_opts = opts[:compile_opts] || {}
|
17
|
+
@fileslookup = opts[:fileslookup]
|
18
|
+
@ident = opts[:ident]
|
19
|
+
@isodoc = opts[:isodoc]
|
20
|
+
end
|
21
|
+
|
22
|
+
def ns(xpath)
|
23
|
+
@isodoc.ns(xpath)
|
24
|
+
end
|
25
|
+
|
26
|
+
def build_collection
|
27
|
+
collection_setup(@base, @dir)
|
28
|
+
files = sectionsplit # (@input_filename, @base, @dir, @compile_opts)
|
29
|
+
input_xml = Nokogiri::XML(File.read(@input_filename,
|
30
|
+
encoding: "UTF-8"), &:huge)
|
31
|
+
collection_manifest(@base, files, input_xml, @xml, @dir).render(
|
32
|
+
{ format: %i(html), output_folder: "#{@output_filename}_collection",
|
33
|
+
coverpage: File.join(@dir, "cover.html") }.merge(@compile_opts),
|
34
|
+
)
|
35
|
+
end
|
36
|
+
|
37
|
+
def collection_manifest(filename, files, origxml, _presxml, dir)
|
38
|
+
File.open(File.join(dir, "#{filename}.html.yaml"), "w:UTF-8") do |f|
|
39
|
+
f.write(collectionyaml(files, origxml))
|
40
|
+
end
|
41
|
+
Metanorma::Collection.parse File.join(dir, "#{filename}.html.yaml")
|
42
|
+
end
|
43
|
+
|
44
|
+
def collection_setup(filename, dir)
|
45
|
+
FileUtils.mkdir_p "#{filename}_collection" if filename
|
46
|
+
FileUtils.mkdir_p dir
|
47
|
+
File.open(File.join(dir, "cover.html"), "w:UTF-8") do |f|
|
48
|
+
f.write(coll_cover)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def coll_cover
|
53
|
+
<<~COVER
|
54
|
+
<html><head><meta charset="UTF-8"/></head><body>
|
55
|
+
<h1>{{ doctitle }}</h1>
|
56
|
+
<h2>{{ docnumber }}</h2>
|
57
|
+
<nav>{{ navigation }}</nav>
|
58
|
+
</body></html>
|
59
|
+
COVER
|
60
|
+
end
|
61
|
+
|
62
|
+
SPLITSECTIONS =
|
63
|
+
[["//preface/*", "preface"], ["//sections/*", "sections"],
|
64
|
+
["//annex", nil],
|
65
|
+
["//bibliography/*[not(@hidden = 'true')]", "bibliography"],
|
66
|
+
["//indexsect", nil], ["//colophon", nil]].freeze
|
67
|
+
|
68
|
+
# Input XML is Semantic
|
69
|
+
# def sectionsplit(filename, basename, dir, compile_options, fileslookup = nil, ident = nil)
|
70
|
+
def sectionsplit
|
71
|
+
xml = sectionsplit_prep(File.read(@input_filename), @base, @dir)
|
72
|
+
@key = Metanorma::Collection::XrefProcess::xref_preprocess(xml, @isodoc)
|
73
|
+
SPLITSECTIONS.each_with_object([]) do |n, ret|
|
74
|
+
conflate_floatingtitles(xml.xpath(ns(n[0]))).each do |s|
|
75
|
+
ret << sectionfile(xml, emptydoc(xml), "#{@base}.#{ret.size}", s,
|
76
|
+
n[1])
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def block?(node)
|
82
|
+
%w(p table formula admonition ol ul dl figure quote sourcecode example
|
83
|
+
pre note pagebrreak hr bookmark requirement recommendation permission
|
84
|
+
svgmap inputform toc passthrough review imagemap).include?(node.name)
|
85
|
+
end
|
86
|
+
|
87
|
+
def conflate_floatingtitles(nodes)
|
88
|
+
holdover = false
|
89
|
+
nodes.each_with_object([]) do |x, m|
|
90
|
+
if holdover then m.last << x
|
91
|
+
else m << [x]
|
92
|
+
end
|
93
|
+
holdover = block?(x)
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
def sectionsplit_prep(file, filename, dir)
|
98
|
+
@splitdir = dir
|
99
|
+
xml1filename, type = sectionsplit_preprocess_semxml(file, filename)
|
100
|
+
Compile.new.compile(
|
101
|
+
xml1filename,
|
102
|
+
{ format: :asciidoc, extension_keys: [:presentation], type: type }
|
103
|
+
.merge(@compile_opts),
|
104
|
+
)
|
105
|
+
Nokogiri::XML(File.read(xml1filename.sub(/\.xml$/, ".presentation.xml"),
|
106
|
+
encoding: "utf-8"), &:huge)
|
107
|
+
end
|
108
|
+
|
109
|
+
def sectionsplit_preprocess_semxml(file, filename)
|
110
|
+
xml = Nokogiri::XML(file, &:huge)
|
111
|
+
type = xml.root.name.sub("-standard", "").to_sym
|
112
|
+
sectionsplit_update_xrefs(xml)
|
113
|
+
xml1 = sectionsplit_write_semxml(filename, xml)
|
114
|
+
@filecache ||= []
|
115
|
+
@filecache << xml1
|
116
|
+
[xml1.path, type]
|
117
|
+
end
|
118
|
+
|
119
|
+
def sectionsplit_update_xrefs(xml)
|
120
|
+
if c = @fileslookup&.parent
|
121
|
+
n = c.nested
|
122
|
+
c.nested = true # so unresolved erefs are not deleted
|
123
|
+
c.update_xrefs(xml, @ident, {})
|
124
|
+
c.nested = n
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
def sectionsplit_write_semxml(filename, xml)
|
129
|
+
Tempfile.open([filename, ".xml"], encoding: "utf-8") do |f|
|
130
|
+
# f.write(@isodoc.to_xml(svg_preprocess(xml)))
|
131
|
+
f.write(@isodoc.to_xml(xml))
|
132
|
+
f
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
def emptydoc(xml)
|
137
|
+
out = xml.dup
|
138
|
+
out.xpath(
|
139
|
+
ns("//preface | //sections | //annex | //bibliography/clause | " \
|
140
|
+
"//bibliography/references[not(@hidden = 'true')] | //indexsect | " \
|
141
|
+
"//colophon"),
|
142
|
+
).each(&:remove)
|
143
|
+
out
|
144
|
+
end
|
145
|
+
|
146
|
+
def sectionfile(fulldoc, xml, file, chunks, parentnode)
|
147
|
+
fname = create_sectionfile(fulldoc, xml.dup, file, chunks, parentnode)
|
148
|
+
{ order: chunks.last["displayorder"].to_i, url: fname,
|
149
|
+
title: titlerender(chunks.last) }
|
150
|
+
end
|
151
|
+
|
152
|
+
def create_sectionfile(xml, out, file, chunks, parentnode)
|
153
|
+
ins = out.at(ns("//metanorma-extension")) || out.at(ns("//bibdata"))
|
154
|
+
sectionfile_insert(ins, chunks, parentnode)
|
155
|
+
Metanorma::Collection::XrefProcess::xref_process(out, xml, @key, @ident, @isodoc)
|
156
|
+
outname = "#{file}.xml"
|
157
|
+
File.open(File.join(@splitdir, outname), "w:UTF-8") do |f|
|
158
|
+
f.write(out)
|
159
|
+
end
|
160
|
+
outname
|
161
|
+
end
|
162
|
+
|
163
|
+
def sectionfile_insert(ins, chunks, parentnode)
|
164
|
+
if parentnode
|
165
|
+
ins.next = "<#{parentnode}/>"
|
166
|
+
chunks.each { |c| ins.next.add_child(c.dup) }
|
167
|
+
else chunks.each { |c| ins.next = c.dup }
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
def titlerender(section)
|
172
|
+
title = section.at(ns("./title")) or return "[Untitled]"
|
173
|
+
t = title.dup
|
174
|
+
t.xpath(ns(".//tab | .//br")).each { |x| x.replace(" ") }
|
175
|
+
t.xpath(ns(".//strong")).each { |x| x.replace(x.children) }
|
176
|
+
t.children.to_xml
|
177
|
+
end
|
178
|
+
|
179
|
+
def collectionyaml(files, xml)
|
180
|
+
ret = {
|
181
|
+
directives: ["presentation-xml", "bare-after-first"],
|
182
|
+
bibdata: {
|
183
|
+
title: {
|
184
|
+
type: "title-main", language: @lang,
|
185
|
+
content: xml.at(ns("//bibdata/title")).text
|
186
|
+
},
|
187
|
+
type: "collection",
|
188
|
+
docid: {
|
189
|
+
type: xml.at(ns("//bibdata/docidentifier/@type")).text,
|
190
|
+
id: xml.at(ns("//bibdata/docidentifier")).text,
|
191
|
+
},
|
192
|
+
},
|
193
|
+
manifest: {
|
194
|
+
level: "collection", title: "Collection",
|
195
|
+
docref: files.sort_by { |f| f[:order] }.each.map do |f|
|
196
|
+
{ fileref: f[:url], identifier: f[:title] }
|
197
|
+
end
|
198
|
+
},
|
199
|
+
}
|
200
|
+
::Metanorma::Util::recursive_string_keys(ret).to_yaml
|
201
|
+
end
|
202
|
+
|
203
|
+
def section_split_cover(col, ident, _one_doc_coll)
|
204
|
+
dir = File.dirname(col.file)
|
205
|
+
collection_setup(nil, dir)
|
206
|
+
r = ::Metanorma::Collection::Renderer
|
207
|
+
.new(col, dir, output_folder: "#{ident}_collection",
|
208
|
+
format: %i(html), coverpage: File.join(dir, "cover.html"))
|
209
|
+
r.coverpage
|
210
|
+
# filename = one_doc_coll ? "#{ident}_index.html" : "index.html"
|
211
|
+
filename = File.basename("#{ident}_index.html") # ident can be a directory with YAML indirection
|
212
|
+
FileUtils.mv File.join(r.outdir, "index.html"), File.join(dir, filename)
|
213
|
+
FileUtils.rm_rf r.outdir
|
214
|
+
filename
|
215
|
+
end
|
216
|
+
end
|
217
|
+
end
|
218
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module Metanorma
|
2
|
+
class Collection
|
3
|
+
module Util
|
4
|
+
class DisambigFiles
|
5
|
+
def initialize
|
6
|
+
@seen_filenames = []
|
7
|
+
end
|
8
|
+
|
9
|
+
def strip_root(name)
|
10
|
+
name.sub(%r{^(\./)?(\.\./)+}, "")
|
11
|
+
end
|
12
|
+
|
13
|
+
def source2dest_filename(name, disambig = true)
|
14
|
+
n = strip_root(name)
|
15
|
+
dir = File.dirname(n)
|
16
|
+
base = File.basename(n)
|
17
|
+
if disambig && @seen_filenames.include?(base)
|
18
|
+
base = disambiguate_filename(base)
|
19
|
+
end
|
20
|
+
@seen_filenames << base
|
21
|
+
dir == "." ? base : File.join(dir, base)
|
22
|
+
end
|
23
|
+
|
24
|
+
def disambiguate_filename(base)
|
25
|
+
m = /^(?<start>.+\.)(?!0)(?<num>\d+)\.(?<suff>[^.]*)$/.match(base) ||
|
26
|
+
/^(?<start>.+\.)(?<suff>[^.]*)/.match(base) ||
|
27
|
+
/^(?<start>.+)$/.match(base)
|
28
|
+
i = m.names.include?("num") ? m["num"].to_i + 1 : 1
|
29
|
+
while @seen_filenames.include? base = "#{m['start']}#{i}.#{m['suff']}"
|
30
|
+
i += 1
|
31
|
+
end
|
32
|
+
base
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
module Metanorma
|
2
|
+
class Collection
|
3
|
+
module Util
|
4
|
+
class << self
|
5
|
+
def gather_bibitems(xml)
|
6
|
+
xml.xpath("//xmlns:bibitem[@id]").each_with_object({}) do |b, m|
|
7
|
+
if m[b["id"]]
|
8
|
+
b.remove
|
9
|
+
next
|
10
|
+
# we can't update duplicate bibitem, processing updates wrong one
|
11
|
+
else
|
12
|
+
m[b["id"]] = b
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def gather_bibitemids(xml)
|
18
|
+
xml.xpath("//*[@bibitemid]").each_with_object({}) do |e, m|
|
19
|
+
/^semantic__/.match?(e.name) and next
|
20
|
+
m[e["bibitemid"]] ||= []
|
21
|
+
m[e["bibitemid"]] << e
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def gather_citeases(xml)
|
26
|
+
xml.xpath("//*[@citeas]").each_with_object({}) do |e, m|
|
27
|
+
/^semantic__/.match?(e.name) and next
|
28
|
+
m[e["citeas"]] ||= []
|
29
|
+
m[e["citeas"]] << e
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def add_suffix_to_attributes(doc, suffix, tag_name, attr_name,
|
34
|
+
isodoc)
|
35
|
+
(suffix.nil? || suffix.empty?) and return
|
36
|
+
doc.xpath(isodoc.ns("//#{tag_name}[@#{attr_name}]")).each do |elem|
|
37
|
+
a = elem.attributes[attr_name].value
|
38
|
+
/_#{suffix}$/.match?(a) or
|
39
|
+
elem.attributes[attr_name].value = "#{a}_#{suffix}"
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def hash_key_detect(directives, key, variable)
|
44
|
+
c = directives.detect { |x| x.key == key } or
|
45
|
+
return variable
|
46
|
+
c.value
|
47
|
+
end
|
48
|
+
|
49
|
+
def rel_path_resolve(dir, path)
|
50
|
+
path.nil? and return path
|
51
|
+
path.empty? and return path
|
52
|
+
p = Pathname.new(path)
|
53
|
+
p.absolute? ? path : File.join(dir, path)
|
54
|
+
end
|
55
|
+
|
56
|
+
def key(ident)
|
57
|
+
@c ||= HTMLEntities.new
|
58
|
+
@c.decode(ident).gsub(/(\p{Zs})+/, " ")
|
59
|
+
end
|
60
|
+
|
61
|
+
class Dummy
|
62
|
+
def attr(_key); end
|
63
|
+
end
|
64
|
+
|
65
|
+
def load_isodoc(doctype)
|
66
|
+
x = Asciidoctor.load nil, backend: doctype.to_sym
|
67
|
+
x.converter.html_converter(Dummy.new) # to obtain Isodoc class
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|