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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c68a706bac6918c95daef5ada0de0d6a8471cbd69cc83ced875119ca69b90f58
4
- data.tar.gz: c2683ddf3c70e743faff32a73442ef651fd17145191148e4a5930ac7d16852f9
3
+ metadata.gz: 1d98287cf9a15751a442de9b1a07565c097206aae0912ca204ecaf4bdede4020
4
+ data.tar.gz: b1252225ed15a9f093d8a3c1d577e2bfa23c2abe7962981d638f49ea81d90a7b
5
5
  SHA512:
6
- metadata.gz: 45ea1d0252ebfab9fc9dfba56b13a3497ddf1e5ca58cb05777c941829ec2316f0f194a87bef490483c800d43cd7cf0e008804cb4f92ad4955cc864203ad26dfb
7
- data.tar.gz: 3fec5d036175f848b0fa26df6c47439ee2f61a776393c097ecb0e79e0f407939e99df233bb1461360feaf4aae4224377aadff7bbc9d93ffa6fad6af62f7fc40e
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
- Metrics/LineLength:
5
- Max: 160
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: 30
28
+ Max: 31
29
+
30
+ Metrics/ParameterLists:
31
+ Max: 7
32
+
33
+ Gemspec/RequiredRubyVersion:
34
+ Enabled: false
data/.ruby-version CHANGED
@@ -1 +1 @@
1
- 2.6.5
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.3.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.10)
11
- ast (2.4.1)
12
- diff-lcs (1.3)
13
- jaro_winkler (1.5.4)
14
- parallel (1.19.1)
15
- parser (2.7.1.3)
16
- ast (~> 2.4.0)
17
- rainbow (3.0.0)
18
- rake (12.3.3)
19
- rspec (3.8.0)
20
- rspec-core (~> 3.8.0)
21
- rspec-expectations (~> 3.8.0)
22
- rspec-mocks (~> 3.8.0)
23
- rspec-core (3.8.2)
24
- rspec-support (~> 3.8.0)
25
- rspec-expectations (3.8.6)
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.8.0)
28
- rspec-mocks (3.8.2)
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.8.0)
31
- rspec-support (3.8.3)
32
- rubocop (0.74.0)
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 (>= 2.6)
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, < 1.7)
39
- ruby-progressbar (1.10.1)
40
- unicode-display_width (1.6.1)
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 (~> 12.3.2)
48
- rspec (~> 3.8.0)
49
- rubocop (~> 0.74.0)
52
+ rake (~> 13.0.6)
53
+ rspec (~> 3.10.0)
54
+ rubocop (~> 1.30)
50
55
 
51
56
  BUNDLED WITH
52
- 1.17.3
57
+ 2.3.15
@@ -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 = '0.3.0'
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', '~> 12.3.2'
24
- s.add_development_dependency 'rspec', '~> 3.8.0'
25
- s.add_development_dependency 'rubocop', '~> 0.74.0'
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
- diagram_text = read(target)
36
- KrokiProcessor.process(self, parent, attrs, diagram_type, diagram_text)
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
- URI.open(target, &:read)
93
+ ::OpenURI.open_uri(target, &:read)
43
94
  else
44
- File.open(target, &:read)
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
- wavedrow
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
- def process(processor, parent, attrs, diagram_type, diagram_text)
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(server_url(doc), http_method(doc), KrokiHttpClient)
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
- # TODO: this behaves different than the JS version
118
- # The file should be added by !include #{plantuml_include}" once we have a preprocessor for ruby
119
- config = File.read(doc.attr('kroki-plantuml-include'))
120
- diagram_text = config + '\n' + diagram_text
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
- # The JavaFX preview doesn't support SVG well, therefore we'll use PNG format...
150
- if doc.attr?('env-idea') && format == 'svg'
151
- # ... unless the diagram library does not support PNG as output format!
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 = %w[:mermaid :nomnoml :svgbob :wavedrom]
154
- format = 'png' unless svg_only_diagram_types.include?(diagram_type)
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
- elsif out_dir
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 = if @format == 'txt' || @format == 'atxt' || @format == 'utxt'
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
- contents = File.exist?(file_path) ? File.open(file_path, &:read) : kroki_client.get_image(self, encoding)
232
- FileUtils.mkdir_p(output_dir_path)
233
- if encoding == 'binary'
234
- File.binwrite(file_path, contents)
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
- attr_reader :server_url
261
- attr_reader :method
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(server_url, http_method, http_client)
266
- @server_url = server_url
267
- @max_uri_length = 4096
268
- @http_client = http_client
269
- method = (http_method || 'adaptive').downcase
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
- puts "Invalid value '#{method}' for kroki-http-method attribute. The value must be either: 'get', 'post' or 'adaptive'. Proceeding using: 'adaptive'."
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 4096.
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
- ::OpenURI.open_uri(uri, 'r', &:read)
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.request_post(uri, data)
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,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Asciidoctor
4
+ module AsciidoctorKroki
5
+ VERSION = '0.6.0'
6
+ end
7
+ end
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'asciidoctor/extensions' unless RUBY_ENGINE == 'opal'
4
+ require_relative 'asciidoctor_kroki/version'
4
5
  require_relative 'asciidoctor_kroki/extension'
5
6
 
6
7
  Asciidoctor::Extensions.register do
@@ -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, "expected diagram to be saved at #{diagram_path}"
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
- expect(kroki_http_client).to receive(:get).once
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, "expected diagram to be saved at #{diagram_path}"
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 env-idea is defined' do
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: { 'env-idea' => '' }, standalone: false)
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 include the plantuml-include file' do
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: { 'env-idea' => '', 'kroki-plantuml-include' => 'spec/fixtures/config.puml' }, standalone: false)
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/png/eNorzs7MK0gsSsxVyM3Py0_OKMrPTVUoKSpN5YrJS8zJTE5V0LVTSMpPslLISM3JyQcArVsRHA==" alt="Diagram">
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.3.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: 2021-01-12 00:00:00.000000000 Z
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: 12.3.2
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: 12.3.2
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.8.0
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.8.0
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: 0.74.0
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: 0.74.0
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.0.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: []