metanorma 1.2.7 → 1.3.3

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: 6c6df255e2338335a6f670965e34d61d3d808a3d9a1a69c78ef9af1f9a2f306f
4
- data.tar.gz: b5c485bdcd52c100d141b80c1ceb5a0f2a66b0eb45fa2a7efd56e3b57653596d
3
+ metadata.gz: fec4f760c22a19793bca3f3cb2c5abc0b355a8554d5ac0720fe8e679a26db842
4
+ data.tar.gz: ffa03687166474e66611a2fa0f5841281ae5b1127e078dd7cbf2993ec1a15f65
5
5
  SHA512:
6
- metadata.gz: 638bede7f3dffde3a6169e51a684fa10efec05975273ab6dc1495e95f074b21b0cc7cefaf168cb6a0ebe0d8c903dcf37ebbc4c023a6c1149cc42d16f517e67fd
7
- data.tar.gz: 727a3a66032ed783b5b099a035589666818d71a67e9f88366cf888fd3879c40ff5872533d39ef1e7b31dc8d15289274aea866637233b88c60e0f244b92d79f17
6
+ metadata.gz: 9721c89fe96d4bfb1bf6458fc79d824fa16887a349b2bdcd9618d6528ec0b32abf86158bc7658de8288bcf130ce3008427fcc06fe036179c652b70a2a3edd9f6
7
+ data.tar.gz: 74993bec3d7dca356699d821dadb55f35f7f7c20d6a8270e2c3fc9e224225504fe4fe3dee77cdf9cbc0a55eeee033df0253a17307fac8fec76772dc02c5c2f2f
@@ -49,5 +49,5 @@ jobs:
49
49
  with:
50
50
  token: ${{ secrets.METANORMA_CI_PAT_TOKEN || secrets.GITHUB_TOKEN }}
51
51
  repository: ${{ github.repository }}
52
- event-type: notify
52
+ event-type: tests-passed
53
53
  client-payload: '{"ref": "${{ github.ref }}", "sha": "${{ github.sha }}"}'
data/.gitignore CHANGED
@@ -20,3 +20,5 @@
20
20
  Gemfile.lock
21
21
  relaton/
22
22
  .vscode/
23
+
24
+ .rubocop-https--*
data/.hound.yml CHANGED
@@ -1,3 +1,5 @@
1
+ # Auto-generated by Cimas: Do not edit it manually!
2
+ # See https://github.com/metanorma/cimas
1
3
  ruby:
2
- Enabled: true
4
+ enabled: true
3
5
  config_file: .rubocop.yml
data/.rubocop.yml CHANGED
@@ -1,6 +1,10 @@
1
- # This project follows the Ribose OSS style guide.
2
- # https://github.com/riboseinc/oss-guides
3
- # All project-specific additions and overrides should be specified in this file.
4
-
1
+ # Auto-generated by Cimas: Do not edit it manually!
2
+ # See https://github.com/metanorma/cimas
5
3
  inherit_from:
6
4
  - https://raw.githubusercontent.com/riboseinc/oss-guides/master/ci/rubocop.yml
5
+
6
+ # local repo-specific modifications
7
+ # ...
8
+
9
+ AllCops:
10
+ TargetRubyVersion: 2.4
data/Rakefile CHANGED
@@ -3,4 +3,4 @@ require "rspec/core/rake_task"
3
3
 
4
4
  RSpec::Core::RakeTask.new(:spec)
5
5
 
6
- task :default => :spec
6
+ task default: :spec
@@ -1,20 +1,18 @@
1
1
  module Metanorma::AsciidoctorExtensions
2
-
3
2
  class GlobIncludeProcessor < ::Asciidoctor::Extensions::IncludeProcessor
4
- def process doc, reader, target_glob, attributes
3
+ def process(_doc, reader, target_glob, attributes)
5
4
  Dir[File.join reader.dir, target_glob].sort.reverse_each do |target|
6
5
  content = IO.readlines target
7
- content.unshift '' unless attributes['adjoin-option']
6
+ content.unshift "" unless attributes["adjoin-option"]
8
7
  reader.push_include content, target, target, 1, attributes
9
8
  end
10
9
  reader
11
10
  end
12
11
 
13
- def handles? target
14
- target.include? '*'
12
+ def handles?(target)
13
+ target.include? "*"
15
14
  end
