metanorma 1.2.6 → 1.3.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e4552898da027404dc0a7556a0c3b97d8c55c014c8ef397dff1d421f495a748d
4
- data.tar.gz: a9a7f45f7e35f5a06bdc05c367a8ff3f25369251f5de1993fdbd166604a9349e
3
+ metadata.gz: 6da8527ed559d4b6833977c169022db5dfec3a9d93926257586d9e676a11e578
4
+ data.tar.gz: cf9cc8d31d2ae7cbd08787dcb3f4a79747e85fad5c142bc02fd377df91e467e0
5
5
  SHA512:
6
- metadata.gz: 9be3cea69411bf8f1b48dde44a432353f9b93741ff13ce388312386817e6a8a90a2290dafa222013b7397838cd948b40228882e329bb2d89270924c1b0a08469
7
- data.tar.gz: 1eff396a38c708948620c489664f8d9713ac0b76e7df72d1631e60e31f1bda0d2aea93ac7015a6a6f7863b9ed466eac731db6ec90fd42ca831d6ffead3f0ecfc
6
+ metadata.gz: 07f86288c180813daf6ceed810dec2bfecc1cdb2605bf45de5f363cf0a7187babffa37095f208679fd1d1a3cdc6aeebfc879a5293f51c4f49ecc9c473a077295
7
+ data.tar.gz: bc111d4ca32a5b3135cf518c748370654b9f99803b4123de42b2603965bba4a1e6164e6b3307f7f9afa8b53b7b721b1b01941eee22fd3dd5d63d95a8597cb71e
@@ -16,35 +16,28 @@ jobs:
16
16
  strategy:
17
17
  fail-fast: false
18
18
  matrix:
19
- ruby: [ '2.6', '2.5', '2.4' ]
19
+ ruby: [ '2.7', '2.6', '2.5', '2.4' ]
20
20
  os: [ ubuntu-latest, windows-latest, macos-latest ]
21
21
  experimental: [ false ]
22
22
  include:
23
- - ruby: '2.7'
23
+ - ruby: '3.0'
24
24
  os: 'ubuntu-latest'
25
25
  experimental: true
26
- - ruby: '2.7'
26
+ - ruby: '3.0'
27
27
  os: 'windows-latest'
28
28
  experimental: true
29
- - ruby: '2.7'
29
+ - ruby: '3.0'
30
30
  os: 'macos-latest'
31
31
  experimental: true
32
32
  steps:
33
- - uses: actions/checkout@master
33
+ - uses: actions/checkout@v2
34
+ with:
35
+ submodules: true
34
36
 
35
37
  - uses: ruby/setup-ruby@v1
36
38
  with:
37
39
  ruby-version: ${{ matrix.ruby }}
38
-
39
- - uses: actions/cache@v2
40
- with:
41
- path: vendor/bundle
42
- key: bundle-${{ matrix.os }}-${{ matrix.ruby }}-${{ hashFiles('**/*.gemspec') }}
43
- restore-keys: bundle-${{ matrix.os }}-${{ matrix.ruby }}
44
-
45
- - run: bundle config set path 'vendor/bundle'
46
-
47
- - run: bundle install --jobs 4 --retry 3
40
+ bundler-cache: true
48
41
 
49
42
  - run: bundle exec rake
50
43
 
@@ -54,7 +47,7 @@ jobs:
54
47
  steps:
55
48
  - uses: peter-evans/repository-dispatch@v1
56
49
  with:
57
- token: ${{ secrets.GITHUB_TOKEN }}
50
+ token: ${{ secrets.METANORMA_CI_PAT_TOKEN || secrets.GITHUB_TOKEN }}
58
51
  repository: ${{ github.repository }}
59
- event-type: notify
60
- client-payload: '{"ref": "${{ github.ref }}"}'
52
+ event-type: tests-passed
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,9 +44,10 @@ 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
@@ -110,7 +111,7 @@ module Metanorma
110
111
  # @parma mnf [Metanorma::CollectionManifest]
111
112
  # @return [Hash{String=>Metanorma::Document}]
