asciidoctor-kroki 0.1.2 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/.rubocop.yml +15 -3
- data/Gemfile.lock +2 -51
- data/asciidoctor-kroki.gemspec +1 -2
- data/lib/asciidoctor/extensions/asciidoctor_kroki.rb +1 -2
- data/lib/asciidoctor/extensions/asciidoctor_kroki/extension.rb +274 -22
- data/spec/asciidoctor_kroki_block_macro_spec.rb +128 -0
- data/spec/asciidoctor_kroki_client_spec.rb +91 -0
- data/spec/asciidoctor_kroki_diagram_spec.rb +61 -0
- data/spec/asciidoctor_kroki_spec.rb +101 -3
- data/spec/fixtures/alice.puml +1 -0
- data/spec/rspec_helper.rb +10 -0
- metadata +13 -16
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: dfa0c461bdb74571b618747d791e059125dc09a5e67dd6886861101fe972237f
|
4
|
+
data.tar.gz: d882ff8e33c787b3a1578eb7d11b590411e18f594eaec188d7f06ffc182a3b11
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f72b7293f3fb8c6d37b456c39d4e2691c0b65e1cb908d5f3f29d23466f0c51135b9977dd0977a2ccac7adb667b4fc5071a4a5fc59bed6a3304154bddc8efda3d
|
7
|
+
data.tar.gz: 1e93fbf9df1cab9282f7743f76331ea6caddfdce150fff36fb7aa7222d561d089c31101ec0f16a939f5aa2c0c7dd5a09206059700974b76ae6fadcfc0150acd3
|
data/.gitignore
CHANGED
data/.rubocop.yml
CHANGED
@@ -1,14 +1,26 @@
|
|
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
|
9
15
|
|
10
16
|
Metrics/CyclomaticComplexity:
|
11
|
-
Max
|
17
|
+
Max: 10
|
18
|
+
|
19
|
+
Metrics/PerceivedComplexity:
|
20
|
+
Max: 10
|
12
21
|
|
13
22
|
Metrics/AbcSize:
|
14
|
-
Max:
|
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.4.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
|
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.4.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'
|
@@ -4,8 +4,7 @@ require 'asciidoctor/extensions' unless RUBY_ENGINE == 'opal'
|
|
4
4
|
require_relative 'asciidoctor_kroki/extension'
|
5
5
|
|
6
6
|
Asciidoctor::Extensions.register do
|
7
|
-
|
8
|
-
names.each do |name|
|
7
|
+
::AsciidoctorExtensions::Kroki::SUPPORTED_DIAGRAM_NAMES.each do |name|
|
9
8
|
block_macro ::AsciidoctorExtensions::KrokiBlockMacroProcessor, name
|
10
9
|
block ::AsciidoctorExtensions::KrokiBlockProcessor, name
|
11
10
|
end
|
@@ -1,8 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'asciidoctor/extensions' unless RUBY_ENGINE == 'opal'
|
4
|
-
require 'stringio'
|
5
|
-
require 'zlib'
|
6
4
|
|
7
5
|
# Asciidoctor extensions
|
8
6
|
#
|
@@ -17,11 +15,24 @@ module AsciidoctorExtensions
|
|
17
15
|
on_context :listing, :literal
|
18
16
|
name_positional_attributes 'target', 'format'
|
19
17
|
|
18
|
+
# @param name [String] name of the block macro (optional)
|
19
|
+
# @param config [Hash] a config hash (optional)
|
20
|
+
# @param logger [Logger] a logger used to log warning and errors (optional)
|
21
|
+
#
|
22
|
+
def initialize(name = nil, config = {}, logger: ::Asciidoctor::LoggerManager.logger)
|
23
|
+
super(name, config)
|
24
|
+
@logger = logger
|
25
|
+
end
|
26
|
+
|
20
27
|
def process(parent, reader, attrs)
|
21
28
|
diagram_type = @name
|
22
29
|
diagram_text = reader.string
|
23
|
-
KrokiProcessor.process(self, parent, attrs, diagram_type, diagram_text)
|
30
|
+
KrokiProcessor.process(self, parent, attrs, diagram_type, diagram_text, @logger)
|
24
31
|
end
|
32
|
+
|
33
|
+
protected
|
34
|
+
|
35
|
+
attr_reader :logger
|
25
36
|
end
|
26
37
|
|
27
38
|
# A block macro extension that converts a diagram into an image.
|
@@ -29,11 +40,50 @@ module AsciidoctorExtensions
|
|
29
40
|
class KrokiBlockMacroProcessor < Asciidoctor::Extensions::BlockMacroProcessor
|
30
41
|
use_dsl
|
31
42
|
|
43
|
+
name_positional_attributes 'format'
|
44
|
+
|
45
|
+
# @param name [String] name of the block macro (optional)
|
46
|
+
# @param config [Hash] a config hash (optional)
|
47
|
+
# @param logger [Logger] a logger used to log warning and errors (optional)
|
48
|
+
#
|
49
|
+
def initialize(name = nil, config = {}, logger: ::Asciidoctor::LoggerManager.logger)
|
50
|
+
super(name, config)
|
51
|
+
@logger = logger
|
52
|
+
end
|
53
|
+
|
32
54
|
def process(parent, target, attrs)
|
33
55
|
diagram_type = @name
|
34
|
-
target = parent.apply_subs(target, [
|
35
|
-
|
36
|
-
|
56
|
+
target = parent.apply_subs(target, [:attributes])
|
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,15 +94,49 @@ 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
|
101
|
+
end
|
102
|
+
|
103
|
+
# Kroki API
|
104
|
+
#
|
105
|
+
module Kroki
|
106
|
+
SUPPORTED_DIAGRAM_NAMES = %w[
|
107
|
+
actdiag
|
108
|
+
blockdiag
|
109
|
+
bpmn
|
110
|
+
bytefield
|
111
|
+
c4plantuml
|
112
|
+
ditaa
|
113
|
+
erd
|
114
|
+
excalidraw
|
115
|
+
graphviz
|
116
|
+
mermaid
|
117
|
+
nomnoml
|
118
|
+
nwdiag
|
119
|
+
packetdiag
|
120
|
+
plantuml
|
121
|
+
rackdiag
|
122
|
+
seqdiag
|
123
|
+
svgbob
|
124
|
+
umlet
|
125
|
+
vega
|
126
|
+
vegalite
|
127
|
+
wavedrom
|
128
|
+
].freeze
|
47
129
|
end
|
48
130
|
|
49
131
|
# Internal processor
|
50
132
|
#
|
51
133
|
class KrokiProcessor
|
134
|
+
TEXT_FORMATS = %w[txt atxt utxt].freeze
|
135
|
+
|
52
136
|
class << self
|
53
|
-
def process(processor, parent, attrs, diagram_type, diagram_text)
|
137
|
+
def process(processor, parent, attrs, diagram_type, diagram_text, logger)
|
54
138
|
doc = parent.document
|
55
|
-
diagram_text = prepend_plantuml_config(diagram_text, diagram_type, doc)
|
139
|
+
diagram_text = prepend_plantuml_config(diagram_text, diagram_type, doc, logger)
|
56
140
|
# If "subs" attribute is specified, substitute accordingly.
|
57
141
|
# Be careful not to specify "specialcharacters" or your diagram code won't be valid anymore!
|
58
142
|
if (subs = attrs['subs'])
|
@@ -64,23 +148,35 @@ module AsciidoctorExtensions
|
|
64
148
|
role = attrs['role']
|
65
149
|
format = get_format(doc, attrs, diagram_type)
|
66
150
|
attrs['role'] = get_role(format, role)
|
67
|
-
attrs['alt'] = get_alt(attrs)
|
68
|
-
attrs['target'] = create_image_src(doc, diagram_type, format, diagram_text)
|
69
151
|
attrs['format'] = format
|
70
|
-
|
71
|
-
|
152
|
+
kroki_diagram = KrokiDiagram.new(diagram_type, format, diagram_text)
|
153
|
+
kroki_client = KrokiClient.new(server_url(doc), http_method(doc), KrokiHttpClient, logger, max_uri_length(doc))
|
154
|
+
if TEXT_FORMATS.include?(format)
|
155
|
+
text_content = kroki_client.text_content(kroki_diagram)
|
156
|
+
block = processor.create_block(parent, 'literal', text_content, attrs)
|
157
|
+
else
|
158
|
+
attrs['alt'] = get_alt(attrs)
|
159
|
+
attrs['target'] = create_image_src(doc, kroki_diagram, kroki_client)
|
160
|
+
block = processor.create_image_block(parent, attrs)
|
161
|
+
end
|
162
|
+
block.title = title if title
|
72
163
|
block.assign_caption(caption, 'figure')
|
73
164
|
block
|
74
165
|
end
|
75
166
|
|
76
167
|
private
|
77
168
|
|
78
|
-
def prepend_plantuml_config(diagram_text, diagram_type, doc)
|
79
|
-
if diagram_type == :plantuml && doc.attr?('kroki-plantuml-include')
|
80
|
-
#
|
81
|
-
#
|
82
|
-
|
83
|
-
|
169
|
+
def prepend_plantuml_config(diagram_text, diagram_type, doc, logger)
|
170
|
+
if diagram_type == :plantuml && doc.safe < ::Asciidoctor::SafeMode::SECURE && doc.attr?('kroki-plantuml-include')
|
171
|
+
# REMIND: this behaves different than the JS version
|
172
|
+
# Once we have a preprocessor for Ruby, the value should be added in the diagram source as "!include #{plantuml_include}"
|
173
|
+
plantuml_include_path = doc.normalize_system_path(doc.attr('kroki-plantuml-include'))
|
174
|
+
if ::File.readable? plantuml_include_path
|
175
|
+
config = File.read(plantuml_include_path)
|
176
|
+
diagram_text = config + "\n" + diagram_text
|
177
|
+
else
|
178
|
+
logger.warn "Unable to read plantuml-include. File not found or not readable: #{plantuml_include_path}."
|
179
|
+
end
|
84
180
|
end
|
85
181
|
diagram_text
|
86
182
|
end
|
@@ -119,13 +215,169 @@ module AsciidoctorExtensions
|
|
119
215
|
format
|
120
216
|
end
|
121
217
|
|
122
|
-
def create_image_src(doc,
|
123
|
-
|
124
|
-
|
218
|
+
def create_image_src(doc, kroki_diagram, kroki_client)
|
219
|
+
if doc.attr('kroki-fetch-diagram') && doc.safe < ::Asciidoctor::SafeMode::SECURE
|
220
|
+
kroki_diagram.save(output_dir_path(doc), kroki_client)
|
221
|
+
else
|
222
|
+
kroki_diagram.get_diagram_uri(server_url(doc))
|
223
|
+
end
|
125
224
|
end
|
126
225
|
|
127
226
|
def server_url(doc)
|
128
|
-
doc.attr('kroki-server-url'
|
227
|
+
doc.attr('kroki-server-url', 'https://kroki.io')
|
228
|
+
end
|
229
|
+
|
230
|
+
def http_method(doc)
|
231
|
+
doc.attr('kroki-http-method', 'adaptive').downcase
|
232
|
+
end
|
233
|
+
|
234
|
+
def max_uri_length(doc)
|
235
|
+
doc.attr('kroki-max-uri-length', '4000').to_i
|
236
|
+
end
|
237
|
+
|
238
|
+
def output_dir_path(doc)
|
239
|
+
images_dir = doc.attr('imagesdir', '')
|
240
|
+
if (images_output_dir = doc.attr('imagesoutdir'))
|
241
|
+
images_output_dir
|
242
|
+
elsif (out_dir = doc.attr('outdir'))
|
243
|
+
File.join(out_dir, images_dir)
|
244
|
+
elsif (to_dir = doc.attr('to_dir'))
|
245
|
+
File.join(to_dir, images_dir)
|
246
|
+
else
|
247
|
+
File.join(doc.base_dir, images_dir)
|
248
|
+
end
|
249
|
+
end
|
250
|
+
end
|
251
|
+
end
|
252
|
+
|
253
|
+
# Kroki diagram
|
254
|
+
#
|
255
|
+
class KrokiDiagram
|
256
|
+
require 'fileutils'
|
257
|
+
require 'zlib'
|
258
|
+
require 'digest'
|
259
|
+
|
260
|
+
attr_reader :type
|
261
|
+
attr_reader :text
|
262
|
+
attr_reader :format
|
263
|
+
|
264
|
+
def initialize(type, format, text)
|
265
|
+
@text = text
|
266
|
+
@type = type
|
267
|
+
@format = format
|
268
|
+
end
|
269
|
+
|
270
|
+
def get_diagram_uri(server_url)
|
271
|
+
_join_uri_segments(server_url, @type, @format, encode)
|
272
|
+
end
|
273
|
+
|
274
|
+
def encode
|
275
|
+
Base64.urlsafe_encode64(Zlib::Deflate.deflate(@text, 9))
|
276
|
+
end
|
277
|
+
|
278
|
+
def save(output_dir_path, kroki_client)
|
279
|
+
diagram_url = get_diagram_uri(kroki_client.server_url)
|
280
|
+
diagram_name = "diag-#{Digest::SHA256.hexdigest diagram_url}.#{@format}"
|
281
|
+
file_path = File.join(output_dir_path, diagram_name)
|
282
|
+
encoding = if @format == 'txt' || @format == 'atxt' || @format == 'utxt'
|
283
|
+
'utf8'
|
284
|
+
elsif @format == 'svg'
|
285
|
+
'binary'
|
286
|
+
else
|
287
|
+
'binary'
|
288
|
+
end
|
289
|
+
# file is either (already) on the file system or we should read it from Kroki
|
290
|
+
contents = File.exist?(file_path) ? File.open(file_path, &:read) : kroki_client.get_image(self, encoding)
|
291
|
+
FileUtils.mkdir_p(output_dir_path)
|
292
|
+
if encoding == 'binary'
|
293
|
+
File.binwrite(file_path, contents)
|
294
|
+
else
|
295
|
+
File.write(file_path, contents)
|
296
|
+
end
|
297
|
+
diagram_name
|
298
|
+
end
|
299
|
+
|
300
|
+
private
|
301
|
+
|
302
|
+
def _join_uri_segments(base, *uris)
|
303
|
+
segments = []
|
304
|
+
# remove trailing slashes
|
305
|
+
segments.push(base.gsub(%r{[/]+$}, ''))
|
306
|
+
segments.concat(uris.map do |uri|
|
307
|
+
# remove leading and trailing slashes
|
308
|
+
uri.to_s
|
309
|
+
.gsub(%r{^[/]+}, '')
|
310
|
+
.gsub(%r{[/]+$}, '')
|
311
|
+
end)
|
312
|
+
segments.join('/')
|
313
|
+
end
|
314
|
+
end
|
315
|
+
|
316
|
+
# Kroki client
|
317
|
+
#
|
318
|
+
class KrokiClient
|
319
|
+
attr_reader :server_url
|
320
|
+
attr_reader :method
|
321
|
+
attr_reader :max_uri_length
|
322
|
+
|
323
|
+
SUPPORTED_HTTP_METHODS = %w[get post adaptive].freeze
|
324
|
+
|
325
|
+
def initialize(server_url, http_method, http_client, logger = ::Asciidoctor::LoggerManager.logger, max_uri_length = 4000)
|
326
|
+
@server_url = server_url
|
327
|
+
@max_uri_length = max_uri_length
|
328
|
+
@http_client = http_client
|
329
|
+
method = (http_method || 'adaptive').downcase
|
330
|
+
if SUPPORTED_HTTP_METHODS.include?(method)
|
331
|
+
@method = method
|
332
|
+
else
|
333
|
+
logger.warn "Invalid value '#{method}' for kroki-http-method attribute. The value must be either: 'get', 'post' or 'adaptive'. Proceeding using: 'adaptive'."
|
334
|
+
@method = 'adaptive'
|
335
|
+
end
|
336
|
+
end
|
337
|
+
|
338
|
+
def text_content(kroki_diagram)
|
339
|
+
get_image(kroki_diagram, 'utf-8')
|
340
|
+
end
|
341
|
+
|
342
|
+
def get_image(kroki_diagram, encoding)
|
343
|
+
type = kroki_diagram.type
|
344
|
+
format = kroki_diagram.format
|
345
|
+
text = kroki_diagram.text
|
346
|
+
if @method == 'adaptive' || @method == 'get'
|
347
|
+
uri = kroki_diagram.get_diagram_uri(server_url)
|
348
|
+
if uri.length > @max_uri_length
|
349
|
+
# The request URI is longer than the max URI length.
|
350
|
+
if @method == 'get'
|
351
|
+
# The request might be rejected by the server with a 414 Request-URI Too Large.
|
352
|
+
# Consider using the attribute kroki-http-method with the value 'adaptive'.
|
353
|
+
@http_client.get(uri, encoding)
|
354
|
+
else
|
355
|
+
@http_client.post("#{@server_url}/#{type}/#{format}", text, encoding)
|
356
|
+
end
|
357
|
+
else
|
358
|
+
@http_client.get(uri, encoding)
|
359
|
+
end
|
360
|
+
else
|
361
|
+
@http_client.post("#{@server_url}/#{type}/#{format}", text, encoding)
|
362
|
+
end
|
363
|
+
end
|
364
|
+
end
|
365
|
+
|
366
|
+
# Kroki HTTP client
|
367
|
+
#
|
368
|
+
class KrokiHttpClient
|
369
|
+
require 'net/http'
|
370
|
+
require 'uri'
|
371
|
+
require 'json'
|
372
|
+
|
373
|
+
class << self
|
374
|
+
def get(uri, _)
|
375
|
+
::OpenURI.open_uri(uri, 'r', &:read)
|
376
|
+
end
|
377
|
+
|
378
|
+
def post(uri, data, _)
|
379
|
+
res = ::Net::HTTP.request_post(uri, data)
|
380
|
+
res.body
|
129
381
|
end
|
130
382
|
end
|
131
383
|
end
|
@@ -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
|
@@ -0,0 +1,91 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'rspec_helper'
|
4
|
+
require 'asciidoctor'
|
5
|
+
require_relative '../lib/asciidoctor/extensions/asciidoctor_kroki'
|
6
|
+
|
7
|
+
describe ::AsciidoctorExtensions::KrokiClient do
|
8
|
+
it 'should use adaptive method when http method is invalid' do
|
9
|
+
kroki_http_client = ::AsciidoctorExtensions::KrokiHttpClient
|
10
|
+
kroki_client = ::AsciidoctorExtensions::KrokiClient.new('http://localhost:8000', 'patch', kroki_http_client)
|
11
|
+
expect(kroki_client.method).to eq('adaptive')
|
12
|
+
end
|
13
|
+
it 'should use post method when http method is post' do
|
14
|
+
kroki_http_client = ::AsciidoctorExtensions::KrokiHttpClient
|
15
|
+
kroki_client = ::AsciidoctorExtensions::KrokiClient.new('http://localhost:8000', 'POST', kroki_http_client)
|
16
|
+
expect(kroki_client.method).to eq('post')
|
17
|
+
end
|
18
|
+
it 'should use get method when http method is get' do
|
19
|
+
kroki_http_client = ::AsciidoctorExtensions::KrokiHttpClient
|
20
|
+
kroki_client = ::AsciidoctorExtensions::KrokiClient.new('http://localhost:8000', 'get', kroki_http_client)
|
21
|
+
expect(kroki_client.method).to eq('get')
|
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
|
91
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'rspec_helper'
|
4
|
+
require 'asciidoctor'
|
5
|
+
require_relative '../lib/asciidoctor/extensions/asciidoctor_kroki'
|
6
|
+
|
7
|
+
describe ::AsciidoctorExtensions::KrokiDiagram do
|
8
|
+
it 'should compute a diagram URI' do
|
9
|
+
kroki_diagram = ::AsciidoctorExtensions::KrokiDiagram.new('vegalite', 'png', '{}')
|
10
|
+
diagram_uri = kroki_diagram.get_diagram_uri('http://localhost:8000')
|
11
|
+
expect(diagram_uri).to eq('http://localhost:8000/vegalite/png/eNqrrgUAAXUA-Q==')
|
12
|
+
end
|
13
|
+
it 'should compute a diagram URI with a trailing slashes' do
|
14
|
+
kroki_diagram = ::AsciidoctorExtensions::KrokiDiagram.new('vegalite', 'png', '{}')
|
15
|
+
diagram_uri = kroki_diagram.get_diagram_uri('https://my.domain.org/kroki/')
|
16
|
+
expect(diagram_uri).to eq('https://my.domain.org/kroki/vegalite/png/eNqrrgUAAXUA-Q==')
|
17
|
+
end
|
18
|
+
it 'should compute a diagram URI with trailing slashes' do
|
19
|
+
kroki_diagram = ::AsciidoctorExtensions::KrokiDiagram.new('vegalite', 'png', '{}')
|
20
|
+
diagram_uri = kroki_diagram.get_diagram_uri('https://my-server/kroki//')
|
21
|
+
expect(diagram_uri).to eq('https://my-server/kroki/vegalite/png/eNqrrgUAAXUA-Q==')
|
22
|
+
end
|
23
|
+
it 'should encode a diagram text definition' do
|
24
|
+
kroki_diagram = ::AsciidoctorExtensions::KrokiDiagram.new('plantuml', 'txt', ' alice -> bob: hello')
|
25
|
+
diagram_definition_encoded = kroki_diagram.encode
|
26
|
+
expect(diagram_definition_encoded).to eq('eNpTSMzJTE5V0LVTSMpPslLISM3JyQcAQAwGaw==')
|
27
|
+
end
|
28
|
+
it 'should fetch a diagram from Kroki and save it to disk' do
|
29
|
+
kroki_diagram = ::AsciidoctorExtensions::KrokiDiagram.new('plantuml', 'txt', ' alice -> bob: hello')
|
30
|
+
kroki_http_client = ::AsciidoctorExtensions::KrokiHttpClient
|
31
|
+
kroki_client = ::AsciidoctorExtensions::KrokiClient.new('https://kroki.io', 'get', kroki_http_client)
|
32
|
+
output_dir_path = "#{__dir__}/../.asciidoctor/kroki"
|
33
|
+
diagram_name = kroki_diagram.save(output_dir_path, kroki_client)
|
34
|
+
diagram_path = File.join(output_dir_path, diagram_name)
|
35
|
+
expect(File.exist?(diagram_path)).to be_truthy, "expected diagram to be saved at #{diagram_path}"
|
36
|
+
content = <<-TXT.chomp
|
37
|
+
,-----. ,---.
|
38
|
+
|alice| |bob|
|
39
|
+
`--+--' `-+-'
|
40
|
+
| hello |
|
41
|
+
|-------------->|
|
42
|
+
,--+--. ,-+-.
|
43
|
+
|alice| |bob|
|
44
|
+
`-----' `---'
|
45
|
+
TXT
|
46
|
+
expect(File.read(diagram_path).split("\n").map(&:rstrip).join("\n")).to eq(content)
|
47
|
+
end
|
48
|
+
it 'should fetch a diagram from Kroki with the same definition only once' do
|
49
|
+
kroki_diagram = ::AsciidoctorExtensions::KrokiDiagram.new('plantuml', 'png', ' guillaume -> dan: hello')
|
50
|
+
kroki_http_client = ::AsciidoctorExtensions::KrokiHttpClient
|
51
|
+
kroki_client = ::AsciidoctorExtensions::KrokiClient.new('https://kroki.io', 'get', kroki_http_client)
|
52
|
+
output_dir_path = "#{__dir__}/../.asciidoctor/kroki"
|
53
|
+
# make sure that we are doing only one GET request
|
54
|
+
expect(kroki_http_client).to receive(:get).once
|
55
|
+
diagram_name = kroki_diagram.save(output_dir_path, kroki_client)
|
56
|
+
diagram_path = File.join(output_dir_path, diagram_name)
|
57
|
+
expect(File.exist?(diagram_path)).to be_truthy, "expected diagram to be saved at #{diagram_path}"
|
58
|
+
# calling again... should read the file from disk (and not do a GET request)
|
59
|
+
kroki_diagram.save(output_dir_path, kroki_client)
|
60
|
+
end
|
61
|
+
end
|
@@ -1,5 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'rspec_helper'
|
3
4
|
require 'asciidoctor'
|
4
5
|
require_relative '../lib/asciidoctor/extensions/asciidoctor_kroki'
|
5
6
|
|
@@ -33,19 +34,116 @@ describe ::AsciidoctorExtensions::KrokiBlockProcessor do
|
|
33
34
|
</div>
|
34
35
|
</div>)
|
35
36
|
end
|
36
|
-
it 'should include the plantuml-include file' do
|
37
|
+
it 'should include the plantuml-include file when safe mode is safe' do
|
37
38
|
input = <<~'ADOC'
|
38
39
|
[plantuml]
|
39
40
|
....
|
40
41
|
alice -> bob: hello
|
41
42
|
....
|
42
43
|
ADOC
|
43
|
-
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)
|
44
45
|
(expect output).to eql %(<div class="imageblock kroki">
|
45
46
|
<div class="content">
|
46
|
-
<img src="https://kroki.io/plantuml/png/
|
47
|
+
<img src="https://kroki.io/plantuml/png/eNorzs7MK0gsSsxVyM3Py0_OKMrPTVUoKSpN5eJKzMlMTlXQtVNIyk-yUshIzcnJBwCT9xBc" alt="Diagram">
|
47
48
|
</div>
|
48
49
|
</div>)
|
49
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">
|
90
|
+
</div>
|
91
|
+
</div>)
|
92
|
+
end
|
93
|
+
it 'should create SVG diagram in imagesdir if kroki-fetch-diagram is set' do
|
94
|
+
input = <<~'ADOC'
|
95
|
+
:imagesdir: .asciidoctor/kroki
|
96
|
+
|
97
|
+
plantuml::spec/fixtures/alice.puml[svg,role=sequence]
|
98
|
+
ADOC
|
99
|
+
output = Asciidoctor.convert(input, attributes: { 'kroki-fetch-diagram' => '' }, standalone: false, safe: :safe)
|
100
|
+
(expect output).to eql %(<div class="imageblock sequence kroki-format-svg kroki">
|
101
|
+
<div class="content">
|
102
|
+
<img src=".asciidoctor/kroki/diag-f6acdc206506b6ca7badd3fe722f252af992871426e580c8361ff4d47c2c7d9b.svg" alt="Diagram">
|
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>
|
117
|
+
</div>)
|
118
|
+
end
|
119
|
+
it 'should create PNG diagram in imagesdir if kroki-fetch-diagram is set' do
|
120
|
+
input = <<~'ADOC'
|
121
|
+
:imagesdir: .asciidoctor/kroki
|
122
|
+
|
123
|
+
plantuml::spec/fixtures/alice.puml[png,role=sequence]
|
124
|
+
ADOC
|
125
|
+
output = Asciidoctor.convert(input, attributes: { 'kroki-fetch-diagram' => '' }, standalone: false, safe: :safe)
|
126
|
+
(expect output).to eql %(<div class="imageblock sequence kroki-format-png kroki">
|
127
|
+
<div class="content">
|
128
|
+
<img src=".asciidoctor/kroki/diag-d4f314b2d4e75cc08aa4f8c2c944f7bf78321895d8ec5f665b42476d4e67e610.png" alt="Diagram">
|
129
|
+
</div>
|
130
|
+
</div>)
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
describe ::AsciidoctorExtensions::Kroki do
|
136
|
+
it 'should return the list of supported diagrams' do
|
137
|
+
diagram_names = ::AsciidoctorExtensions::Kroki::SUPPORTED_DIAGRAM_NAMES
|
138
|
+
expect(diagram_names).to include('vegalite', 'plantuml', 'bytefield', 'bpmn', 'excalidraw', 'wavedrom')
|
139
|
+
end
|
140
|
+
it 'should register the extension for the list of supported diagrams' do
|
141
|
+
doc = Asciidoctor::Document.new
|
142
|
+
registry = Asciidoctor::Extensions::Registry.new
|
143
|
+
registry.activate doc
|
144
|
+
::AsciidoctorExtensions::Kroki::SUPPORTED_DIAGRAM_NAMES.each do |name|
|
145
|
+
expect(registry.find_block_extension(name)).to_not be_nil, "expected block extension named '#{name}' to be registered"
|
146
|
+
expect(registry.find_block_macro_extension(name)).to_not be_nil, "expected block macro extension named '#{name}' to be registered "
|
147
|
+
end
|
50
148
|
end
|
51
149
|
end
|
@@ -0,0 +1 @@
|
|
1
|
+
alice -> bob: hello
|
@@ -0,0 +1,10 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
RSpec.configure do |config|
|
4
|
+
config.before(:suite) do
|
5
|
+
FileUtils.rm(Dir.glob("#{__dir__}/../.asciidoctor/kroki/diag-*"))
|
6
|
+
end
|
7
|
+
config.after(:suite) do
|
8
|
+
FileUtils.rm(Dir.glob("#{__dir__}/../.asciidoctor/kroki/diag-*")) unless ENV['DEBUG']
|
9
|
+
end
|
10
|
+
end
|
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.4.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-02-16 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
|
@@ -87,6 +73,7 @@ executables: []
|
|
87
73
|
extensions: []
|
88
74
|
extra_rdoc_files: []
|
89
75
|
files:
|
76
|
+
- ".asciidoctor/kroki/.gitkeep"
|
90
77
|
- ".gitignore"
|
91
78
|
- ".rubocop.yml"
|
92
79
|
- ".ruby-version"
|
@@ -98,9 +85,14 @@ files:
|
|
98
85
|
- lib/asciidoctor/extensions/asciidoctor_kroki.rb
|
99
86
|
- lib/asciidoctor/extensions/asciidoctor_kroki/extension.rb
|
100
87
|
- spec/.rubocop.yml
|
88
|
+
- spec/asciidoctor_kroki_block_macro_spec.rb
|
89
|
+
- spec/asciidoctor_kroki_client_spec.rb
|
90
|
+
- spec/asciidoctor_kroki_diagram_spec.rb
|
101
91
|
- spec/asciidoctor_kroki_spec.rb
|
92
|
+
- spec/fixtures/alice.puml
|
102
93
|
- spec/fixtures/config.puml
|
103
94
|
- spec/require_spec.rb
|
95
|
+
- spec/rspec_helper.rb
|
104
96
|
- tasks/bundler.rake
|
105
97
|
- tasks/lint.rake
|
106
98
|
- tasks/rspec.rake
|
@@ -131,9 +123,14 @@ specification_version: 4
|
|
131
123
|
summary: Asciidoctor extension to convert diagrams to images using Kroki
|
132
124
|
test_files:
|
133
125
|
- spec/.rubocop.yml
|
126
|
+
- spec/asciidoctor_kroki_block_macro_spec.rb
|
127
|
+
- spec/asciidoctor_kroki_client_spec.rb
|
128
|
+
- spec/asciidoctor_kroki_diagram_spec.rb
|
134
129
|
- spec/asciidoctor_kroki_spec.rb
|
130
|
+
- spec/fixtures/alice.puml
|
135
131
|
- spec/fixtures/config.puml
|
136
132
|
- spec/require_spec.rb
|
133
|
+
- spec/rspec_helper.rb
|
137
134
|
- tasks/bundler.rake
|
138
135
|
- tasks/lint.rake
|
139
136
|
- tasks/rspec.rake
|