metanorma 1.2.6 → 1.3.2

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: 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