112
113
  def docs_from_xml(xml, mnf)
113
- xml.xpath("//xmlns:doc-container/*/xmlns:bibdata")
114
+ xml.xpath("//xmlns:doc-container//xmlns:bibdata")
114
115
  .each_with_object({}) do |b, m|
115
116
  bd = Relaton::Cli.parse_xml b
116
117
  docref = mnf.docref_by_id bd.docidentifier.first.id
@@ -153,7 +154,7 @@ module Metanorma
153
154
 
154
155
  require "metanorma-#{doctype}"
155
156
  out = sections(dummy_header + cnt)
156
- builder.send(elm + "-content") { |b| b << out }
157
+ builder.send("#{elm}-content") { |b| b << out }
157
158
  end
158
159
 
159
160
  # @param cnt [String] prefatory/final content
@@ -169,7 +170,13 @@ module Metanorma
169
170
 
170
171
  documents.each_with_index do |(_, d), i|
171
172
  id = format("doc%<index>09d", index: i)
172
- builder.send("doc-container", id: id) { |b| d.to_xml b }
173
+ builder.send("doc-container", id: id) do |b|
174
+ if d.attachment
175
+ d.bibitem and b << d.bibitem.root.to_xml
176
+ b.attachment Metanorma::Utils::datauri(d.file)
177
+ else d.to_xml b
178
+ end
179
+ end
173
180
  end
174
181
  end
175
182
 