16
15
  end
17
-
18
16
  end
19
17
 
20
18
  Asciidoctor::Extensions.register do
@@ -44,22 +44,28 @@ module Metanorma
44
44
  end
45
45
 
46
46
  # rubocop:enable Metrics/AbcSize,Metrics/MethodLength
47
- def clean_exit
48
- @log.write(File.join(File.dirname(@file), File.basename(@file, ".*") + ".err"))
49
- end
47
+ def clean_exit
48
+ @log.write(File.join(File.dirname(@file),
49
+ "#{File.basename(@file, '.*')}.err"))
50
+ end
50
51
 
51
52
  # @return [String] XML
52
53
  def to_xml
53
- Nokogiri::XML::Builder.new do |xml|
54
+ b = Nokogiri::XML::Builder.new do |xml|
54
55
  xml.send("metanorma-collection",
55
56
  "xmlns" => "http://metanorma.org") do |mc|
56
- mc << @bibdata.to_xml(bibdata: true, date_format: :full)
57
- @manifest.to_xml mc
58
- content_to_xml "prefatory", mc
59
- doccontainer mc
60
- content_to_xml "final", mc
57
+ collection_body(mc)
61
58
  end
62
- end.to_xml
59
+ end
60
+ b.to_xml
61
+ end
62
+
63
+ def collection_body(coll)
64
+ coll << @bibdata.to_xml(bibdata: true, date_format: :full)
65
+ @manifest.to_xml coll
66
+ content_to_xml "prefatory", coll
67
+ doccontainer coll
68
+ content_to_xml "final", coll
63
69
  end
64
70
 
65
71
  def render(opts)
@@ -110,7 +116,7 @@ module Metanorma
110
116
  # @parma mnf [Metanorma::CollectionManifest]
111
117
  # @return [Hash{String=>Metanorma::Document}]
112
118
  def docs_from_xml(xml, mnf)
113
- xml.xpath("//xmlns:doc-container/*/xmlns:bibdata")
119
+ xml.xpath("//xmlns:doc-container//xmlns:bibdata")
114
120
  .each_with_object({}) do |b, m|
115
121
  bd = Relaton::Cli.parse_xml b
116
122
  docref = mnf.docref_by_id bd.docidentifier.first.id
@@ -127,7 +133,7 @@ module Metanorma
127
133
  <<~CONT
128
134
 
129
135
  == #{xml.at('title')&.text}
130
- #{xml.at('p')&.text}
136
+ #{xml.at('p')&.text}
131
137
  CONT
132
138
  end
133
139
  end
@@ -152,8 +158,8 @@ module Metanorma
152
158
  return unless (cnt = send(elm))
153
159
 
154
160
  require "metanorma-#{doctype}"
155
- out = sections(dummy_header + cnt)
156
- builder.send(elm + "-content") { |b| b << out }
161
+ out = sections(dummy_header + cnt.strip)
162
+ builder.send("#{elm}-content") { |b| b << out }
157
163
  end
158
164
 
159
165
  # @param cnt [String] prefatory/final content
@@ -168,8 +174,18 @@ module Metanorma
168
174
  return unless Array(@directives).include? "documents-inline"
169
175
 
170
176
  documents.each_with_index do |(_, d), i|
171
- id = format("doc%<index>09d", index: i)
172
- builder.send("doc-container", id: id) { |b| d.to_xml b }
177
+ doccontainer1(builder, d, i)
178
+ end
179
+ end
180
+
181
+ def doccontainer1(builder, doc, idx)
182
+ id = format("doc%<index>09d", index: idx)
183
+ builder.send("doc-container", id: id) do |b|
184
+ if doc.attachment
185
+ doc.bibitem and b << doc.bibitem.root.to_xml
186
+ b.attachment Metanorma::Utils::datauri(doc.file)
187
+ else doc.to_xml b
188
+ end
173
189
  end
174
190
  end
175
191
 
