metanorma 1.2.3 → 1.2.7
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/notify.yml +7 -7
- data/.github/workflows/rake.yml +14 -26
- data/lib/metanorma/collection.rb +8 -1
- data/lib/metanorma/collection_fileprocess.rb +292 -0
- data/lib/metanorma/collection_renderer.rb +2 -189
- data/lib/metanorma/compile.rb +15 -10
- data/lib/metanorma/input/asciidoc.rb +1 -1
- data/lib/metanorma/version.rb +1 -1
- data/metanorma.gemspec +5 -5
- metadata +22 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6c6df255e2338335a6f670965e34d61d3d808a3d9a1a69c78ef9af1f9a2f306f
|
4
|
+
data.tar.gz: b5c485bdcd52c100d141b80c1ceb5a0f2a66b0eb45fa2a7efd56e3b57653596d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 638bede7f3dffde3a6169e51a684fa10efec05975273ab6dc1495e95f074b21b0cc7cefaf168cb6a0ebe0d8c903dcf37ebbc4c023a6c1149cc42d16f517e67fd
|
7
|
+
data.tar.gz: 727a3a66032ed783b5b099a035589666818d71a67e9f88366cf888fd3879c40ff5872533d39ef1e7b31dc8d15289274aea866637233b88c60e0f244b92d79f17
|
@@ -3,16 +3,16 @@
|
|
3
3
|
name: notify
|
4
4
|
|
5
5
|
on:
|
6
|
-
|
7
|
-
|
8
|
-
tags:
|
9
|
-
- '*'
|
6
|
+
repository_dispatch:
|
7
|
+
types: [ notify ]
|
10
8
|
|
11
9
|
jobs:
|
12
10
|
notify:
|
13
11
|
name: Notify dependent repos
|
14
12
|
runs-on: ubuntu-latest
|
15
13
|
steps:
|
14
|
+
- uses: actions/checkout@v2
|
15
|
+
|
16
16
|
- name: Trigger repositories
|
17
17
|
env:
|
18
18
|
GH_USERNAME: metanorma-ci
|
@@ -21,7 +21,7 @@ jobs:
|
|
21
21
|
curl -LO --retry 3 https://raw.githubusercontent.com/metanorma/metanorma-build-scripts/master/trigger-gh-actions.sh
|
22
22
|
[[ -f ".github/workflows/dependent_repos.env" ]] && source .github/workflows/dependent_repos.env
|
23
23
|
CLIENT_PAYLOAD=$(cat <<EOF
|
24
|
-
"{ "ref": "${
|
24
|
+
"{ "ref": "${{ github.event.client_payload.ref }}", "repo": "${GITHUB_REPOSITORY}" }"
|
25
25
|
EOF
|
26
26
|
)
|
27
27
|
for repo in $TEMPLATE_REPOS" $SAMPLES_REPOS"
|
@@ -30,7 +30,7 @@ jobs:
|
|
30
30
|
done
|
31
31
|
|
32
32
|
- name: Trigger release repositories
|
33
|
-
if: github.ref == 'refs/heads/master' || startsWith(github.ref, 'refs/tags/v')
|
33
|
+
if: github.event.client_payload.ref == 'refs/heads/master' || startsWith(github.event.client_payload.ref, 'refs/tags/v')
|
34
34
|
env:
|
35
35
|
GH_USERNAME: metanorma-ci
|
36
36
|
GH_ACCESS_TOKEN: ${{ secrets.METANORMA_CI_PAT_TOKEN }}
|
@@ -38,7 +38,7 @@ jobs:
|
|
38
38
|
curl -LO --retry 3 https://raw.githubusercontent.com/metanorma/metanorma-build-scripts/master/trigger-gh-actions.sh
|
39
39
|
[[ -f ".github/workflows/dependent_repos.env" ]] && source .github/workflows/dependent_repos.env
|
40
40
|
CLIENT_PAYLOAD=$(cat <<EOF
|
41
|
-
"{ "ref": "${
|
41
|
+
"{ "ref": "${{ github.event.client_payload.ref }}", "repo": "${GITHUB_REPOSITORY}" }"
|
42
42
|
EOF
|
43
43
|
)
|
44
44
|
for repo in $DEPENDENT_REPOS
|
data/.github/workflows/rake.yml
CHANGED
@@ -4,7 +4,7 @@ name: rake
|
|
4
4
|
|
5
5
|
on:
|
6
6
|
push:
|
7
|
-
branches: [ master, main
|
7
|
+
branches: [ master, main ]
|
8
8
|
tags: [ v* ]
|
9
9
|
pull_request:
|
10
10
|
|
@@ -16,38 +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
|
-
- if: matrix.os == 'macos-latest'
|
40
|
-
run: brew install autoconf automake libtool
|
41
|
-
|
42
|
-
- uses: actions/cache@v2
|
43
|
-
with:
|
44
|
-
path: vendor/bundle
|
45
|
-
key: bundle-${{ matrix.os }}-${{ matrix.ruby }}-${{ hashFiles('**/*.gemspec') }}
|
46
|
-
restore-keys: bundle-${{ matrix.os }}-${{ matrix.ruby }}
|
47
|
-
|
48
|
-
- run: bundle config set path 'vendor/bundle'
|
49
|
-
|
50
|
-
- run: bundle install --jobs 4 --retry 3
|
40
|
+
bundler-cache: true
|
51
41
|
|
52
42
|
- run: bundle exec rake
|
53
43
|
|
@@ -55,11 +45,9 @@ jobs:
|
|
55
45
|
needs: rake
|
56
46
|
runs-on: ubuntu-latest
|
57
47
|
steps:
|
58
|
-
-
|
59
|
-
uses: Sibz/github-status-action@v1
|
48
|
+
- uses: peter-evans/repository-dispatch@v1
|
60
49
|
with:
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
sha: ${{ github.event.pull_request.head.sha || github.sha }}
|
50
|
+
token: ${{ secrets.METANORMA_CI_PAT_TOKEN || secrets.GITHUB_TOKEN }}
|
51
|
+
repository: ${{ github.repository }}
|
52
|
+
event-type: notify
|
53
|
+
client-payload: '{"ref": "${{ github.ref }}", "sha": "${{ github.sha }}"}'
|
data/lib/metanorma/collection.rb
CHANGED
@@ -3,6 +3,7 @@
|
|
3
3
|
require "relaton"
|
4
4
|
require "relaton/cli"
|
5
5
|
require "metanorma/collection_manifest"
|
6
|
+
require "metanorma-utils"
|
6
7
|
|
7
8
|
module Metanorma
|
8
9
|
# Metanorma collection of documents
|
@@ -39,8 +40,13 @@ module Metanorma
|
|
39
40
|
@documents.merge! @manifest.documents(File.dirname(@file))
|
40
41
|
@prefatory = args[:prefatory]
|
41
42
|
@final = args[:final]
|
43
|
+
@log = Metanorma::Utils::Log.new
|
42
44
|
end
|
45
|
+
|
43
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
|
44
50
|
|
45
51
|
# @return [String] XML
|
46
52
|
def to_xml
|
@@ -57,7 +63,8 @@ module Metanorma
|
|
57
63
|
end
|
58
64
|
|
59
65
|
def render(opts)
|
60
|
-
CollectionRenderer.render self, opts
|
66
|
+
CollectionRenderer.render self, opts.merge(log: @log)
|
67
|
+
clean_exit
|
61
68
|
end
|
62
69
|
|
63
70
|
class << self
|
@@ -0,0 +1,292 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "isodoc"
|
4
|
+
require "metanorma-utils"
|
5
|
+
|
6
|
+
module Metanorma
|
7
|
+
# XML collection renderer
|
8
|
+
class CollectionRenderer
|
9
|
+
# hash for each document in collection of document identifier to:
|
10
|
+
# document reference (fileref or id), type of document reference,
|
11
|
+
# and bibdata entry for that file
|
12
|
+
# @param path [String] path to collection
|
13
|
+
# @return [Hash{String=>Hash}]
|
14
|
+
def read_files(path) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
|
15
|
+
files = {}
|
16
|
+
@xml.xpath(ns("//docref")).each do |d|
|
17
|
+
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"))
|
28
|
+
end
|
29
|
+
files
|
30
|
+
end
|
31
|
+
|
32
|
+
def add_suffix_to_attributes(doc, suffix, tag_name, attribute_name)
|
33
|
+
doc.xpath(ns("//#{tag_name}[@#{attribute_name}]")).each do |elem|
|
34
|
+
elem.attributes[attribute_name].value =
|
35
|
+
"#{elem.attributes[attribute_name].value}_#{suffix}"
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def add_document_suffix(identifier, doc)
|
40
|
+
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)|
|
49
|
+
add_suffix_to_attributes(doc, document_suffix, tag_name, attribute_name)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
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
|
+
# return file contents + output filename for each file in the collection,
|
72
|
+
# given a docref entry
|
73
|
+
# @param data [Hash]
|
74
|
+
# @param read [Boolean]
|
75
|
+
# @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
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
# @param ref [String]
|
83
|
+
# @param read [Boolean]
|
84
|
+
# @return [Array<String, nil>]
|
85
|
+
def ref_file(ref, read)
|
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"
|
97
|
+
[file, filename]
|
98
|
+
end
|
99
|
+
|
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
|
+
# compile and output individual file in collection
|
230
|
+
def file_compile(f, filename, identifier)
|
231
|
+
# warn "metanorma compile -x html #{f.path}"
|
232
|
+
c = Compile.new
|
233
|
+
c.compile f.path, { format: :asciidoc, extension_keys: @format }.merge(@compile_options)
|
234
|
+
@files[identifier][:outputs] = {}
|
235
|
+
@format.each do |e|
|
236
|
+
ext = c.processor.output_formats[e]
|
237
|
+
fn = File.basename(filename).sub(/(?<=\.)[^\.]+$/, ext.to_s)
|
238
|
+
FileUtils.mv f.path.sub(/\.xml$/, ".#{ext}"), File.join(@outdir, fn)
|
239
|
+
@files[identifier][:outputs][e] = File.join(@outdir, fn)
|
240
|
+
end
|
241
|
+
end
|
242
|
+
|
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
|
275
|
+
end
|
276
|
+
|
277
|
+
# process each file in the collection
|
278
|
+
# files are held in memory, and altered as postprocessing
|
279
|
+
def files # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
|
280
|
+
internal_refs = locate_internal_refs
|
281
|
+
@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)
|
288
|
+
end
|
289
|
+
end
|
290
|
+
end
|
291
|
+
end
|
292
|
+
end
|
@@ -1,6 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "isodoc"
|
4
|
+
require_relative "./collection_fileprocess"
|
4
5
|
|
5
6
|
module Metanorma
|
6
7
|
# XML collection renderer
|
@@ -34,6 +35,7 @@ module Metanorma
|
|
34
35
|
@coverpage = options[:coverpage]
|
35
36
|
@format = options[:format]
|
36
37
|
@compile_options = options[:compile] || {}
|
38
|
+
@log = options[:log]
|
37
39
|
|
38
40
|
# list of files in the collection
|
39
41
|
@files = read_files folder
|
@@ -114,68 +116,6 @@ module Metanorma
|
|
114
116
|
IsoDoc::Convert.new({}).ns(xpath)
|
115
117
|
end
|
116
118
|
|
117
|
-
# hash for each document in collection of document identifier to:
|
118
|
-
# document reference (fileref or id), type of document reference,
|
119
|
-
# and bibdata entry for that file
|
120
|
-
# @param path [String] path to collection
|
121
|
-
# @return [Hash{String=>Hash}]
|
122
|
-
def read_files(path) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
|
123
|
-
files = {}
|
124
|
-
@xml.xpath(ns("//docref")).each do |d|
|
125
|
-
identifier = d.at(ns("./identifier")).text
|
126
|
-
files[identifier] = if d["fileref"]
|
127
|
-
{ type: "fileref",
|
128
|
-
ref: File.join(path, d["fileref"]) }
|
129
|
-
else { type: "id", ref: d["id"] }
|
130
|
-
end
|
131
|
-
file, _filename = targetfile(files[identifier], true)
|
132
|
-
xml = Nokogiri::XML(file)
|
133
|
-
add_document_suffix(identifier, xml)
|
134
|
-
files[identifier][:anchors] = read_anchors(xml)
|
135
|
-
files[identifier][:bibdata] = xml.at(ns("//bibdata"))
|
136
|
-
end
|
137
|
-
files
|
138
|
-
end
|
139
|
-
|
140
|
-
def add_suffix_to_attributes(doc, suffix, tag_name, attribute_name)
|
141
|
-
doc.xpath(ns("//#{tag_name}[@#{attribute_name}]")).each do |elem|
|
142
|
-
elem.attributes[attribute_name].value =
|
143
|
-
"#{elem.attributes[attribute_name].value}_#{suffix}"
|
144
|
-
end
|
145
|
-
end
|
146
|
-
|
147
|
-
def add_document_suffix(identifier, doc)
|
148
|
-
document_suffix = Asciidoctor::Standoc::Cleanup.to_ncname(identifier)
|
149
|
-
[%w[* id],
|
150
|
-
%w[* bibitemid],
|
151
|
-
%w[review from],
|
152
|
-
%w[review to],
|
153
|
-
%w[index to],
|
154
|
-
%w[xref target],
|
155
|
-
%w[callout target]]
|
156
|
-
.each do |(tag_name, attribute_name)|
|
157
|
-
add_suffix_to_attributes(doc, document_suffix, tag_name, attribute_name)
|
158
|
-
end
|
159
|
-
end
|
160
|
-
|
161
|
-
# map locality type and label (e.g. "clause" "1") to id = anchor for
|
162
|
-
# a document
|
163
|
-
def read_anchors(xml)
|
164
|
-
ret = {}
|
165
|
-
xrefs = @isodoc.xref_init(@lang, @script, @isodoc, @isodoc.i18n, {})
|
166
|
-
xrefs.parse xml
|
167
|
-
xrefs.get.each do |k, v|
|
168
|
-
ret[v[:type]] ||= {}
|
169
|
-
index = v[:container] || v[:label].nil? || v[:label].empty? ?
|
170
|
-
UUIDTools::UUID.random_create.to_s : v[:label]
|
171
|
-
# Note: will only key clauses, which have unambiguous reference label in locality.
|
172
|
-
# Notes, examples etc with containers are just plunked agaisnt UUIDs, so that their
|
173
|
-
# IDs can at least be registered to be tracked as existing.
|
174
|
-
ret[v[:type]][index] = k
|
175
|
-
end
|
176
|
-
ret
|
177
|
-
end
|
178
|
-
|
179
119
|
# populate liquid template of ARGV[1] with metadata extracted from
|
180
120
|
# collection manifest
|
181
121
|
def coverpage
|
@@ -235,132 +175,6 @@ module Metanorma
|
|
235
175
|
end.doc.root.to_html
|
236
176
|
end
|
237
177
|
|
238
|
-
# return file contents + output filename for each file in the collection,
|
239
|
-
# given a docref entry
|
240
|
-
# @param data [Hash]
|
241
|
-
# @param read [Boolean]
|
242
|
-
# @return [Array<String, nil>]
|
243
|
-
def targetfile(data, read = false)
|
244
|
-
if data[:type] == "fileref" then ref_file data[:ref], read
|
245
|
-
else xml_file data[:id], read
|
246
|
-
end
|
247
|
-
end
|
248
|
-
|
249
|
-
# @param ref [String]
|
250
|
-
# @param read [Boolean]
|
251
|
-
# @return [Array<String, nil>]
|
252
|
-
def ref_file(ref, read)
|
253
|
-
file = File.read(ref, encoding: "utf-8") if read
|
254
|
-
filename = ref.sub(/\.xml$/, ".html")
|
255
|
-
[file, filename]
|
256
|
-
end
|
257
|
-
|
258
|
-
# @param id [String]
|
259
|
-
# @param read [Boolean]
|
260
|
-
# @return [Array<String, nil>]
|
261
|
-
def xml_file(id, read)
|
262
|
-
file = @xml.at(ns("//doc-container[@id = '#{id}']")).to_xml if read
|
263
|
-
filename = id + ".html"
|
264
|
-
[file, filename]
|
265
|
-
end
|
266
|
-
|
267
|
-
# @param bib [Nokogiri::XML::Element]
|
268
|
-
# @param identifier [String]
|
269
|
-
def update_bibitem(bib, identifier) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
|
270
|
-
docid = bib&.at(ns("./docidentifier"))&.text
|
271
|
-
unless @files[docid]
|
272
|
-
warn "Cannot find crossreference to document #{docid} in document "\
|
273
|
-
"#{identifier}!"
|
274
|
-
abort
|
275
|
-
end
|
276
|
-
id = bib["id"]
|
277
|
-
newbib = bib.replace(@files[docid][:bibdata])
|
278
|
-
newbib.name = "bibitem"
|
279
|
-
newbib["id"] = id
|
280
|
-
newbib["hidden"] = "true"
|
281
|
-
newbib&.at(ns("./ext"))&.remove
|
282
|
-
_file, url = targetfile(@files[docid], false)
|
283
|
-
uri_node = Nokogiri::XML::Node.new "uri", newbib
|
284
|
-
uri_node[:type] = "citation"
|
285
|
-
uri_node.content = url
|
286
|
-
newbib.at(ns("./docidentifier")).previous = uri_node
|
287
|
-
end
|
288
|
-
|
289
|
-
# TODO: update crossreferences to other files in the selection
|
290
|
-
# repo(current-metanorma-collection/ISO 17301-1:2016)
|
291
|
-
# replaced by
|
292
|
-
# bibdata of "ISO 17301-1:2016" in situ as bibitem
|
293
|
-
# Any erefs to that bibitem id are replaced with relative URL
|
294
|
-
# Preferably with anchor, and is a job to realise dynamic lookup of
|
295
|
-
# localities
|
296
|
-
# @param file [String] XML content
|
297
|
-
# @param identifier [String] docid
|
298
|
-
# @return [String] XML content
|
299
|
-
def update_xrefs(file, identifier)
|
300
|
-
docxml = Nokogiri::XML(file)
|
301
|
-
add_document_suffix(identifier, docxml)
|
302
|
-
docxml.xpath(ns("//bibitem[not(ancestor::bibitem)]")).each do |b|
|
303
|
-
docid = b&.at(ns("./docidentifier[@type = 'repository']"))&.text
|
304
|
-
next unless docid && %r{^current-metanorma-collection/}.match(docid)
|
305
|
-
update_bibitem(b, identifier)
|
306
|
-
update_anchors(b, docxml, docid)
|
307
|
-
end
|
308
|
-
docxml.xpath(ns("//references[not(./bibitem[not(@hidden) or @hidden = 'false'])]")).each do |f|
|
309
|
-
f["hidden"] = "true"
|
310
|
-
end
|
311
|
-
docxml.to_xml
|
312
|
-
end
|
313
|
-
|
314
|
-
# if there is a crossref to another document, with no anchor, retrieve the
|
315
|
-
# anchor given the locality, and insert it into the crossref
|
316
|
-
def update_anchors(bib, docxml, _id) # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
|
317
|
-
docid = bib&.at(ns("./docidentifier"))&.text
|
318
|
-
document_suffix = Asciidoctor::Standoc::Cleanup.to_ncname(docid)
|
319
|
-
docxml.xpath("//xmlns:eref[@citeas = '#{docid}']").each do |e|
|
320
|
-
if loc = e.at(ns(".//locality[@type = 'anchor']"))
|
321
|
-
ref = loc.at(ns("./referenceFrom")) || next
|
322
|
-
anchor = "#{ref.text}_#{document_suffix}"
|
323
|
-
next unless @files[docid][:anchors].inject([]) { |m, (_, x)| m+= x.values }.include?(anchor)
|
324
|
-
ref.content = anchor
|
325
|
-
else
|
326
|
-
ins = e.at(ns("./localityStack")) || next
|
327
|
-
type = ins&.at(ns("./locality/@type"))&.text
|
328
|
-
ref = ins&.at(ns("./locality/referenceFrom"))&.text
|
329
|
-
(anchor = @files[docid][:anchors][type][ref]) || next
|
330
|
-
ref_from = Nokogiri::XML::Node.new "referenceFrom", bib
|
331
|
-
ref_from.content = anchor.sub(/^_/, "")
|
332
|
-
locality = Nokogiri::XML::Node.new "locality", bib
|
333
|
-
locality[:type] = "anchor"
|
334
|
-
locality.add_child ref_from
|
335
|
-
ins << locality
|
336
|
-
end
|
337
|
-
end
|
338
|
-
end
|
339
|
-
|
340
|
-
# process each file in the collection
|
341
|
-
# files are held in memory, and altered as postprocessing
|
342
|
-
def files # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
|
343
|
-
@files.each do |identifier, x|
|
344
|
-
file, filename = targetfile(x, true)
|
345
|
-
file = update_xrefs(file, identifier)
|
346
|
-
Tempfile.open(["collection", ".xml"], encoding: "utf-8") do |f|
|
347
|
-
f.write(file)
|
348
|
-
f.close
|
349
|
-
# warn "metanorma compile -x html #{f.path}"
|
350
|
-
c = Compile.new
|
351
|
-
options = { format: :asciidoc, extension_keys: @format }.merge @compile_options
|
352
|
-
c.compile f.path, options
|
353
|
-
@files[identifier][:outputs] = {}
|
354
|
-
@format.each do |e|
|
355
|
-
ext = c.processor.output_formats[e]
|
356
|
-
fn = File.basename(filename).sub(/(?<=\.)[^\.]+$/, ext.to_s)
|
357
|
-
FileUtils.mv f.path.sub(/\.xml$/, ".#{ext}"), File.join(@outdir, fn)
|
358
|
-
@files[identifier][:outputs][e] = File.join(@outdir, fn)
|
359
|
-
end
|
360
|
-
end
|
361
|
-
end
|
362
|
-
end
|
363
|
-
|
364
178
|
private
|
365
179
|
|
366
180
|
# @param options [Hash]
|
@@ -370,7 +184,6 @@ module Metanorma
|
|
370
184
|
raise ArgumentError, "Need to specify formats (xml,html,pdf,doc)"
|
371
185
|
end
|
372
186
|
return if !options[:format].include?(:html) || options[:coverpage]
|
373
|
-
|
374
187
|
raise ArgumentError, "Need to specify a coverpage to render HTML"
|
375
188
|
end
|
376
189
|
end
|
data/lib/metanorma/compile.rb
CHANGED
@@ -261,6 +261,7 @@ module Metanorma
|
|
261
261
|
@processor.output(isodoc, xml_name, outfilename, ext, isodoc_options)
|
262
262
|
rescue StandardError => e
|
263
263
|
puts e.message
|
264
|
+
puts e.backtrace.join("\n")
|
264
265
|
end
|
265
266
|
end
|
266
267
|
wrap_html(options, file_extension, outfilename)
|
@@ -268,7 +269,7 @@ module Metanorma
|
|
268
269
|
end
|
269
270
|
|
270
271
|
def install_fonts(options)
|
271
|
-
if options[:
|
272
|
+
if options[:no_install_fonts]
|
272
273
|
Util.log("[fontist] Skip font installation because" \
|
273
274
|
" --no-install-fonts argument passed", :debug)
|
274
275
|
return
|
@@ -279,9 +280,11 @@ module Metanorma
|
|
279
280
|
return
|
280
281
|
end
|
281
282
|
|
283
|
+
@updated_formulas_repo = false
|
284
|
+
|
282
285
|
manifest = @processor.fonts_manifest
|
283
|
-
agree_to_terms = options[:
|
284
|
-
continue_without_fonts = options[:
|
286
|
+
agree_to_terms = options[:agree_to_terms] || false
|
287
|
+
continue_without_fonts = options[:continue_without_fonts] || false
|
285
288
|
|
286
289
|
install_fonts_safe(manifest, agree_to_terms, continue_without_fonts)
|
287
290
|
end
|
@@ -297,15 +300,17 @@ module Metanorma
|
|
297
300
|
Util.log("[fontist] Aborting without proper fonts installed," \
|
298
301
|
" make sure that you have set option --agree-to-terms", :fatal)
|
299
302
|
end
|
300
|
-
rescue Fontist::Errors::
|
301
|
-
|
302
|
-
Util.log("[fontist] '#{font}' font is not supported. " \
|
303
|
+
rescue Fontist::Errors::FontError => e
|
304
|
+
log_level = continue ? :warning : :fatal
|
305
|
+
Util.log("[fontist] '#{e.font}' font is not supported. " \
|
303
306
|
"Please report this issue at github.com/metanorma/metanorma-#{@processor.short}/issues" \
|
304
|
-
" to report this issue.",
|
307
|
+
" to report this issue.", log_level)
|
305
308
|
rescue Fontist::Errors::FormulaIndexNotFoundError
|
309
|
+
Util.log("[fontist] Bug: formula index not found after 'fontist update'", :fatal) if @updated_formulas_repo
|
306
310
|
Util.log("[fontist] Missing formula index. Fetching it...", :debug)
|
307
311
|
Fontist::Formula.update_formulas_repo
|
308
|
-
|
312
|
+
@updated_formulas_repo = true
|
313
|
+
install_fonts_safe(manifest, agree, continue)
|
309
314
|
end
|
310
315
|
|
311
316
|
def fontist_install(manifest, agree)
|
@@ -318,8 +323,8 @@ module Metanorma
|
|
318
323
|
# @param options [Hash]
|
319
324
|
# @return [String]
|
320
325
|
def change_output_dir(options)
|
321
|
-
if options[:
|
322
|
-
File.join options[:
|
326
|
+
if options[:output_dir]
|
327
|
+
File.join options[:output_dir], File.basename(options[:filename])
|
323
328
|
else options[:filename]
|
324
329
|
end
|
325
330
|
end
|
@@ -14,7 +14,7 @@ module Metanorma
|
|
14
14
|
header_footer: true,
|
15
15
|
attributes: [
|
16
16
|
"nodoc", "stem", "xrefstyle=short", "docfile=#{filename}",
|
17
|
-
"output_dir=#{options[:
|
17
|
+
"output_dir=#{options[:output_dir]}"
|
18
18
|
]
|
19
19
|
}
|
20
20
|
unless asciidoctor_validate(file, filename, out_opts)
|
data/lib/metanorma/version.rb
CHANGED
data/metanorma.gemspec
CHANGED
@@ -27,19 +27,19 @@ Gem::Specification.new do |spec|
|
|
27
27
|
spec.add_runtime_dependency 'htmlentities'
|
28
28
|
spec.add_runtime_dependency 'nokogiri'
|
29
29
|
spec.add_runtime_dependency 'mn2pdf', "~> 1"
|
30
|
+
spec.add_runtime_dependency 'metanorma-utils', "~> 1.0.3"
|
30
31
|
spec.add_runtime_dependency 'pry'
|
31
32
|
spec.add_runtime_dependency 'fontist', '~> 1.8'
|
32
33
|
|
33
|
-
# get relaton-cli to
|
34
|
+
# get relaton-cli to avoid circular reference with metanorma-standoc
|
34
35
|
#spec.add_dependency "relaton-cli"
|
35
|
-
#spec.add_dependency "metanorma-standoc"
|
36
|
+
#spec.add_dependency "metanorma-standoc"
|
36
37
|
|
37
|
-
spec.add_development_dependency "rake", "~>
|
38
|
+
spec.add_development_dependency "rake", "~> 13.0"
|
38
39
|
spec.add_development_dependency "rspec", "~> 3.0"
|
39
40
|
spec.add_development_dependency "byebug", "~> 10.0"
|
40
41
|
spec.add_development_dependency "rspec-command", "~> 1.0"
|
41
42
|
spec.add_development_dependency "equivalent-xml", "~> 0.6"
|
42
|
-
spec.add_development_dependency "metanorma-iso", "~> 1.
|
43
|
+
spec.add_development_dependency "metanorma-iso", "~> 1.7.0"
|
43
44
|
spec.add_development_dependency "sassc", "~> 2.4.0"
|
44
|
-
#spec.add_development_dependency "isodoc", "~> 1.2.1"
|
45
45
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: metanorma
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.2.
|
4
|
+
version: 1.2.7
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ribose Inc.
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-
|
11
|
+
date: 2021-03-16 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: asciidoctor
|
@@ -66,6 +66,20 @@ dependencies:
|
|
66
66
|
- - "~>"
|
67
67
|
- !ruby/object:Gem::Version
|
68
68
|
version: '1'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: metanorma-utils
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: 1.0.3
|
76
|
+
type: :runtime
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: 1.0.3
|
69
83
|
- !ruby/object:Gem::Dependency
|
70
84
|
name: pry
|
71
85
|
requirement: !ruby/object:Gem::Requirement
|
@@ -100,14 +114,14 @@ dependencies:
|
|
100
114
|
requirements:
|
101
115
|
- - "~>"
|
102
116
|
- !ruby/object:Gem::Version
|
103
|
-
version: '
|
117
|
+
version: '13.0'
|
104
118
|
type: :development
|
105
119
|
prerelease: false
|
106
120
|
version_requirements: !ruby/object:Gem::Requirement
|
107
121
|
requirements:
|
108
122
|
- - "~>"
|
109
123
|
- !ruby/object:Gem::Version
|
110
|
-
version: '
|
124
|
+
version: '13.0'
|
111
125
|
- !ruby/object:Gem::Dependency
|
112
126
|
name: rspec
|
113
127
|
requirement: !ruby/object:Gem::Requirement
|
@@ -170,14 +184,14 @@ dependencies:
|
|
170
184
|
requirements:
|
171
185
|
- - "~>"
|
172
186
|
- !ruby/object:Gem::Version
|
173
|
-
version: 1.
|
187
|
+
version: 1.7.0
|
174
188
|
type: :development
|
175
189
|
prerelease: false
|
176
190
|
version_requirements: !ruby/object:Gem::Requirement
|
177
191
|
requirements:
|
178
192
|
- - "~>"
|
179
193
|
- !ruby/object:Gem::Version
|
180
|
-
version: 1.
|
194
|
+
version: 1.7.0
|
181
195
|
- !ruby/object:Gem::Dependency
|
182
196
|
name: sassc
|
183
197
|
requirement: !ruby/object:Gem::Requirement
|
@@ -224,6 +238,7 @@ files:
|
|
224
238
|
- lib/metanorma/asciidoctor_extensions.rb
|
225
239
|
- lib/metanorma/asciidoctor_extensions/glob_include_processor.rb
|
226
240
|
- lib/metanorma/collection.rb
|
241
|
+
- lib/metanorma/collection_fileprocess.rb
|
227
242
|
- lib/metanorma/collection_manifest.rb
|
228
243
|
- lib/metanorma/collection_renderer.rb
|
229
244
|
- lib/metanorma/compile.rb
|
@@ -261,7 +276,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
261
276
|
- !ruby/object:Gem::Version
|
262
277
|
version: '0'
|
263
278
|
requirements: []
|
264
|
-
rubygems_version: 3.
|
279
|
+
rubygems_version: 3.1.4
|
265
280
|
signing_key:
|
266
281
|
specification_version: 4
|
267
282
|
summary: Metanorma is the standard of standards; the metanorma gem allows you to create
|