metanorma-plugin-plantuml 1.0.14 → 1.0.15

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: 76a24adfb562fe1a39ccb67f4544884e11249e781d1c018cf4fba54d98c5459e
4
- data.tar.gz: 165e9f1a919f0f7a51cbd929c259ef82ce5ae9e5d694a4bbd36d9cbe32a5cdda
3
+ metadata.gz: 2c4b579643b6072bf87b205256a322daee254f200b829539d5f972da33ac46c0
4
+ data.tar.gz: 3ba87fc795b42832ee26a4dce6450d83c53c5625d24e0ab17fa51cf056b60feb
5
5
  SHA512:
6
- metadata.gz: b097cbd66938f606fb2d8375754aa5950d8c6e6d0fa53549d9136620c843adc4b9fc4723cb845e623d3c8a35e0d2d27f5b6303cc57fb1fea078926984ae13ce9
7
- data.tar.gz: b78558a93c73146a893f77017c2d9959a9235068246b5a15911c419e3f340b4769ba16d3490c376c652242d3658cd01c4df5e1eb76ba8b062f0522807e43476c
6
+ metadata.gz: d602eddb79c725717821bdeaeb1bc9eba1a7c67f2e1096ce282b288d5f958cd8af9432fbeecddf55ae285eb0d4e608cca4f844a582f56d384f1b236ad109e153
7
+ data.tar.gz: 1eb514f53f64d1782efd2d5e9b375478e08501bea47394450f34001fadbb7494ccfda070022fb9b5ea7a56e994e0b80bb06be1ffc441ef9ce90b59b49a27b156
data/.rubocop_todo.yml CHANGED
@@ -1,6 +1,6 @@
1
1
  # This configuration was generated by
2
2
  # `rubocop --auto-gen-config`
3
- # on 2026-05-11 22:41:11 UTC using RuboCop version 1.86.1.
3
+ # on 2026-05-12 02:38:27 UTC using RuboCop version 1.86.1.
4
4
  # The point is for the user to remove these configuration records
5
5
  # one by one as the offenses are removed from the code base.
6
6
  # Note that changes in the inspected code, or installation of new
@@ -11,14 +11,13 @@ Gemspec/RequiredRubyVersion:
11
11
  Exclude:
12
12
  - 'metanorma-plugin-plantuml.gemspec'
13
13
 
14
- # Offense count: 8
14
+ # Offense count: 6
15
15
  # This cop supports safe autocorrection (--autocorrect).
16
16
  # Configuration parameters: Max, AllowHeredoc, AllowURI, AllowQualifiedName, URISchemes, AllowRBSInlineAnnotation, AllowCopDirectives, AllowedPatterns, SplitStrings.
17
17
  # URISchemes: http, https
18
18
  Layout/LineLength:
19
19
  Exclude:
20
20
  - 'Rakefile'
21
- - 'lib/metanorma/plugin/plantuml/backend.rb'
22
21
  - 'lib/metanorma/plugin/plantuml/config.rb'
23
22
  - 'lib/metanorma/plugin/plantuml/wrapper.rb'
24
23
  - 'spec/metanorma/plugin/plantuml/plantuml_integration_spec.rb'
@@ -6,14 +6,12 @@ require "fileutils"
6
6
  module Metanorma
7
7
  module Plugin
8
8
  module Plantuml
9
- # Backend class for PlantUML diagram generation
10
- # Adapted from metanorma-standoc's PlantUMLBlockMacroBackend
11
9
  class Backend
12
10
  class << self
13
11
  def plantuml_installed?
14
12
  return true if plantuml_available?
15
13
 
16
- raise "PlantUML not installed"
14
+ raise PlantumlError, "PlantUML not installed"
17
15
  end
18
16
 
19
17
  def plantuml_available?
@@ -21,53 +19,64 @@ module Metanorma
21
19
  end
22
20
 