@@ -0,0 +1,220 @@
1
+ module Metanorma
2
+ # XML collection renderer
3
+ class CollectionRenderer
4
+ # map locality type and label (e.g. "clause" "1") to id = anchor for
5
+ # a document
6
+ # Note: will only key clauses, which have unambiguous reference label in
7
+ # locality. Notes, examples etc with containers are just plunked against
8
+ # UUIDs, so that their IDs can at least be registered to be tracked
9
+ # as existing.
10
+ def read_anchors(xml)
11
+ xrefs = @isodoc.xref_init(@lang, @script, @isodoc, @isodoc.i18n, {})
12
+ xrefs.parse xml
13
+ xrefs.get.each_with_object({}) do |(k, v), ret|
14
+ ret[v[:type]] ||= {}
15
+ index = if v[:container] || v[:label].nil? || v[:label].empty?
16
+ UUIDTools::UUID.random_create.to_s
17
+ else v[:label]
18
+ end
19
+ ret[v[:type]][index] = k
20
+ end
21
+ end
22
+
23
+ # @param id [String]
24
+ # @param read [Boolean]
25
+ # @return [Array<String, nil>]
26
+ def xml_file(id, read)
27
+ file = @xml.at(ns("//doc-container[@id = '#{id}']")).to_xml if read
28
+ filename = "#{id}.html"
29
+ [file, filename]
30
+ end
31
+
32
+ # @param bib [Nokogiri::XML::Element]
33
+ # @param identifier [String]
34
+ def update_bibitem(bib, identifier) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
35
+ docid = bib&.at(ns("./docidentifier"))&.text
36
+ unless @files[docid]
37
+ error = "[metanorma] Cannot find crossreference to document #{docid} "\
38
+ "in document #{identifier}."
39
+ @log.add("Cross-References", nil, error)
40
+ Util.log(error, :warning)
41
+ return
42
+ end
43
+ id = bib["id"]
44
+ newbib = bib.replace(@files[docid][:bibdata])
45
+ newbib.name = "bibitem"
46
+ newbib["id"] = id
47
+ newbib["hidden"] = "true"
48
+ newbib&.at(ns("./ext"))&.remove
49
+ _file, url = targetfile(@files[docid], relative: true, read: false,
50
+ doc: !@files[docid][:attachment])
51
+ uri_node = Nokogiri::XML::Node.new "uri", newbib
52
+ uri_node[:type] = "citation"
53
+ uri_node.content = url
54
+ newbib.at(ns("./docidentifier")).previous = uri_node
55
+ end
56
+
57
+ # Resolves direct links to other files in collection
58
+ # (repo(current-metanorma-collection/x),
59
+ # and indirect links to other files in collection
60
+ # (bibitem[@type = 'internal'] pointing to a file anchor
61
+ # in another file in the collection)
62
+ # @param file [String] XML content
63
+ # @param identifier [String] docid
64
+ # @param internal_refs [Hash{String=>Hash{String=>String}] schema name to anchor to filename
65
+ # @return [String] XML content
66
+ def update_xrefs(file, identifier, internal_refs)
67
+ docxml = Nokogiri::XML(file)
68
+ update_indirect_refs_to_docs(docxml, internal_refs)
69
+ add_document_suffix(identifier, docxml)
70
+ update_direct_refs_to_docs(docxml, identifier)
71
+ svgmap_resolve(datauri_encode(docxml))
72
+ docxml.xpath(ns("//references[not(./bibitem[not(@hidden) or "\
73
+ "@hidden = 'false'])]")).each do |f|
74
+ f["hidden"] = "true"
75
+ end
76
+ docxml.to_xml
77
+ end
78
+
79
+ def datauri_encode(docxml)
80
+ docxml.xpath(ns("//image")).each do |i|
81
+ i["src"] = Metanorma::Utils::datauri(i["src"])
82
+ end
83
+ docxml
84
+ end
85
+
86
+ def svgmap_resolve(docxml)
87
+ isodoc = IsoDoc::Convert.new({})
88
+ docxml.xpath(ns("//svgmap//eref")).each do |e|
89
+ href = isodoc.eref_target(e)
90
+ next if href == "##{e['bibitemid']}" ||
91
+ href =~ /^#/ && !docxml.at("//*[@id = '#{href.sub(/^#/, '')}']")
92
+
93
+ e["target"] = href.strip
94
+ e.name = "link"
95
+ e&.elements&.remove
96
+ end
97
+ Metanorma::Utils::svgmap_rewrite(docxml, "")
98
+ end
99
+
100
+ # repo(current-metanorma-collection/ISO 17301-1:2016)
101
+ # replaced by bibdata of "ISO 17301-1:2016" in situ as bibitem.
102
+ # Any erefs to that bibitem id are replaced with relative URL
103
+ # Preferably with anchor, and is a job to realise dynamic lookup
104
+ # of localities.
105
+ def update_direct_refs_to_docs(docxml, identifier)
106
+ docxml.xpath(ns("//bibitem[not(ancestor::bibitem)]")).each do |b|
107
+ docid = b&.at(ns("./docidentifier[@type = 'repository']"))&.text
108
+ next unless docid && %r{^current-metanorma-collection/}.match(docid)
109
+
110
+ update_bibitem(b, identifier)
111
+ update_anchors(b, docxml, docid)
112
+ end
113
+ end
114
+
115
+ # Resolve erefs to a container of ids in another doc,
116
+ # to an anchor eref (direct link)
117
+ def update_indirect_refs_to_docs(docxml, internal_refs)
118
+ internal_refs.each do |schema, ids|
119
+ ids.each do |id, file|
120
+ update_indirect_refs_to_docs1(docxml, schema, id, file)
121
+ end
122
+ end
123
+ end
124
+
125
+ def update_indirect_refs_to_docs1(docxml, schema, id, file)
126
+ docxml.xpath(ns("//eref[@bibitemid = '#{schema}_#{id}']")).each do |e|
127
+ e["citeas"] = file
128
+ end
129
+ docid = docxml.at(ns("//bibitem[@id = '#{schema}_#{id}']/"\
130
+ "docidentifier[@type = 'repository']")) or return
131
+ docid.children = "current-metanorma-collection/#{file}"
132
+ docid.previous = "<docidentifier type='X'>#{file}</docidentifier>"
133
+ end
134
+
135
+ # update crossrefences to other documents, to include
136
+ # disambiguating document suffix on id
137
+ def update_anchors(bib, docxml, _id) # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
138
+ docid = bib&.at(ns("./docidentifier"))&.text
139
+ docxml.xpath("//xmlns:eref[@citeas = '#{docid}']").each do |e|
140
+ if @files[docid]
141
+ update_anchor_loc(bib, e, docid)
142
+ else
143
+ e << "<strong>** Unresolved reference to document #{docid}, "\
144
+ "id #{e['bibitemid']}</strong>"
145
+ end
146
+ end
147
+ end
148
+
149
+ def update_anchor_loc(bib, e, docid)
150
+ loc = e.at(ns(".//locality[@type = 'anchor']")) or
151
+ return update_anchor_create_loc(bib, e, docid)
152
+ document_suffix = Metanorma::Utils::to_ncname(docid)
153
+ ref = loc.at(ns("./referenceFrom")) || return
154
+ anchor = "#{ref.text}_#{document_suffix}"
155
+ return unless @files[docid][:anchors].inject([]) do |m, (_, x)|
156
+ m += x.values
157
+ end.include?(anchor)
158
+
159
+ ref.content = anchor
160
+ end
161
+
162
+ # if there is a crossref to another document, with no anchor, retrieve the
163
+ # anchor given the locality, and insert it into the crossref
164
+ def update_anchor_create_loc(bib, e, docid)
165
+ ins = e.at(ns("./localityStack")) || return
166
+ type = ins&.at(ns("./locality/@type"))&.text
167
+ ref = ins&.at(ns("./locality/referenceFrom"))&.text
168
+ (anchor = @files[docid][:anchors][type][ref]) || return
169
+ ref_from = Nokogiri::XML::Node.new "referenceFrom", bib
170
+ ref_from.content = anchor.sub(/^_/, "")
171
+ locality = Nokogiri::XML::Node.new "locality", bib
172
+ locality[:type] = "anchor"
173
+ locality.add_child ref_from
174
+ ins << locality
175
+ end
176
+
177
+ # gather internal bibitem references
178
+ def gather_internal_refs
179
+ @files.each_with_object({}) do |(_, x), refs|
180
+ next if x[:attachment]
181
+
182
+ file, = targetfile(x, read: true)
183
+ Nokogiri::XML(file)
184
+ .xpath(ns("//bibitem[@type = 'internal']/"\
185
+ "docidentifier[@type = 'repository']")).each do |d|
186
+ a = d.text.split(%r{/}, 2)
187
+ a.size > 1 or next
188
+ refs[a[0]] ||= {}
189
+ refs[a[0]][a[1]] = true
190
+ end
191
+ end
192
+ end
193
+
194
+ # resolve file location for the target of each internal reference
195
+ def locate_internal_refs
196
+ refs = gather_internal_refs
197
+ @files.keys.reject { |k| @files[k][:attachment] }.each do |identifier|
198
+ locate_internal_refs1(refs, identifier, @files[identifier])
199
+ end
200
+ refs.each do |schema, ids|
201
+ ids.each do |id, key|
202
+ key == true and refs[schema][id] = "Missing:#{schema}:#{id}"
203
+ end
204
+ end
205
+ refs
206
+ end
207
+
208
+ def locate_internal_refs1(refs, identifier, filedesc)
209
+ file, _filename = targetfile(filedesc, read: true)
210
+ docxml = Nokogiri::XML(file)
211
+ refs.each do |schema, ids|
212
+ ids.each_key do |id|
213
+ n = docxml.at("//*[@id = '#{id}']") and
214
+ n.at("./ancestor-or-self::*[@type = '#{schema}']") and
215
+ refs[schema][id] = identifier
216
+ end
217
+ end
218
+ end
219
+ end
220
+ end
@@ -2,6 +2,7 @@
2
2
 
