metanorma 1.3.5 → 1.3.9

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d4ccf8d6a09fd9345faa44ae7201b4f7ee8816a6f36245c26b2482abd3f7afa9
4
- data.tar.gz: 7997e0bea6b752e07f7db96f19b6d136b7a9740c046a0850022b477a2223a85b
3
+ metadata.gz: 46ea9a7ce8316d94001c40043488f3472bcf639264e446bfb5bfaad88b6bed70
4
+ data.tar.gz: 7e4bfc4c4346c518d845052fd2dbb0b1f51f63e2951a317c18d938f9663cdea3
5
5
  SHA512:
6
- metadata.gz: 162c6e5e79ff9f7f4f41b17444c68ec23168ee593173b72c251c8623f9a16916f6ae557bc581f39d220c2c6d68d6350c2e4f4de7c000a87e90f39bed7e825609
7
- data.tar.gz: a92a8a6ddd41e404cb6a1e00e0a0aaa2ecd645723486769b8656bb09e10f9e595a9df81231713224f6f9781d17c1c6943135d978b5865d0c02842b5e0ccbb84c
6
+ metadata.gz: fdb777c1e35bbeeac65f3e5b0654ead9633a196340017da8cd4bd84342a9500a891a14ac19d83cc0cda0e5301728afdddf367fa3871eece62b389d93d0144238
7
+ data.tar.gz: c264222db4c7e2cbd7342aac8da9c5480a1d48f277ce2c5ef23000443d618379abb0769d111a8846733d60a53364706a65edd1a14de7ada03b94d16182c479bb
@@ -16,7 +16,7 @@ jobs:
16
16
  strategy:
17
17
  fail-fast: false
18
18
  matrix:
19
- ruby: [ '3.0', '2.7', '2.6', '2.5', '2.4' ]
19
+ ruby: [ '3.0', '2.7', '2.6', '2.5' ]
20
20
  os: [ ubuntu-latest, windows-latest, macos-latest ]
21
21
  experimental: [ false ]
22
22
  steps:
data/Gemfile CHANGED
@@ -6,6 +6,6 @@ git_source(:github) { |repo| "https://github.com/#{repo}" }
6
6
 
7
7
  gemspec
8
8
 
9
- if File.exist? 'Gemfile.devel'
10
- eval File.read('Gemfile.devel'), nil, 'Gemfile.devel' # rubocop:disable Security/Eval
9
+ if File.exist? "Gemfile.devel"
10
+ eval File.read("Gemfile.devel"), nil, "Gemfile.devel" # rubocop:disable Security/Eval
11
11
  end
data/lib/metanorma.rb CHANGED
@@ -5,7 +5,6 @@ require "asciidoctor"
5
5
  require "metanorma/util"
6
6
  require "metanorma/config"
7
7
  require "metanorma/input"
8
- require "metanorma/output"
9
8
  require "metanorma/registry"
10
9
  require "metanorma/processor"
11
10
  require "metanorma/asciidoctor_extensions"
@@ -91,7 +91,9 @@ module Metanorma
91
91
  private
92
92
 
93
93
  def parse_xml(file)
94
- xml = Nokogiri::XML File.read(file, encoding: "UTF-8")
94
+ xml = Nokogiri::XML File.read(file, encoding: "UTF-8") do |config|
95
+ config.huge
96
+ end
95
97
  if (b = xml.at("/xmlns:metanorma-collection/xmlns:bibdata"))
96
98
  bd = Relaton::Cli.parse_xml b
97
99
  end
@@ -11,17 +11,21 @@ module Metanorma
11
11
  xrefs = @isodoc.xref_init(@lang, @script, @isodoc, @isodoc.i18n, {})
12
12
  xrefs.parse xml
13
13
  xrefs.get.each_with_object({}) do |(k, v), ret|
14
- v[:type] ||= "clause"
15
- ret[v[:type]] ||= {}
16
- index = if v[:container] || v[:label].nil? || v[:label].empty?
17
- UUIDTools::UUID.random_create.to_s
18
- else v[:label]
19
- end
20
- ret[v[:type]][index] = k
21
- ret[v[:type]][v[:value]] = k if v[:value]
14
+ read_anchors1(k, v, ret)
22
15
  end