23
21
  def generate_file( # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
24
- parent, reader, format_override: nil, options: {}
22
+ parent, source, format_override: nil, options: {}
25
23
  )
26
24
  ldir, imagesdir, fmt = generate_file_prep(parent)
27
25
  fmt = format_override if format_override
28
- plantuml_content = prep_source(parent, reader)
26
+ validate_source(source)
29
27
 
30
- # Extract filename from PlantUML source if specified
31
28
  filename = generate_unique_filename(fmt)
32
- extracted_filename = extract_plantuml_filename(plantuml_content)
29
+ extracted_filename = FilenameResolver.extract(source)
33
30
 
34
- filename = "#{extracted_filename}.#{fmt}" if extracted_filename
31
+ if extracted_filename
32
+ safe_filename = FilenameResolver.sanitize(extracted_filename)
33
+ filename = "#{safe_filename}.#{fmt}"
34
+ end
35
35
 
36
36
  absolute_path, relative_path = path_prep(ldir, imagesdir)
37
37
  output_file = File.join(absolute_path, filename)
38
38
 
39
39
  result = Wrapper.generate(
40
- plantuml_content,
40
+ source,
41
41
  format: fmt,
42
42
  output_file: output_file,
43
43
  includedirs: options[:includedirs],
44
44
  layout: options[:layout],
45
45
  )
46
46
 
47
- raise "No image output from PlantUML: #{result[:error].message}" unless result[:success]
47
+ unless result[:success]
48
+ raise GenerationError,
49
+ "No image output from PlantUML: #{result[:error].message}"
50
+ end
48
51
 
49
52
  File.join(relative_path, filename)
50
53
  end
51
54
 
52
55
  def generate_multiple_files(
53
- parent, reader, formats, attrs, options: {}
56
+ parent, source, formats, attrs, options: {}
54
57
  )
55
- # Generate files for each format
56
58
  filenames = formats.map do |format|
57
- generate_file(parent, reader, format, options: options)
59
+ generate_file(parent, source,
60
+ format_override: format, options: options)
58
61
  end
59
62
 
60
- # Return data for BlockProcessor to create image block
61
63
  through_attrs = generate_attrs attrs
62
64
  through_attrs["target"] = filenames.first
63
-
64
- # Store additional formats for potential future use
65
65
  through_attrs["data-formats"] = formats.join(",")
66
66
  through_attrs["data-files"] = filenames.join(",")
67
67
 
68
68
  through_attrs
69
69
  end
70
70
 
71
+ def validate_source(source)
72
+ diagram_type = extract_diagram_type(source)
73
+ return if diagram_type && matching_end?(source, diagram_type)
74
+
75
+ raise GenerationError,
76
+ "@start#{diagram_type} without matching " \
77
+ "@end#{diagram_type} in PlantUML!"
78
+ end
79
+
71
80
  def generate_file_prep(parent) # rubocop:disable Metrics/AbcSize,Metrics/MethodLength
72
81
  imagesdir = if parent.document.attr("docfile") &&
73
82
  parent.document.attr("imagesdir")
@@ -92,11 +101,11 @@ module Metanorma
92
101
  ret = Utils.localdir(parent.document)
93
102
  return ret if File.writable?(ret)
94
103
 
95
- raise "Destination directory #{ret} not writable for PlantUML!"
104
+ raise GenerationError,
105
+ "Destination directory #{ret} not writable for PlantUML!"
96
106
  end
97
107
 
98
108
  def path_prep(localdir, imagesdir) # rubocop:disable Metrics/AbcSize,Metrics/MethodLength
99
- # Determine source path
100
109
  sourcepath = if imagesdir.nil?
101
110
  localdir
102
111
  elsif Pathname.new(imagesdir).absolute?
@@ -105,14 +114,14 @@ module Metanorma
105
114
  File.join(localdir, imagesdir)
106
115
  end
107
116
 