3
3
  require "isodoc"
4
4
  require "metanorma-utils"
5
+ require_relative "collection_fileparse"
5
6
 
6
7
  module Metanorma
7
8
  # XML collection renderer
@@ -15,20 +16,36 @@ module Metanorma
15
16
  files = {}
16
17
  @xml.xpath(ns("//docref")).each do |d|
17
18
  identifier = d.at(ns("./identifier")).text
18
- files[identifier] = if d["fileref"]
19
- { type: "fileref",
20
- ref: File.join(path, d["fileref"]) }
21
- else { type: "id", ref: d["id"] }
22
- end
23
- file, _filename = targetfile(files[identifier], true)
24
- xml = Nokogiri::XML(file)
25
- add_document_suffix(identifier, xml)
26
- files[identifier][:anchors] = read_anchors(xml)
27
- files[identifier][:bibdata] = xml.at(ns("//bibdata"))
19
+ files[identifier] = file_entry(d, identifier, path)
20
+ if files[identifier][:attachment]
21
+ files[identifier][:bibdata] = Metanorma::Document
22
+ .attachment_bibitem(identifier).root
23
+ else
24
+ file, _filename = targetfile(files[identifier], read: true)
25
+ xml = Nokogiri::XML(file)
26
+ add_document_suffix(identifier, xml)
27
+ files[identifier][:anchors] = read_anchors(xml)
28
+ files[identifier][:bibdata] = xml.at(ns("//bibdata"))
29
+ end
28
30
  end
