metanorma 1.3.4 → 1.3.8
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/rake.yml +1 -1
- data/.rubocop.yml +1 -1
- data/Gemfile +2 -2
- data/lib/metanorma.rb +0 -1
- data/lib/metanorma/collection.rb +7 -1
- data/lib/metanorma/collection_fileparse.rb +65 -47
- data/lib/metanorma/collection_fileprocess.rb +123 -23
- data/lib/metanorma/collection_manifest.rb +36 -11
- data/lib/metanorma/collection_renderer.rb +50 -14
- data/lib/metanorma/compile.rb +81 -63
- data/lib/metanorma/document.rb +12 -5
- data/lib/metanorma/input/asciidoc.rb +2 -2
- data/lib/metanorma/processor.rb +3 -6
- data/lib/metanorma/sectionsplit.rb +270 -0
- data/lib/metanorma/util.rb +43 -2
- data/lib/metanorma/version.rb +1 -1
- data/metanorma.gemspec +4 -3
- metadata +22 -12
- data/lib/metanorma/output.rb +0 -8
- data/lib/metanorma/output/base.rb +0 -13
- data/lib/metanorma/output/pdf.rb +0 -32
- data/lib/metanorma/output/utils.rb +0 -17
- data/lib/metanorma/output/xslfo.rb +0 -21
data/lib/metanorma/document.rb
CHANGED
@@ -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]
|
@@ -30,7 +33,9 @@ module Metanorma
|
|
30
33
|
|
31
34
|
# raw XML file, can be used to put in entire file instead of just bibitem
|
32
35
|
def raw_file(filename)
|
33
|
-
doc = Nokogiri::XML(File.read(filename, encoding: "UTF-8"))
|
36
|
+
doc = Nokogiri::XML(File.read(filename, encoding: "UTF-8")) do |config|
|
37
|
+
config.huge
|
38
|
+
end
|
34
39
|
new(doc, filename, raw: true)
|
35
40
|
end
|
36
41
|
|
@@ -100,7 +105,9 @@ module Metanorma
|
|
100
105
|
if @raw
|
101
106
|
builder << @bibitem.root.to_xml
|
102
107
|
else
|
103
|
-
builder.send(type
|
108
|
+
builder.send("#{type}-standard") do |b|
|
109
|
+
b << @bibitem.to_xml(bibdata: true)
|
110
|
+
end
|
104
111
|
end
|
105
112
|
end
|
106
113
|
end
|
@@ -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
|
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
|
data/lib/metanorma/processor.rb
CHANGED
@@ -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,
|
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,270 @@
|
|
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>
|
50
|
+
<head/>
|
51
|
+
<body>
|
52
|
+
<h1>{{ doctitle }}</h1>
|
53
|
+
<h2>{{ docnumber }}</h2>
|
54
|
+
<nav>{{ labels["navigation"] }}</nav>
|
55
|
+
</body>
|
56
|
+
</html>
|
57
|
+
COVER
|
58
|
+
end
|
59
|
+
|
60
|
+
SPLITSECTIONS =
|
61
|
+
[["//preface/*", "preface"], ["//sections/*", "sections"],
|
62
|
+
["//annex", nil],
|
63
|
+
["//bibliography/*[not(@hidden = 'true')]", "bibliography"],
|
64
|
+
["//indexsect", nil]].freeze
|
65
|
+
|
66
|
+
def sectionsplit(xml, filename, dir)
|
67
|
+
@key = xref_preprocess(xml)
|
68
|
+
@splitdir = dir
|
69
|
+
out = emptydoc(xml)
|
70
|
+
SPLITSECTIONS.each_with_object([]) do |n, ret|
|
71
|
+
xml.xpath(ns(n[0])).each do |s|
|
72
|
+
ret << sectionfile(xml, out, "#{filename}.#{ret.size}", s, n[1])
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def emptydoc(xml)
|
78
|
+
out = xml.dup
|
79
|
+
out.xpath(
|
80
|
+
ns("//preface | //sections | //annex | //bibliography/clause | "\
|
81
|
+
"//bibliography/references[not(@hidden = 'true')] | //indexsect"),
|
82
|
+
).each(&:remove)
|
83
|
+
out
|
84
|
+
end
|
85
|
+
|
86
|
+
def sectionfile(fulldoc, xml, file, chunk, parentnode)
|
87
|
+
fname = create_sectionfile(fulldoc, xml.dup, file, chunk, parentnode)
|
88
|
+
{ order: chunk["displayorder"].to_i, url: fname,
|
89
|
+
title: titlerender(chunk) }
|
90
|
+
end
|
91
|
+
|
92
|
+
def create_sectionfile(xml, out, file, chunk, parentnode)
|
93
|
+
ins = out.at(ns("//misccontainer")) || out.at(ns("//bibdata"))
|
94
|
+
if parentnode
|
95
|
+
ins.next = "<#{parentnode}/>"
|
96
|
+
ins.next.add_child(chunk.dup)
|
97
|
+
else ins.next = chunk.dup
|
98
|
+
end
|
99
|
+
xref_process(out, xml, @key)
|
100
|
+
outname = "#{file}.xml"
|
101
|
+
File.open(File.join(@splitdir, outname), "w:UTF-8") { |f| f.write(out) }
|
102
|
+
outname
|
103
|
+
end
|
104
|
+
|
105
|
+
# def xref_preprocess(xml)
|
106
|
+
# svg_preprocess(xml)
|
107
|
+
# key = (0...8).map { rand(65..90).chr }.join # random string
|
108
|
+
# xml.root["type"] = key # to force recognition of internal refs
|
109
|
+
# refs = eref_to_internal_eref(xml, key)
|
110
|
+
# refs += xref_to_internal_eref(xml, key)
|
111
|
+
# ins = new_hidden_ref(xml)
|
112
|
+
# copy_repo_items_biblio(ins, xml)
|
113
|
+
# insert_indirect_biblio(ins, refs, key)
|
114
|
+
# end
|
115
|
+
|
116
|
+
def xref_preprocess(xml)
|
117
|
+
svg_preprocess(xml)
|
118
|
+
key = (0...8).map { rand(65..90).chr }.join # random string
|
119
|
+
xml.root["type"] = key # to force recognition of internal refs
|
120
|
+
key
|
121
|
+
end
|
122
|
+
|
123
|
+
def xref_process(section, xml, key)
|
124
|
+
refs = eref_to_internal_eref(section, xml, key)
|
125
|
+
refs += xref_to_internal_eref(section, key)
|
126
|
+
ins = new_hidden_ref(section)
|
127
|
+
copied_refs = copy_repo_items_biblio(ins, section, xml)
|
128
|
+
insert_indirect_biblio(ins, refs - copied_refs, key)
|
129
|
+
end
|
130
|
+
|
131
|
+
def svg_preprocess(xml)
|
132
|
+
xml.xpath("//m:svg", "m" => "http://www.w3.org/2000/svg").each do |s|
|
133
|
+
m = svgmap_wrap(s)
|
134
|
+
s.xpath(".//m:a", "m" => "http://www.w3.org/2000/svg").each do |a|
|
135
|
+
next unless /^#/.match? a["href"]
|
136
|
+
|
137
|
+
a["href"] = a["href"].sub(/^#/, "")
|
138
|
+
m << "<target href='#{a['href']}'>"\
|
139
|
+
"<xref target='#{a['href']}'/></target>"
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
def svgmap_wrap(svg)
|
145
|
+
ret = svg.at("./ancestor::xmlns:svgmap") and return ret
|
146
|
+
ret = svg.at("./ancestor::xmlns:figure")
|
147
|
+
ret.wrap("<svgmap/>")
|
148
|
+
svg.at("./ancestor::xmlns:svgmap")
|
149
|
+
end
|
150
|
+
|
151
|
+
def make_anchor(anchor)
|
152
|
+
"<localityStack><locality type='anchor'><referenceFrom>"\
|
153
|
+
"#{anchor}</referenceFrom></locality></localityStack>"
|
154
|
+
end
|
155
|
+
|
156
|
+
def xref_to_internal_eref(xml, key)
|
157
|
+
xml.xpath(ns("//xref")).each_with_object({}) do |x, m|
|
158
|
+
x["bibitemid"] = "#{key}_#{x['target']}"
|
159
|
+
x << make_anchor(x["target"])
|
160
|
+
m[x["bibitemid"]] = true
|
161
|
+
x.delete("target")
|
162
|
+
x["type"] = key
|
163
|
+
x.name = "eref"
|
164
|
+
end.keys
|
165
|
+
end
|
166
|
+
|
167
|
+
def eref_to_internal_eref(section, xml, key)
|
168
|
+
eref_to_internal_eref_select(section, xml).each_with_object([]) do |x, m|
|
169
|
+
url = xml.at(ns("//bibitem[@id = '#{x}']/url[@type = 'citation']"))
|
170
|
+
section.xpath(("//*[@bibitemid = '#{x}']")).each do |e|
|
171
|
+
id = eref_to_internal_eref1(e, key, url)
|
172
|
+
id and m << id
|
173
|
+
end
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
def eref_to_internal_eref1(elem, key, url)
|
178
|
+
if url
|
179
|
+
elem.name = "link"
|
180
|
+
elem["target"] = url
|
181
|
+
nil
|
182
|
+
else
|
183
|
+
elem["bibitemid"] = "#{key}_#{elem['bibitemid']}"
|
184
|
+
elem << make_anchor(elem["bibitemid"])
|
185
|
+
elem["type"] = key
|
186
|
+
elem["bibitemid"]
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
def eref_to_internal_eref_select(section, xml)
|
191
|
+
refs = section.xpath(("//*/@bibitemid")).map { |x| x.text } # rubocop:disable Style/SymbolProc
|
192
|
+
refs.uniq.reject do |x|
|
193
|
+
xml.at(ns("//bibitem[@id = '#{x}'][@type = 'internal']")) ||
|
194
|
+
xml.at(ns("//bibitem[@id = '#{x}']"\
|
195
|
+
"[docidentifier/@type = 'repository']"))
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
199
|
+
# from standoc
|
200
|
+
def new_hidden_ref(xmldoc)
|
201
|
+
ins = xmldoc.at("bibliography") or
|
202
|
+
xmldoc.root << "<bibliography/>" and ins = xmldoc.at("bibliography")
|
203
|
+
ins.add_child("<references hidden='true' normative='false'/>").first
|
204
|
+
end
|
205
|
+
|
206
|
+
def copy_repo_items_biblio(ins, section, xml)
|
207
|
+
xml.xpath(ns("//references/bibitem[docidentifier/@type = 'repository']"))
|
208
|
+
.each_with_object([]) do |b, m|
|
209
|
+
section.at("//*[@bibitemid = '#{b['id']}']") or next
|
210
|
+
ins << b.dup
|
211
|
+
m << b["id"]
|
212
|
+
end
|
213
|
+
end
|
214
|
+
|
215
|
+
def insert_indirect_biblio(ins, refs, prefix)
|
216
|
+
refs.each do |x|
|
217
|
+
ins << <<~BIBENTRY
|
218
|
+
<bibitem id="#{x}" type="internal">
|
219
|
+
<docidentifier type="repository">#{x.sub(/^#{prefix}_/, "#{prefix}/")}</docidentifier>
|
220
|
+
</bibitem>
|
221
|
+
BIBENTRY
|
222
|
+
end
|
223
|
+
end
|
224
|
+
|
225
|
+
def recursive_string_keys(hash)
|
226
|
+
case hash
|
227
|
+
when Hash then Hash[
|
228
|
+
hash.map { |k, v| [k.to_s, recursive_string_keys(v)] }
|
229
|
+
]
|
230
|
+
when Enumerable then hash.map { |v| recursive_string_keys(v) }
|
231
|
+
else
|
232
|
+
hash
|
233
|
+
end
|
234
|
+
end
|
235
|
+
|
236
|
+
def titlerender(section)
|
237
|
+
title = section.at(ns("./title")) or return "[Untitled]"
|
238
|
+
t = title.dup
|
239
|
+
t.xpath(ns(".//tab | .//br")).each { |x| x.replace(" ") }
|
240
|
+
t.xpath(ns(".//strong")).each { |x| x.replace(x.children) }
|
241
|
+
t.children.to_xml
|
242
|
+
end
|
243
|
+
|
244
|
+
def collectionyaml(files, xml)
|
245
|
+
ret = {
|
246
|
+
directives: ["presentation-xml", "bare-after-first"],
|
247
|
+
bibdata: {
|
248
|
+
title: {
|
249
|
+
type: "title-main",
|
250
|
+
language: @lang,
|
251
|
+
content: xml.at(ns("//bibdata/title")).text,
|
252
|
+
},
|
253
|
+
type: "collection",
|
254
|
+
docid: {
|
255
|
+
type: xml.at(ns("//bibdata/docidentifier/@type")).text,
|
256
|
+
id: xml.at(ns("//bibdata/docidentifier")).text,
|
257
|
+
},
|
258
|
+
},
|
259
|
+
manifest: {
|
260
|
+
level: "collection",
|
261
|
+
title: "Collection",
|
262
|
+
docref: files.sort_by { |f| f[:order] }.each.map do |f|
|
263
|
+
{ fileref: f[:url], identifier: f[:title] }
|
264
|
+
end,
|
265
|
+
},
|
266
|
+
}
|
267
|
+
recursive_string_keys(ret).to_yaml
|
268
|
+
end
|
269
|
+
end
|
270
|
+
end
|
data/lib/metanorma/util.rb
CHANGED
@@ -12,8 +12,49 @@ module Metanorma
|
|
12
12
|
end
|
13
13
|
end
|
14
14
|
|
15
|
-
|
16
|
-
|
15
|
+
# dependency ordering
|
16
|
+
def self.sort_extensions_execution_ord(ext)
|
17
|
+
case ext
|
18
|
+
when :xml then 0
|
19
|
+
when :rxl then 1
|
20
|
+
when :presentation then 2
|
21
|
+
else
|
22
|
+
99
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.sort_extensions_execution(ext)
|
27
|
+
ext.sort do |a, b|
|
28
|
+
sort_extensions_execution_ord(a) <=> sort_extensions_execution_ord(b)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
class DisambigFiles
|
33
|
+
def initialize
|
34
|
+
@seen_filenames = []
|
35
|
+
end
|
36
|
+
|
37
|
+
def source2dest_filename(name, disambig = true)
|
38
|
+
n = name.sub(%r{^(\./)?(\.\./)+}, "")
|
39
|
+
dir = File.dirname(n)
|
40
|
+
base = File.basename(n)
|
41
|
+
if disambig && @seen_filenames.include?(base)
|
42
|
+
base = disambiguate_filename(base)
|
43
|
+
end
|
44
|
+
@seen_filenames << base
|
45
|
+
dir == "." ? base : File.join(dir, base)
|
46
|
+
end
|
47
|
+
|
48
|
+
def disambiguate_filename(base)
|
49
|
+
m = /^(?<start>.+\.)(?!0)(?<num>\d+)\.(?<suff>[^.]*)$/.match(base) ||
|
50
|
+
/^(?<start>.+\.)(?<suff>[^.]*)/.match(base) ||
|
51
|
+
/^(?<start>.+)$/.match(base)
|
52
|
+
i = m.names.include?("num") ? m["num"].to_i + 1 : 1
|
53
|
+
while @seen_filenames.include? base = "#{m['start']}#{i}.#{m['suff']}"
|
54
|
+
i += 1
|
55
|
+
end
|
56
|
+
base
|
57
|
+
end
|
17
58
|
end
|
18
59
|
end
|
19
60
|
end
|
data/lib/metanorma/version.rb
CHANGED
data/metanorma.gemspec
CHANGED
@@ -20,10 +20,10 @@ Gem::Specification.new do |spec|
|
|
20
20
|
spec.bindir = "bin"
|
21
21
|
# spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
22
22
|
spec.require_paths = ["lib"]
|
23
|
-
spec.required_ruby_version = ">= 2.
|
23
|
+
spec.required_ruby_version = ">= 2.5.0"
|
24
24
|
|
25
25
|
spec.add_runtime_dependency "asciidoctor"
|
26
|
-
spec.add_runtime_dependency "fontist", "~> 1.
|
26
|
+
spec.add_runtime_dependency "fontist", "~> 1.9.0"
|
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.
|
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
|