metanorma 1.3.4 → 1.3.8
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/.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
|