metanorma 1.3.4 → 1.3.8

Sign up to get free protection for your applications and to get access to all the features.
@@ -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 + "-standard") { |b| b << @bibitem.to_xml(bibdata: true) }
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 bare i18nyaml
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
@@ -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, inname, outname, format, options={})
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
@@ -12,8 +12,49 @@ module Metanorma
12
12
  end
13
13
  end
14
14
 
15
- def self.source2dest_filename(name)
16
- name.sub(%r{^(\./)?(\.\./)+}, "")
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
@@ -1,3 +1,3 @@
1
1
  module Metanorma
2
- VERSION = "1.3.4".freeze
2
+ VERSION = "1.3.8".freeze
3
3
  end
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.4.0"
23
+ spec.required_ruby_version = ">= 2.5.0"
24
24
 
25
25
  spec.add_runtime_dependency "asciidoctor"
26
- spec.add_runtime_dependency "fontist", "~> 1.8"
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.8.0"
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