@@ -0,0 +1,243 @@
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
+ ret = {}
12
+ xrefs = @isodoc.xref_init(@lang, @script, @isodoc, @isodoc.i18n, {})
13
+ xrefs.parse xml
14
+ xrefs.get.each do |k, v|
15
+ ret[v[:type]] ||= {}
16
+ index = if v[:container] || v[:label].nil? || v[:label].empty?
17
+ UUIDTools::UUID.random_create.to_s
18
+ else
19
+ v[:label]
20
+ end
21
+ ret[v[:type]][index] = k
22
+ end
23
+ ret
24
+ end
25
+
26
+ # @param id [String]
27
+ # @param read [Boolean]
28
+ # @return [Array<String, nil>]
29
+ def xml_file(id, read)
30
+ file = @xml.at(ns("//doc-container[@id = '#{id}']")).to_xml if read
31
+ filename = "#{id}.html"
32
+ [file, filename]
33
+ end
34
+
35
+ # @param bib [Nokogiri::XML::Element]
36
+ # @param identifier [String]
37
+ def update_bibitem(bib, identifier) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
38
+ docid = bib&.at(ns("./docidentifier"))&.text
39
+ unless @files[docid]
40
+ error = "[metanorma] Cannot find crossreference to document #{docid} "\
41
+ "in document #{identifier}."
42
+ @log.add("Cross-References", nil, error)
43
+ Util.log(error, :warning)
44
+ return
45
+ end
46
+ id = bib["id"]
47
+ newbib = bib.replace(@files[docid][:bibdata])
48
+ newbib.name = "bibitem"
49
+ newbib["id"] = id
50
+ newbib["hidden"] = "true"
51
+ newbib&.at(ns("./ext"))&.remove
52
+ _file, url = targetfile(@files[docid], relative: true, read: false,
53
+ doc: !@files[docid][:attachment])
54
+ uri_node = Nokogiri::XML::Node.new "uri", newbib
55
+ uri_node[:type] = "citation"
56
+ uri_node.content = url
57
+ newbib.at(ns("./docidentifier")).previous = uri_node
58
+ end
59
+
60
+ # Resolves direct links to other files in collection
61
+ # (repo(current-metanorma-collection/x),
62
+ # and indirect links to other files in collection
63
+ # (bibitem[@type = 'internal'] pointing to a file anchor
64
+ # in another file in the collection)
65
+ # @param file [String] XML content
66
+ # @param identifier [String] docid
67
+ # @param internal_refs [Hash{String=>Hash{String=>String}] schema name to anchor to filename
68
+ # @return [String] XML content
69
+ def update_xrefs(file, identifier, internal_refs)
70
+ docxml = Nokogiri::XML(file)
71
+ update_indirect_refs_to_docs(docxml, internal_refs)
72
+ add_document_suffix(identifier, docxml)
73
+ update_direct_refs_to_docs(docxml, identifier)
74
+ svgmap_resolve(datauri_encode(docxml))
75
+ docxml.xpath(ns("//references[not(./bibitem[not(@hidden) or @hidden = 'false'])]")).each do |f|
76
+ f["hidden"] = "true"
77
+ end
78
+ docxml.to_xml
79
+ end
80
+
81
+ def datauri_encode(docxml)
82
+ docxml.xpath(ns("//image")).each do |i|
83
+ i["src"] = Metanorma::Utils::datauri(i["src"])
84
+ end
85
+ docxml
86
+ end
87
+
88
+ def svgmap_resolve(docxml)
89
+ isodoc = IsoDoc::Convert.new({})
90
+ docxml.xpath(ns("//svgmap//eref")).each do |e|
91
+ href = isodoc.eref_target(e)
92
+ next if href == "##{e['bibitemid']}"
93
+
94
+ # XML collection renderer
95
+ # map locality type and label (e.g. "clause" "1") to id = anchor for
96
+ # a document
97
+ # Note: will only key clauses, which have unambiguous reference label in
98
+ # locality. Notes, examples etc with containers are just plunked against
99
+ # UUIDs, so that their IDs can at least be registered to be tracked
100
+ # as existing.
101
+ # @param id [String]
102
+ # @param read [Boolean]
103
+ # @return [Array<String, nil>]
104
+ # @param bib [Nokogiri::XML::Element]
105
+ # @param identifier [String]
106
+ # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
107
+ # Resolves direct links to other files in collection
108
+ # (repo(current-metanorma-collection/x),
109
+ # and indirect links to other files in collection
110
+ # (bibitem[@type = 'internal'] pointing to a file anchor
111
+ # in another file in the collection)
112
+ # @param file [String] XML content
113
+ # @param identifier [String] docid
114
+ # @param internal_refs [Hash{String=>Hash{String=>String}] schema name to anchor to filename
115
+ # @return [String] XML content
116
+ if href =~ /^#/ && !docxml.at("//*[@id = '#{href.sub(/^#/, '')}']")
117
+ next
118
+ end
119
+
120
+ e["target"] = href.strip
121
+ e.name = "link"
122
+ e&.elements&.remove
123
+ end
124
+ Metanorma::Utils::svgmap_rewrite(docxml, "")
125
+ end
126
+
127
+ # repo(current-metanorma-collection/ISO 17301-1:2016)
128
+ # replaced by bibdata of "ISO 17301-1:2016" in situ as bibitem.
129
+ # Any erefs to that bibitem id are replaced with relative URL
130
+ # Preferably with anchor, and is a job to realise dynamic lookup
131
+ # of localities.
132
+ def update_direct_refs_to_docs(docxml, identifier)
133
+ docxml.xpath(ns("//bibitem[not(ancestor::bibitem)]")).each do |b|
134
+ docid = b&.at(ns("./docidentifier[@type = 'repository']"))&.text
135
+ next unless docid && %r{^current-metanorma-collection/}.match(docid)
136
+
137
+ update_bibitem(b, identifier)
138
+ update_anchors(b, docxml, docid)
139
+ end
140
+ end
141
+
142
+ # Resolve erefs to a container of ids in another doc,
143
+ # to an anchor eref (direct link)
144
+ def update_indirect_refs_to_docs(docxml, internal_refs)
145
+ internal_refs.each do |schema, ids|
146
+ ids.each do |id, file|
147
+ update_indirect_refs_to_docs1(docxml, schema, id, file)
148
+ end
149
+ end
150
+ end
151
+
152
+ def update_indirect_refs_to_docs1(docxml, schema, id, file)
153
+ docxml.xpath(ns("//eref[@bibitemid = '#{schema}_#{id}']")).each do |e|
154
+ e["citeas"] = file
155
+ end
156
+ docid = docxml.at(ns("//bibitem[@id = '#{schema}_#{id}']/"\
157
+ "docidentifier[@type = 'repository']")) or return
158
+ docid.children = "current-metanorma-collection/#{file}"
159
+ docid.previous = "<docidentifier type='X'>#{file}</docidentifier>"
160
+ end
161
+
162
+ # update crossrefences to other documents, to include disambiguating document suffix on id
163
+ def update_anchors(bib, docxml, _id) # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
164
+ docid = bib&.at(ns("./docidentifier"))&.text
165
+ docxml.xpath("//xmlns:eref[@citeas = '#{docid}']").each do |e|
166
+ if @files[docid]
167
+ update_anchor_loc(bib, e, docid)
168
+ else
169
+ e << "<strong>** Unresolved reference to document #{docid}, id #{e['bibitemid']}</strong>"
170
+ end
171
+ end
172
+ end
173
+
174
+ def update_anchor_loc(bib, e, docid)
175
+ loc = e.at(ns(".//locality[@type = 'anchor']")) or
176
+ return update_anchor_create_loc(bib, e, docid)
177
+ document_suffix = Metanorma::Utils::to_ncname(docid)
178
+ ref = loc.at(ns("./referenceFrom")) || return
179
+ anchor = "#{ref.text}_#{document_suffix}"
180
+ return unless @files[docid][:anchors].inject([]) do |m, (_, x)|
181
+ m += x.values
182
+ end.include?(anchor)
183
+
184
+ ref.content = anchor
185
+ end
186
+
187
+ # if there is a crossref to another document, with no anchor, retrieve the
188
+ # anchor given the locality, and insert it into the crossref
189
+ def update_anchor_create_loc(bib, e, docid)
190
+ ins = e.at(ns("./localityStack")) || return
191
+ type = ins&.at(ns("./locality/@type"))&.text
192
+ ref = ins&.at(ns("./locality/referenceFrom"))&.text
193
+ (anchor = @files[docid][:anchors][type][ref]) || return
194
+ ref_from = Nokogiri::XML::Node.new "referenceFrom", bib
195
+ ref_from.content = anchor.sub(/^_/, "")
196
+ locality = Nokogiri::XML::Node.new "locality", bib
197
+ locality[:type] = "anchor"
198
+ locality.add_child ref_from
199
+ ins << locality
200
+ end
201
+
202
+ # gather internal bibitem references
203
+ def gather_internal_refs
204
+ @files.each_with_object({}) do |(_, x), refs|
205
+ next if x[:attachment]
206
+
207
+ file, = targetfile(x, read: true)
208
+ Nokogiri::XML(file)
209
+ .xpath(ns("//bibitem[@type = 'internal']/"\
210
+ "docidentifier[@type = 'repository']")).each do |d|
211
+ a = d.text.split(%r{/}, 2)
212
+ a.size > 1 or next
213
+ refs[a[0]] ||= {}
214
+ refs[a[0]][a[1]] = true
215
+ end
216
+ end
217
+ end
218
+
219
+ # resolve file location for the target of each internal reference
220
+ def locate_internal_refs
221
+ refs = gather_internal_refs
222
+ @files.each do |identifier, x|
223
+ next if x[:attachment]
224
+
225
+ file, _filename = targetfile(x, read: true)
226
+ docxml = Nokogiri::XML(file)
227
+ refs.each do |schema, ids|
228
+ ids.each_key do |id|
229
+ n = docxml.at("//*[@id = '#{id}']") and
230
+ n.at("./ancestor-or-self::*[@type = '#{schema}']") and
231
+ refs[schema][id] = identifier
232
+ end
233
+ end
234
+ end
235
+ refs.each do |schema, ids|
236
+ ids.each do |id, key|
237
+ key == true and refs[schema][id] = "Missing:#{schema}:#{id}"
238
+ end
239
+ end
240
+ refs
241
+ end
242
+ end
243
+ 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,32 @@ 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, 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
+ def file_entry(docref, path)
35
+ ret = if docref["fileref"]
36
+ { type: "fileref", ref: File.join(path, docref["fileref"]),
37
+ rel_path: docref["fileref"] }
38
+ else
39
+ { type: "id", ref: docref["id"] }
40
+ end
41
+ ret[:attachment] = docref["attachment"] if docref["attachment"]
42
+ ret
43
+ end
44
+
32
45
  def add_suffix_to_attributes(doc, suffix, tag_name, attribute_name)
