asciidoctor-kroki 0.3.0 → 0.6.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 +20 -3
- data/.ruby-version +1 -1
- data/Gemfile.lock +36 -31
- data/asciidoctor-kroki.gemspec +8 -6
- data/lib/asciidoctor/extensions/asciidoctor_kroki/extension.rb +149 -62
- data/lib/asciidoctor/extensions/asciidoctor_kroki/version.rb +7 -0
- data/lib/asciidoctor/extensions/asciidoctor_kroki.rb +1 -0
- data/spec/asciidoctor_kroki_block_macro_spec.rb +130 -0
- data/spec/asciidoctor_kroki_client_spec.rb +71 -3
- data/spec/asciidoctor_kroki_diagram_spec.rb +28 -5
- data/spec/asciidoctor_kroki_processor_spec.rb +33 -0
- data/spec/asciidoctor_kroki_spec.rb +91 -8
- data/spec/fixtures/plantuml-diagram.png +0 -0
- metadata +15 -21
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1d98287cf9a15751a442de9b1a07565c097206aae0912ca204ecaf4bdede4020
|
4
|
+
data.tar.gz: b1252225ed15a9f093d8a3c1d577e2bfa23c2abe7962981d638f49ea81d90a7b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 46688eb160c567e33ba1f220ab229848a66874af0713962c339bc4d3b7d3352a5ef3f2f74e9c257bae6c579e03bf6c32cdf55e16f9b64d7b189aa103bf2d8550
|
7
|
+
data.tar.gz: 78a231f8b5921330aab30a2cd5c4f56ab84f917e31dc4cc85d2eb126cec84f04bd52756db2ff1fd8991116086b1100184c0644f35929fadb8ae49f95806e1248
|
data/.rubocop.yml
CHANGED
@@ -1,8 +1,19 @@
|
|
1
|
+
AllCops:
|
2
|
+
TargetRubyVersion: 2.7
|
3
|
+
SuggestExtensions: false
|
4
|
+
NewCops: enable
|
5
|
+
|
1
6
|
Style/Encoding:
|
2
7
|
Enabled: false
|
3
8
|
|
4
|
-
|
5
|
-
|
9
|
+
Layout/EndOfLine:
|
10
|
+
EnforcedStyle: lf
|
11
|
+
|
12
|
+
Layout/LineLength:
|
13
|
+
Max: 180
|
14
|
+
|
15
|
+
Metrics/ClassLength:
|
16
|
+
Max: 150
|
6
17
|
|
7
18
|
Metrics/MethodLength:
|
8
19
|
Max: 50
|
@@ -14,4 +25,10 @@ Metrics/PerceivedComplexity:
|
|
14
25
|
Max: 10
|
15
26
|
|
16
27
|
Metrics/AbcSize:
|
17
|
-
Max:
|
28
|
+
Max: 31
|
29
|
+
|
30
|
+
Metrics/ParameterLists:
|
31
|
+
Max: 7
|
32
|
+
|
33
|
+
Gemspec/RequiredRubyVersion:
|
34
|
+
Enabled: false
|
data/.ruby-version
CHANGED
@@ -1 +1 @@
|
|
1
|
-
|
1
|
+
3.1.2
|
data/Gemfile.lock
CHANGED
@@ -1,52 +1,57 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
asciidoctor-kroki (0.
|
4
|
+
asciidoctor-kroki (0.6.0)
|
5
5
|
asciidoctor (~> 2.0)
|
6
6
|
|
7
7
|
GEM
|
8
8
|
remote: https://rubygems.org/
|
9
9
|
specs:
|
10
|
-
asciidoctor (2.0.
|
11
|
-
ast (2.4.
|
12
|
-
diff-lcs (1.
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
rspec-
|
22
|
-
rspec-
|
23
|
-
|
24
|
-
|
25
|
-
|
10
|
+
asciidoctor (2.0.11)
|
11
|
+
ast (2.4.2)
|
12
|
+
diff-lcs (1.4.4)
|
13
|
+
parallel (1.22.1)
|
14
|
+
parser (3.1.2.0)
|
15
|
+
ast (~> 2.4.1)
|
16
|
+
rainbow (3.1.1)
|
17
|
+
rake (13.0.6)
|
18
|
+
regexp_parser (2.5.0)
|
19
|
+
rexml (3.2.5)
|
20
|
+
rspec (3.10.0)
|
21
|
+
rspec-core (~> 3.10.0)
|
22
|
+
rspec-expectations (~> 3.10.0)
|
23
|
+
rspec-mocks (~> 3.10.0)
|
24
|
+
rspec-core (3.10.1)
|
25
|
+
rspec-support (~> 3.10.0)
|
26
|
+
rspec-expectations (3.10.1)
|
26
27
|
diff-lcs (>= 1.2.0, < 2.0)
|
27
|
-
rspec-support (~> 3.
|
28
|
-
rspec-mocks (3.
|
28
|
+
rspec-support (~> 3.10.0)
|
29
|
+
rspec-mocks (3.10.2)
|
29
30
|
diff-lcs (>= 1.2.0, < 2.0)
|
30
|
-
rspec-support (~> 3.
|
31
|
-
rspec-support (3.
|
32
|
-
rubocop (
|
33
|
-
jaro_winkler (~> 1.5.1)
|
31
|
+
rspec-support (~> 3.10.0)
|
32
|
+
rspec-support (3.10.2)
|
33
|
+
rubocop (1.30.0)
|
34
34
|
parallel (~> 1.10)
|
35
|
-
parser (>=
|
35
|
+
parser (>= 3.1.0.0)
|
36
36
|
rainbow (>= 2.2.2, < 4.0)
|
37
|
+
regexp_parser (>= 1.8, < 3.0)
|
38
|
+
rexml (>= 3.2.5, < 4.0)
|
39
|
+
rubocop-ast (>= 1.18.0, < 2.0)
|
37
40
|
ruby-progressbar (~> 1.7)
|
38
|
-
unicode-display_width (>= 1.4.0, <
|
39
|
-
|
40
|
-
|
41
|
+
unicode-display_width (>= 1.4.0, < 3.0)
|
42
|
+
rubocop-ast (1.18.0)
|
43
|
+
parser (>= 3.1.1.0)
|
44
|
+
ruby-progressbar (1.11.0)
|
45
|
+
unicode-display_width (2.1.0)
|
41
46
|
|
42
47
|
PLATFORMS
|
43
48
|
ruby
|
44
49
|
|
45
50
|
DEPENDENCIES
|
46
51
|
asciidoctor-kroki!
|
47
|
-
rake (~>
|
48
|
-
rspec (~> 3.
|
49
|
-
rubocop (~>
|
52
|
+
rake (~> 13.0.6)
|
53
|
+
rspec (~> 3.10.0)
|
54
|
+
rubocop (~> 1.30)
|
50
55
|
|
51
56
|
BUNDLED WITH
|
52
|
-
|
57
|
+
2.3.15
|
data/asciidoctor-kroki.gemspec
CHANGED
@@ -1,8 +1,10 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require_relative 'lib/asciidoctor/extensions/asciidoctor_kroki/version'
|
4
|
+
|
3
5
|
Gem::Specification.new do |s|
|
4
6
|
s.name = 'asciidoctor-kroki'
|
5
|
-
s.version =
|
7
|
+
s.version = Asciidoctor::AsciidoctorKroki::VERSION
|
6
8
|
s.summary = 'Asciidoctor extension to convert diagrams to images using Kroki'
|
7
9
|
s.description = 'An extension for Asciidoctor to convert diagrams to images using https://kroki.io'
|
8
10
|
|
@@ -12,15 +14,15 @@ Gem::Specification.new do |s|
|
|
12
14
|
s.license = 'MIT'
|
13
15
|
s.metadata = {
|
14
16
|
'bug_tracker_uri' => 'https://github.com/Mogztter/asciidoctor-kroki/issues',
|
15
|
-
'source_code_uri' => 'https://github.com/Mogztter/asciidoctor-kroki'
|
17
|
+
'source_code_uri' => 'https://github.com/Mogztter/asciidoctor-kroki',
|
18
|
+
'rubygems_mfa_required' => 'true'
|
16
19
|
}
|
17
20
|
s.files = `git ls-files`.split($RS)
|
18
|
-
s.test_files = s.files.grep(%r{^(test|spec|features|tasks)/})
|
19
21
|
s.require_paths = ['lib']
|
20
22
|
|
21
23
|
s.add_runtime_dependency 'asciidoctor', '~> 2.0'
|
22
24
|
|
23
|
-
s.add_development_dependency 'rake', '~>
|
24
|
-
s.add_development_dependency 'rspec', '~> 3.
|
25
|
-
s.add_development_dependency 'rubocop', '~>
|
25
|
+
s.add_development_dependency 'rake', '~> 13.0.6'
|
26
|
+
s.add_development_dependency 'rspec', '~> 3.10.0'
|
27
|
+
s.add_development_dependency 'rubocop', '~> 1.30'
|
26
28
|
end
|
@@ -15,35 +15,90 @@ 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.
|
26
39
|
#
|
27
40
|
class KrokiBlockMacroProcessor < Asciidoctor::Extensions::BlockMacroProcessor
|
41
|
+
include Asciidoctor::Logging
|
28
42
|
use_dsl
|
29
43
|
|
30
44
|
name_positional_attributes 'format'
|
31
45
|
|
46
|
+
# @param name [String] name of the block macro (optional)
|
47
|
+
# @param config [Hash] a config hash (optional)
|
48
|
+
# - :logger a logger used to log warning and errors (optional)
|
49
|
+
#
|
50
|
+
def initialize(name = nil, config = {})
|
51
|
+
@logger = (config || {}).delete(:logger) { ::Asciidoctor::LoggerManager.logger }
|
52
|
+
super(name, config)
|
53
|
+
end
|
54
|
+
|
32
55
|
def process(parent, target, attrs)
|
33
56
|
diagram_type = @name
|
34
57
|
target = parent.apply_subs(target, [:attributes])
|
35
|
-
|
36
|
-
|
58
|
+
|
59
|
+
unless read_allowed?(target)
|
60
|
+
link = create_inline(parent, :anchor, target, type: :link, target: target)
|
61
|
+
return create_block(parent, :paragraph, link.convert, {}, content_model: :raw)
|
62
|
+
end
|
63
|
+
|
64
|
+
unless (path = resolve_target_path(target))
|
65
|
+
logger.error message_with_context "#{diagram_type} block macro not found: #{target}.", source_location: parent.document.reader.cursor_at_mark
|
66
|
+
return create_block(parent, 'paragraph', unresolved_block_macro_message(diagram_type, target), {})
|
67
|
+
end
|
68
|
+
|
69
|
+
begin
|
70
|
+
diagram_text = read(path)
|
71
|
+
rescue => e # rubocop:disable Style/RescueStandardError
|
72
|
+
logger.error message_with_context "Failed to read #{diagram_type} file: #{path}. #{e}.", source_location: parent.document.reader.cursor_at_mark
|
73
|
+
return create_block(parent, 'paragraph', unresolved_block_macro_message(diagram_type, path), {})
|
74
|
+
end
|
75
|
+
KrokiProcessor.process(self, parent, attrs, diagram_type, diagram_text, @logger)
|
76
|
+
end
|
77
|
+
|
78
|
+
protected
|
79
|
+
|
80
|
+
attr_reader :logger
|
81
|
+
|
82
|
+
def resolve_target_path(target)
|
83
|
+
target
|
84
|
+
end
|
85
|
+
|
86
|
+
def read_allowed?(_target)
|
87
|
+
true
|
37
88
|
end
|
38
89
|
|
39
90
|
def read(target)
|
40
91
|
if target.start_with?('http://') || target.start_with?('https://')
|
41
92
|
require 'open-uri'
|
42
|
-
|
93
|
+
::OpenURI.open_uri(target, &:read)
|
43
94
|
else
|
44
|
-
File.
|
95
|
+
File.read(target, mode: 'rb:utf-8:utf-8')
|
45
96
|
end
|
46
97
|
end
|
98
|
+
|
99
|
+
def unresolved_block_macro_message(name, target)
|
100
|
+
"Unresolved block macro - #{name}::#{target}[]"
|
101
|
+
end
|
47
102
|
end
|
48
103
|
|
49
104
|
# Kroki API
|
@@ -63,6 +118,7 @@ module AsciidoctorExtensions
|
|
63
118
|
nomnoml
|
64
119
|
nwdiag
|
65
120
|
packetdiag
|
121
|
+
pikchr
|
66
122
|
plantuml
|
67
123
|
rackdiag
|
68
124
|
seqdiag
|
@@ -70,19 +126,23 @@ module AsciidoctorExtensions
|
|
70
126
|
umlet
|
71
127
|
vega
|
72
128
|
vegalite
|
73
|
-
|
129
|
+
wavedrom
|
130
|
+
structurizr
|
74
131
|
].freeze
|
75
132
|
end
|
76
133
|
|
77
134
|
# Internal processor
|
78
135
|
#
|
79
136
|
class KrokiProcessor
|
137
|
+
include Asciidoctor::Logging
|
138
|
+
|
80
139
|
TEXT_FORMATS = %w[txt atxt utxt].freeze
|
81
140
|
|
82
141
|
class << self
|
83
|
-
|
142
|
+
# rubocop:disable Metrics/AbcSize
|
143
|
+
def process(processor, parent, attrs, diagram_type, diagram_text, logger)
|
84
144
|
doc = parent.document
|
85
|
-
diagram_text = prepend_plantuml_config(diagram_text, diagram_type, doc)
|
145
|
+
diagram_text = prepend_plantuml_config(diagram_text, diagram_type, doc, logger)
|
86
146
|
# If "subs" attribute is specified, substitute accordingly.
|
87
147
|
# Be careful not to specify "specialcharacters" or your diagram code won't be valid anymore!
|
88
148
|
if (subs = attrs['subs'])
|
@@ -91,12 +151,17 @@ module AsciidoctorExtensions
|
|
91
151
|
title = attrs.delete('title')
|
92
152
|
caption = attrs.delete('caption')
|
93
153
|
attrs.delete('opts')
|
94
|
-
role = attrs['role']
|
95
154
|
format = get_format(doc, attrs, diagram_type)
|
96
|
-
attrs['role'] = get_role(format, role)
|
155
|
+
attrs['role'] = get_role(format, attrs['role'])
|
97
156
|
attrs['format'] = format
|
98
|
-
kroki_diagram = KrokiDiagram.new(diagram_type, format, diagram_text)
|
99
|
-
kroki_client = KrokiClient.new(
|
157
|
+
kroki_diagram = KrokiDiagram.new(diagram_type, format, diagram_text, attrs['target'])
|
158
|
+
kroki_client = KrokiClient.new({
|
159
|
+
server_url: server_url(doc),
|
160
|
+
http_method: http_method(doc),
|
161
|
+
max_uri_length: max_uri_length(doc),
|
162
|
+
source_location: doc.reader.cursor_at_mark,
|
163
|
+
http_client: KrokiHttpClient
|
164
|
+
}, logger)
|
100
165
|
if TEXT_FORMATS.include?(format)
|
101
166
|
text_content = kroki_client.text_content(kroki_diagram)
|
102
167
|
block = processor.create_block(parent, 'literal', text_content, attrs)
|
@@ -109,15 +174,22 @@ module AsciidoctorExtensions
|
|
109
174
|
block.assign_caption(caption, 'figure')
|
110
175
|
block
|
111
176
|
end
|
177
|
+
# rubocop:enable Metrics/AbcSize
|
112
178
|
|
113
179
|
private
|
114
180
|
|
115
|
-
def prepend_plantuml_config(diagram_text, diagram_type, doc)
|
116
|
-
if diagram_type == :plantuml && doc.attr?('kroki-plantuml-include')
|
117
|
-
#
|
118
|
-
#
|
119
|
-
|
120
|
-
|
181
|
+
def prepend_plantuml_config(diagram_text, diagram_type, doc, logger)
|
182
|
+
if diagram_type == :plantuml && doc.safe < ::Asciidoctor::SafeMode::SECURE && doc.attr?('kroki-plantuml-include')
|
183
|
+
# REMIND: this behaves different than the JS version
|
184
|
+
# Once we have a preprocessor for Ruby, the value should be added in the diagram source as "!include #{plantuml_include}"
|
185
|
+
plantuml_include_path = doc.normalize_system_path(doc.attr('kroki-plantuml-include'))
|
186
|
+
if ::File.readable? plantuml_include_path
|
187
|
+
config = File.read(plantuml_include_path)
|
188
|
+
diagram_text = "#{config}\n#{diagram_text}"
|
189
|
+
else
|
190
|
+
logger.warn message_with_context "Unable to read plantuml-include. File not found or not readable: #{plantuml_include_path}.",
|
191
|
+
source_location: doc.reader.cursor_at_mark
|
192
|
+
end
|
121
193
|
end
|
122
194
|
diagram_text
|
123
195
|
end
|
@@ -145,19 +217,19 @@ module AsciidoctorExtensions
|
|
145
217
|
end
|
146
218
|
|
147
219
|
def get_format(doc, attrs, diagram_type)
|
148
|
-
format = attrs['format'] || 'svg'
|
149
|
-
|
150
|
-
|
151
|
-
#
|
220
|
+
format = attrs['format'] || doc.attr('kroki-default-format') || 'svg'
|
221
|
+
if format == 'png'
|
222
|
+
# redirect PNG format to SVG if the diagram library only supports SVG as output format.
|
223
|
+
# this is useful when the default format has been set to PNG
|
152
224
|
# Currently, mermaid, nomnoml, svgbob, wavedrom only support SVG as output format.
|
153
|
-
svg_only_diagram_types = %
|
154
|
-
format = '
|
225
|
+
svg_only_diagram_types = %i[mermaid nomnoml svgbob wavedrom]
|
226
|
+
format = 'svg' if svg_only_diagram_types.include?(diagram_type)
|
155
227
|
end
|
156
228
|
format
|
157
229
|
end
|
158
230
|
|
159
231
|
def create_image_src(doc, kroki_diagram, kroki_client)
|
160
|
-
if doc.attr('kroki-fetch-diagram')
|
232
|
+
if doc.attr('kroki-fetch-diagram') && doc.safe < ::Asciidoctor::SafeMode::SECURE
|
161
233
|
kroki_diagram.save(output_dir_path(doc), kroki_client)
|
162
234
|
else
|
163
235
|
kroki_diagram.get_diagram_uri(server_url(doc))
|
@@ -172,20 +244,19 @@ module AsciidoctorExtensions
|
|
172
244
|
doc.attr('kroki-http-method', 'adaptive').downcase
|
173
245
|
end
|
174
246
|
|
247
|
+
def max_uri_length(doc)
|
248
|
+
doc.attr('kroki-max-uri-length', '4000').to_i
|
249
|
+
end
|
250
|
+
|
175
251
|
def output_dir_path(doc)
|
176
|
-
images_output_dir = doc.attr('imagesoutdir')
|
177
|
-
out_dir = doc.attr('outdir')
|
178
|
-
to_dir = doc.attr('to_dir')
|
179
|
-
base_dir = doc.base_dir
|
180
252
|
images_dir = doc.attr('imagesdir', '')
|
181
|
-
if images_output_dir
|
253
|
+
if (images_output_dir = doc.attr('imagesoutdir'))
|
182
254
|
images_output_dir
|
183
|
-
|
255
|
+
# the nested document logic will become obsolete once https://github.com/asciidoctor/asciidoctor/commit/7edc9da023522be67b17e2a085d72e056703a438 is released
|
256
|
+
elsif (out_dir = doc.attr('outdir') || (doc.nested? ? doc.parent_document : doc).options[:to_dir])
|
184
257
|
File.join(out_dir, images_dir)
|
185
|
-
elsif to_dir
|
186
|
-
File.join(to_dir, images_dir)
|
187
258
|
else
|
188
|
-
File.join(base_dir, images_dir)
|
259
|
+
File.join(doc.base_dir, images_dir)
|
189
260
|
end
|
190
261
|
end
|
191
262
|
end
|
@@ -198,14 +269,13 @@ module AsciidoctorExtensions
|
|
198
269
|
require 'zlib'
|
199
270
|
require 'digest'
|
200
271
|
|
201
|
-
attr_reader :type
|
202
|
-
attr_reader :text
|
203
|
-
attr_reader :format
|
272
|
+
attr_reader :type, :text, :format, :target
|
204
273
|
|
205
|
-
def initialize(type, format, text)
|
274
|
+
def initialize(type, format, text, target = nil)
|
206
275
|
@text = text
|
207
276
|
@type = type
|
208
277
|
@format = format
|
278
|
+
@target = target
|
209
279
|
end
|
210
280
|
|
211
281
|
def get_diagram_uri(server_url)
|
@@ -218,23 +288,21 @@ module AsciidoctorExtensions
|
|
218
288
|
|
219
289
|
def save(output_dir_path, kroki_client)
|
220
290
|
diagram_url = get_diagram_uri(kroki_client.server_url)
|
221
|
-
diagram_name = "diag-#{Digest::SHA256.hexdigest diagram_url}.#{@format}"
|
291
|
+
diagram_name = "#{@target || 'diag'}-#{Digest::SHA256.hexdigest diagram_url}.#{@format}"
|
222
292
|
file_path = File.join(output_dir_path, diagram_name)
|
223
|
-
encoding =
|
293
|
+
encoding = case @format
|
294
|
+
when 'txt', 'atxt', 'utxt', 'svg'
|
224
295
|
'utf8'
|
225
|
-
elsif @format == 'svg'
|
226
|
-
'binary'
|
227
296
|
else
|
228
297
|
'binary'
|
229
298
|
end
|
230
299
|
# file is either (already) on the file system or we should read it from Kroki
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
File.
|
235
|
-
else
|
236
|
-
File.write(file_path, contents)
|
300
|
+
unless File.exist?(file_path)
|
301
|
+
contents = kroki_client.get_image(self, encoding)
|
302
|
+
FileUtils.mkdir_p(output_dir_path)
|
303
|
+
File.write(file_path, contents, mode: 'wb')
|
237
304
|
end
|
305
|
+
|
238
306
|
diagram_name
|
239
307
|
end
|
240
308
|
|
@@ -243,12 +311,12 @@ module AsciidoctorExtensions
|
|
243
311
|
def _join_uri_segments(base, *uris)
|
244
312
|
segments = []
|
245
313
|
# remove trailing slashes
|
246
|
-
segments.push(base.gsub(%r{
|
314
|
+
segments.push(base.gsub(%r{/+$}, ''))
|
247
315
|
segments.concat(uris.map do |uri|
|
248
316
|
# remove leading and trailing slashes
|
249
317
|
uri.to_s
|
250
|
-
.gsub(%r{
|
251
|
-
.gsub(%r{
|
318
|
+
.gsub(%r{^/+}, '')
|
319
|
+
.gsub(%r{/+$}, '')
|
252
320
|
end)
|
253
321
|
segments.join('/')
|
254
322
|
end
|
@@ -257,20 +325,23 @@ module AsciidoctorExtensions
|
|
257
325
|
# Kroki client
|
258
326
|
#
|
259
327
|
class KrokiClient
|
260
|
-
|
261
|
-
|
328
|
+
include Asciidoctor::Logging
|
329
|
+
|
330
|
+
attr_reader :server_url, :method, :max_uri_length
|
262
331
|
|
263
332
|
SUPPORTED_HTTP_METHODS = %w[get post adaptive].freeze
|
264
333
|
|
265
|
-
def initialize(
|
266
|
-
@server_url = server_url
|
267
|
-
@max_uri_length =
|
268
|
-
@http_client = http_client
|
269
|
-
method = (http_method
|
334
|
+
def initialize(opts, logger = ::Asciidoctor::LoggerManager.logger)
|
335
|
+
@server_url = opts[:server_url]
|
336
|
+
@max_uri_length = opts.fetch(:max_uri_length, 4000)
|
337
|
+
@http_client = opts[:http_client]
|
338
|
+
method = opts.fetch(:http_method, 'adaptive').downcase
|
270
339
|
if SUPPORTED_HTTP_METHODS.include?(method)
|
271
340
|
@method = method
|
272
341
|
else
|
273
|
-
|
342
|
+
logger.warn message_with_context "Invalid value '#{method}' for kroki-http-method attribute. The value must be either: " \
|
343
|
+
"'get', 'post' or 'adaptive'. Proceeding using: 'adaptive'.",
|
344
|
+
source_location: opts[:source_location]
|
274
345
|
@method = 'adaptive'
|
275
346
|
end
|
276
347
|
end
|
@@ -286,7 +357,7 @@ module AsciidoctorExtensions
|
|
286
357
|
if @method == 'adaptive' || @method == 'get'
|
287
358
|
uri = kroki_diagram.get_diagram_uri(server_url)
|
288
359
|
if uri.length > @max_uri_length
|
289
|
-
# The request URI is longer than
|
360
|
+
# The request URI is longer than the max URI length.
|
290
361
|
if @method == 'get'
|
291
362
|
# The request might be rejected by the server with a 414 Request-URI Too Large.
|
292
363
|
# Consider using the attribute kroki-http-method with the value 'adaptive'.
|
@@ -311,12 +382,28 @@ module AsciidoctorExtensions
|
|
311
382
|
require 'json'
|
312
383
|
|
313
384
|
class << self
|
385
|
+
REFERER = "asciidoctor/kroki.rb/#{Asciidoctor::AsciidoctorKroki::VERSION}"
|
386
|
+
|
314
387
|
def get(uri, _)
|
315
|
-
|
388
|
+
uri = URI(uri)
|
389
|
+
request = ::Net::HTTP::Get.new(uri)
|
390
|
+
request['referer'] = REFERER
|
391
|
+
::Net::HTTP.start(
|
392
|
+
uri.hostname,
|
393
|
+
uri.port,
|
394
|
+
use_ssl: (uri.scheme == 'https')
|
395
|
+
) do |http|
|
396
|
+
http.request(request).body
|
397
|
+
end
|
316
398
|
end
|
317
399
|
|
318
400
|
def post(uri, data, _)
|
319
|
-
res = ::Net::HTTP.
|
401
|
+
res = ::Net::HTTP.post(
|
402
|
+
URI(uri),
|
403
|
+
data,
|
404
|
+
'Content-Type' => 'text/plain',
|
405
|
+
'Referer' => REFERER
|
406
|
+
)
|
320
407
|
res.body
|
321
408
|
end
|
322
409
|
end
|
@@ -0,0 +1,130 @@
|
|
1
|
+
# rubocop:disable Lint/ConstantDefinitionInBlock
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require 'rspec_helper'
|
5
|
+
require 'asciidoctor'
|
6
|
+
require_relative '../lib/asciidoctor/extensions/asciidoctor_kroki'
|
7
|
+
require_relative '../lib/asciidoctor/extensions/asciidoctor_kroki/extension'
|
8
|
+
|
9
|
+
describe ::AsciidoctorExtensions::KrokiBlockMacroProcessor do
|
10
|
+
context 'convert to html5' do
|
11
|
+
it 'should catch exception if target is not readable' do
|
12
|
+
input = <<~'ADOC'
|
13
|
+
plantuml::spec/fixtures/missing.puml[svg,role=sequence]
|
14
|
+
ADOC
|
15
|
+
output = Asciidoctor.convert(input, standalone: false)
|
16
|
+
(expect output).to eql %(<div class="paragraph">
|
17
|
+
<p>Unresolved block macro - plantuml::spec/fixtures/missing.puml[]</p>
|
18
|
+
</div>)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
context 'using a custom block macro' do
|
22
|
+
it 'should disallow read' do
|
23
|
+
# noinspection RubyClassModuleNamingConvention
|
24
|
+
class DisallowReadKrokiBlockMacroProcessor < ::AsciidoctorExtensions::KrokiBlockMacroProcessor
|
25
|
+
def read_allowed?(_target)
|
26
|
+
false
|
27
|
+
end
|
28
|
+
end
|
29
|
+
registry = Asciidoctor::Extensions.create do
|
30
|
+
block_macro DisallowReadKrokiBlockMacroProcessor, 'plantuml'
|
31
|
+
end
|
32
|
+
input = <<~'ADOC'
|
33
|
+
plantuml::spec/fixtures/alice.puml[svg,role=sequence]
|
34
|
+
ADOC
|
35
|
+
output = Asciidoctor.convert(input, standalone: false, extension_registry: registry)
|
36
|
+
(expect output).to eql %(<div class="paragraph">
|
37
|
+
<p><a href="spec/fixtures/alice.puml">spec/fixtures/alice.puml</a></p>
|
38
|
+
</div>)
|
39
|
+
end
|
40
|
+
it 'should allow read if target is not a URI' do
|
41
|
+
# noinspection RubyClassModuleNamingConvention
|
42
|
+
class DisallowUriReadKrokiBlockMacroProcessor < ::AsciidoctorExtensions::KrokiBlockMacroProcessor
|
43
|
+
def read_allowed?(target)
|
44
|
+
return false if ::Asciidoctor::Helpers.uriish?(target)
|
45
|
+
|
46
|
+
true
|
47
|
+
end
|
48
|
+
end
|
49
|
+
registry = Asciidoctor::Extensions.create do
|
50
|
+
block_macro DisallowUriReadKrokiBlockMacroProcessor, 'plantuml'
|
51
|
+
end
|
52
|
+
input = <<~'ADOC'
|
53
|
+
plantuml::https://domain.org/alice.puml[svg,role=sequence]
|
54
|
+
|
55
|
+
plantuml::file://path/to/alice.puml[svg,role=sequence]
|
56
|
+
|
57
|
+
plantuml::spec/fixtures/alice.puml[svg,role=sequence]
|
58
|
+
ADOC
|
59
|
+
output = Asciidoctor.convert(input, standalone: false, extension_registry: registry)
|
60
|
+
(expect output).to eql %(<div class="paragraph">
|
61
|
+
<p><a href="https://domain.org/alice.puml">https://domain.org/alice.puml</a></p>
|
62
|
+
</div>
|
63
|
+
<div class="paragraph">
|
64
|
+
<p><a href="file://path/to/alice.puml">file://path/to/alice.puml</a></p>
|
65
|
+
</div>
|
66
|
+
<div class="imageblock sequence kroki-format-svg kroki">
|
67
|
+
<div class="content">
|
68
|
+
<img src="https://kroki.io/plantuml/svg/eNpLzMlMTlXQtVNIyk-yUshIzcnJ5wIAQ-AGVQ==" alt="Diagram">
|
69
|
+
</div>
|
70
|
+
</div>)
|
71
|
+
end
|
72
|
+
it 'should override the resolve target method' do
|
73
|
+
# noinspection RubyClassModuleNamingConvention
|
74
|
+
class FixtureResolveTargetKrokiBlockMacroProcessor < ::AsciidoctorExtensions::KrokiBlockMacroProcessor
|
75
|
+
def resolve_target_path(target)
|
76
|
+
"spec/fixtures/#{target}"
|
77
|
+
end
|
78
|
+
end
|
79
|
+
registry = Asciidoctor::Extensions.create do
|
80
|
+
block_macro FixtureResolveTargetKrokiBlockMacroProcessor, 'plantuml'
|
81
|
+
end
|
82
|
+
input = <<~'ADOC'
|
83
|
+
plantuml::alice.puml[svg,role=sequence]
|
84
|
+
ADOC
|
85
|
+
output = Asciidoctor.convert(input, standalone: false, extension_registry: registry)
|
86
|
+
(expect output).to eql %(<div class="imageblock sequence kroki-format-svg kroki">
|
87
|
+
<div class="content">
|
88
|
+
<img src="https://kroki.io/plantuml/svg/eNpLzMlMTlXQtVNIyk-yUshIzcnJ5wIAQ-AGVQ==" alt="Diagram">
|
89
|
+
</div>
|
90
|
+
</div>)
|
91
|
+
end
|
92
|
+
it 'should display unresolved block macro message when the target cannot be resolved' do
|
93
|
+
# noinspection RubyClassModuleNamingConvention
|
94
|
+
class UnresolvedTargetKrokiBlockMacroProcessor < ::AsciidoctorExtensions::KrokiBlockMacroProcessor
|
95
|
+
def resolve_target_path(_target)
|
96
|
+
nil
|
97
|
+
end
|
98
|
+
end
|
99
|
+
registry = Asciidoctor::Extensions.create do
|
100
|
+
block_macro UnresolvedTargetKrokiBlockMacroProcessor, 'plantuml'
|
101
|
+
end
|
102
|
+
input = <<~'ADOC'
|
103
|
+
plantuml::alice.puml[svg,role=sequence]
|
104
|
+
ADOC
|
105
|
+
output = Asciidoctor.convert(input, standalone: false, extension_registry: registry)
|
106
|
+
(expect output).to eql %(<div class="paragraph">
|
107
|
+
<p>Unresolved block macro - plantuml::alice.puml[]</p>
|
108
|
+
</div>)
|
109
|
+
end
|
110
|
+
it 'should override the unresolved block macro message' do
|
111
|
+
# noinspection RubyClassModuleNamingConvention
|
112
|
+
class CustomUnresolvedTargetMessageKrokiBlockMacroProcessor < ::AsciidoctorExtensions::KrokiBlockMacroProcessor
|
113
|
+
def unresolved_block_macro_message(name, target)
|
114
|
+
"*[ERROR: #{name}::#{target}[] - unresolved block macro]*"
|
115
|
+
end
|
116
|
+
end
|
117
|
+
registry = Asciidoctor::Extensions.create do
|
118
|
+
block_macro CustomUnresolvedTargetMessageKrokiBlockMacroProcessor, 'plantuml'
|
119
|
+
end
|
120
|
+
input = <<~'ADOC'
|
121
|
+
plantuml::spec/fixtures/missing.puml[svg,role=sequence]
|
122
|
+
ADOC
|
123
|
+
output = Asciidoctor.convert(input, standalone: false, extension_registry: registry)
|
124
|
+
(expect output).to eql %(<div class="paragraph">
|
125
|
+
<p><strong>[ERROR: plantuml::spec/fixtures/missing.puml[] - unresolved block macro]</strong></p>
|
126
|
+
</div>)
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
# rubocop:enable Lint/ConstantDefinitionInBlock
|
@@ -7,17 +7,85 @@ require_relative '../lib/asciidoctor/extensions/asciidoctor_kroki'
|
|
7
7
|
describe ::AsciidoctorExtensions::KrokiClient do
|
8
8
|
it 'should use adaptive method when http method is invalid' do
|
9
9
|
kroki_http_client = ::AsciidoctorExtensions::KrokiHttpClient
|
10
|
-
kroki_client = ::AsciidoctorExtensions::KrokiClient.new('http://localhost:8000', 'patch', kroki_http_client)
|
10
|
+
kroki_client = ::AsciidoctorExtensions::KrokiClient.new(server_url: 'http://localhost:8000', http_method: 'patch', http_client: kroki_http_client)
|
11
11
|
expect(kroki_client.method).to eq('adaptive')
|
12
12
|
end
|
13
13
|
it 'should use post method when http method is post' do
|
14
14
|
kroki_http_client = ::AsciidoctorExtensions::KrokiHttpClient
|
15
|
-
kroki_client = ::AsciidoctorExtensions::KrokiClient.new('http://localhost:8000', 'POST', kroki_http_client)
|
15
|
+
kroki_client = ::AsciidoctorExtensions::KrokiClient.new(server_url: 'http://localhost:8000', http_method: 'POST', http_client: kroki_http_client)
|
16
16
|
expect(kroki_client.method).to eq('post')
|
17
17
|
end
|
18
18
|
it 'should use get method when http method is get' do
|
19
19
|
kroki_http_client = ::AsciidoctorExtensions::KrokiHttpClient
|
20
|
-
kroki_client = ::AsciidoctorExtensions::KrokiClient.new('http://localhost:8000', 'get', kroki_http_client)
|
20
|
+
kroki_client = ::AsciidoctorExtensions::KrokiClient.new(server_url: 'http://localhost:8000', http_method: 'get', http_client: 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(server_url: 'http://localhost:8000', http_method: 'get', http_client: 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(server_url: 'http://localhost:8000', http_method: 'get', http_client: kroki_http_client, max_uri_length: 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(server_url: 'http://localhost:8000', http_method: 'adaptive', http_client: kroki_http_client, max_uri_length: 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(server_url: 'http://localhost:8000', http_method: 'adaptive', http_client: kroki_http_client, max_uri_length: 11)
|
88
|
+
result = kroki_client.get_image(kroki_diagram, 'utf8')
|
89
|
+
expect(result).to eq('GET diagram-uri')
|
90
|
+
end
|
23
91
|
end
|
@@ -28,11 +28,32 @@ describe ::AsciidoctorExtensions::KrokiDiagram do
|
|
28
28
|
it 'should fetch a diagram from Kroki and save it to disk' do
|
29
29
|
kroki_diagram = ::AsciidoctorExtensions::KrokiDiagram.new('plantuml', 'txt', ' alice -> bob: hello')
|
30
30
|
kroki_http_client = ::AsciidoctorExtensions::KrokiHttpClient
|
31
|
-
kroki_client = ::AsciidoctorExtensions::KrokiClient.new('https://kroki.io', 'get', kroki_http_client)
|
31
|
+
kroki_client = ::AsciidoctorExtensions::KrokiClient.new(server_url: 'https://kroki.io', http_method: 'get', http_client: kroki_http_client)
|
32
32
|
output_dir_path = "#{__dir__}/../.asciidoctor/kroki"
|
33
33
|
diagram_name = kroki_diagram.save(output_dir_path, kroki_client)
|
34
34
|
diagram_path = File.join(output_dir_path, diagram_name)
|
35
|
-
expect(File.exist?(diagram_path)).to be_truthy, "
|
35
|
+
expect(File.exist?(diagram_path)).to be_truthy, "diagram should 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 and save it to disk using the target name' do
|
49
|
+
kroki_diagram = ::AsciidoctorExtensions::KrokiDiagram.new('plantuml', 'txt', ' alice -> bob: hello', 'hello-world')
|
50
|
+
kroki_http_client = ::AsciidoctorExtensions::KrokiHttpClient
|
51
|
+
kroki_client = ::AsciidoctorExtensions::KrokiClient.new(server_url: 'https://kroki.io', http_method: 'get', http_client: kroki_http_client)
|
52
|
+
output_dir_path = "#{__dir__}/../.asciidoctor/kroki"
|
53
|
+
diagram_name = kroki_diagram.save(output_dir_path, kroki_client)
|
54
|
+
diagram_path = File.join(output_dir_path, diagram_name)
|
55
|
+
expect(diagram_name).to start_with('hello-world-'), "diagram name should use the target as a prefix, got: #{diagram_name}"
|
56
|
+
expect(File.exist?(diagram_path)).to be_truthy, "diagram should be saved at: #{diagram_path}"
|
36
57
|
content = <<-TXT.chomp
|
37
58
|
,-----. ,---.
|
38
59
|
|alice| |bob|
|
@@ -48,14 +69,16 @@ describe ::AsciidoctorExtensions::KrokiDiagram do
|
|
48
69
|
it 'should fetch a diagram from Kroki with the same definition only once' do
|
49
70
|
kroki_diagram = ::AsciidoctorExtensions::KrokiDiagram.new('plantuml', 'png', ' guillaume -> dan: hello')
|
50
71
|
kroki_http_client = ::AsciidoctorExtensions::KrokiHttpClient
|
51
|
-
kroki_client = ::AsciidoctorExtensions::KrokiClient.new('https://kroki.io', 'get', kroki_http_client)
|
72
|
+
kroki_client = ::AsciidoctorExtensions::KrokiClient.new(server_url: 'https://kroki.io', http_method: 'get', http_client: kroki_http_client)
|
52
73
|
output_dir_path = "#{__dir__}/../.asciidoctor/kroki"
|
53
74
|
# make sure that we are doing only one GET request
|
54
|
-
|
75
|
+
diagram_contents = File.read("#{__dir__}/fixtures/plantuml-diagram.png", mode: 'rb')
|
76
|
+
expect(kroki_http_client).to receive(:get).once.and_return(diagram_contents)
|
55
77
|
diagram_name = kroki_diagram.save(output_dir_path, kroki_client)
|
56
78
|
diagram_path = File.join(output_dir_path, diagram_name)
|
57
|
-
expect(File.exist?(diagram_path)).to be_truthy, "
|
79
|
+
expect(File.exist?(diagram_path)).to be_truthy, "diagram should be saved at: #{diagram_path}"
|
58
80
|
# calling again... should read the file from disk (and not do a GET request)
|
59
81
|
kroki_diagram.save(output_dir_path, kroki_client)
|
82
|
+
expect(File.size(diagram_path)).to be_eql(diagram_contents.length), 'diagram should be fully saved on disk'
|
60
83
|
end
|
61
84
|
end
|
@@ -0,0 +1,33 @@
|
|
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::KrokiProcessor' do
|
8
|
+
it 'should return the images output directory (imagesoutdir attribute)' do
|
9
|
+
doc = Asciidoctor.load('hello', attributes: { 'imagesoutdir' => '.asciidoctor/kroki/images', 'imagesdir' => '../images' })
|
10
|
+
output_dir_path = AsciidoctorExtensions::KrokiProcessor.send(:output_dir_path, doc)
|
11
|
+
expect(output_dir_path).to eq '.asciidoctor/kroki/images'
|
12
|
+
end
|
13
|
+
it 'should return a path relative to output directory (to_dir option)' do
|
14
|
+
doc = Asciidoctor.load('hello', to_dir: '.asciidoctor/kroki/relative', attributes: { 'imagesdir' => '../images' })
|
15
|
+
output_dir_path = AsciidoctorExtensions::KrokiProcessor.send(:output_dir_path, doc)
|
16
|
+
expect(output_dir_path).to eq '.asciidoctor/kroki/relative/../images'
|
17
|
+
end
|
18
|
+
it 'should return a path relative to output directory (outdir attribute)' do
|
19
|
+
doc = Asciidoctor.load('hello', attributes: { 'imagesdir' => 'resources/images', 'outdir' => '.asciidoctor/kroki/out' })
|
20
|
+
output_dir_path = AsciidoctorExtensions::KrokiProcessor.send(:output_dir_path, doc)
|
21
|
+
expect(output_dir_path).to eq '.asciidoctor/kroki/out/resources/images'
|
22
|
+
end
|
23
|
+
it 'should return a path relative to the base directory (base_dir option)' do
|
24
|
+
doc = Asciidoctor.load('hello', base_dir: '.asciidoctor/kroki', attributes: { 'imagesdir' => 'img' })
|
25
|
+
output_dir_path = AsciidoctorExtensions::KrokiProcessor.send(:output_dir_path, doc)
|
26
|
+
expect(output_dir_path).to eq "#{::Dir.pwd}/.asciidoctor/kroki/img"
|
27
|
+
end
|
28
|
+
it 'should return a path relative to the base directory (default value is current working directory)' do
|
29
|
+
doc = Asciidoctor.load('hello', attributes: { 'imagesdir' => 'img' })
|
30
|
+
output_dir_path = AsciidoctorExtensions::KrokiProcessor.send(:output_dir_path, doc)
|
31
|
+
expect(output_dir_path).to eq "#{::Dir.pwd}/img"
|
32
|
+
end
|
33
|
+
end
|
@@ -20,31 +20,90 @@ describe ::AsciidoctorExtensions::KrokiBlockProcessor do
|
|
20
20
|
</div>
|
21
21
|
</div>)
|
22
22
|
end
|
23
|
-
it 'should use png if
|
23
|
+
it 'should use png if kroki-default-format is set to png' do
|
24
24
|
input = <<~'ADOC'
|
25
25
|
[plantuml]
|
26
26
|
....
|
27
27
|
alice -> bob: hello
|
28
28
|
....
|
29
29
|
ADOC
|
30
|
-
output = Asciidoctor.convert(input, attributes: { '
|
30
|
+
output = Asciidoctor.convert(input, attributes: { 'kroki-default-format' => 'png' }, standalone: false)
|
31
31
|
(expect output).to eql %(<div class="imageblock kroki">
|
32
32
|
<div class="content">
|
33
33
|
<img src="https://kroki.io/plantuml/png/eNpLzMlMTlXQtVNIyk-yUshIzcnJBwA9iwZL" alt="Diagram">
|
34
34
|
</div>
|
35
35
|
</div>)
|
36
36
|
end
|
37
|
-
it 'should
|
37
|
+
it 'should use svg if kroki-default-format is set to png and the diagram type does not support png' do
|
38
|
+
input = <<~'ADOC'
|
39
|
+
[mermaid]
|
40
|
+
....
|
41
|
+
graph TD;
|
42
|
+
A-->B;
|
43
|
+
....
|
44
|
+
ADOC
|
45
|
+
output = Asciidoctor.convert(input, attributes: { 'kroki-default-format' => 'png' }, standalone: false)
|
46
|
+
(expect output).to eql %(<div class="imageblock kroki">
|
47
|
+
<div class="content">
|
48
|
+
<img src="https://kroki.io/mermaid/svg/eNpLL0osyFAIcbHmUlBw1NW1c7IGADLKBKY=" alt="Diagram">
|
49
|
+
</div>
|
50
|
+
</div>)
|
51
|
+
end
|
52
|
+
it 'should include the plantuml-include file when safe mode is safe' do
|
53
|
+
input = <<~'ADOC'
|
54
|
+
[plantuml]
|
55
|
+
....
|
56
|
+
alice -> bob: hello
|
57
|
+
....
|
58
|
+
ADOC
|
59
|
+
output = Asciidoctor.convert(input,
|
60
|
+
attributes: { 'kroki-plantuml-include' => 'spec/fixtures/config.puml' },
|
61
|
+
standalone: false, safe: :safe)
|
62
|
+
(expect output).to eql %(<div class="imageblock kroki">
|
63
|
+
<div class="content">
|
64
|
+
<img src="https://kroki.io/plantuml/svg/eNorzs7MK0gsSsxVyM3Py0_OKMrPTVUoKSpN5eJKzMlMTlXQtVNIyk-yUshIzcnJBwCT9xBc" alt="Diagram">
|
65
|
+
</div>
|
66
|
+
</div>)
|
67
|
+
end
|
68
|
+
it 'should normalize plantuml-include path when safe mode is safe' do
|
38
69
|
input = <<~'ADOC'
|
39
70
|
[plantuml]
|
40
71
|
....
|
41
72
|
alice -> bob: hello
|
42
73
|
....
|
43
74
|
ADOC
|
44
|
-
output = Asciidoctor.convert(input, attributes: { '
|
75
|
+
output = Asciidoctor.convert(input, attributes: { 'kroki-plantuml-include' => '../../../spec/fixtures/config.puml' }, standalone: false, safe: :safe)
|
45
76
|
(expect output).to eql %(<div class="imageblock kroki">
|
46
77
|
<div class="content">
|
47
|
-
<img src="https://kroki.io/plantuml/
|
78
|
+
<img src="https://kroki.io/plantuml/svg/eNorzs7MK0gsSsxVyM3Py0_OKMrPTVUoKSpN5eJKzMlMTlXQtVNIyk-yUshIzcnJBwCT9xBc" alt="Diagram">
|
79
|
+
</div>
|
80
|
+
</div>)
|
81
|
+
end
|
82
|
+
it 'should not include file which reside outside of the parent directory of the source when safe mode is safe' do
|
83
|
+
input = <<~'ADOC'
|
84
|
+
[plantuml]
|
85
|
+
....
|
86
|
+
alice -> bob: hello
|
87
|
+
....
|
88
|
+
ADOC
|
89
|
+
output = Asciidoctor.convert(input, attributes: { 'kroki-plantuml-include' => '/etc/passwd' }, standalone: false, safe: :safe)
|
90
|
+
(expect output).to eql %(<div class="imageblock kroki">
|
91
|
+
<div class="content">
|
92
|
+
<img src="https://kroki.io/plantuml/svg/eNpLzMlMTlXQtVNIyk-yUshIzcnJBwA9iwZL" alt="Diagram">
|
93
|
+
</div>
|
94
|
+
</div>)
|
95
|
+
end
|
96
|
+
it 'should not include file when safe mode is secure' do
|
97
|
+
input = <<~'ADOC'
|
98
|
+
[plantuml]
|
99
|
+
....
|
100
|
+
alice -> bob: hello
|
101
|
+
....
|
102
|
+
ADOC
|
103
|
+
output = Asciidoctor.convert(input, attributes: { 'kroki-plantuml-include' => 'spec/fixtures/config.puml' }, standalone: false, safe: :secure)
|
104
|
+
(expect output).to eql %(<div class="imageblock kroki">
|
105
|
+
<div class="content">
|
106
|
+
<img src="https://kroki.io/plantuml/svg/eNpLzMlMTlXQtVNIyk-yUshIzcnJBwA9iwZL" alt="Diagram">
|
48
107
|
</div>
|
49
108
|
</div>)
|
50
109
|
end
|
@@ -54,11 +113,24 @@ describe ::AsciidoctorExtensions::KrokiBlockProcessor do
|
|
54
113
|
|
55
114
|
plantuml::spec/fixtures/alice.puml[svg,role=sequence]
|
56
115
|
ADOC
|
57
|
-
output = Asciidoctor.convert(input, attributes: { 'kroki-fetch-diagram' => '' }, standalone: false)
|
116
|
+
output = Asciidoctor.convert(input, attributes: { 'kroki-fetch-diagram' => '' }, standalone: false, safe: :safe)
|
58
117
|
(expect output).to eql %(<div class="imageblock sequence kroki-format-svg kroki">
|
59
118
|
<div class="content">
|
60
119
|
<img src=".asciidoctor/kroki/diag-f6acdc206506b6ca7badd3fe722f252af992871426e580c8361ff4d47c2c7d9b.svg" alt="Diagram">
|
61
120
|
</div>
|
121
|
+
</div>)
|
122
|
+
end
|
123
|
+
it 'should not fetch diagram when safe mode is secure' do
|
124
|
+
input = <<~'ADOC'
|
125
|
+
:imagesdir: .asciidoctor/kroki
|
126
|
+
|
127
|
+
plantuml::spec/fixtures/alice.puml[svg,role=sequence]
|
128
|
+
ADOC
|
129
|
+
output = Asciidoctor.convert(input, attributes: { 'kroki-fetch-diagram' => '' }, standalone: false)
|
130
|
+
(expect output).to eql %(<div class="imageblock sequence kroki-format-svg kroki">
|
131
|
+
<div class="content">
|
132
|
+
<img src="https://kroki.io/plantuml/svg/eNpLzMlMTlXQtVNIyk-yUshIzcnJ5wIAQ-AGVQ==" alt="Diagram">
|
133
|
+
</div>
|
62
134
|
</div>)
|
63
135
|
end
|
64
136
|
it 'should create PNG diagram in imagesdir if kroki-fetch-diagram is set' do
|
@@ -67,7 +139,7 @@ describe ::AsciidoctorExtensions::KrokiBlockProcessor do
|
|
67
139
|
|
68
140
|
plantuml::spec/fixtures/alice.puml[png,role=sequence]
|
69
141
|
ADOC
|
70
|
-
output = Asciidoctor.convert(input, attributes: { 'kroki-fetch-diagram' => '' }, standalone: false)
|
142
|
+
output = Asciidoctor.convert(input, attributes: { 'kroki-fetch-diagram' => '' }, standalone: false, safe: :safe)
|
71
143
|
(expect output).to eql %(<div class="imageblock sequence kroki-format-png kroki">
|
72
144
|
<div class="content">
|
73
145
|
<img src=".asciidoctor/kroki/diag-d4f314b2d4e75cc08aa4f8c2c944f7bf78321895d8ec5f665b42476d4e67e610.png" alt="Diagram">
|
@@ -75,12 +147,23 @@ describe ::AsciidoctorExtensions::KrokiBlockProcessor do
|
|
75
147
|
</div>)
|
76
148
|
end
|
77
149
|
end
|
150
|
+
context 'instantiate' do
|
151
|
+
it 'should instantiate block processor without warning' do
|
152
|
+
original_stderr = $stderr
|
153
|
+
$stderr = StringIO.new
|
154
|
+
::AsciidoctorExtensions::KrokiBlockProcessor.new :plantuml, {}
|
155
|
+
output = $stderr.string
|
156
|
+
(expect output).to eql ''
|
157
|
+
ensure
|
158
|
+
$stderr = original_stderr
|
159
|
+
end
|
160
|
+
end
|
78
161
|
end
|
79
162
|
|
80
163
|
describe ::AsciidoctorExtensions::Kroki do
|
81
164
|
it 'should return the list of supported diagrams' do
|
82
165
|
diagram_names = ::AsciidoctorExtensions::Kroki::SUPPORTED_DIAGRAM_NAMES
|
83
|
-
expect(diagram_names).to include('vegalite', 'plantuml', 'bytefield', 'bpmn', 'excalidraw')
|
166
|
+
expect(diagram_names).to include('vegalite', 'plantuml', 'bytefield', 'bpmn', 'excalidraw', 'wavedrom', 'pikchr', 'structurizr')
|
84
167
|
end
|
85
168
|
it 'should register the extension for the list of supported diagrams' do
|
86
169
|
doc = Asciidoctor::Document.new
|
Binary file
|
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.6.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: 2022-06-22 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: asciidoctor
|
@@ -30,42 +30,42 @@ dependencies:
|
|
30
30
|
requirements:
|
31
31
|
- - "~>"
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version:
|
33
|
+
version: 13.0.6
|
34
34
|
type: :development
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version:
|
40
|
+
version: 13.0.6
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: rspec
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
45
|
- - "~>"
|
46
46
|
- !ruby/object:Gem::Version
|
47
|
-
version: 3.
|
47
|
+
version: 3.10.0
|
48
48
|
type: :development
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
52
|
- - "~>"
|
53
53
|
- !ruby/object:Gem::Version
|
54
|
-
version: 3.
|
54
|
+
version: 3.10.0
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
56
|
name: rubocop
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
58
58
|
requirements:
|
59
59
|
- - "~>"
|
60
60
|
- !ruby/object:Gem::Version
|
61
|
-
version:
|
61
|
+
version: '1.30'
|
62
62
|
type: :development
|
63
63
|
prerelease: false
|
64
64
|
version_requirements: !ruby/object:Gem::Requirement
|
65
65
|
requirements:
|
66
66
|
- - "~>"
|
67
67
|
- !ruby/object:Gem::Version
|
68
|
-
version:
|
68
|
+
version: '1.30'
|
69
69
|
description: An extension for Asciidoctor to convert diagrams to images using https://kroki.io
|
70
70
|
email:
|
71
71
|
- ggrossetie@yuzutech.fr
|
@@ -84,12 +84,16 @@ files:
|
|
84
84
|
- lib/asciidoctor-kroki.rb
|
85
85
|
- lib/asciidoctor/extensions/asciidoctor_kroki.rb
|
86
86
|
- lib/asciidoctor/extensions/asciidoctor_kroki/extension.rb
|
87
|
+
- lib/asciidoctor/extensions/asciidoctor_kroki/version.rb
|
87
88
|
- spec/.rubocop.yml
|
89
|
+
- spec/asciidoctor_kroki_block_macro_spec.rb
|
88
90
|
- spec/asciidoctor_kroki_client_spec.rb
|
89
91
|
- spec/asciidoctor_kroki_diagram_spec.rb
|
92
|
+
- spec/asciidoctor_kroki_processor_spec.rb
|
90
93
|
- spec/asciidoctor_kroki_spec.rb
|
91
94
|
- spec/fixtures/alice.puml
|
92
95
|
- spec/fixtures/config.puml
|
96
|
+
- spec/fixtures/plantuml-diagram.png
|
93
97
|
- spec/require_spec.rb
|
94
98
|
- spec/rspec_helper.rb
|
95
99
|
- tasks/bundler.rake
|
@@ -101,6 +105,7 @@ licenses:
|
|
101
105
|
metadata:
|
102
106
|
bug_tracker_uri: https://github.com/Mogztter/asciidoctor-kroki/issues
|
103
107
|
source_code_uri: https://github.com/Mogztter/asciidoctor-kroki
|
108
|
+
rubygems_mfa_required: 'true'
|
104
109
|
post_install_message:
|
105
110
|
rdoc_options: []
|
106
111
|
require_paths:
|
@@ -116,19 +121,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
116
121
|
- !ruby/object:Gem::Version
|
117
122
|
version: '0'
|
118
123
|
requirements: []
|
119
|
-
rubygems_version: 3.
|
124
|
+
rubygems_version: 3.1.6
|
120
125
|
signing_key:
|
121
126
|
specification_version: 4
|
122
127
|
summary: Asciidoctor extension to convert diagrams to images using Kroki
|
123
|
-
test_files:
|
124
|
-
- spec/.rubocop.yml
|
125
|
-
- spec/asciidoctor_kroki_client_spec.rb
|
126
|
-
- spec/asciidoctor_kroki_diagram_spec.rb
|
127
|
-
- spec/asciidoctor_kroki_spec.rb
|
128
|
-
- spec/fixtures/alice.puml
|
129
|
-
- spec/fixtures/config.puml
|
130
|
-
- spec/require_spec.rb
|
131
|
-
- spec/rspec_helper.rb
|
132
|
-
- tasks/bundler.rake
|
133
|
-
- tasks/lint.rake
|
134
|
-
- tasks/rspec.rake
|
128
|
+
test_files: []
|