23
16
  end
24
17
 
18
+ def read_anchors1(key, val, ret)
19
+ val[:type] ||= "clause"
20
+ ret[val[:type]] ||= {}
21
+ index = if val[:container] || val[:label].nil? || val[:label].empty?
22
+ UUIDTools::UUID.random_create.to_s
23
+ else val[:label]
24
+ end
25
+ ret[val[:type]][index] = key
26
+ ret[val[:type]][val[:value]] = key if val[:value]
27
+ end
28
+
25
29
  # @param id [String]
26
30
  # @param read [Boolean]
27
31
  # @return [Array<String, nil>]
@@ -33,30 +37,36 @@ module Metanorma
33
37
 
34
38
  # @param bib [Nokogiri::XML::Element]
35
39
  # @param identifier [String]
36
- def update_bibitem(bib, identifier) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
40
+ def update_bibitem(bib, identifier) # rubocop:disable Metrics/AbcSize
37
41
  docid = bib&.at(ns("./docidentifier"))&.children&.to_xml
38
- unless @files[docid]
39
- error = "[metanorma] Cannot find crossreference to document #{docid} "\
40
- "in document #{identifier}."
41
- @log.add("Cross-References", nil, error)
42
- Util.log(error, :warning)
43
- return
44
- end
45
- id = bib["id"]
46
- newbib = @files[docid][:bibdata].dup
47
- newbib.name = "bibitem"
48
- newbib["id"] = id
49
- newbib["hidden"] = "true"
50
- newbib&.at("./*[local-name() = 'ext']")&.remove
42
+ return fail_update_bibitem(docid, identifier) unless @files[docid]
43
+
44
+ newbib = dup_bibitem(docid, bib)
51
45
  bib.replace(newbib)
52
46
  _file, url = targetfile(@files[docid], relative: true, read: false,
53
- doc: !@files[docid][:attachment])
47
+ doc: !@files[docid][:attachment])
54
48
  uri_node = Nokogiri::XML::Node.new "uri", newbib
55
49
  uri_node[:type] = "citation"
56
50
  uri_node.content = url
57
51
  newbib.at(ns("./docidentifier")).previous = uri_node
58
52
  end
59
53
 
54
+ def fail_update_bibitem(docid, identifier)
55
+ error = "[metanorma] Cannot find crossreference to document #{docid} "\
56
+ "in document #{identifier}."
57
+ @log.add("Cross-References", nil, error)
58
+ Util.log(error, :warning)
59
+ end
60
+
61
+ def dup_bibitem(docid, bib)
62
+ newbib = @files[docid][:bibdata].dup
63
+ newbib.name = "bibitem"
64
+ newbib["hidden"] = "true"
65
+ newbib&.at("./*[local-name() = 'ext']")&.remove
66
+ newbib["id"] = bib["id"]
67
+ newbib
68
+ end
69
+
60
70
  # Resolves direct links to other files in collection
61
71
  # (repo(current-metanorma-collection/x),
62
72
  # and indirect links to other files in collection
@@ -67,7 +77,7 @@ module Metanorma
67
77
  # @param internal_refs [Hash{String=>Hash{String=>String}] schema name to anchor to filename
68
78
  # @return [String] XML content
69
79
  def update_xrefs(file, identifier, internal_refs)
70
- docxml = Nokogiri::XML(file)
80
+ docxml = Nokogiri::XML(file) { |config| config.huge }
71
81
  update_indirect_refs_to_docs(docxml, internal_refs)
72
82
  add_document_suffix(identifier, docxml)
73
83
  update_direct_refs_to_docs(docxml, identifier)
@@ -106,12 +116,18 @@ module Metanorma
106
116
  # Preferably with anchor, and is a job to realise dynamic lookup
107
117
  # of localities.
108
118
  def update_direct_refs_to_docs(docxml, identifier)