33
46
  doc.xpath(ns("//#{tag_name}[@#{attribute_name}]")).each do |elem|
34
47
  elem.attributes[attribute_name].value =
@@ -38,199 +51,50 @@ module Metanorma
38
51
 
39
52
  def add_document_suffix(identifier, doc)
40
53
  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)|
54
+ [%w[* id], %w[* bibitemid], %w[review from],
55
+ %w[review to], %w[index to], %w[xref target],
56
+ %w[callout target]]
57
+ .each do |(tag_name, attribute_name)|
49
58
  add_suffix_to_attributes(doc, document_suffix, tag_name, attribute_name)
50
59
  end
51
60
  end
52
61
 
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
62
  # return file contents + output filename for each file in the collection,
72
63
  # given a docref entry
73
- # @param data [Hash]
74
- # @param read [Boolean]
64
+ # @param data [Hash] docref entry
65
+ # @param read [Boolean] read the file in and return it
66
+ # @param doc [Boolean] I am a Metanorma document,
67
+ # so my URL should end with html or pdf or whatever
68
+ # @param relative [Boolean] Return path relative to YAML file,
69
+ # not relative to calling function
75
70
  # @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
71
+ def targetfile(data, options)
72
+ options = { read: false, doc: true, relative: false }.merge(options)
73
+ path = options[:relative] ? data[:rel_path] : data[:ref]
74
+ if data[:type] == "fileref"
75
+ ref_file path, options[:read], options[:doc]
76
+ else
77
+ xml_file data[:id], options[:read]
79
78
  end