108
- # Determine PlantUML images destination absolute path
109
117
  path = Pathname.new(
110
118
  File.expand_path(File.join(localdir, "_plantuml_images")),
111
119
  )
112
120
  path.mkpath
113
121
 
114
122
  unless File.writable?(path)
115
- raise "Destination path #{path} not writable for PlantUML!"
123
+ raise GenerationError,
124
+ "Destination path #{path} not writable for PlantUML!"
116
125
  end
117
126
 
118
127
  [
@@ -122,28 +131,6 @@ module Metanorma
122
131
  ]
123
132
  end
124
133
 
125
- def prep_source(parent, reader) # rubocop:disable Metrics/MethodLength
126
- src = if reader.respond_to?(:source)
127
- # get content from BlockProcessor
128
- reader.source
129
- else
130
- # get content from ImageBlockMacroProcessor
131
- docfile_directory = File.dirname(
132
- parent.document.attributes["docfile"] || ".",
133
- )
134
-
135
- resolved_path = parent.document
136
- .path_resolver
137
- .system_path(reader, docfile_directory)
138
-
139
- File.read(resolved_path, encoding: "UTF-8")
140
- end
141
-
142
- # Validate that we have matching start/end pairs
143
- validate_plantuml_delimiters(src)
144
- src
145
- end
146
-
147
134
  def generate_attrs(attrs)
148
135
  %w[id align float title role width height alt]
149
136
  .each_with_object({}) do |key, memo|
@@ -153,49 +140,19 @@ module Metanorma
153
140
 
154
141
  private
155
142
 
156
- def validate_plantuml_delimiters(src)
157
- # Find @start... pattern
158
- # (case insensitive, support all PlantUML diagram types)
159
- start_match = src.match(/^@start(\w+)/i)
160
- raise "PlantUML content must start with @start... directive!" unless start_match
161
-
162
- diagram_type = start_match[1].downcase
163
- end_pattern = "@end#{diagram_type}"
164
-
165
- # Look for matching @end... directive (case insensitive)
166
- return if /#{Regexp.escape(end_pattern)}\s*$/mi.match?(src)
167
-
168
- raise "@start#{diagram_type} without matching #{end_pattern} " \
169
- "in PlantUML!"
170
- end
171
-
172
- def extract_plantuml_filename(plantuml_content)
173
- # Extract filename from any @start... line if specified
174
- # Only match when filename is on the same line as @start...
175
- # (no newlines)
176
- lines = plantuml_content.lines
177
- first_line = lines.first&.strip
178
- return nil unless first_line
179
-
180
- match = first_line.match(/^@start\w+\s+(.+)$/i)
181
- return nil unless match
182
-
183
- filename = match[1].strip
184
- return nil if filename.nil? || filename.empty?
143
+ def extract_diagram_type(source)
144
+ match = source.match(/^@start(\w+)/i)
145
+ unless match
146
+ raise GenerationError,
147
+ "PlantUML content must start with @start... directive!"
148
+ end
185
149
 
186
- # Sanitize filename for filesystem use
187
- sanitize_filename(filename)
150
+ match[1].downcase
188
151
  end
189
152
 