119
+ erefs = docxml.xpath(ns("//eref"))
120
+ .each_with_object({ citeas: {}, bibitemid: {} }) do |i, m|
121
+ m[:citeas][i["citeas"]] = true
122
+ m[:bibitemid][i["bibitemid"]] = true
123
+ end
109
124
  docxml.xpath(ns("//bibitem[not(ancestor::bibitem)]")).each do |b|
110
125
  docid = b&.at(ns("./docidentifier[@type = 'repository']"))&.text
111
126
  next unless docid && %r{^current-metanorma-collection/}.match(docid)
112
127
 
113
128
  update_bibitem(b, identifier)
114
- update_anchors(b, docxml, docid)
129
+ docid = b&.at(ns("./docidentifier"))&.children&.to_xml or next
130
+ erefs[:citeas][docid] and update_anchors(b, docxml, docid)
115
131
  end
116
132
  end
117
133
 
@@ -128,6 +144,9 @@ module Metanorma
128
144
  def update_indirect_refs_to_docs1(docxml, schema, id, file)
129
145
  docxml.xpath(ns("//eref[@bibitemid = '#{schema}_#{id}']")).each do |e|
130
146
  e["citeas"] = file
147
+ if a = e.at(ns(".//locality[@type = 'anchor']/referenceFrom"))
148
+ a.children = "#{a.text}_#{Metanorma::Utils::to_ncname(file)}"
149
+ end
131
150
  end
132
151
  docid = docxml.at(ns("//bibitem[@id = '#{schema}_#{id}']/"\
133
152
  "docidentifier[@type = 'repository']")) or return
@@ -137,21 +156,19 @@ module Metanorma
137
156
 
138
157
  # update crossrefences to other documents, to include
139
158
  # disambiguating document suffix on id
140
- def update_anchors(bib, docxml, _id) # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
141
- docid = bib&.at(ns("./docidentifier"))&.children.to_xml
159
+ def update_anchors(bib, docxml, docid) # rubocop:disable Metrics/AbcSize
142
160
  docxml.xpath("//xmlns:eref[@citeas = '#{docid}']").each do |e|
143
- if @files[docid]
144
- update_anchor_loc(bib, e, docid)
161
+ if @files[docid] then update_anchor_loc(bib, e, docid)
145
162
  else
146
- e << "<strong>** Unresolved reference to document #{docid}, "\
147
- "id #{e['bibitemid']}</strong>"
163
+ e << "<strong>** Unresolved reference to document #{docid} "\
164
+ "from eref</strong>"
148
165
  end
149
166
  end
150
167
  end
151
168
 
152
- def update_anchor_loc(bib, e, docid)
153
- loc = e.at(ns(".//locality[@type = 'anchor']")) or
154
- return update_anchor_create_loc(bib, e, docid)
169
+ def update_anchor_loc(bib, eref, docid)
170
+ loc = eref.at(ns(".//locality[@type = 'anchor']")) or
171
+ return update_anchor_create_loc(bib, eref, docid)
155
172
  document_suffix = Metanorma::Utils::to_ncname(docid)
156
173
  ref = loc.at(ns("./referenceFrom")) || return
157
174
  anchor = "#{ref.text}_#{document_suffix}"
@@ -164,18 +181,14 @@ module Metanorma
164
181
 
165
182
  # if there is a crossref to another document, with no anchor, retrieve the
166
183
  # anchor given the locality, and insert it into the crossref
167
- def update_anchor_create_loc(bib, eref, docid)
184
+ def update_anchor_create_loc(_bib, eref, docid)
168
185
  ins = eref.at(ns("./localityStack")) or return
169
186
  type = ins&.at(ns("./locality/@type"))&.text
170
187
  type = "clause" if type == "annex"
171
188
  ref = ins&.at(ns("./locality/referenceFrom"))&.text
172
189
  anchor = @files[docid][:anchors].dig(type, ref) or return
173
- ref_from = Nokogiri::XML::Node.new "referenceFrom", bib
174
- ref_from.content = anchor.sub(/^_/, "")
175
- locality = Nokogiri::XML::Node.new "locality", bib
176
- locality[:type] = "anchor"
177
- locality.add_child ref_from
178
- ins << locality
190
+ ins << "<locality type='anchor'><referenceFrom>#{anchor.sub(/^_/, '')}"\
191
+ "</referenceFrom></locality>"
179
192
  end