29
31
  files
30
32
  end
31
33
 
34
+ # rel_path is the source file address, determined relative to the YAML.
35
+ # out_path is the destination file address, with any references outside
36
+ # the working directory (../../...) truncated
37
+ def file_entry(docref, identifier, _path)
38
+ ret = if docref["fileref"]
39
+ { type: "fileref", ref: @documents[identifier].file,
40
+ rel_path: docref["fileref"],
41
+ out_path: Util::source2dest_filename(docref["fileref"]) }
42
+ else
43
+ { type: "id", ref: docref["id"] }
44
+ end
45
+ ret[:attachment] = docref["attachment"] if docref["attachment"]
46
+ ret
47
+ end
48
+
32
49
  def add_suffix_to_attributes(doc, suffix, tag_name, attribute_name)
33
50
  doc.xpath(ns("//#{tag_name}[@#{attribute_name}]")).each do |elem|
34
51
  elem.attributes[attribute_name].value =
@@ -38,240 +55,64 @@ module Metanorma
38
55
 
39
56
  def add_document_suffix(identifier, doc)
40
57
  document_suffix = Metanorma::Utils::to_ncname(identifier)
41
- [%w[* id],
42
- %w[* bibitemid],
43
- %w[review from],
44
- %w[review to],
45
- %w[index to],
46
- %w[xref target],
47
- %w[callout target]]
48
- .each do |(tag_name, attribute_name)|
58
+ [%w[* id], %w[* bibitemid], %w[review from],
59
+ %w[review to], %w[index to], %w[xref target],
60
+ %w[callout target]]
61
+ .each do |(tag_name, attribute_name)|
49
62
  add_suffix_to_attributes(doc, document_suffix, tag_name, attribute_name)
