metanorma-standoc 1.3.17 → 1.3.18
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/macos.yml +2 -2
- data/.github/workflows/ubuntu.yml +1 -1
- data/.github/workflows/windows.yml +1 -1
- data/lib/asciidoctor/standoc/base.rb +1 -1
- data/lib/asciidoctor/standoc/blocks.rb +3 -2
- data/lib/asciidoctor/standoc/cleanup.rb +1 -0
- data/lib/asciidoctor/standoc/cleanup_boilerplate.rb +1 -2
- data/lib/asciidoctor/standoc/cleanup_section.rb +36 -0
- data/lib/asciidoctor/standoc/converter.rb +0 -1
- data/lib/asciidoctor/standoc/isodoc.rng +1 -1
- data/lib/asciidoctor/standoc/macros.rb +1 -101
- data/lib/asciidoctor/standoc/macros_plantuml.rb +100 -0
- data/lib/asciidoctor/standoc/reqt.rb +6 -6
- data/lib/asciidoctor/standoc/utils.rb +2 -2
- data/lib/asciidoctor/standoc/validate_section.rb +11 -1
- data/lib/metanorma/standoc/version.rb +1 -1
- data/metanorma-standoc.gemspec +2 -1
- data/spec/asciidoctor-standoc/base_spec.rb +2 -2
- data/spec/asciidoctor-standoc/blocks_spec.rb +1 -1
- data/spec/asciidoctor-standoc/cleanup_spec.rb +98 -2
- data/spec/asciidoctor-standoc/inline_spec.rb +1 -1
- data/spec/asciidoctor-standoc/macros_spec.rb +60 -0
- data/spec/asciidoctor-standoc/refs_spec.rb +1 -1
- data/spec/asciidoctor-standoc/validate_spec.rb +14 -0
- data/spec/spec_helper.rb +1 -1
- data/spec/vcr_cassettes/dated_iso_ref_joint_iso_iec.yml +98 -98
- data/spec/vcr_cassettes/isobib_get_123.yml +31 -31
- data/spec/vcr_cassettes/isobib_get_123_2001.yml +16 -16
- data/spec/vcr_cassettes/isobib_get_124.yml +27 -27
- data/spec/vcr_cassettes/rfcbib_get_rfc8341.yml +8 -8
- data/spec/vcr_cassettes/separates_iev_citations_by_top_level_clause.yml +36 -36
- metadata +19 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 29fb2b3bd1b2182033a91de521a848994d54d41592d3c1f850572fd9e4ab6bd5
|
4
|
+
data.tar.gz: 1cdecf3c34899fb71b342eafdf16a249e399e35c5382d41fc5965e2870b80988
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 61be98b3231edd09a06711527c2c482cf276fc57bc09eaa10f83316574a9c13aba58b16ab32df29879ffe821d908dc6ad5ea72673328a440da232bd769c8b912
|
7
|
+
data.tar.gz: 9f41b2ccbb3e865c7b738a67d00f26c7ddd5230e67af501fc696fb5b80793e933dcd56b08f21e56fab318ad877af77a0c24cce2e454aac85dd1f8d3febc8793a
|
data/.github/workflows/macos.yml
CHANGED
@@ -29,8 +29,8 @@ jobs:
|
|
29
29
|
- name: Install LaTeXML
|
30
30
|
run: |
|
31
31
|
# https://github.com/Homebrew/homebrew-core/issues/44950
|
32
|
-
|
33
|
-
|
32
|
+
brew install cpanminus
|
33
|
+
cpanm --notest XML::LibXSLT@1.96 LaTeXML@0.8.4
|
34
34
|
- name: Install PlantUML
|
35
35
|
run: |
|
36
36
|
brew install plantuml
|
@@ -12,7 +12,7 @@ module Asciidoctor
|
|
12
12
|
module Standoc
|
13
13
|
module Base
|
14
14
|
XML_ROOT_TAG = "standard-document".freeze
|
15
|
-
XML_NAMESPACE = "https://www.metanorma.
|
15
|
+
XML_NAMESPACE = "https://www.metanorma.org/ns/standoc".freeze
|
16
16
|
|
17
17
|
Asciidoctor::Extensions.register do
|
18
18
|
inline_macro Asciidoctor::Standoc::AltTermInlineMacro
|
@@ -206,8 +206,9 @@ module Asciidoctor
|
|
206
206
|
def quote_attribution(node, out)
|
207
207
|
if node.attr("citetitle")
|
208
208
|
m = /^(?<cite>[^,]+)(,(?<text>.*$))?$/m.match node.attr("citetitle")
|
209
|
-
out.source m[:
|
210
|
-
|
209
|
+
out.source **attr_code(target: m[:cite], type: "inline") do |s|
|
210
|
+
s << m[:text]
|
211
|
+
end
|
211
212
|
end
|
212
213
|
if node.attr("attribution")
|
213
214
|
out.author { |a| a << node.attr("attribution") }
|
@@ -51,8 +51,7 @@ module Asciidoctor
|
|
51
51
|
|
52
52
|
def boilerplate_isodoc(xmldoc)
|
53
53
|
x = xmldoc.dup
|
54
|
-
|
55
|
-
x.root.add_namespace(nil, "http://riboseinc.com/isoxml")
|
54
|
+
x.root.add_namespace(nil, self.class::XML_NAMESPACE)
|
56
55
|
xml = Nokogiri::XML(x.to_xml)
|
57
56
|
conv = html_converter(EmptyAttr.new)
|
58
57
|
@lang = xmldoc&.at("//bibdata/language")&.text
|
@@ -4,6 +4,7 @@ require "htmlentities"
|
|
4
4
|
require "json"
|
5
5
|
require "pathname"
|
6
6
|
require "open-uri"
|
7
|
+
require "mathml2asciimath"
|
7
8
|
|
8
9
|
module Asciidoctor
|
9
10
|
module Standoc
|
@@ -190,6 +191,41 @@ module Asciidoctor
|
|
190
191
|
term_children_cleanup(xmldoc)
|
191
192
|
termdocsource_cleanup(xmldoc)
|
192
193
|
end
|
194
|
+
|
195
|
+
# Indices sort after letter but before any following
|
196
|
+
# letter (x, x_m, x_1, xa); we use colon to force that sort order.
|
197
|
+
# Numbers sort *after* letters; we use thorn to force that sort order.
|
198
|
+
def symbol_key(x)
|
199
|
+
key = x.dup
|
200
|
+
key.xpath("//*[local-name() = 'math']").each do |m|
|
201
|
+
m.replace(MathML2AsciiMath.m2a(m.to_xml))
|
202
|
+
end
|
203
|
+
ret = Nokogiri::XML(MathML2AsciiMath.m2a(key.to_xml))
|
204
|
+
HTMLEntities.new.decode(ret.text).strip.
|
205
|
+
gsub(/[[:punct]]|[_^]/, ":\\0").gsub(/`/, "").
|
206
|
+
gsub(/[0-9]+/, "þ\\0")
|
207
|
+
end
|
208
|
+
|
209
|
+
def extract_symbols_list(dl)
|
210
|
+
dl_out = []
|
211
|
+
dl.xpath("./dt | ./dd").each do |dtd|
|
212
|
+
if dtd.name == "dt"
|
213
|
+
dl_out << { dt: dtd.remove, key: symbol_key(dtd) }
|
214
|
+
else
|
215
|
+
dl_out.last[:dd] = dtd.remove
|
216
|
+
end
|
217
|
+
end
|
218
|
+
dl_out
|
219
|
+
end
|
220
|
+
|
221
|
+
def symbols_cleanup(docxml)
|
222
|
+
docxml.xpath("//definitions/dl").each do |dl|
|
223
|
+
dl_out = extract_symbols_list(dl)
|
224
|
+
dl_out.sort! { |a, b| a[:key] <=> b[:key] }
|
225
|
+
dl.children = dl_out.map { |d| d[:dt].to_s + d[:dd].to_s }.join("\n")
|
226
|
+
end
|
227
|
+
docxml
|
228
|
+
end
|
193
229
|
end
|
194
230
|
end
|
195
231
|
end
|
@@ -17,7 +17,7 @@
|
|
17
17
|
these elements; we just want one namespace for any child grammars
|
18
18
|
of this.
|
19
19
|
-->
|
20
|
-
<grammar ns="https://www.metanorma.
|
20
|
+
<grammar ns="https://www.metanorma.org/ns/standoc" xmlns="http://relaxng.org/ns/structure/1.0" datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes">
|
21
21
|
<include href="reqt.rng"/>
|
22
22
|
<!-- include "biblio.rnc" { } -->
|
23
23
|
<include href="basicdoc.rng">
|
@@ -1,6 +1,7 @@
|
|
1
1
|
require "asciidoctor/extensions"
|
2
2
|
require "fileutils"
|
3
3
|
require "uuidtools"
|
4
|
+
require_relative "./macros_plantuml.rb"
|
4
5
|
|
5
6
|
module Asciidoctor
|
6
7
|
module Standoc
|
@@ -156,106 +157,5 @@ module Asciidoctor
|
|
156
157
|
end
|
157
158
|
end
|
158
159
|
end
|
159
|
-
|
160
|
-
class PlantUMLBlockMacroBackend
|
161
|
-
# https://stackoverflow.com/questions/2108727/which-in-ruby-checking-if-program-exists-in-path-from-ruby
|
162
|
-
def self.plantuml_installed?
|
163
|
-
cmd = "plantuml"
|
164
|
-
exts = ENV['PATHEXT'] ? ENV['PATHEXT'].split(';') : ['']
|
165
|
-
ENV['PATH'].split(File::PATH_SEPARATOR).each do |path|
|
166
|
-
exts.each do |ext|
|
167
|
-
exe = File.join(path, "#{cmd}#{ext}")
|
168
|
-
return exe if File.executable?(exe) && !File.directory?(exe)
|
169
|
-
end
|
170
|
-
end
|
171
|
-
nil
|
172
|
-
end
|
173
|
-
|
174
|
-
def self.run umlfile, outfile
|
175
|
-
system "plantuml #{umlfile.path}" or (warn $? and return false)
|
176
|
-
i = 0
|
177
|
-
until !Gem.win_platform? || File.exist?(outfile) || i == 15
|
178
|
-
sleep(1)
|
179
|
-
i += 1
|
180
|
-
end
|
181
|
-
File.exist?(outfile)
|
182
|
-
end
|
183
|
-
|
184
|
-
# if no :imagesdir: leave image file in plantuml
|
185
|
-
# sleep need for windows because dot works in separate process and
|
186
|
-
# plantuml process may finish earlier then dot, as result png file
|
187
|
-
# maybe not created yet after plantuml finish
|
188
|
-
def self.generate_file parent, reader
|
189
|
-
localdir = Utils::localdir(parent.document)
|
190
|
-
|
191
|
-
imagesdir = parent.document.attr('imagesdir')
|
192
|
-
umlfile, outfile = save_plantuml parent, reader, localdir
|
193
|
-
|
194
|
-
# TODO: this should raise failure if there is no image output!!
|
195
|
-
run(umlfile, outfile) or return
|
196
|
-
umlfile.unlink
|
197
|
-
|
198
|
-
path = Pathname.new(localdir) + (imagesdir || "plantuml")
|
199
|
-
path.mkpath
|
200
|
-
|
201
|
-
# TODO: this should raise failure if the destination path already exists!
|
202
|
-
File.exist?(path) or return
|
203
|
-
|
204
|
-
# TODO: this should raise failure if the destination path is not writable!
|
205
|
-
File.writable?(path) or return
|
206
|
-
|
207
|
-
# Warning for Heisenbug: metanorma/metanorma-standoc#187
|
208
|
-
# Windows Ruby 2.4 will crash if a Tempfile is "mv"ed.
|
209
|
-
# This is why we need to copy and then unlink.
|
210
|
-
filename = File.basename(outfile.to_s)
|
211
|
-
FileUtils.cp(outfile, path) && outfile.unlink
|
212
|
-
|
213
|
-
imagesdir ? filename : File.join(path, filename)
|
214
|
-
end
|
215
|
-
|
216
|
-
def self.save_plantuml parent, reader, localdir
|
217
|
-
src = reader.source
|
218
|
-
reader.lines.first.sub(/\s+$/, "").match /^@startuml($| )/ or
|
219
|
-
src = "@startuml\n#{src}\n@enduml\n"
|
220
|
-
/^@startuml (?<fn>[^\n]+)\n/ =~ src
|
221
|
-
Tempfile.open(["plantuml", ".pml"], :encoding => "utf-8") do |f|
|
222
|
-
f.write(src)
|
223
|
-
[f, File.join(File.dirname(f.path),
|
224
|
-
(fn || File.basename(f.path, ".pml")) + ".png")]
|
225
|
-
end
|
226
|
-
end
|
227
|
-
|
228
|
-
def self.generate_attrs attrs
|
229
|
-
through_attrs = %w(id align float title role width height alt).
|
230
|
-
inject({}) do |memo, key|
|
231
|
-
memo[key] = attrs[key] if attrs.has_key? key
|
232
|
-
memo
|
233
|
-
end
|
234
|
-
end
|
235
|
-
end
|
236
|
-
|
237
|
-
class PlantUMLBlockMacro < Asciidoctor::Extensions::BlockProcessor
|
238
|
-
use_dsl
|
239
|
-
named :plantuml
|
240
|
-
on_context :literal
|
241
|
-
parse_content_as :raw
|
242
|
-
|
243
|
-
def abort(parent, reader, attrs, msg)
|
244
|
-
# TODO: Abort should really raise an error
|
245
|
-
warn msg
|
246
|
-
attrs["language"] = "plantuml"
|
247
|
-
create_listing_block parent, reader.source, attrs.reject { |k, v| k == 1 }
|
248
|
-
end
|
249
|
-
|
250
|
-
def process(parent, reader, attrs)
|
251
|
-
PlantUMLBlockMacroBackend.plantuml_installed? or
|
252
|
-
return abort(parent, reader, attrs, "PlantUML not installed")
|
253
|
-
filename = PlantUMLBlockMacroBackend.generate_file(parent, reader) or
|
254
|
-
return abort(parent, reader, attrs, "Failed to process PlantUML")
|
255
|
-
through_attrs = PlantUMLBlockMacroBackend.generate_attrs attrs
|
256
|
-
through_attrs["target"] = filename
|
257
|
-
create_image_block parent, through_attrs
|
258
|
-
end
|
259
|
-
end
|
260
160
|
end
|
261
161
|
end
|
@@ -0,0 +1,100 @@
|
|
1
|
+
module Asciidoctor
|
2
|
+
module Standoc
|
3
|
+
class PlantUMLBlockMacroBackend
|
4
|
+
# https://stackoverflow.com/questions/2108727/which-in-ruby-checking-if-program-exists-in-path-from-ruby
|
5
|
+
def self.plantuml_installed?
|
6
|
+
cmd = "plantuml"
|
7
|
+
exts = ENV['PATHEXT'] ? ENV['PATHEXT'].split(';') : ['']
|
8
|
+
ENV['PATH'].split(File::PATH_SEPARATOR).each do |path|
|
9
|
+
exts.each do |ext|
|
10
|
+
exe = File.join(path, "#{cmd}#{ext}")
|
11
|
+
return exe if File.executable?(exe) && !File.directory?(exe)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
raise "PlantUML not installed"
|
15
|
+
nil
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.run umlfile, outfile
|
19
|
+
system "plantuml #{umlfile.path}" or (warn $? and return false)
|
20
|
+
i = 0
|
21
|
+
until !Gem.win_platform? || File.exist?(outfile) || i == 15
|
22
|
+
sleep(1)
|
23
|
+
i += 1
|
24
|
+
end
|
25
|
+
File.exist?(outfile)
|
26
|
+
end
|
27
|
+
|
28
|
+
# if no :imagesdir: leave image file in plantuml
|
29
|
+
# sleep need for windows because dot works in separate process and
|
30
|
+
# plantuml process may finish earlier then dot, as result png file
|
31
|
+
# maybe not created yet after plantuml finish
|
32
|
+
def self.generate_file parent, reader
|
33
|
+
localdir = Utils::localdir(parent.document)
|
34
|
+
imagesdir = parent.document.attr('imagesdir')
|
35
|
+
umlfile, outfile = save_plantuml parent, reader, localdir
|
36
|
+
run(umlfile, outfile) or raise "No image output from PlantUML (#{umlfile}, #{outfile})!"
|
37
|
+
umlfile.unlink
|
38
|
+
|
39
|
+
path = Pathname.new(localdir) + (imagesdir || "plantuml")
|
40
|
+
File.writable?(localdir) or raise "Destination path #{path} not writable for PlantUML!"
|
41
|
+
path.mkpath
|
42
|
+
File.writable?(path) or raise "Destination path #{path} not writable for PlantUML!"
|
43
|
+
#File.exist?(path) or raise "Destination path #{path} already exists for PlantUML!"
|
44
|
+
|
45
|
+
# Warning: metanorma/metanorma-standoc#187
|
46
|
+
# Windows Ruby 2.4 will crash if a Tempfile is "mv"ed.
|
47
|
+
# This is why we need to copy and then unlink.
|
48
|
+
filename = File.basename(outfile.to_s)
|
49
|
+
FileUtils.cp(outfile, path) && outfile.unlink
|
50
|
+
|
51
|
+
imagesdir ? filename : File.join(path, filename)
|
52
|
+
end
|
53
|
+
|
54
|
+
def self.save_plantuml parent, reader, localdir
|
55
|
+
src = reader.source
|
56
|
+
reader.lines.first.sub(/\s+$/, "").match /^@startuml($| )/ or
|
57
|
+
src = "@startuml\n#{src}\n@enduml\n"
|
58
|
+
/^@startuml (?<fn>[^\n]+)\n/ =~ src
|
59
|
+
Tempfile.open(["plantuml", ".pml"], :encoding => "utf-8") do |f|
|
60
|
+
f.write(src)
|
61
|
+
[f, File.join(File.dirname(f.path),
|
62
|
+
(fn || File.basename(f.path, ".pml")) + ".png")]
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def self.generate_attrs attrs
|
67
|
+
through_attrs = %w(id align float title role width height alt).
|
68
|
+
inject({}) do |memo, key|
|
69
|
+
memo[key] = attrs[key] if attrs.has_key? key
|
70
|
+
memo
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
class PlantUMLBlockMacro < Asciidoctor::Extensions::BlockProcessor
|
76
|
+
use_dsl
|
77
|
+
named :plantuml
|
78
|
+
on_context :literal
|
79
|
+
parse_content_as :raw
|
80
|
+
|
81
|
+
def abort(parent, reader, attrs, msg)
|
82
|
+
warn msg
|
83
|
+
attrs["language"] = "plantuml"
|
84
|
+
create_listing_block parent, reader.source, attrs.reject { |k, v| k == 1 }
|
85
|
+
end
|
86
|
+
|
87
|
+
def process(parent, reader, attrs)
|
88
|
+
begin
|
89
|
+
PlantUMLBlockMacroBackend.plantuml_installed?
|
90
|
+
filename = PlantUMLBlockMacroBackend.generate_file(parent, reader)
|
91
|
+
through_attrs = PlantUMLBlockMacroBackend.generate_attrs attrs
|
92
|
+
through_attrs["target"] = filename
|
93
|
+
create_image_block parent, through_attrs
|
94
|
+
rescue StandardError => e
|
95
|
+
abort(parent, reader, attrs, e.message)
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
@@ -29,8 +29,8 @@ module Asciidoctor
|
|
29
29
|
def requirement_classification(classif, ex)
|
30
30
|
req_classif_parse(classif).each do |r|
|
31
31
|
ex.classification do |c|
|
32
|
-
c.tag r[0]
|
33
|
-
c.value r[1]
|
32
|
+
c.tag { |t| t << r[0] }
|
33
|
+
c.value { |v| v << r[1] }
|
34
34
|
end
|
35
35
|
end
|
36
36
|
end
|
@@ -51,11 +51,11 @@ module Asciidoctor
|
|
51
51
|
classif = node.attr("classification")
|
52
52
|
noko do |xml|
|
53
53
|
xml.send obligation, **attr_code(reqt_attributes(node)) do |ex|
|
54
|
-
|
55
|
-
|
56
|
-
|
54
|
+
node.title and ex.title { |t| t << node.title }
|
55
|
+
node.attr("label") and ex.label { |l| l << node.attr("label") }
|
56
|
+
node.attr("subject") and ex.subject { |s| s << node.attr("subject") }
|
57
57
|
node&.attr("inherit")&.split(/;\s*/)&.each do |i|
|
58
|
-
ex.inherit i
|
58
|
+
ex.inherit { |inh| inh << i }
|
59
59
|
end
|
60
60
|
requirement_classification(classif, ex) if classif
|
61
61
|
wrap_in_para(node, ex)
|
@@ -77,8 +77,8 @@ module Asciidoctor
|
|
77
77
|
end
|
78
78
|
|
79
79
|
def mn_code(code)
|
80
|
-
|
81
|
-
|
80
|
+
code.sub(/^\(/, "[").sub(/\).*$/, "]").sub(/^nofetch\((.+)\)$/, "\\1")
|
81
|
+
end
|
82
82
|
|
83
83
|
def emend_biblio(xml, code, title, usrlbl)
|
84
84
|
unless xml.at("/bibitem/docidentifier[not(@type = 'DOI')][text()]")
|
@@ -5,6 +5,7 @@ module Asciidoctor
|
|
5
5
|
module Validate
|
6
6
|
def section_validate(doc)
|
7
7
|
sourcecode_style(doc.root)
|
8
|
+
hanging_para_style(doc.root)
|
8
9
|
asset_style(doc.root)
|
9
10
|
end
|
10
11
|
|
@@ -18,7 +19,7 @@ module Asciidoctor
|
|
18
19
|
end
|
19
20
|
end
|
20
21
|
|
21
|
-
def style_warning(node, msg, text)
|
22
|
+
def style_warning(node, msg, text = nil)
|
22
23
|
return if @novalid
|
23
24
|
w = "ISO style: WARNING (#{Utils::current_location(node)}): #{msg}"
|
24
25
|
w += ": #{text}" if text
|
@@ -37,6 +38,15 @@ module Asciidoctor
|
|
37
38
|
def asset_style(root)
|
38
39
|
asset_title_style(root)
|
39
40
|
end
|
41
|
+
|
42
|
+
def hanging_para_style(root)
|
43
|
+
root.xpath("//clause | //annex | //foreword | //introduction | "\
|
44
|
+
"//acknowledgements").each do |c|
|
45
|
+
next unless c.at("./clause")
|
46
|
+
next if c.elements.select { |n| n.name != "clause" }.empty?
|
47
|
+
style_warning(c, "Hanging paragraph in clause")
|
48
|
+
end
|
49
|
+
end
|
40
50
|
end
|
41
51
|
end
|
42
52
|
end
|