80
79
  end
81
80
 
82
81
  # @param ref [String]
83
82
  # @param read [Boolean]
83
+ # @param doc [Boolean]
84
84
  # @return [Array<String, nil>]
85
- def ref_file(ref, read)
85
+ def ref_file(ref, read, doc)
86
86
  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"
87
+ filename = ref.dup
88
+ filename.sub!(/\.xml$/, ".html") if doc
97
89
  [file, filename]
98
90
  end
99
91
 
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
92
  # compile and output individual file in collection
230
93
  def file_compile(f, filename, identifier)
231
94
  # warn "metanorma compile -x html #{f.path}"
232
95
  c = Compile.new
233
- c.compile f.path, { format: :asciidoc, extension_keys: @format }.merge(@compile_options)
96
+ c.compile f.path, { format: :asciidoc,
97
+ extension_keys: @format }.merge(@compile_options)
234
98
  @files[identifier][:outputs] = {}
235
99
  @format.each do |e|
236
100
  ext = c.processor.output_formats[e]
@@ -240,38 +104,11 @@ module Metanorma
240
104
  end
241
105
  end
242
106
 
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
- docxml.at(ns("//*[@id = '#{id}'][@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
107
+ def copy_file_to_dest(fileref)
108
+ _file, filename = targetfile(fileref, read: true, doc: false)
109
+ dest = File.join(@outdir, fileref[:rel_path])
110
+ FileUtils.mkdir_p(File.dirname(dest))
111
+ FileUtils.cp filename, dest
275
112
  end
276
113
 
277
114
  # process each file in the collection
@@ -279,12 +116,15 @@ module Metanorma
279
116
  def files # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
280
117
  internal_refs = locate_internal_refs
281
118
  @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)
119
+ if x[:attachment] then copy_file_to_dest(x)
120
+ else
121
+ file, filename = targetfile(x, read: true)
122
+ file = update_xrefs(file, identifier, internal_refs)
123
+ Tempfile.open(["collection", ".xml"], encoding: "utf-8") do |f|
124
+ f.write(file)
125
+ f.close
126
+ file_compile(f, filename, identifier)
127
+ end
288
128
  end
289
129
  end
290
130
  end