50
63
  end
51
64
  end
52
65
 
53
- # map locality type and label (e.g. "clause" "1") to id = anchor for
54
- # a document
55
- def read_anchors(xml)
56
- ret = {}
57
- xrefs = @isodoc.xref_init(@lang, @script, @isodoc, @isodoc.i18n, {})
58
- xrefs.parse xml
59
- xrefs.get.each do |k, v|
60
- ret[v[:type]] ||= {}
61
- index = v[:container] || v[:label].nil? || v[:label].empty? ?
62
- UUIDTools::UUID.random_create.to_s : v[:label]
63
- # Note: will only key clauses, which have unambiguous reference label in locality.
64
- # Notes, examples etc with containers are just plunked agaisnt UUIDs, so that their
65
- # IDs can at least be registered to be tracked as existing.
66
- ret[v[:type]][index] = k
67
- end
68
- ret
69
- end
70
-
71
66
  # return file contents + output filename for each file in the collection,
72
67
  # given a docref entry
73
- # @param data [Hash]
74
- # @param read [Boolean]
68
+ # @param data [Hash] docref entry
69
+ # @param read [Boolean] read the file in and return it
70
+ # @param doc [Boolean] I am a Metanorma document,
71
+ # so my URL should end with html or pdf or whatever
72
+ # @param relative [Boolean] Return output path,
73
+ # formed relative to YAML file, not input path, relative to calling function
75
74
  # @return [Array<String, nil>]
76
- def targetfile(data, read = false)
77
- if data[:type] == "fileref" then ref_file data[:ref], read
78
- else xml_file data[:id], read
75
+ def targetfile(data, options)
76
+ options = { read: false, doc: true, relative: false }.merge(options)
77
+ path = options[:relative] ? data[:out_path] : data[:ref]
78
+ if data[:type] == "fileref"
79
+ ref_file path, options[:read], options[:doc]
80
+ else
81
+ xml_file data[:id], options[:read]
79
82
  end
80
83
  end
81
84
 
82
85
  # @param ref [String]
83
86
  # @param read [Boolean]
87
+ # @param doc [Boolean]
84
88
  # @return [Array<String, nil>]
85
- def ref_file(ref, read)
89
+ def ref_file(ref, read, doc)
86
90
  file = File.read(ref, encoding: "utf-8") if read
87
- filename = ref.sub(/\.xml$/, ".html")
88
- [file, filename]
89
- end
90
-
91
- # @param id [String]
92
- # @param read [Boolean]
93
- # @return [Array<String, nil>]
94
- def xml_file(id, read)
95
- file = @xml.at(ns("//doc-container[@id = '#{id}']")).to_xml if read
96
- filename = id + ".html"
91
+ filename = ref.dup
92
+ filename.sub!(/\.xml$/, ".html") if doc
97
93
  [file, filename]
98
94
  end
99
95
 
