asciidoctor-kroki 0.2.0 → 0.5.0
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/.rubocop.yml +10 -1
- data/Gemfile.lock +3 -52
- data/asciidoctor-kroki.gemspec +1 -2
- data/lib/asciidoctor/extensions/asciidoctor_kroki/extension.rb +97 -35
- data/spec/asciidoctor_kroki_block_macro_spec.rb +128 -0
- data/spec/asciidoctor_kroki_client_spec.rb +68 -0
- data/spec/asciidoctor_kroki_spec.rb +72 -6
- metadata +5 -17
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b10096229def31407946a5f7e77eb57a991895d9407d334b6a4ca3dc7e8ba165
|
4
|
+
data.tar.gz: 81497c2124169974c072a57c496b37d8cbd5e96b4793a22d59a3152fb1693c45
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 03e1e7d5dc886c9e4ff9d7199f3289aa1a94d8b97a21209ba4ea9c4b505129646297bb62c02cab6390803b157a7a505e3af944ff533c49086af11927647776ce
|
7
|
+
data.tar.gz: ad4cda7ce19c6ffa1223a224c1528c87e7b8864d554662f26a7534937f4bea49433e500373dad215feb09d71f748c84881ad720ea5c52765977383eb393a9f4c
|
data/.rubocop.yml
CHANGED
@@ -1,8 +1,14 @@
|
|
1
1
|
Style/Encoding:
|
2
2
|
Enabled: false
|
3
3
|
|
4
|
+
Layout/EndOfLine:
|
5
|
+
EnforcedStyle: lf
|
6
|
+
|
4
7
|
Metrics/LineLength:
|
5
|
-
Max:
|
8
|
+
Max: 180
|
9
|
+
|
10
|
+
Metrics/ClassLength:
|
11
|
+
Max: 150
|
6
12
|
|
7
13
|
Metrics/MethodLength:
|
8
14
|
Max: 50
|
@@ -15,3 +21,6 @@ Metrics/PerceivedComplexity:
|
|
15
21
|
|
16
22
|
Metrics/AbcSize:
|
17
23
|
Max: 30
|
24
|
+
|
25
|
+
Metrics/ParameterLists:
|
26
|
+
Max: 7
|
data/Gemfile.lock
CHANGED
@@ -1,62 +1,19 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
asciidoctor-kroki (0.
|
4
|
+
asciidoctor-kroki (0.5.0)
|
5
5
|
asciidoctor (~> 2.0)
|
6
|
-
asciidoctor-pdf (= 1.5.3)
|
7
6
|
|
8
7
|
GEM
|
9
8
|
remote: https://rubygems.org/
|
10
9
|
specs:
|
11
|
-
|
12
|
-
addressable (2.7.0)
|
13
|
-
public_suffix (>= 2.0.2, < 5.0)
|
14
|
-
afm (0.2.2)
|
15
|
-
asciidoctor (2.0.10)
|
16
|
-
asciidoctor-pdf (1.5.3)
|
17
|
-
asciidoctor (>= 1.5.3, < 3.0.0)
|
18
|
-
concurrent-ruby (~> 1.1.0)
|
19
|
-
prawn (~> 2.2.0)
|
20
|
-
prawn-icon (~> 2.5.0)
|
21
|
-
prawn-svg (~> 0.30.0)
|
22
|
-
prawn-table (~> 0.2.0)
|
23
|
-
prawn-templates (~> 0.1.0)
|
24
|
-
safe_yaml (~> 1.0.0)
|
25
|
-
thread_safe (~> 0.3.0)
|
26
|
-
treetop (~> 1.6.0)
|
27
|
-
ttfunk (~> 1.5.0, >= 1.5.1)
|
10
|
+
asciidoctor (2.0.11)
|
28
11
|
ast (2.4.1)
|
29
|
-
concurrent-ruby (1.1.6)
|
30
|
-
css_parser (1.7.1)
|
31
|
-
addressable
|
32
12
|
diff-lcs (1.3)
|
33
|
-
hashery (2.1.2)
|
34
13
|
jaro_winkler (1.5.4)
|
35
14
|
parallel (1.19.1)
|
36
15
|
parser (2.7.1.3)
|
37
16
|
ast (~> 2.4.0)
|
38
|
-
pdf-core (0.7.0)
|
39
|
-
pdf-reader (2.4.0)
|
40
|
-
Ascii85 (~> 1.0.0)
|
41
|
-
afm (~> 0.2.1)
|
42
|
-
hashery (~> 2.0)
|
43
|
-
ruby-rc4
|
44
|
-
ttfunk
|
45
|
-
polyglot (0.3.5)
|
46
|
-
prawn (2.2.2)
|
47
|
-
pdf-core (~> 0.7.0)
|
48
|
-
ttfunk (~> 1.5)
|
49
|
-
prawn-icon (2.5.0)
|
50
|
-
prawn (>= 1.1.0, < 3.0.0)
|
51
|
-
prawn-svg (0.30.0)
|
52
|
-
css_parser (~> 1.6)
|
53
|
-
prawn (>= 0.11.1, < 3)
|
54
|
-
prawn-table (0.2.2)
|
55
|
-
prawn (>= 1.3.0, < 3.0.0)
|
56
|
-
prawn-templates (0.1.2)
|
57
|
-
pdf-reader (~> 2.0)
|
58
|
-
prawn (~> 2.2)
|
59
|
-
public_suffix (4.0.5)
|
60
17
|
rainbow (3.0.0)
|
61
18
|
rake (12.3.3)
|
62
19
|
rspec (3.8.0)
|
@@ -80,12 +37,6 @@ GEM
|
|
80
37
|
ruby-progressbar (~> 1.7)
|
81
38
|
unicode-display_width (>= 1.4.0, < 1.7)
|
82
39
|
ruby-progressbar (1.10.1)
|
83
|
-
ruby-rc4 (0.1.5)
|
84
|
-
safe_yaml (1.0.5)
|
85
|
-
thread_safe (0.3.6)
|
86
|
-
treetop (1.6.10)
|
87
|
-
polyglot (~> 0.3)
|
88
|
-
ttfunk (1.5.1)
|
89
40
|
unicode-display_width (1.6.1)
|
90
41
|
|
91
42
|
PLATFORMS
|
@@ -98,4 +49,4 @@ DEPENDENCIES
|
|
98
49
|
rubocop (~> 0.74.0)
|
99
50
|
|
100
51
|
BUNDLED WITH
|
101
|
-
|
52
|
+
2.2.17
|
data/asciidoctor-kroki.gemspec
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
Gem::Specification.new do |s|
|
4
4
|
s.name = 'asciidoctor-kroki'
|
5
|
-
s.version = '0.
|
5
|
+
s.version = '0.5.0'
|
6
6
|
s.summary = 'Asciidoctor extension to convert diagrams to images using Kroki'
|
7
7
|
s.description = 'An extension for Asciidoctor to convert diagrams to images using https://kroki.io'
|
8
8
|
|
@@ -19,7 +19,6 @@ Gem::Specification.new do |s|
|
|
19
19
|
s.require_paths = ['lib']
|
20
20
|
|
21
21
|
s.add_runtime_dependency 'asciidoctor', '~> 2.0'
|
22
|
-
s.add_runtime_dependency 'asciidoctor-pdf', '1.5.3'
|
23
22
|
|
24
23
|
s.add_development_dependency 'rake', '~> 12.3.2'
|
25
24
|
s.add_development_dependency 'rspec', '~> 3.8.0'
|
@@ -15,11 +15,24 @@ module AsciidoctorExtensions
|
|
15
15
|
on_context :listing, :literal
|
16
16
|
name_positional_attributes 'target', 'format'
|
17
17
|
|
18
|
+
# @param name [String] name of the block macro (optional)
|
19
|
+
# @param config [Hash] a config hash (optional)
|
20
|
+
# - :logger a logger used to log warning and errors (optional)
|
21
|
+
#
|
22
|
+
def initialize(name = nil, config = {})
|
23
|
+
@logger = (config || {}).delete(:logger) { ::Asciidoctor::LoggerManager.logger }
|
24
|
+
super(name, config)
|
25
|
+
end
|
26
|
+
|
18
27
|
def process(parent, reader, attrs)
|
19
28
|
diagram_type = @name
|
20
29
|
diagram_text = reader.string
|
21
|
-
KrokiProcessor.process(self, parent, attrs, diagram_type, diagram_text)
|
30
|
+
KrokiProcessor.process(self, parent, attrs, diagram_type, diagram_text, @logger)
|
22
31
|
end
|
32
|
+
|
33
|
+
protected
|
34
|
+
|
35
|
+
attr_reader :logger
|
23
36
|
end
|
24
37
|
|
25
38
|
# A block macro extension that converts a diagram into an image.
|
@@ -29,11 +42,48 @@ module AsciidoctorExtensions
|
|
29
42
|
|
30
43
|
name_positional_attributes 'format'
|
31
44
|
|
45
|
+
# @param name [String] name of the block macro (optional)
|
46
|
+
# @param config [Hash] a config hash (optional)
|
47
|
+
# - :logger a logger used to log warning and errors (optional)
|
48
|
+
#
|
49
|
+
def initialize(name = nil, config = {})
|
50
|
+
@logger = (config || {}).delete(:logger) { ::Asciidoctor::LoggerManager.logger }
|
51
|
+
super(name, config)
|
52
|
+
end
|
53
|
+
|
32
54
|
def process(parent, target, attrs)
|
33
55
|
diagram_type = @name
|
34
56
|
target = parent.apply_subs(target, [:attributes])
|
35
|
-
|
36
|
-
|
57
|
+
|
58
|
+
unless read_allowed?(target)
|
59
|
+
link = create_inline(parent, :anchor, target, type: :link, target: target)
|
60
|
+
return create_block(parent, :paragraph, link.convert, {}, content_model: :raw)
|
61
|
+
end
|
62
|
+
|
63
|
+
unless (path = resolve_target_path(target))
|
64
|
+
logger.error "#{diagram_type} block macro not found: #{target}."
|
65
|
+
create_block(parent, 'paragraph', unresolved_block_macro_message(diagram_type, target), {})
|
66
|
+
end
|
67
|
+
|
68
|
+
begin
|
69
|
+
diagram_text = read(path)
|
70
|
+
rescue => e # rubocop:disable RescueStandardError
|
71
|
+
logger.error "Failed to read #{diagram_type} file: #{path}. #{e}."
|
72
|
+
return create_block(parent, 'paragraph', unresolved_block_macro_message(diagram_type, path), {})
|
73
|
+
end
|
74
|
+
KrokiProcessor.process(self, parent, attrs, diagram_type, diagram_text, @logger)
|
75
|
+
end
|
76
|
+
|
77
|
+
protected
|
78
|
+
|
79
|
+
attr_reader :logger
|
80
|
+
|
81
|
+
def resolve_target_path(target)
|
82
|
+
target
|
83
|
+
end
|
84
|
+
|
85
|
+
def read_allowed?(_target)
|
86
|
+
true
|
37
87
|
end
|
38
88
|
|
39
89
|
def read(target)
|
@@ -44,32 +94,38 @@ module AsciidoctorExtensions
|
|
44
94
|
File.open(target, &:read)
|
45
95
|
end
|
46
96
|
end
|
97
|
+
|
98
|
+
def unresolved_block_macro_message(name, target)
|
99
|
+
"Unresolved block macro - #{name}::#{target}[]"
|
100
|
+
end
|
47
101
|
end
|
48
102
|
|
49
103
|
# Kroki API
|
50
104
|
#
|
51
105
|
module Kroki
|
52
106
|
SUPPORTED_DIAGRAM_NAMES = %w[
|
53
|
-
plantuml
|
54
|
-
ditaa
|
55
|
-
graphviz
|
56
|
-
blockdiag
|
57
|
-
seqdiag
|
58
107
|
actdiag
|
59
|
-
|
60
|
-
|
61
|
-
|
108
|
+
blockdiag
|
109
|
+
bpmn
|
110
|
+
bytefield
|
62
111
|
c4plantuml
|
112
|
+
ditaa
|
63
113
|
erd
|
114
|
+
excalidraw
|
115
|
+
graphviz
|
64
116
|
mermaid
|
65
117
|
nomnoml
|
118
|
+
nwdiag
|
119
|
+
packetdiag
|
120
|
+
pikchr
|
121
|
+
plantuml
|
122
|
+
rackdiag
|
123
|
+
seqdiag
|
66
124
|
svgbob
|
67
125
|
umlet
|
68
126
|
vega
|
69
127
|
vegalite
|
70
128
|
wavedrom
|
71
|
-
bytefield
|
72
|
-
bpmn
|
73
129
|
].freeze
|
74
130
|
end
|
75
131
|
|
@@ -79,9 +135,9 @@ module AsciidoctorExtensions
|
|
79
135
|
TEXT_FORMATS = %w[txt atxt utxt].freeze
|
80
136
|
|
81
137
|
class << self
|
82
|
-
def process(processor, parent, attrs, diagram_type, diagram_text)
|
138
|
+
def process(processor, parent, attrs, diagram_type, diagram_text, logger)
|
83
139
|
doc = parent.document
|
84
|
-
diagram_text = prepend_plantuml_config(diagram_text, diagram_type, doc)
|
140
|
+
diagram_text = prepend_plantuml_config(diagram_text, diagram_type, doc, logger)
|
85
141
|
# If "subs" attribute is specified, substitute accordingly.
|
86
142
|
# Be careful not to specify "specialcharacters" or your diagram code won't be valid anymore!
|
87
143
|
if (subs = attrs['subs'])
|
@@ -95,7 +151,7 @@ module AsciidoctorExtensions
|
|
95
151
|
attrs['role'] = get_role(format, role)
|
96
152
|
attrs['format'] = format
|
97
153
|
kroki_diagram = KrokiDiagram.new(diagram_type, format, diagram_text)
|
98
|
-
kroki_client = KrokiClient.new(server_url(doc), http_method(doc), KrokiHttpClient)
|
154
|
+
kroki_client = KrokiClient.new(server_url(doc), http_method(doc), KrokiHttpClient, logger, max_uri_length(doc))
|
99
155
|
if TEXT_FORMATS.include?(format)
|
100
156
|
text_content = kroki_client.text_content(kroki_diagram)
|
101
157
|
block = processor.create_block(parent, 'literal', text_content, attrs)
|
@@ -111,12 +167,17 @@ module AsciidoctorExtensions
|
|
111
167
|
|
112
168
|
private
|
113
169
|
|
114
|
-
def prepend_plantuml_config(diagram_text, diagram_type, doc)
|
115
|
-
if diagram_type == :plantuml && doc.attr?('kroki-plantuml-include')
|
116
|
-
#
|
117
|
-
#
|
118
|
-
|
119
|
-
|
170
|
+
def prepend_plantuml_config(diagram_text, diagram_type, doc, logger)
|
171
|
+
if diagram_type == :plantuml && doc.safe < ::Asciidoctor::SafeMode::SECURE && doc.attr?('kroki-plantuml-include')
|
172
|
+
# REMIND: this behaves different than the JS version
|
173
|
+
# Once we have a preprocessor for Ruby, the value should be added in the diagram source as "!include #{plantuml_include}"
|
174
|
+
plantuml_include_path = doc.normalize_system_path(doc.attr('kroki-plantuml-include'))
|
175
|
+
if ::File.readable? plantuml_include_path
|
176
|
+
config = File.read(plantuml_include_path)
|
177
|
+
diagram_text = config + "\n" + diagram_text
|
178
|
+
else
|
179
|
+
logger.warn "Unable to read plantuml-include. File not found or not readable: #{plantuml_include_path}."
|
180
|
+
end
|
120
181
|
end
|
121
182
|
diagram_text
|
122
183
|
end
|
@@ -156,7 +217,7 @@ module AsciidoctorExtensions
|
|
156
217
|
end
|
157
218
|
|
158
219
|
def create_image_src(doc, kroki_diagram, kroki_client)
|
159
|
-
if doc.attr('kroki-fetch-diagram')
|
220
|
+
if doc.attr('kroki-fetch-diagram') && doc.safe < ::Asciidoctor::SafeMode::SECURE
|
160
221
|
kroki_diagram.save(output_dir_path(doc), kroki_client)
|
161
222
|
else
|
162
223
|
kroki_diagram.get_diagram_uri(server_url(doc))
|
@@ -171,20 +232,20 @@ module AsciidoctorExtensions
|
|
171
232
|
doc.attr('kroki-http-method', 'adaptive').downcase
|
172
233
|
end
|
173
234
|
|
235
|
+
def max_uri_length(doc)
|
236
|
+
doc.attr('kroki-max-uri-length', '4000').to_i
|
237
|
+
end
|
238
|
+
|
174
239
|
def output_dir_path(doc)
|
175
|
-
images_output_dir = doc.attr('imagesoutdir')
|
176
|
-
out_dir = doc.attr('outdir')
|
177
|
-
to_dir = doc.attr('to_dir')
|
178
|
-
base_dir = doc.base_dir
|
179
240
|
images_dir = doc.attr('imagesdir', '')
|
180
|
-
if images_output_dir
|
241
|
+
if (images_output_dir = doc.attr('imagesoutdir'))
|
181
242
|
images_output_dir
|
182
|
-
elsif out_dir
|
243
|
+
elsif (out_dir = doc.attr('outdir'))
|
183
244
|
File.join(out_dir, images_dir)
|
184
|
-
elsif to_dir
|
245
|
+
elsif (to_dir = doc.attr('to_dir'))
|
185
246
|
File.join(to_dir, images_dir)
|
186
247
|
else
|
187
|
-
File.join(base_dir, images_dir)
|
248
|
+
File.join(doc.base_dir, images_dir)
|
188
249
|
end
|
189
250
|
end
|
190
251
|
end
|
@@ -258,18 +319,19 @@ module AsciidoctorExtensions
|
|
258
319
|
class KrokiClient
|
259
320
|
attr_reader :server_url
|
260
321
|
attr_reader :method
|
322
|
+
attr_reader :max_uri_length
|
261
323
|
|
262
324
|
SUPPORTED_HTTP_METHODS = %w[get post adaptive].freeze
|
263
325
|
|
264
|
-
def initialize(server_url, http_method, http_client)
|
326
|
+
def initialize(server_url, http_method, http_client, logger = ::Asciidoctor::LoggerManager.logger, max_uri_length = 4000)
|
265
327
|
@server_url = server_url
|
266
|
-
@max_uri_length =
|
328
|
+
@max_uri_length = max_uri_length
|
267
329
|
@http_client = http_client
|
268
330
|
method = (http_method || 'adaptive').downcase
|
269
331
|
if SUPPORTED_HTTP_METHODS.include?(method)
|
270
332
|
@method = method
|
271
333
|
else
|
272
|
-
|
334
|
+
logger.warn "Invalid value '#{method}' for kroki-http-method attribute. The value must be either: 'get', 'post' or 'adaptive'. Proceeding using: 'adaptive'."
|
273
335
|
@method = 'adaptive'
|
274
336
|
end
|
275
337
|
end
|
@@ -285,7 +347,7 @@ module AsciidoctorExtensions
|
|
285
347
|
if @method == 'adaptive' || @method == 'get'
|
286
348
|
uri = kroki_diagram.get_diagram_uri(server_url)
|
287
349
|
if uri.length > @max_uri_length
|
288
|
-
# The request URI is longer than
|
350
|
+
# The request URI is longer than the max URI length.
|
289
351
|
if @method == 'get'
|
290
352
|
# The request might be rejected by the server with a 414 Request-URI Too Large.
|
291
353
|
# Consider using the attribute kroki-http-method with the value 'adaptive'.
|
@@ -0,0 +1,128 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'rspec_helper'
|
4
|
+
require 'asciidoctor'
|
5
|
+
require_relative '../lib/asciidoctor/extensions/asciidoctor_kroki'
|
6
|
+
require_relative '../lib/asciidoctor/extensions/asciidoctor_kroki/extension'
|
7
|
+
|
8
|
+
describe ::AsciidoctorExtensions::KrokiBlockMacroProcessor do
|
9
|
+
context 'convert to html5' do
|
10
|
+
it 'should catch exception if target is not readable' do
|
11
|
+
input = <<~'ADOC'
|
12
|
+
plantuml::spec/fixtures/missing.puml[svg,role=sequence]
|
13
|
+
ADOC
|
14
|
+
output = Asciidoctor.convert(input, standalone: false)
|
15
|
+
(expect output).to eql %(<div class="paragraph">
|
16
|
+
<p>Unresolved block macro - plantuml::spec/fixtures/missing.puml[]</p>
|
17
|
+
</div>)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
context 'using a custom block macro' do
|
21
|
+
it 'should disallow read' do
|
22
|
+
# noinspection RubyClassModuleNamingConvention
|
23
|
+
class DisallowReadKrokiBlockMacroProcessor < ::AsciidoctorExtensions::KrokiBlockMacroProcessor
|
24
|
+
def read_allowed?(_target)
|
25
|
+
false
|
26
|
+
end
|
27
|
+
end
|
28
|
+
registry = Asciidoctor::Extensions.create do
|
29
|
+
block_macro DisallowReadKrokiBlockMacroProcessor, 'plantuml'
|
30
|
+
end
|
31
|
+
input = <<~'ADOC'
|
32
|
+
plantuml::spec/fixtures/alice.puml[svg,role=sequence]
|
33
|
+
ADOC
|
34
|
+
output = Asciidoctor.convert(input, standalone: false, extension_registry: registry)
|
35
|
+
(expect output).to eql %(<div class="paragraph">
|
36
|
+
<p><a href="spec/fixtures/alice.puml">spec/fixtures/alice.puml</a></p>
|
37
|
+
</div>)
|
38
|
+
end
|
39
|
+
it 'should allow read if target is not a URI' do
|
40
|
+
# noinspection RubyClassModuleNamingConvention
|
41
|
+
class DisallowUriReadKrokiBlockMacroProcessor < ::AsciidoctorExtensions::KrokiBlockMacroProcessor
|
42
|
+
def read_allowed?(target)
|
43
|
+
return false if ::Asciidoctor::Helpers.uriish?(target)
|
44
|
+
|
45
|
+
true
|
46
|
+
end
|
47
|
+
end
|
48
|
+
registry = Asciidoctor::Extensions.create do
|
49
|
+
block_macro DisallowUriReadKrokiBlockMacroProcessor, 'plantuml'
|
50
|
+
end
|
51
|
+
input = <<~'ADOC'
|
52
|
+
plantuml::https://domain.org/alice.puml[svg,role=sequence]
|
53
|
+
|
54
|
+
plantuml::file://path/to/alice.puml[svg,role=sequence]
|
55
|
+
|
56
|
+
plantuml::spec/fixtures/alice.puml[svg,role=sequence]
|
57
|
+
ADOC
|
58
|
+
output = Asciidoctor.convert(input, standalone: false, extension_registry: registry)
|
59
|
+
(expect output).to eql %(<div class="paragraph">
|
60
|
+
<p><a href="https://domain.org/alice.puml">https://domain.org/alice.puml</a></p>
|
61
|
+
</div>
|
62
|
+
<div class="paragraph">
|
63
|
+
<p><a href="file://path/to/alice.puml">file://path/to/alice.puml</a></p>
|
64
|
+
</div>
|
65
|
+
<div class="imageblock sequence kroki-format-svg kroki">
|
66
|
+
<div class="content">
|
67
|
+
<img src="https://kroki.io/plantuml/svg/eNpLzMlMTlXQtVNIyk-yUshIzcnJ5wIAQ-AGVQ==" alt="Diagram">
|
68
|
+
</div>
|
69
|
+
</div>)
|
70
|
+
end
|
71
|
+
it 'should override the resolve target method' do
|
72
|
+
# noinspection RubyClassModuleNamingConvention
|
73
|
+
class FixtureResolveTargetKrokiBlockMacroProcessor < ::AsciidoctorExtensions::KrokiBlockMacroProcessor
|
74
|
+
def resolve_target_path(target)
|
75
|
+
"spec/fixtures/#{target}"
|
76
|
+
end
|
77
|
+
end
|
78
|
+
registry = Asciidoctor::Extensions.create do
|
79
|
+
block_macro FixtureResolveTargetKrokiBlockMacroProcessor, 'plantuml'
|
80
|
+
end
|
81
|
+
input = <<~'ADOC'
|
82
|
+
plantuml::alice.puml[svg,role=sequence]
|
83
|
+
ADOC
|
84
|
+
output = Asciidoctor.convert(input, standalone: false, extension_registry: registry)
|
85
|
+
(expect output).to eql %(<div class="imageblock sequence kroki-format-svg kroki">
|
86
|
+
<div class="content">
|
87
|
+
<img src="https://kroki.io/plantuml/svg/eNpLzMlMTlXQtVNIyk-yUshIzcnJ5wIAQ-AGVQ==" alt="Diagram">
|
88
|
+
</div>
|
89
|
+
</div>)
|
90
|
+
end
|
91
|
+
it 'should display unresolved block macro message when the traget cannot be resolved' do
|
92
|
+
# noinspection RubyClassModuleNamingConvention
|
93
|
+
class UnresolvedTargetKrokiBlockMacroProcessor < ::AsciidoctorExtensions::KrokiBlockMacroProcessor
|
94
|
+
def resolve_target_path(_target)
|
95
|
+
nil
|
96
|
+
end
|
97
|
+
end
|
98
|
+
registry = Asciidoctor::Extensions.create do
|
99
|
+
block_macro UnresolvedTargetKrokiBlockMacroProcessor, 'plantuml'
|
100
|
+
end
|
101
|
+
input = <<~'ADOC'
|
102
|
+
plantuml::alice.puml[svg,role=sequence]
|
103
|
+
ADOC
|
104
|
+
output = Asciidoctor.convert(input, standalone: false, extension_registry: registry)
|
105
|
+
(expect output).to eql %(<div class="paragraph">
|
106
|
+
<p>Unresolved block macro - plantuml::[]</p>
|
107
|
+
</div>)
|
108
|
+
end
|
109
|
+
it 'should override the unresolved block macro message' do
|
110
|
+
# noinspection RubyClassModuleNamingConvention
|
111
|
+
class CustomUnresolvedTargetMessageKrokiBlockMacroProcessor < ::AsciidoctorExtensions::KrokiBlockMacroProcessor
|
112
|
+
def unresolved_block_macro_message(name, target)
|
113
|
+
"*[ERROR: #{name}::#{target}[] - unresolved block macro]*"
|
114
|
+
end
|
115
|
+
end
|
116
|
+
registry = Asciidoctor::Extensions.create do
|
117
|
+
block_macro CustomUnresolvedTargetMessageKrokiBlockMacroProcessor, 'plantuml'
|
118
|
+
end
|
119
|
+
input = <<~'ADOC'
|
120
|
+
plantuml::spec/fixtures/missing.puml[svg,role=sequence]
|
121
|
+
ADOC
|
122
|
+
output = Asciidoctor.convert(input, standalone: false, extension_registry: registry)
|
123
|
+
(expect output).to eql %(<div class="paragraph">
|
124
|
+
<p><strong>[ERROR: plantuml::spec/fixtures/missing.puml[] - unresolved block macro]</strong></p>
|
125
|
+
</div>)
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
@@ -20,4 +20,72 @@ describe ::AsciidoctorExtensions::KrokiClient do
|
|
20
20
|
kroki_client = ::AsciidoctorExtensions::KrokiClient.new('http://localhost:8000', 'get', kroki_http_client)
|
21
21
|
expect(kroki_client.method).to eq('get')
|
22
22
|
end
|
23
|
+
it 'should use 4000 as the default max URI length' do
|
24
|
+
kroki_http_client = ::AsciidoctorExtensions::KrokiHttpClient
|
25
|
+
kroki_client = ::AsciidoctorExtensions::KrokiClient.new('http://localhost:8000', 'get', kroki_http_client)
|
26
|
+
expect(kroki_client.max_uri_length).to eq(4000)
|
27
|
+
end
|
28
|
+
it 'should use a custom value as max URI length' do
|
29
|
+
kroki_http_client = ::AsciidoctorExtensions::KrokiHttpClient
|
30
|
+
kroki_client = ::AsciidoctorExtensions::KrokiClient.new('http://localhost:8000', 'get', kroki_http_client, nil, 8000)
|
31
|
+
expect(kroki_client.max_uri_length).to eq(8000)
|
32
|
+
end
|
33
|
+
it 'should get an image with POST request if the URI length is greater than the value configured' do
|
34
|
+
kroki_http_client = Class.new do
|
35
|
+
class << self
|
36
|
+
def get(uri, _)
|
37
|
+
"GET #{uri}"
|
38
|
+
end
|
39
|
+
|
40
|
+
def post(uri, data, _)
|
41
|
+
"POST #{uri} - #{data}"
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
kroki_diagram = Class.new do
|
46
|
+
attr_reader :type, :text, :format
|
47
|
+
|
48
|
+
def initialize(type, format, text)
|
49
|
+
@text = text
|
50
|
+
@type = type
|
51
|
+
@format = format
|
52
|
+
end
|
53
|
+
|
54
|
+
def get_diagram_uri(_)
|
55
|
+
'diagram-uri'
|
56
|
+
end
|
57
|
+
end.new('type', 'format', 'text')
|
58
|
+
kroki_client = ::AsciidoctorExtensions::KrokiClient.new('http://localhost:8000', 'adaptive', kroki_http_client, nil, 10)
|
59
|
+
result = kroki_client.get_image(kroki_diagram, 'utf8')
|
60
|
+
expect(result).to eq('POST http://localhost:8000/type/format - text')
|
61
|
+
end
|
62
|
+
it 'should get an image with GET request if the URI length is lower or equals than the value configured' do
|
63
|
+
kroki_http_client = Class.new do
|
64
|
+
class << self
|
65
|
+
def get(uri, _)
|
66
|
+
"GET #{uri}"
|
67
|
+
end
|
68
|
+
|
69
|
+
def post(uri, data, _)
|
70
|
+
"POST #{uri} - #{data}"
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
kroki_diagram = Class.new do
|
75
|
+
attr_reader :type, :text, :format
|
76
|
+
|
77
|
+
def initialize(type, format, text)
|
78
|
+
@text = text
|
79
|
+
@type = type
|
80
|
+
@format = format
|
81
|
+
end
|
82
|
+
|
83
|
+
def get_diagram_uri(_)
|
84
|
+
'diagram-uri'
|
85
|
+
end
|
86
|
+
end.new('type', 'format', 'text')
|
87
|
+
kroki_client = ::AsciidoctorExtensions::KrokiClient.new('http://localhost:8000', 'adaptive', kroki_http_client, nil, 11)
|
88
|
+
result = kroki_client.get_image(kroki_diagram, 'utf8')
|
89
|
+
expect(result).to eq('GET diagram-uri')
|
90
|
+
end
|
23
91
|
end
|
@@ -34,17 +34,59 @@ describe ::AsciidoctorExtensions::KrokiBlockProcessor do
|
|
34
34
|
</div>
|
35
35
|
</div>)
|
36
36
|
end
|
37
|
-
it 'should include the plantuml-include file' do
|
37
|
+
it 'should include the plantuml-include file when safe mode is safe' do
|
38
38
|
input = <<~'ADOC'
|
39
39
|
[plantuml]
|
40
40
|
....
|
41
41
|
alice -> bob: hello
|
42
42
|
....
|
43
43
|
ADOC
|
44
|
-
output = Asciidoctor.convert(input, attributes: { 'env-idea' => '', 'kroki-plantuml-include' => 'spec/fixtures/config.puml' }, standalone: false)
|
44
|
+
output = Asciidoctor.convert(input, attributes: { 'env-idea' => '', 'kroki-plantuml-include' => 'spec/fixtures/config.puml' }, standalone: false, safe: :safe)
|
45
45
|
(expect output).to eql %(<div class="imageblock kroki">
|
46
46
|
<div class="content">
|
47
|
-
<img src="https://kroki.io/plantuml/png/
|
47
|
+
<img src="https://kroki.io/plantuml/png/eNorzs7MK0gsSsxVyM3Py0_OKMrPTVUoKSpN5eJKzMlMTlXQtVNIyk-yUshIzcnJBwCT9xBc" alt="Diagram">
|
48
|
+
</div>
|
49
|
+
</div>)
|
50
|
+
end
|
51
|
+
it 'should normalize plantuml-include path when safe mode is safe' do
|
52
|
+
input = <<~'ADOC'
|
53
|
+
[plantuml]
|
54
|
+
....
|
55
|
+
alice -> bob: hello
|
56
|
+
....
|
57
|
+
ADOC
|
58
|
+
output = Asciidoctor.convert(input, attributes: { 'env-idea' => '', 'kroki-plantuml-include' => '../../../spec/fixtures/config.puml' }, standalone: false, safe: :safe)
|
59
|
+
(expect output).to eql %(<div class="imageblock kroki">
|
60
|
+
<div class="content">
|
61
|
+
<img src="https://kroki.io/plantuml/png/eNorzs7MK0gsSsxVyM3Py0_OKMrPTVUoKSpN5eJKzMlMTlXQtVNIyk-yUshIzcnJBwCT9xBc" alt="Diagram">
|
62
|
+
</div>
|
63
|
+
</div>)
|
64
|
+
end
|
65
|
+
it 'should not include file which reside outside of the parent directory of the source when safe mode is safe' do
|
66
|
+
input = <<~'ADOC'
|
67
|
+
[plantuml]
|
68
|
+
....
|
69
|
+
alice -> bob: hello
|
70
|
+
....
|
71
|
+
ADOC
|
72
|
+
output = Asciidoctor.convert(input, attributes: { 'env-idea' => '', 'kroki-plantuml-include' => '/etc/passwd' }, standalone: false, safe: :safe)
|
73
|
+
(expect output).to eql %(<div class="imageblock kroki">
|
74
|
+
<div class="content">
|
75
|
+
<img src="https://kroki.io/plantuml/png/eNpLzMlMTlXQtVNIyk-yUshIzcnJBwA9iwZL" alt="Diagram">
|
76
|
+
</div>
|
77
|
+
</div>)
|
78
|
+
end
|
79
|
+
it 'should not include file when safe mode is secure' do
|
80
|
+
input = <<~'ADOC'
|
81
|
+
[plantuml]
|
82
|
+
....
|
83
|
+
alice -> bob: hello
|
84
|
+
....
|
85
|
+
ADOC
|
86
|
+
output = Asciidoctor.convert(input, attributes: { 'env-idea' => '', 'kroki-plantuml-include' => 'spec/fixtures/config.puml' }, standalone: false, safe: :secure)
|
87
|
+
(expect output).to eql %(<div class="imageblock kroki">
|
88
|
+
<div class="content">
|
89
|
+
<img src="https://kroki.io/plantuml/png/eNpLzMlMTlXQtVNIyk-yUshIzcnJBwA9iwZL" alt="Diagram">
|
48
90
|
</div>
|
49
91
|
</div>)
|
50
92
|
end
|
@@ -54,11 +96,24 @@ describe ::AsciidoctorExtensions::KrokiBlockProcessor do
|
|
54
96
|
|
55
97
|
plantuml::spec/fixtures/alice.puml[svg,role=sequence]
|
56
98
|
ADOC
|
57
|
-
output = Asciidoctor.convert(input, attributes: { 'kroki-fetch-diagram' => '' }, standalone: false)
|
99
|
+
output = Asciidoctor.convert(input, attributes: { 'kroki-fetch-diagram' => '' }, standalone: false, safe: :safe)
|
58
100
|
(expect output).to eql %(<div class="imageblock sequence kroki-format-svg kroki">
|
59
101
|
<div class="content">
|
60
102
|
<img src=".asciidoctor/kroki/diag-f6acdc206506b6ca7badd3fe722f252af992871426e580c8361ff4d47c2c7d9b.svg" alt="Diagram">
|
61
103
|
</div>
|
104
|
+
</div>)
|
105
|
+
end
|
106
|
+
it 'should not fetch diagram when safe mode is secure' do
|
107
|
+
input = <<~'ADOC'
|
108
|
+
:imagesdir: .asciidoctor/kroki
|
109
|
+
|
110
|
+
plantuml::spec/fixtures/alice.puml[svg,role=sequence]
|
111
|
+
ADOC
|
112
|
+
output = Asciidoctor.convert(input, attributes: { 'kroki-fetch-diagram' => '' }, standalone: false)
|
113
|
+
(expect output).to eql %(<div class="imageblock sequence kroki-format-svg kroki">
|
114
|
+
<div class="content">
|
115
|
+
<img src="https://kroki.io/plantuml/svg/eNpLzMlMTlXQtVNIyk-yUshIzcnJ5wIAQ-AGVQ==" alt="Diagram">
|
116
|
+
</div>
|
62
117
|
</div>)
|
63
118
|
end
|
64
119
|
it 'should create PNG diagram in imagesdir if kroki-fetch-diagram is set' do
|
@@ -67,7 +122,7 @@ describe ::AsciidoctorExtensions::KrokiBlockProcessor do
|
|
67
122
|
|
68
123
|
plantuml::spec/fixtures/alice.puml[png,role=sequence]
|
69
124
|
ADOC
|
70
|
-
output = Asciidoctor.convert(input, attributes: { 'kroki-fetch-diagram' => '' }, standalone: false)
|
125
|
+
output = Asciidoctor.convert(input, attributes: { 'kroki-fetch-diagram' => '' }, standalone: false, safe: :safe)
|
71
126
|
(expect output).to eql %(<div class="imageblock sequence kroki-format-png kroki">
|
72
127
|
<div class="content">
|
73
128
|
<img src=".asciidoctor/kroki/diag-d4f314b2d4e75cc08aa4f8c2c944f7bf78321895d8ec5f665b42476d4e67e610.png" alt="Diagram">
|
@@ -75,12 +130,23 @@ describe ::AsciidoctorExtensions::KrokiBlockProcessor do
|
|
75
130
|
</div>)
|
76
131
|
end
|
77
132
|
end
|
133
|
+
context 'instantiate' do
|
134
|
+
it 'should instantiate block processor without warning' do
|
135
|
+
original_stderr = $stderr
|
136
|
+
$stderr = StringIO.new
|
137
|
+
::AsciidoctorExtensions::KrokiBlockProcessor.new 'plantuml'.to_sym, {}
|
138
|
+
output = $stderr.string
|
139
|
+
(expect output).to eql ''
|
140
|
+
ensure
|
141
|
+
$stderr = original_stderr
|
142
|
+
end
|
143
|
+
end
|
78
144
|
end
|
79
145
|
|
80
146
|
describe ::AsciidoctorExtensions::Kroki do
|
81
147
|
it 'should return the list of supported diagrams' do
|
82
148
|
diagram_names = ::AsciidoctorExtensions::Kroki::SUPPORTED_DIAGRAM_NAMES
|
83
|
-
expect(diagram_names).to include('vegalite', 'plantuml', 'bytefield', 'bpmn')
|
149
|
+
expect(diagram_names).to include('vegalite', 'plantuml', 'bytefield', 'bpmn', 'excalidraw', 'wavedrom', 'pikchr')
|
84
150
|
end
|
85
151
|
it 'should register the extension for the list of supported diagrams' do
|
86
152
|
doc = Asciidoctor::Document.new
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: asciidoctor-kroki
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Guillaume Grossetie
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2021-07-05 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: asciidoctor
|
@@ -24,20 +24,6 @@ dependencies:
|
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '2.0'
|
27
|
-
- !ruby/object:Gem::Dependency
|
28
|
-
name: asciidoctor-pdf
|
29
|
-
requirement: !ruby/object:Gem::Requirement
|
30
|
-
requirements:
|
31
|
-
- - '='
|
32
|
-
- !ruby/object:Gem::Version
|
33
|
-
version: 1.5.3
|
34
|
-
type: :runtime
|
35
|
-
prerelease: false
|
36
|
-
version_requirements: !ruby/object:Gem::Requirement
|
37
|
-
requirements:
|
38
|
-
- - '='
|
39
|
-
- !ruby/object:Gem::Version
|
40
|
-
version: 1.5.3
|
41
27
|
- !ruby/object:Gem::Dependency
|
42
28
|
name: rake
|
43
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -99,6 +85,7 @@ files:
|
|
99
85
|
- lib/asciidoctor/extensions/asciidoctor_kroki.rb
|
100
86
|
- lib/asciidoctor/extensions/asciidoctor_kroki/extension.rb
|
101
87
|
- spec/.rubocop.yml
|
88
|
+
- spec/asciidoctor_kroki_block_macro_spec.rb
|
102
89
|
- spec/asciidoctor_kroki_client_spec.rb
|
103
90
|
- spec/asciidoctor_kroki_diagram_spec.rb
|
104
91
|
- spec/asciidoctor_kroki_spec.rb
|
@@ -130,12 +117,13 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
130
117
|
- !ruby/object:Gem::Version
|
131
118
|
version: '0'
|
132
119
|
requirements: []
|
133
|
-
rubygems_version: 3.
|
120
|
+
rubygems_version: 3.1.6
|
134
121
|
signing_key:
|
135
122
|
specification_version: 4
|
136
123
|
summary: Asciidoctor extension to convert diagrams to images using Kroki
|
137
124
|
test_files:
|
138
125
|
- spec/.rubocop.yml
|
126
|
+
- spec/asciidoctor_kroki_block_macro_spec.rb
|
139
127
|
- spec/asciidoctor_kroki_client_spec.rb
|
140
128
|
- spec/asciidoctor_kroki_diagram_spec.rb
|
141
129
|
- spec/asciidoctor_kroki_spec.rb
|