180
193
 
181
194
  # gather internal bibitem references
@@ -186,7 +199,7 @@ module Metanorma
186
199
  file, = targetfile(x, read: true)
187
200
  Nokogiri::XML(file)
188
201
  .xpath(ns("//bibitem[@type = 'internal']/"\
189
- "docidentifier[@type = 'repository']")).each do |d|
202
+ "docidentifier[@type = 'repository']")).each do |d|
190
203
  a = d.text.split(%r{/}, 2)
191
204
  a.size > 1 or next
192
205
  refs[a[0]] ||= {}
@@ -211,10 +224,11 @@ module Metanorma
211
224
 
212
225
  def locate_internal_refs1(refs, identifier, filedesc)
213
226
  file, _filename = targetfile(filedesc, read: true)
214
- docxml = Nokogiri::XML(file)
227
+ xml = Nokogiri::XML(file) { |config| config.huge }
228
+ t = xml.xpath("//*/@id").each_with_object({}) { |i, x| x[i.text] = true }
215
229
  refs.each do |schema, ids|
216
- ids.each_key do |id|
217
- n = docxml.at("//*[@id = '#{id}']") and
230
+ ids.keys.select { |id| t[id] }.each do |id|
231
+ n = xml.at("//*[@id = '#{id}']") and
218
232
  n.at("./ancestor-or-self::*[@type = '#{schema}']") and
219
233
  refs[schema][id] = identifier
220
234
  end
@@ -27,8 +27,69 @@ module Metanorma
27
27
  files[identifier][:anchors] = read_anchors(xml)
28
28
  files[identifier][:bibdata] = xml.at(ns("//bibdata"))
29
29
  end
30
+ files[identifier][:bibitem] = files[identifier][:bibdata].dup
31
+ files[identifier][:bibitem].name = "bibitem"
32
+ files[identifier][:bibitem]["hidden"] = "true"
33
+ files[identifier][:bibitem]&.at("./*[local-name() = 'ext']")&.remove
30
34
  end
31
- files
35
+ add_section_split(files)
36
+ end
37
+
38
+ def add_section_split(files)
39
+ files.keys.each_with_object({}) do |k, m|
40
+ if files[k][:sectionsplit] == "true" && !files[k]["attachment"]
41
+ s, manifest = sectionsplit(files[k][:ref])
42
+ s.each_with_index do |f1, i|
43
+ add_section_split_instance(f1, m, k, i, files)
44
+ end
45
+ m["#{k}:index.html"] = add_section_split_cover(files, manifest, k)
46
+ end
47
+ m[k] = files[k]
48
+ end
49
+ end
50
+
51
+ def add_section_split_cover(files, manifest, ident)
52
+ cover = section_split_cover(manifest, ident)
53
+ files[ident][:out_path] = cover
54
+ { attachment: true, index: false, out_path: cover,
55
+ ref: File.join(File.dirname(manifest.file), cover) }
56
+ end
57
+
58
+ def section_split_cover(col, ident)
59
+ dir = File.dirname(col.file)
60
+ @compile.collection_setup(nil, dir)
61
+ CollectionRenderer.new(col, dir,
62
+ output_folder: "#{ident}_collection",
63
+ format: %i(html),
64
+ coverpage: File.join(dir, "cover.html")).coverpage
65
+ FileUtils.mv "#{ident}_collection/index.html",
66
+ File.join(dir, "#{ident}_index.html")
67
+ FileUtils.rm_rf "#{ident}_collection"
68
+ "#{ident}_index.html"
69
+ end
70
+
71
+ def add_section_split_instance(file, manifest, key, idx, files)
72
+ dir = File.dirname(files[key][:ref])
73
+ presfile = File.join(dir, File.basename(file[:url]))
74
+ manifest["#{key} #{file[:title]}"] =
75
+ { parentid: key, presentationxml: true, type: "fileref",
76
+ rel_path: file[:url], out_path: File.basename(file[:url]),
77
+ anchors: read_anchors(Nokogiri::XML(File.read(presfile))),
78
+ bibdata: files[key][:bibdata], ref: presfile }
79
+ manifest["#{key} #{file[:title]}"][:bare] = true unless idx.zero?
80
+ end
81
+
82
+ def sectionsplit(file)
83
+ @compile.compile(
84
+ file, { format: :asciidoc, extension_keys: [:presentation] }
85
+ .merge(@compile_options)
86
+ )
87
+ r = file.sub(/\.xml$/, ".presentation.xml")
88
+ xml = Nokogiri::XML(File.read(r))
89
+ s = @compile.sectionsplit(xml, File.basename(r), File.dirname(r))
90
+ .sort_by { |f| f[:order] }
91
+ [s, @compile.collection_manifest(File.basename(r), s, xml, nil,
92
+ File.dirname(r))]
32
93
  end