100
- # @param bib [Nokogiri::XML::Element]
101
- # @param identifier [String]
102
- def update_bibitem(bib, identifier) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
103
- docid = bib&.at(ns("./docidentifier"))&.text
104
- unless @files[docid]
105
- error = "[metanorma] Cannot find crossreference to document #{docid} in document #{identifier}."
106
- @log.add("Cross-References", nil, error)
107
- Util.log(error, :warning)
108
- return
109
- end
110
- id = bib["id"]
111
- newbib = bib.replace(@files[docid][:bibdata])
112
- newbib.name = "bibitem"
113
- newbib["id"] = id
114
- newbib["hidden"] = "true"
115
- newbib&.at(ns("./ext"))&.remove
116
- _file, url = targetfile(@files[docid], false)
117
- uri_node = Nokogiri::XML::Node.new "uri", newbib
118
- uri_node[:type] = "citation"
119
- uri_node.content = url
120
- newbib.at(ns("./docidentifier")).previous = uri_node
121
- end
122
-
123
- # Resolves direct links to other files in collection (repo(current-metanorma-collection/x),
124
- # and indirect links to other files in collection (bibitem[@type = 'internal'] pointing to a file anchor
125
- # in another file in the collection)
126
- # @param file [String] XML content
127
- # @param identifier [String] docid
128
- # @param internal_refs [Hash{String=>Hash{String=>String}] schema name to anchor to filename
129
- # @return [String] XML content
130
- def update_xrefs(file, identifier, internal_refs)
131
- docxml = Nokogiri::XML(file)
132
- update_indirect_refs_to_docs(docxml, internal_refs)
133
- add_document_suffix(identifier, docxml)
134
- update_direct_refs_to_docs(docxml, identifier)
135
- svgmap_resolve(datauri_encode(docxml))
136
- docxml.xpath(ns("//references[not(./bibitem[not(@hidden) or @hidden = 'false'])]")).each do |f|
137
- f["hidden"] = "true"
138
- end
139
- docxml.to_xml
140
- end
141
-
142
- def datauri_encode(docxml)
143
- docxml.xpath(ns("//image")).each { |i| i["src"] = Metanorma::Utils::datauri(i["src"]) }
144
- docxml
145
- end
146
-
147
- def svgmap_resolve(docxml)
148
- isodoc = IsoDoc::Convert.new({})
149
- docxml.xpath(ns("//svgmap//eref")).each do |e|
150
- href = isodoc.eref_target(e)
151
- next if href == "#" + e["bibitemid"]
152
- if href.match(/^#/)
153
- next unless docxml.at("//*[@id = '#{href.sub(/^#/, '')}']")
154
- end
155
- e["target"] = href.strip
156
- e.name = "link"
157
- e&.elements&.remove
158
- end
159
- Metanorma::Utils::svgmap_rewrite(docxml, "")
160
- end
161
-
162
- # repo(current-metanorma-collection/ISO 17301-1:2016)
163
- # replaced by bibdata of "ISO 17301-1:2016" in situ as bibitem.
164
- # Any erefs to that bibitem id are replaced with relative URL
165
- # Preferably with anchor, and is a job to realise dynamic lookup of localities.
166
- def update_direct_refs_to_docs(docxml, identifier)
167
- docxml.xpath(ns("//bibitem[not(ancestor::bibitem)]")).each do |b|
168
- docid = b&.at(ns("./docidentifier[@type = 'repository']"))&.text
169
- next unless docid && %r{^current-metanorma-collection/}.match(docid)
170
- update_bibitem(b, identifier)
171
- update_anchors(b, docxml, docid)
172
- end
173
- end
174
-
175
- # Resolve erefs to a container of ids in another doc, to an anchor eref (direct link)
176
- def update_indirect_refs_to_docs(docxml, internal_refs)
177
- internal_refs.each do |schema, ids|
178
- ids.each do |id, file|
179
- update_indirect_refs_to_docs1(docxml, schema, id, file)
180
- end
181
- end
182
- end
183
-
184
- def update_indirect_refs_to_docs1(docxml, schema, id, file)
185
- docxml.xpath(ns("//eref[@bibitemid = '#{schema}_#{id}']")).each do |e|
186
- e["citeas"] = file
187
- end
188
- docid = docxml.at(ns("//bibitem[@id = '#{schema}_#{id}']/docidentifier[@type = 'repository']")) or return
189
- docid.children = "current-metanorma-collection/#{file}"
190
- docid.previous = "<docidentifier type='X'>#{file}</docidentifier>"
191
- end
192
-
193
- # update crossrefences to other documents, to include disambiguating document suffix on id
194
- def update_anchors(bib, docxml, _id) # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
195
- docid = bib&.at(ns("./docidentifier"))&.text
196
- docxml.xpath("//xmlns:eref[@citeas = '#{docid}']").each do |e|
197
- if @files[docid]
198
- update_anchor_loc(bib, e, docid)
199
- else
200
- e << "<strong>** Unresolved reference to document #{docid}, id #{e['bibitemid']}</strong>"
201
- end
202
- end
203
- end
204
-
205
- def update_anchor_loc(bib, e, docid)
206
- loc = e.at(ns(".//locality[@type = 'anchor']")) or return update_anchor_create_loc(bib, e, docid)
207
- document_suffix = Metanorma::Utils::to_ncname(docid)
208
- ref = loc.at(ns("./referenceFrom")) || return
209
- anchor = "#{ref.text}_#{document_suffix}"
210
- return unless @files[docid][:anchors].inject([]) { |m, (_, x)| m+= x.values }.include?(anchor)
211
- ref.content = anchor
212
- end
213
-
214
- # if there is a crossref to another document, with no anchor, retrieve the
215
- # anchor given the locality, and insert it into the crossref
216
- def update_anchor_create_loc(bib, e, docid)
217
- ins = e.at(ns("./localityStack")) || return
218
- type = ins&.at(ns("./locality/@type"))&.text
219
- ref = ins&.at(ns("./locality/referenceFrom"))&.text
220
- (anchor = @files[docid][:anchors][type][ref]) || return
221
- ref_from = Nokogiri::XML::Node.new "referenceFrom", bib
222
- ref_from.content = anchor.sub(/^_/, "")
223
- locality = Nokogiri::XML::Node.new "locality", bib
224
- locality[:type] = "anchor"
225
- locality.add_child ref_from
226
- ins << locality
227
- end
228
-
229
96
  # compile and output individual file in collection
230
- def file_compile(f, filename, identifier)
97
+ def file_compile(file, filename, identifier)
231
98
  # warn "metanorma compile -x html #{f.path}"
232
99
  c = Compile.new
233
- c.compile f.path, { format: :asciidoc, extension_keys: @format }.merge(@compile_options)
100
+ c.compile file.path, { format: :asciidoc,
101
+ extension_keys: @format }.merge(@compile_options)
234
102
  @files[identifier][:outputs] = {}
235
103
  @format.each do |e|
236
104
  ext = c.processor.output_formats[e]
237
105
  fn = File.basename(filename).sub(/(?<=\.)[^\.]+$/, ext.to_s)
238
- FileUtils.mv f.path.sub(/\.xml$/, ".#{ext}"), File.join(@outdir, fn)
106
+ FileUtils.mv file.path.sub(/\.xml$/, ".#{ext}"), File.join(@outdir, fn)
239
107
  @files[identifier][:outputs][e] = File.join(@outdir, fn)
240
108
  end
241
109
  end
242
110
 
243
- # gather internal bibitem references
244
- def gather_internal_refs
245
- @files.each_with_object({}) do |(identifier, x), refs|
246
- file, _ = targetfile(x, true)
247
- Nokogiri::XML(file).xpath(ns("//bibitem[@type = 'internal']/docidentifier[@type = 'repository']")).each do |d|
248
- a = d.text.split(%r{/}, 2)
249
- a.size > 1 or next
250
- refs[a[0]] ||= {}
251
- refs[a[0]][a[1]] = true
252
- end
253
- end
254
- end
255
-
256
- # resolve file location for the target of each internal reference
257
- def locate_internal_refs
258
- refs = gather_internal_refs
259
- @files.each do |identifier, x|
260
- file, filename = targetfile(x, true)
261
- docxml = Nokogiri::XML(file)
262
- refs.each do |schema, ids|
263
- ids.keys.each do |id|
264
- n = docxml.at("//*[@id = '#{id}']") and n.at("./ancestor-or-self::*[@type = '#{schema}']") and
265
- refs[schema][id] = identifier
266
- end
267
- end
268
- end
269
- refs.each do |schema, ids|
270
- ids.each do |id, key|
271
- key == true and refs[schema][id] = "Missing:#{schema}:#{id}"
272
- end
273
- end
274
- refs
111
+ def copy_file_to_dest(fileref)
112
+ _file, filename = targetfile(fileref, read: true, doc: false)
113
+ dest = File.join(@outdir, fileref[:out_path])
114
+ FileUtils.mkdir_p(File.dirname(dest))
115
+ FileUtils.cp filename, dest
275
116
  end
276
117
 
277
118
  # process each file in the collection
@@ -279,12 +120,15 @@ module Metanorma
279
120
  def files # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
280
121
  internal_refs = locate_internal_refs
281
122
  @files.each do |identifier, x|
282
- file, filename = targetfile(x, true)
283
- file = update_xrefs(file, identifier, internal_refs)
284
- Tempfile.open(["collection", ".xml"], encoding: "utf-8") do |f|
285
- f.write(file)
286
- f.close
287
- file_compile(f, filename, identifier)
123
+ if x[:attachment] then copy_file_to_dest(x)
124
+ else
125
+ file, filename = targetfile(x, read: true)
126
+ file = update_xrefs(file, identifier, internal_refs)
127
+ Tempfile.open(["collection", ".xml"], encoding: "utf-8") do |f|
128
+ f.write(file)
129
+ f.close
130
+ file_compile(f, filename, identifier)
131
+ end
288
132
  end
289
133
  end
290
134
  end