190
- def sanitize_filename(filename)
191
- # Remove quotes and sanitize for filesystem
192
- filename = filename.gsub(/^["']|["']$/, "")
193
- # Replace any non-alphanumeric characters
194
- # (except dash, underscore, dot) with underscore
195
- filename.gsub(/[^\w\-.]/, "_")
196
- .gsub(/\.{2,}/, "_") # Replace multiple dots with underscore
197
- .gsub(/_{2,}/, "_") # Replace multiple underscores with single
198
- .gsub(/^[_\-.]+|[_\-.]+$/, "") # Remove leading/trailing chars
153
+ def matching_end?(source, diagram_type)
154
+ end_directive = "@end#{diagram_type}"
155
+ source.downcase.include?(end_directive.downcase)
199
156
  end
200
157
 
201
158
  def generate_unique_filename(format)
@@ -3,7 +3,6 @@
3
3
  module Metanorma
4
4
  module Plugin
5
5
  module Plantuml
6
- # PlantUML block processor
7
6
  class BlockProcessor < ::Asciidoctor::Extensions::BlockProcessor
8
7
  include ::Metanorma::Plugin::Plantuml::BlockProcessorBase
9
8
 
@@ -13,25 +12,23 @@ module Metanorma
13
12
  parse_content_as :raw
14
13
 
15
14
  def process(parent, reader, attrs)
16
- # Check for document-level disable flag
15
+ source = reader.source
16
+
17
17
  if parent.document.attr("plantuml-disabled")
18
- return abort(parent, reader, attrs,
18
+ return abort(parent, source, attrs,
19
19
  "PlantUML processing disabled")
20
20
  end
21
21
 
22
- # Check PlantUML availability explicitly
23
22
  unless Backend.plantuml_available?
24
- return abort(parent, reader, attrs,
25
- "PlantUML not installed")
23
+ return abort(parent, source, attrs, "PlantUML not installed")
26
24
  end
27
25
 
28
- # Parse format specifications
29
26
  formats = parse_formats(attrs, parent.document)
30
27
  options = parse_options(parent, reader, attrs)
31
28
 
32
- process_image_block(parent, reader, attrs, formats, options)
29
+ process_image_block(parent, source, attrs, formats, options)
33
30
  rescue StandardError => e
34
- abort(parent, reader, attrs, e.message)
31
+ abort(parent, source, attrs, e.message)
35
32
  end
36
33
 
37
34
  private
@@ -39,7 +36,6 @@ module Metanorma
39
36
  def parse_options(parent, _reader, attrs)
40
37
  options = {}
41
38
 
42
- # Parse include directory
43
39
  options[:includedirs] = add_attrs_to_includedirs(
44
40
  parent.document, attrs, parse_doc_includedirs(parent.document)
45
41
  )
@@ -7,12 +7,12 @@ module Metanorma
7
7
  module Plugin
8
8
  module Plantuml
9
9
  module BlockProcessorBase
10
- def abort(parent, reader, attrs, msg)
10
+ def abort(parent, text, attrs, msg)
11
11
  warn msg
12
12
  attrs["language"] = "plantuml"
13
13
  create_listing_block(
14
14
  parent,
15
- reader.respond_to?(:source) ? reader.source : reader,
15
+ text,
16
16
  attrs.reject { |k, _v| k.to_s.match?(/^\d+$/) },
17
17
  )
18
18
  end
@@ -35,19 +35,16 @@ module Metanorma
35
35
  end
36
36
 
37
37
  def parse_formats(attrs, document) # rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity, Metrics/AbcSize, Metrics/MethodLength
38
- # Check for formats attribute (multiple formats)
39
38
  if attrs["formats"]
40
39
  formats = attrs["formats"].split(",").map(&:strip).map(&:downcase)
41
40
  return formats.select { |f| valid_format?(f) }
42
41
  end
43
42
 
44
- # Check for format attribute (single format override)
45
43
  if attrs["format"]
46
44
  format = attrs["format"].strip.downcase
47
45
  return [format] if valid_format?(format)
48
46
  end
49
47
 
50
- # Fall back to document attribute or default
51
48
  default_format = document
52
49
  .attr("plantuml-image-format")&.strip&.downcase ||
53
50
  Wrapper::DEFAULT_FORMAT
@@ -74,19 +71,17 @@ module Metanorma
74
71
  includedirs.compact.uniq
75
72
  end
76
73
 
77
- def process_image_block(parent, reader, attrs, formats, options) # rubocop:disable Metrics/MethodLength
74
+ def process_image_block(parent, source, attrs, formats, options) # rubocop:disable Metrics/MethodLength
78
75
  if formats.length == 1
79
- # Single format - original behavior
80
76
  filename = Backend.generate_file(
81
- parent, reader, format_override: formats.first, options: options
77
+ parent, source, format_override: formats.first, options: options
82
78
  )
83
79
  through_attrs = Backend.generate_attrs(attrs)
84
80
  through_attrs["target"] = filename
85
81
  else
86
- # Multiple formats - generate multiple files
87
82
  through_attrs = Backend
88
83
  .generate_multiple_files(
89
- parent, reader, formats, attrs, options: options
84
+ parent, source, formats, attrs, options: options
90
85
  )
91
86
  end
92
87
 
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Metanorma
4
+ module Plugin
5
+ module Plantuml
6
+ class FilenameResolver
7
+ class << self
8
+ def extract(content)
9
+ first_line = content.lines.first&.strip
10
+ return nil unless first_line
11
+
12
+ match = first_line.match(/^@start\w+\s+([^\n]+)/i)
13
+ return nil unless match
14
+
15
+ filename = match[1].strip
16
+ return nil if filename.empty?
17
+
18
+ filename.gsub(/^["']|["']$/, "")
19
+ end
20
+
21
+ def sanitize(filename)
22
+ result = filename.gsub(/[^\w\-.]/, "_")
23
+ result = result.tr_s("._", "._")
24
+ result = result.gsub(/\.{2,}/, ".")
25
+ result = result.gsub(/_{2,}/, "_")
26
+ strip_special_edges(result)
27
+ end
28
+
29
+ private
30
+
31
+ def strip_special_edges(str)
32
+ result = str
33
+ trim = { "_" => true, "-" => true, "." => true }
34
+ result = result[1..] while result.length > 1 && trim[result[0]]
35
+ result = result[..-2] while result.length > 1 && trim[result[-1]]
36
+ result
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
@@ -3,37 +3,47 @@
3
3
  module Metanorma
4
4
  module Plugin
5
5
  module Plantuml
6
- # PlantUML block processor
7
6
  class ImageBlockMacroProcessor < ::Asciidoctor::Extensions::BlockMacroProcessor
8
7
  include ::Metanorma::Plugin::Plantuml::BlockProcessorBase
9
8
 
10
9
  use_dsl
11
10
  named :plantuml_image
12
11
 
13
- def process(parent, reader, attrs)
14
- # Check for document-level disable flag
12
+ def process(parent, target, attrs)
13
+ display_text = target
14
+
15
15
  if parent.document.attr("plantuml-disabled")
16
- return abort(parent, reader, attrs,
16
+ return abort(parent, display_text, attrs,
17
17
  "PlantUML processing disabled")
18
18
  end
19
19
 
20
- # Check PlantUML availability explicitly
21
20
  unless Backend.plantuml_available?
22
- return abort(parent, reader, attrs,
23
- "PlantUML not installed")
21
+ return abort(parent, display_text, attrs, "PlantUML not installed")
24
22
  end
25
23
 
26
- # Parse format specifications
24
+ source = read_source_file(parent, target)
27
25
  formats = parse_formats(attrs, parent.document)
28
- options = parse_options(parent, reader, attrs)
26
+ options = parse_options(parent, target, attrs)
29
27
 
30
- process_image_block(parent, reader, attrs, formats, options)
28
+ process_image_block(parent, source, attrs, formats, options)
31
29
  rescue StandardError => e
32
- abort(parent, reader, attrs, e.message)
30
+ abort(parent, display_text, attrs, e.message)
33
31
  end
34
32
 
35
33
  private
36
34
 
35
+ def read_source_file(parent, target)
36
+ docfile_directory = File.dirname(
37
+ parent.document.attributes["docfile"] || ".",
38
+ )
39
+
40
+ resolved_path = parent.document
41
+ .path_resolver
42
+ .system_path(target, docfile_directory)
43
+
44
+ File.read(resolved_path, encoding: "UTF-8")
45
+ end
46
+
37
47
  def add_image_path_to_includedirs(document, image_path, includedirs)
38
48
  docdir = document.attributes["docdir"]
39
49
  includedirs << File.dirname(
@@ -42,16 +52,15 @@ module Metanorma
42
52
  includedirs.compact.uniq
43
53
  end
44
54
 
45
- def parse_options(parent, reader, attrs) # rubocop:disable Metrics/AbcSize
55
+ def parse_options(parent, target, attrs) # rubocop:disable Metrics/AbcSize
46
56
  options = {}
47
57
 
48
- # Parse include directory
49
58
  options[:includedirs] = parse_doc_includedirs(parent.document)
50
59
  options[:includedirs] = add_attrs_to_includedirs(
51
60
  parent.document, attrs, options[:includedirs]
52
61
  )
53
62
  options[:includedirs] = add_image_path_to_includedirs(
54
- parent.document, reader, options[:includedirs]
63
+ parent.document, target, options[:includedirs]
55
64
  )
56
65
 
57
66
  if attrs["layout"]
@@ -3,7 +3,7 @@
3
3
  module Metanorma
4
4
  module Plugin
5
5
  module Plantuml
6
- VERSION = "1.0.14"
6
+ VERSION = "1.0.15"
7
7
  PLANTUML_JAR_VERSION = "1.2026.3"
8
8
  end
9
9
  end
@@ -67,7 +67,6 @@ module Metanorma
67
67
  output, _, status = Open3.capture3(*cmd)
68
68
 
69
69
  if status.success?
70
- # Extract version from output
71
70
  version_match = output.match(/PlantUML version ([\d.]+)/)
72
71
  version_match ? version_match[1] : PLANTUML_JAR_VERSION
73
72
  end
@@ -141,24 +140,16 @@ module Metanorma
141
140
  end
142
141
 
143
142
  def execute_plantuml(content, format, output_file, options) # rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity, Metrics/AbcSize, Metrics/MethodLength
144
- # PlantUML generates output files based on filename specified in
145
- # @start... line
146
- # We need to use a temp directory and then move the file
147
143
  Dir.mktmpdir do |temp_dir| # rubocop:disable Metrics/BlockLength
148
- # create input file
149
144
  File.write("#{temp_dir}/plantuml_input.puml", content)
150
145
 
151
- # Handle include files
152
146
  if options[:include_files] && !options[:include_files].empty?
153
147
  if options[:includedirs].empty?
154
- # raise error when include files are found but includedirs
155
- # is nil
156
148
  raise PlantumlError,
157
149
  "includedirs is required when include files are specified"
158
150
  end
159
151
 
160
152
  options[:include_files].each do |include_file|
161
- # find local include file in includedirs
162
153
  found_include_file = nil
163
154
  options[:includedirs].each do |includedir|
164
155
  include_file_path = Pathname.new(includedir)
@@ -172,7 +163,6 @@ module Metanorma
172
163
 
173
164
  next unless found_include_file
174
165
 
175
- # create include file in temp directory
176
166
  temp_include_file = Pathname.new(temp_dir)
177
167
  .join(include_file).to_s
178
168
 
@@ -202,14 +192,12 @@ module Metanorma
202
192
  raise GenerationError.new(error_message, error)
203
193
  end
204
194
 
205
- # Find the generated file and move it to the desired location
206
195
  if output_file
207
196
  generated_file = find_generated_file(temp_dir, content,
208
197
  format)
209
198
  if generated_file && File.exist?(generated_file)
210
199
  FileUtils.mv(generated_file, output_file)
211
200
  else
212
- # Debug: List what files were actually generated
213
201
  generated_files = Dir.glob(File.join(temp_dir, "*"))
214
202
  error_msg = "Generated file not found in temp directory. "
215
203
  error_msg += "Expected: #{generated_file}. "
@@ -225,37 +213,19 @@ module Metanorma
225
213
  end
226
214
 
227
215
  def find_generated_file(temp_dir, content, format)
228
- # PlantUML generates files based on the filename specified in
229
- # @start... line
230
216
  extension = format.to_s.downcase
231
217
 
232
- # First, try to extract filename from PlantUML content
233
- plantuml_filename = extract_plantuml_filename_from_content(content)
218
+ plantuml_filename = FilenameResolver.extract(content)
234
219
 
235
220
  if plantuml_filename
236
- # Look for file with PlantUML-specified name
237
221
  generated_file = File.join(temp_dir,
238
222
  "#{plantuml_filename}.#{extension}")
239
223
  return generated_file if File.exist?(generated_file)
240
224
  end
241
225
 
242
- # Fallback: scan directory for any generated files with
243
- # the correct extension
244
226
  Dir.glob(File.join(temp_dir, "*.#{extension}")).first
245
227
  end
246
228
 
247
- def extract_plantuml_filename_from_content(content)
248
- # Extract the raw filename from @start... line (don't sanitize)
249
- match = content.match(/^@start\w+\s+(.{1,999})$/mi)
250
- return nil unless match
251
-
252
- filename = match[1].strip.split("\n").first&.strip
253
- return nil if filename.nil? || filename.empty?
254
-
255
- # Remove quotes but keep the original name as PlantUML will use it
256
- filename.gsub(/^["']|["']$/, "")
257
- end
258
-
259
229
  def build_command(input_file, format, output_dir, options) # rubocop:disable Metrics/MethodLength,Metrics/AbcSize
260
230
  cmd = [
261
231
  configuration.java_path,
@@ -263,21 +233,14 @@ module Metanorma
263
233
  "-jar", PLANTUML_JAR_PATH
264
234
  ]
265
235
 
266
- # Add format-specific options
267
236
  format_str = format.to_s.downcase
268
237
  cmd << "-t#{format_str}" if SUPPORTED_FORMATS.include?(format_str)
269
238
 
270
- # Use 'smetana' layout engine for pragma
271
239
  layout = options[:layout] || "smetana"
272
240
  cmd << "-Playout=#{layout}"
273
241
 
274
- # Add output directory option
275
242
  cmd << "-o" << output_dir
276
-
277
- # Add charset option for better compatibility
278
243
  cmd << "-charset" << "UTF-8"
279
-
280
- # Add input file
281
244
  cmd << input_file
282
245
 
283
246
  cmd
@@ -27,6 +27,8 @@ module Metanorma
27
27
  "metanorma/plugin/plantuml/invalid_format_error"
28
28
  autoload :Config, "metanorma/plugin/plantuml/config"
29
29
  autoload :Utils, "metanorma/plugin/plantuml/utils"
30
+ autoload :FilenameResolver,
31
+ "metanorma/plugin/plantuml/filename_resolver"
30
32
  autoload :Wrapper, "metanorma/plugin/plantuml/wrapper"
31
33
  autoload :Backend, "metanorma/plugin/plantuml/backend"
32
34
  autoload :BlockProcessorBase,
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: metanorma-plugin-plantuml
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.14
4
+ version: 1.0.15
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ribose Inc.
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2026-05-11 00:00:00.000000000 Z
11
+ date: 2026-05-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: asciidoctor
@@ -49,6 +49,7 @@ files:
49
49
  - lib/metanorma/plugin/plantuml/block_processor.rb
50
50
  - lib/metanorma/plugin/plantuml/block_processor_base.rb
51
51
  - lib/metanorma/plugin/plantuml/config.rb
52
+ - lib/metanorma/plugin/plantuml/filename_resolver.rb
52
53
  - lib/metanorma/plugin/plantuml/generation_error.rb
53
54
  - lib/metanorma/plugin/plantuml/image_block_macro_processor.rb
54
55
  - lib/metanorma/plugin/plantuml/invalid_format_error.rb