33
94
 
34
95
  # rel_path is the source file address, determined relative to the YAML.
@@ -43,7 +104,11 @@ module Metanorma
43
104
  else
44
105
  { type: "id", ref: ref["id"] }
45
106
  end
46
- ret[:attachment] = ref["attachment"] if ref["attachment"]
107
+ %i(attachment sectionsplit index).each do |s|
108
+ ret[s] = ref[s.to_s] if ref[s.to_s]
109
+ end
110
+ ret[:presentationxml] = ref["presentation-xml"] if ref["presentation-xml"]
111
+ ret[:bareafterfirst] = ref["bare-after-first"] if ref["bare-after-first"]
47
112
  ret
48
113
  end
49
114
 
@@ -95,22 +160,51 @@ module Metanorma
95
160
  end
96
161
 
97
162
  # compile and output individual file in collection
163
+ # warn "metanorma compile -x html #{f.path}"
98
164
  def file_compile(file, filename, identifier)
99
- # warn "metanorma compile -x html #{f.path}"
100
- Array(@directives).include?("presentation-xml") and
101
- @compile_options.merge!(passthrough_presentation_xml: true)
102
- c = Compile.new
103
- c.compile file.path, { format: :asciidoc,
104
- extension_keys: @format }.merge(@compile_options)
165
+ return if @files[identifier][:sectionsplit] == "true"
166
+
167
+ @compile.compile file.path, { format: :asciidoc, extension_keys: @format }
168
+ .merge(compile_options(identifier))
105
169
  @files[identifier][:outputs] = {}
170
+ file_compile_formats(file, filename, identifier)
171
+ end
172
+
173
+ def compile_options(identifier)
174
+ ret = @compile_options.dup
175
+ Array(@directives).include?("presentation-xml") ||
176
+ @files[identifier][:presentationxml] and
177
+ ret.merge!(passthrough_presentation_xml: true)
178
+ @files[identifier][:sectionsplit] == "true" and
179
+ ret.merge!(sectionsplit: "true")
180
+ @files[identifier][:bare] == true and
181
+ ret.merge!(bare: true)
182
+ ret
183
+ end
184
+
185
+ def file_compile_formats(file, filename, identifier)
106
186
  @format.each do |e|
107
- ext = c.processor.output_formats[e]
108
- fn = File.basename(filename).sub(/(?<=\.)[^\.]+$/, ext.to_s)
109
- FileUtils.cp file.path.sub(/\.xml$/, ".#{ext}"), File.join(@outdir, fn)
110
- @files[identifier][:outputs][e] = File.join(@outdir, fn)
187
+ ext = @compile.processor.output_formats[e]
188
+ fn = File.basename(filename).sub(/(?<=\.)[^.]+$/, ext.to_s)
189
+ if /html$/.match?(ext) && @files[identifier][:sectionsplit]
190
+ # file_sectionsplit_copy(file, fn, identifier, ext, e)
191
+ else
192
+ FileUtils.cp file.path.sub(/\.xml$/, ".#{ext}"),
193
+ File.join(@outdir, fn)
194
+ @files[identifier][:outputs][e] = File.join(@outdir, fn)
195
+ end
111
196
  end
112
197
  end
113
198
 
