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 +4 -4
- data/.github/workflows/rake.yml +11 -18
- data/.gitignore +2 -0
- data/.hound.yml +3 -1
- data/.rubocop.yml +8 -4
- data/Rakefile +1 -1
- data/lib/metanorma/asciidoctor_extensions/glob_include_processor.rb +4 -6
- data/lib/metanorma/collection.rb +13 -6
- data/lib/metanorma/collection_fileparse.rb +243 -0
- data/lib/metanorma/collection_fileprocess.rb +60 -220
- data/lib/metanorma/collection_manifest.rb +7 -4
- data/lib/metanorma/collection_renderer.rb +20 -4
- data/lib/metanorma/compile.rb +34 -117
- data/lib/metanorma/compile_validate.rb +45 -0
- data/lib/metanorma/config.rb +1 -1
- data/lib/metanorma/document.rb +24 -10
- data/lib/metanorma/fontist_utils.rb +108 -0
- data/lib/metanorma/input.rb +0 -1
- data/lib/metanorma/input/asciidoc.rb +21 -51
- data/lib/metanorma/output.rb +0 -2
- data/lib/metanorma/output/utils.rb +2 -1
- data/lib/metanorma/version.rb +1 -1
- data/metanorma.gemspec +22 -22
- metadata +51 -34
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6da8527ed559d4b6833977c169022db5dfec3a9d93926257586d9e676a11e578
|
4
|
+
data.tar.gz: cf9cc8d31d2ae7cbd08787dcb3f4a79747e85fad5c142bc02fd377df91e467e0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 07f86288c180813daf6ceed810dec2bfecc1cdb2605bf45de5f363cf0a7187babffa37095f208679fd1d1a3cdc6aeebfc879a5293f51c4f49ecc9c473a077295
|
7
|
+
data.tar.gz: bc111d4ca32a5b3135cf518c748370654b9f99803b4123de42b2603965bba4a1e6164e6b3307f7f9afa8b53b7b721b1b01941eee22fd3dd5d63d95a8597cb71e
|
data/.github/workflows/rake.yml
CHANGED
@@ -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: '
|
23
|
+
- ruby: '3.0'
|
24
24
|
os: 'ubuntu-latest'
|
25
25
|
experimental: true
|
26
|
-
- ruby: '
|
26
|
+
- ruby: '3.0'
|
27
27
|
os: 'windows-latest'
|
28
28
|
experimental: true
|
29
|
-
- ruby: '
|
29
|
+
- ruby: '3.0'
|
30
30
|
os: 'macos-latest'
|
31
31
|
experimental: true
|
32
32
|
steps:
|
33
|
-
- uses: actions/checkout@
|
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:
|
60
|
-
client-payload: '{"ref": "${{ github.ref }}"}'
|
52
|
+
event-type: tests-passed
|
53
|
+
client-payload: '{"ref": "${{ github.ref }}", "sha": "${{ github.sha }}"}'
|
data/.gitignore
CHANGED
data/.hound.yml
CHANGED
data/.rubocop.yml
CHANGED
@@ -1,6 +1,10 @@
|
|
1
|
-
#
|
2
|
-
# https://github.com/
|
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
@@ -1,20 +1,18 @@
|
|
1
1
|
module Metanorma::AsciidoctorExtensions
|
2
|
-
|
3
2
|
class GlobIncludeProcessor < ::Asciidoctor::Extensions::IncludeProcessor
|
4
|
-
def process
|
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
|
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?
|
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
|
data/lib/metanorma/collection.rb
CHANGED
@@ -44,9 +44,10 @@ module Metanorma
|
|
44
44
|
end
|
45
45
|
|
46
46
|
# rubocop:enable Metrics/AbcSize,Metrics/MethodLength
|
47
|
-
|
48
|
-
|
49
|
-
|
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
|
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
|
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)
|
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] =
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
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
|
-
|
43
|
-
|
44
|
-
|
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,
|
77
|
-
|
78
|
-
|
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.
|
88
|
-
|
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,
|
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
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
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
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
f
|
287
|
-
|
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
|