199
+ def file_sectionsplit_copy(file, base, identifier, ext, format)
200
+ dir = file.path.sub(/\.xml$/, ".#{ext}_collection")
201
+ files = Dir.glob("#{dir}/*.#{ext}")
202
+ FileUtils.cp files, @outdir
203
+ cover = File.join(@outdir, base.sub(/\.html$/, ".index.html"))
204
+ FileUtils.cp File.join(dir, "index.html"), cover
205
+ @files[identifier][:outputs][format] = cover
206
+ end
207
+
114
208
  def copy_file_to_dest(fileref)
115
209
  dest = File.join(@outdir, fileref[:out_path])
116
210
  FileUtils.mkdir_p(File.dirname(dest))
@@ -120,6 +214,7 @@ module Metanorma
120
214
  # process each file in the collection
121
215
  # files are held in memory, and altered as postprocessing
122
216
  def files # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
217
+ warn "\n\n\n\n\nInternal Refs: #{DateTime.now.strftime('%H:%M:%S')}"
123
218
  internal_refs = locate_internal_refs
124
219
  @files.each_with_index do |(identifier, x), i|
125
220
  i.positive? && Array(@directives).include?("bare-after-first") and
@@ -127,6 +222,7 @@ module Metanorma
127
222
  if x[:attachment] then copy_file_to_dest(x)
128
223
  else
129
224
  file, filename = targetfile(x, read: true)
225
+ warn "\n\n\n\n\nProcess #{filename}: #{DateTime.now.strftime('%H:%M:%S')}"
130
226
  file = update_xrefs(file, identifier, internal_refs)
131
227
  Tempfile.open(["collection", ".xml"], encoding: "utf-8") do |f|
132
228
  f.write(file)
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  require_relative "util"
3
4
 
4
5
  module Metanorma
@@ -46,8 +47,10 @@ module Metanorma
46
47
  def parse_docref(mnf)
47
48
  mnf.xpath("xmlns:docref").map do |dr|
48
49
  h = { "identifier" => dr.at("identifier").children.to_xml }
49
- dr[:fileref] and h["fileref"] = dr[:fileref]
50
- h["attachment"] = dr[:attachment] if dr[:attachment]
50
+ %i(fileref attachment sectionsplit index).each do |s|
51
+ h[s.to_s] = dr[s] if dr[s]
52
+ end
53
+ h["presentation-xml"] = dr[:presentationxml] if dr[:presentationxml]
51
54
  h
52
55
  end
53
56
  end
@@ -59,7 +62,7 @@ module Metanorma
59
62
  @manifest.each { |mnf| mnf.collection = col }
60
63
  end
61
64
 
62
- # @param dir [String] path to coolection
65
+ # @param dir [String] path to collection
63
66
  # @return [Hash<String, Metanorma::Document>]
64
67
  def documents(dir = "")
65
68
  docs = @docref.each_with_object({}) do |dr, m|
@@ -67,7 +70,7 @@ module Metanorma
67
70
 
68
71
  m[dr["identifier"]] = Document.parse_file(
69
72
  File.join(dir, dr["fileref"]),
70
- dr["attachment"], dr["identifier"]
73
+ dr["attachment"], dr["identifier"], dr["index"]
71
74
  )
72
75
  m
73
76
  end
@@ -115,7 +118,16 @@ module Metanorma
115
118
 
116
119
  def docref_to_xml_attrs(elem, docref)
117
120
  elem[:fileref] = @disambig.source2dest_filename(docref["fileref"])
118
- elem[:attachment] = docref["attachment"] if docref["attachment"]
121
+ %i(attachment sectionsplit).each do |i|
122
+ elem[i] = docref[i.to_s] if docref[i.to_s]
123
+ end
124
+ elem[:index] = docref.has_key?("index") ? docref["index"] : "true"
125
+ elem[:presentationxml] = "true" if docref["presentation-xml"] &&
126
+ [true, "true"].include?(docref["presentation-xml"])
127
+ docref_to_xml_attrs_id(elem, docref)
128
+ end
129
+
130
+ def docref_to_xml_attrs_id(elem, docref)
119
131
  if collection.directives.include?("documents-inline")
120
132
  id = collection.documents.find_index do |k, _|
121
133
  k == docref["identifier"]