kramdown-plantuml 1.1.2 → 1.1.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/mergify.yml +1 -0
- data/.github/scripts/build-gem.sh +70 -3
- data/.github/scripts/test-gem.sh +57 -12
- data/.github/workflows/ruby.yml +55 -9
- data/README.md +17 -0
- data/Rakefile +1 -1
- data/bin/net/sourceforge/plantuml/plantuml/{1.2021.8/plantuml-1.2021.8.jar → 1.2021.12/plantuml-1.2021.12.jar} +0 -0
- data/kramdown-plantuml.gemspec +1 -1
- data/lib/kramdown-plantuml/diagram.rb +61 -0
- data/lib/kramdown-plantuml/executor.rb +33 -19
- data/lib/kramdown-plantuml/jekyll_provider.rb +97 -0
- data/lib/kramdown-plantuml/{logger.rb → log_wrapper.rb} +30 -20
- data/lib/kramdown-plantuml/options.rb +91 -0
- data/lib/kramdown-plantuml/plantuml_error.rb +51 -14
- data/lib/kramdown-plantuml/plantuml_result.rb +25 -9
- data/lib/kramdown-plantuml/theme.rb +56 -0
- data/lib/kramdown-plantuml/version.rb +1 -1
- data/lib/{which.rb → kramdown-plantuml/which.rb} +2 -1
- data/lib/kramdown-plantuml.rb +3 -2
- data/lib/kramdown_html.rb +27 -7
- data/pom.xml +1 -1
- metadata +9 -8
- data/lib/kramdown-plantuml/converter.rb +0 -52
- data/lib/kramdown-plantuml/hash.rb +0 -14
- data/lib/kramdown-plantuml/themer.rb +0 -64
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2ad198f4e3e4e733d4e12d7e4281131c5ececd42896a0d14bd5815b6a06c5b7a
|
4
|
+
data.tar.gz: d2e558280a863d76b9554845ea31c52d37db234648cd1e2f9dae4fab22f8220f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a7258a0fcf799cbfd27088342d6030a25115118bda6b2c3d188984200d91821df537ab3f863470e497e9331165e06a88dd538650a41177972bb79bde02bb0704
|
7
|
+
data.tar.gz: 774cf7d37cf2968225a0889118e8cafb3f7234ce0caf26b3a969f088418d2c3ba3ce7438b54dfbab3209c81295756c9c1c5f260f5c96ce75f1e8aacc2ebf0c28
|
data/.github/mergify.yml
CHANGED
@@ -1,6 +1,73 @@
|
|
1
1
|
#!/usr/bin/env bash
|
2
2
|
set -o errexit # Abort if any command fails
|
3
3
|
|
4
|
-
|
5
|
-
|
6
|
-
|
4
|
+
me=$(basename "$0")
|
5
|
+
help_message="\
|
6
|
+
Usage:
|
7
|
+
${me} [--ref <ref>] [--verbose]
|
8
|
+
${me} --help
|
9
|
+
Arguments:
|
10
|
+
-r, --ref The Git reference that is being built.
|
11
|
+
-h, --help Displays this help screen.
|
12
|
+
-v, --verbose Increase verbosity. Useful for debugging."
|
13
|
+
|
14
|
+
parse_args() {
|
15
|
+
while : ; do
|
16
|
+
if [[ $1 = "-h" || $1 = "--help" ]]; then
|
17
|
+
echo "${help_message}"
|
18
|
+
return 0
|
19
|
+
elif [[ $1 = "-v" || $1 = "--verbose" ]]; then
|
20
|
+
verbose=true
|
21
|
+
shift
|
22
|
+
elif [[ $1 = "-r" || $1 = "--ref" ]]; then
|
23
|
+
ref=${2// }
|
24
|
+
|
25
|
+
if [[ "${ref}" = "--"* ]]; then
|
26
|
+
ref=""
|
27
|
+
shift 1
|
28
|
+
else
|
29
|
+
shift 2
|
30
|
+
fi
|
31
|
+
else
|
32
|
+
break
|
33
|
+
fi
|
34
|
+
done
|
35
|
+
}
|
36
|
+
|
37
|
+
# Echo expanded commands as they are executed (for debugging)
|
38
|
+
enable_expanded_output() {
|
39
|
+
if [ "${verbose}" = true ]; then
|
40
|
+
set -o xtrace
|
41
|
+
set +o verbose
|
42
|
+
export VERBOSE=true
|
43
|
+
fi
|
44
|
+
}
|
45
|
+
|
46
|
+
add_coverage() {
|
47
|
+
# If we're not building a tag, bootstrap code coverage.
|
48
|
+
if [[ "${ref}" != "refs/tags/"* ]]; then
|
49
|
+
[[ "${verbose}" = true ]] && echo "Bootstrapping code coverage."
|
50
|
+
export COVER=true
|
51
|
+
export COVERAGE=true
|
52
|
+
printf "require 'simplecov'\nSimpleCov.start\n" >> lib/kramdown-plantuml.rb
|
53
|
+
elif [[ "${verbose}" = true ]]; then
|
54
|
+
echo "Skipping coverage report since a tag ref was pushed."
|
55
|
+
fi
|
56
|
+
}
|
57
|
+
|
58
|
+
build_gem() {
|
59
|
+
gem_build_name=$(gem build kramdown-plantuml.gemspec | awk '/File/ {print $2}')
|
60
|
+
|
61
|
+
[[ "${verbose}" = true ]] && echo "Gem filename: '${gem_build_name}'"
|
62
|
+
|
63
|
+
echo "::set-output name=name::${gem_build_name}"
|
64
|
+
}
|
65
|
+
|
66
|
+
main() {
|
67
|
+
parse_args "$@"
|
68
|
+
enable_expanded_output
|
69
|
+
add_coverage
|
70
|
+
build_gem
|
71
|
+
}
|
72
|
+
|
73
|
+
main "$@"
|
data/.github/scripts/test-gem.sh
CHANGED
@@ -6,7 +6,7 @@ me=$(basename "$0")
|
|
6
6
|
|
7
7
|
help_message="\
|
8
8
|
Usage:
|
9
|
-
${me} --workdir <workdir> [--gemdir <gemdir> | --version <version> --token <token>] [--verbose]
|
9
|
+
${me} --workdir <workdir> [--gemdir <gemdir> | --version <version> --token <token>] [--verbose] [--theme <name> [--theme-directory <path>]]
|
10
10
|
${me} --help
|
11
11
|
Arguments:
|
12
12
|
-w, --workdir <workdir> The path to the working directory.
|
@@ -14,6 +14,8 @@ Arguments:
|
|
14
14
|
-v, --version <version> The version of the Gem to test.
|
15
15
|
-t, --token <token> The GitHub token to use for retrieving the gem
|
16
16
|
from the GitHub Package Registry.
|
17
|
+
-T, --theme-name <name> The theme name to use for the test.
|
18
|
+
-p, --theme-directory <path> The directory in which the [--theme-name] is placed.
|
17
19
|
-h, --help Displays this help screen.
|
18
20
|
-v, --verbose Increase verbosity. Useful for debugging."
|
19
21
|
|
@@ -52,6 +54,24 @@ parse_args() {
|
|
52
54
|
else
|
53
55
|
shift 2
|
54
56
|
fi
|
57
|
+
elif [[ $1 = "-T" || $1 = "--theme-name" ]]; then
|
58
|
+
theme_name=${2// }
|
59
|
+
|
60
|
+
if [[ "${theme_name}" = "--"* ]]; then
|
61
|
+
theme_name=""
|
62
|
+
shift 1
|
63
|
+
else
|
64
|
+
shift 2
|
65
|
+
fi
|
66
|
+
elif [[ $1 = "-p" || $1 = "--theme-directory" ]]; then
|
67
|
+
theme_directory=${2// }
|
68
|
+
|
69
|
+
if [[ "${theme_directory}" = "--"* ]]; then
|
70
|
+
theme_directory=""
|
71
|
+
shift 1
|
72
|
+
else
|
73
|
+
shift 2
|
74
|
+
fi
|
55
75
|
elif [[ $1 = "-w" || $1 = "--workdir" ]]; then
|
56
76
|
workdir=${2// }
|
57
77
|
|
@@ -67,22 +87,29 @@ parse_args() {
|
|
67
87
|
done
|
68
88
|
|
69
89
|
if [[ -z "${workdir}" ]]; then
|
70
|
-
echo "Missing required argument: --workdir <workdir>."
|
71
|
-
echo "${help_message}"
|
90
|
+
echo "Missing required argument: --workdir <workdir>." >&2
|
91
|
+
echo "${help_message}" >&2
|
72
92
|
return 1
|
73
93
|
fi
|
74
94
|
|
75
95
|
if [[ (-z "${gemdir}" && -z "${token}") || (-n "${gemdir}" && -n "${token}") ]]; then
|
76
|
-
echo "Missing or invalid required arguments: --gemdir <gem-path> or --token <token>."
|
77
|
-
echo "Either [--gemdir] or [--token] needs to be provided, but not both."
|
96
|
+
echo "Missing or invalid required arguments: --gemdir <gem-path> or --token <token>." >&2
|
97
|
+
echo "Either [--gemdir] or [--token] needs to be provided, but not both." >&2
|
78
98
|
echo "${help_message}"
|
79
99
|
return 1
|
80
100
|
fi
|
81
101
|
|
82
102
|
if [[ (-n "${version}" && -z "${token}") || (-z "${version}" && -n "${token}") ]]; then
|
83
|
-
echo "Missing or invalid required arguments: --version <gem-path> and --token <token>."
|
84
|
-
echo "When either argument is present, both must be."
|
85
|
-
echo "${help_message}"
|
103
|
+
echo "Missing or invalid required arguments: --version <gem-path> and --token <token>." >&2
|
104
|
+
echo "When either argument is present, both must be." >&2
|
105
|
+
echo "${help_message}" >&2
|
106
|
+
return 1
|
107
|
+
fi
|
108
|
+
|
109
|
+
if [[ -z "${theme_name}" && -n "${theme_directory}" ]]; then
|
110
|
+
echo "Missing or invalid required arguments: --theme-name <name>." >&2
|
111
|
+
echo "[--theme-name] is required when [--theme-directory] is provided." >&2
|
112
|
+
echo "${help_message}" >&2
|
86
113
|
return 1
|
87
114
|
fi
|
88
115
|
}
|
@@ -101,19 +128,37 @@ test_gem() {
|
|
101
128
|
|
102
129
|
cd "${workdir}"
|
103
130
|
|
104
|
-
|
131
|
+
# Recreate Gemfile
|
132
|
+
printf "# frozen_string_literal: true\nsource 'https://rubygems.org'\ngem 'jekyll'\ngem 'simplecov'\n" > Gemfile
|
105
133
|
|
106
134
|
if [[ -n "${token}" ]]; then
|
107
135
|
# A non-empty $token means we should install the Gem from GPR
|
108
136
|
repository="https://rubygems.pkg.github.com/swedbankpay"
|
109
137
|
bundle config "${repository}" "SwedbankPay:${token}"
|
110
|
-
printf "source '%s' do\n\tgem 'kramdown-plantuml', '%s'\nend" "${repository}" "${version}" >> Gemfile
|
138
|
+
printf "source '%s' do\n\tgem 'kramdown-plantuml', '%s'\nend\n" "${repository}" "${version}" >> Gemfile
|
139
|
+
else
|
140
|
+
printf "gem 'kramdown-plantuml', path: '%s'\n" "${gemdir}" >> Gemfile
|
141
|
+
fi
|
142
|
+
|
143
|
+
# Recreate _config.yml
|
144
|
+
printf "plugins:\n- kramdown-plantuml\n" > _config.yml
|
145
|
+
|
146
|
+
if [[ -n "${theme_name}" ]]; then
|
147
|
+
printf "kramdown:\n plantuml:\n theme:\n name: %s\n" "${theme_name}" >> _config.yml
|
148
|
+
class="plantuml theme-${theme_name}"
|
111
149
|
else
|
112
|
-
|
150
|
+
class='plantuml'
|
151
|
+
fi
|
152
|
+
|
153
|
+
if [[ -n "${theme_directory}" ]]; then
|
154
|
+
printf " directory: %s\n" "${theme_directory}" >> _config.yml
|
113
155
|
fi
|
114
156
|
|
115
157
|
if [[ "${verbose}" = true ]]; then
|
158
|
+
printf "\nGemfile:\n"
|
116
159
|
cat Gemfile
|
160
|
+
printf "\n_config.yml\n"
|
161
|
+
cat _config.yml
|
117
162
|
jekyll_build_args+=(--verbose)
|
118
163
|
fi
|
119
164
|
|
@@ -122,7 +167,7 @@ test_gem() {
|
|
122
167
|
|
123
168
|
file="${workdir}/_site/index.html"
|
124
169
|
|
125
|
-
file_contains "${file}" "class=\"
|
170
|
+
file_contains "${file}" "class=\"${class}\""
|
126
171
|
file_contains "${file}" "<svg"
|
127
172
|
file_contains "${file}" "<ellipse"
|
128
173
|
file_contains "${file}" "<polygon"
|
data/.github/workflows/ruby.yml
CHANGED
@@ -91,20 +91,51 @@ jobs:
|
|
91
91
|
- name: rubocop
|
92
92
|
run: bundle exec rubocop --fail-level warning --display-only-fail-level-offenses
|
93
93
|
|
94
|
-
- name: Test with Rake
|
95
|
-
run: bundle exec rake
|
96
|
-
|
97
94
|
- name: RSPec (debug)
|
98
95
|
env:
|
99
96
|
DEBUG: 1
|
100
|
-
run: bundle exec rspec --tag debug
|
97
|
+
run: bundle exec rspec --format documentation --tag debug
|
98
|
+
|
99
|
+
- name: Upload code coverage (debug)
|
100
|
+
uses: actions/upload-artifact@v2
|
101
|
+
with:
|
102
|
+
name: rspec-debug-coverage
|
103
|
+
path: ./coverage
|
104
|
+
|
105
|
+
- name: Codecov upload (debug)
|
106
|
+
run: bundle exec rake codecov:upload || echo 'Codecov upload failed'
|
107
|
+
|
108
|
+
- name: Test with Rake
|
109
|
+
run: bundle exec rake
|
110
|
+
|
111
|
+
- name: Upload code coverage
|
112
|
+
uses: actions/upload-artifact@v2
|
113
|
+
with:
|
114
|
+
name: rspec-coverage
|
115
|
+
path: ./coverage
|
101
116
|
|
102
117
|
- name: Codecov upload
|
103
118
|
run: bundle exec rake codecov:upload || echo 'Codecov upload failed'
|
104
119
|
|
120
|
+
- name: RSPec (Jekyll)
|
121
|
+
run: |
|
122
|
+
echo "gem 'jekyll', require: false, group: :test" >> Gemfile
|
123
|
+
bundle install
|
124
|
+
bundle exec rspec --format documentation --tag jekyll
|
125
|
+
git checkout HEAD -- Gemfile
|
126
|
+
|
127
|
+
- name: Upload code coverage (Jekyll)
|
128
|
+
uses: actions/upload-artifact@v2
|
129
|
+
with:
|
130
|
+
name: rspec-jekyll-coverage
|
131
|
+
path: ./coverage
|
132
|
+
|
133
|
+
- name: Codecov upload (Jekyll)
|
134
|
+
run: bundle exec rake codecov:upload || echo 'Codecov upload failed'
|
135
|
+
|
105
136
|
- name: Build gem
|
106
137
|
id: gem
|
107
|
-
run: .github/scripts/build-gem.sh
|
138
|
+
run: .github/scripts/build-gem.sh --ref ${{ github.ref }} --verbose
|
108
139
|
|
109
140
|
- name: Upload gem
|
110
141
|
uses: actions/upload-artifact@v2-preview
|
@@ -116,7 +147,16 @@ jobs:
|
|
116
147
|
run: .github/scripts/inspect-gem.sh --gem "${{ github.workspace }}/${{ steps.gem.outputs.name }}" --verbose
|
117
148
|
|
118
149
|
- name: Test gem
|
119
|
-
run: .github/scripts/test-gem.sh --workdir "${{ github.workspace }}/spec/
|
150
|
+
run: .github/scripts/test-gem.sh --workdir "${{ github.workspace }}/spec/examples" --gemdir "${{ github.workspace }}" --verbose
|
151
|
+
|
152
|
+
- name: Upload code coverage (gem)
|
153
|
+
uses: actions/upload-artifact@v2
|
154
|
+
with:
|
155
|
+
name: gem-coverage
|
156
|
+
path: ./coverage
|
157
|
+
|
158
|
+
- name: Codecov upload (gem)
|
159
|
+
run: bundle exec rake codecov:upload || echo 'Codecov upload failed'
|
120
160
|
|
121
161
|
publish-dev:
|
122
162
|
needs: [version, gem]
|
@@ -150,15 +190,21 @@ jobs:
|
|
150
190
|
- name: Publish to GPR
|
151
191
|
run: .github/scripts/publish-gem.sh --gem ${{ needs.gem.outputs.name }} --token "${{ secrets.GPR_TOKEN }}" --owner SwedbankPay --verbose
|
152
192
|
|
153
|
-
- name: Test gem
|
154
|
-
run: .github/scripts/test-gem.sh --workdir "${{ github.workspace }}/spec/
|
193
|
+
- name: Test gem (no theme)
|
194
|
+
run: .github/scripts/test-gem.sh --workdir "${{ github.workspace }}/spec/examples" --version ${{ needs.version.outputs.version }} --token "${{ secrets.GPR_TOKEN }}" --verbose
|
195
|
+
|
196
|
+
- name: Test gem (built-in theme)
|
197
|
+
run: .github/scripts/test-gem.sh --workdir "${{ github.workspace }}/spec/examples" --version ${{ needs.version.outputs.version }} --token "${{ secrets.GPR_TOKEN }}" --verbose --theme-name spacelab
|
198
|
+
|
199
|
+
- name: Test gem (custom theme)
|
200
|
+
run: .github/scripts/test-gem.sh --workdir "${{ github.workspace }}/spec/examples" --version ${{ needs.version.outputs.version }} --token "${{ secrets.GPR_TOKEN }}" --verbose --theme-name c2a3b0 --theme-directory "${{ github.workspace }}/spec/examples"
|
155
201
|
|
156
202
|
- name: Upload Jekyll site
|
157
203
|
uses: actions/upload-artifact@v2-preview
|
158
204
|
if: always()
|
159
205
|
with:
|
160
206
|
name: site
|
161
|
-
path: ${{ github.workspace }}/spec/
|
207
|
+
path: ${{ github.workspace }}/spec/examples/_site
|
162
208
|
|
163
209
|
publish-prod:
|
164
210
|
needs: [version, gem]
|
data/README.md
CHANGED
@@ -6,6 +6,7 @@
|
|
6
6
|
[![No PlantUML][no-plantuml-badge]][no-plantuml-workflow]
|
7
7
|
[![Shell][shell-badge]][shell-workflow]
|
8
8
|
[![Codecov][codecov-badge]][codecov]
|
9
|
+
[![Codacy Badge][codacy-badge]][codacy]
|
9
10
|
[![License][license-badge]][license]
|
10
11
|
[![CLA assistant][cla-badge]][cla]
|
11
12
|
[![Contributor Covenant][coc-badge]][coc]
|
@@ -129,6 +130,20 @@ kramdown:
|
|
129
130
|
directory: path/to/themes
|
130
131
|
```
|
131
132
|
|
133
|
+
### Errors
|
134
|
+
|
135
|
+
By default, `kramdown-plantuml` will raise an error and crash if something goes
|
136
|
+
wrong during processing. This can be circumvented by setting the `raise_errors`
|
137
|
+
configuration key to `false`:
|
138
|
+
|
139
|
+
```yaml
|
140
|
+
kramdown:
|
141
|
+
plantuml:
|
142
|
+
raise_errors: false
|
143
|
+
```
|
144
|
+
|
145
|
+
The default value of `raise_errors` is `true`.
|
146
|
+
|
132
147
|
## Contributing
|
133
148
|
|
134
149
|
Bug reports and pull requests are welcome on [GitHub][github]. This project is
|
@@ -180,6 +195,8 @@ agreement][cla].
|
|
180
195
|
[clone]: https://docs.github.com/en/free-pro-team@latest/github/creating-cloning-and-archiving-repositories/cloning-a-repository
|
181
196
|
[coc-badge]: https://img.shields.io/badge/Contributor%20Covenant-v2.0%20adopted-ff69b4.svg
|
182
197
|
[coc]: ./CODE_OF_CONDUCT.md
|
198
|
+
[codacy-badge]: https://app.codacy.com/project/badge/Grade/de72385f4ca444c18819a3ce8a506638
|
199
|
+
[codacy]: https://www.codacy.com/gh/SwedbankPay/kramdown-plantuml/dashboard?utm_source=github.com&utm_medium=referral&utm_content=SwedbankPay/kramdown-plantuml&utm_campaign=Badge_Grade
|
183
200
|
[codecov-badge]: https://codecov.io/gh/SwedbankPay/kramdown-plantuml/branch/main/graph/badge.svg?token=U3QJLVG3HY
|
184
201
|
[codecov]: https://codecov.io/gh/SwedbankPay/kramdown-plantuml/
|
185
202
|
[diagram-svg]: ./spec/examples/diagram.svg
|
data/Rakefile
CHANGED
@@ -6,7 +6,7 @@ require 'rspec/core/rake_task'
|
|
6
6
|
|
7
7
|
RSpec::Core::RakeTask.new(:spec) do |t|
|
8
8
|
t.pattern = Dir.glob('spec/**/*_spec.rb')
|
9
|
-
t.rspec_opts = '--format documentation --tag ~no_plantuml --tag ~no_java --tag ~debug'
|
9
|
+
t.rspec_opts = '--format documentation --tag ~no_plantuml --tag ~no_java --tag ~debug --tag ~jekyll'
|
10
10
|
end
|
11
11
|
|
12
12
|
namespace :maven do
|
Binary file
|
data/kramdown-plantuml.gemspec
CHANGED
@@ -0,0 +1,61 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'version'
|
4
|
+
require_relative 'theme'
|
5
|
+
require_relative 'options'
|
6
|
+
require_relative 'plantuml_error'
|
7
|
+
require_relative 'log_wrapper'
|
8
|
+
require_relative 'executor'
|
9
|
+
|
10
|
+
module Kramdown
|
11
|
+
module PlantUml
|
12
|
+
# Represents a PlantUML diagram that can be converted to SVG.
|
13
|
+
class Diagram
|
14
|
+
attr_reader :theme, :plantuml, :result
|
15
|
+
|
16
|
+
def initialize(plantuml, options)
|
17
|
+
raise ArgumentError, 'options cannot be nil' if options.nil?
|
18
|
+
raise ArgumentError, "options must be a '#{Options}'." unless options.is_a?(Options)
|
19
|
+
|
20
|
+
@plantuml = plantuml
|
21
|
+
@options = options
|
22
|
+
@theme = Theme.new(options)
|
23
|
+
@logger = LogWrapper.init
|
24
|
+
@executor = Executor.new
|
25
|
+
@logger.warn 'PlantUML diagram is empty' if @plantuml.nil? || @plantuml.empty?
|
26
|
+
end
|
27
|
+
|
28
|
+
def convert_to_svg
|
29
|
+
return @svg unless @svg.nil?
|
30
|
+
return @plantuml if @plantuml.nil? || @plantuml.empty?
|
31
|
+
|
32
|
+
@plantuml = @theme.apply(@plantuml)
|
33
|
+
log(plantuml)
|
34
|
+
@result = @executor.execute(self)
|
35
|
+
@result.validate
|
36
|
+
@svg = wrap(@result.without_xml_prologue)
|
37
|
+
rescue StandardError => e
|
38
|
+
raise e if @options.raise_errors?
|
39
|
+
|
40
|
+
@logger.error e.to_s
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
|
45
|
+
def wrap(svg)
|
46
|
+
theme_class = @theme.name ? "theme-#{@theme.name}" : ''
|
47
|
+
class_name = "plantuml #{theme_class}".strip
|
48
|
+
|
49
|
+
wrapper_element_start = "<div class=\"#{class_name}\">"
|
50
|
+
wrapper_element_end = '</div>'
|
51
|
+
|
52
|
+
"#{wrapper_element_start}#{svg}#{wrapper_element_end}"
|
53
|
+
end
|
54
|
+
|
55
|
+
def log(plantuml)
|
56
|
+
@logger.debug 'PlantUML converting diagram:'
|
57
|
+
@logger.debug_multiline plantuml
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -1,8 +1,8 @@
|
|
1
|
-
# frozen_string_literal:
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'open3'
|
4
|
-
require_relative '
|
5
|
-
require_relative '
|
4
|
+
require_relative 'which'
|
5
|
+
require_relative 'log_wrapper'
|
6
6
|
require_relative 'plantuml_result'
|
7
7
|
|
8
8
|
module Kramdown
|
@@ -10,38 +10,52 @@ module Kramdown
|
|
10
10
|
# Executes the PlantUML Java application.
|
11
11
|
class Executor
|
12
12
|
def initialize
|
13
|
-
@logger =
|
13
|
+
@logger = LogWrapper.init
|
14
|
+
|
15
|
+
java_location = Which.which('java')
|
16
|
+
|
17
|
+
raise IOError, 'Java can not be found' if java_location.nil?
|
18
|
+
|
19
|
+
@logger.debug "Java found: #{java_location}"
|
14
20
|
@plantuml_jar_file = find_plantuml_jar_file
|
15
21
|
|
16
|
-
raise IOError, 'Java can not be found' unless Which.which('java')
|
17
|
-
raise IOError, "No 'plantuml.jar' file could be found" if @plantuml_jar_file.nil?
|
18
22
|
raise IOError, "'#{@plantuml_jar_file}' does not exist" unless File.exist? @plantuml_jar_file
|
23
|
+
|
24
|
+
@logger.debug "plantuml.jar found: #{@plantuml_jar_file}"
|
19
25
|
end
|
20
26
|
|
21
|
-
def execute(
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
' -nometadata'
|
27
|
-
end
|
27
|
+
def execute(diagram)
|
28
|
+
raise ArgumentError, 'diagram cannot be nil' if diagram.nil?
|
29
|
+
raise ArgumentError, "diagram must be a #{Diagram}" unless diagram.is_a?(Diagram)
|
30
|
+
|
31
|
+
cmd = "java -Djava.awt.headless=true -jar #{@plantuml_jar_file} -tsvg -failfast -pipe #{debug_args}"
|
28
32
|
|
29
|
-
@logger.debug "
|
33
|
+
@logger.debug "Executing '#{cmd}'."
|
30
34
|
|
31
|
-
stdout, stderr, status = Open3.capture3 cmd, stdin_data:
|
35
|
+
stdout, stderr, status = Open3.capture3 cmd, stdin_data: diagram.plantuml
|
32
36
|
|
33
|
-
@logger.debug "
|
37
|
+
@logger.debug "PlantUML exit code '#{status.exitstatus}'."
|
34
38
|
|
35
|
-
PlantUmlResult.new(stdout, stderr, status)
|
39
|
+
PlantUmlResult.new(diagram, stdout, stderr, status.exitstatus)
|
36
40
|
end
|
37
41
|
|
38
42
|
private
|
39
43
|
|
40
44
|
def find_plantuml_jar_file
|
41
45
|
dir = File.dirname __dir__
|
42
|
-
|
46
|
+
bin_dir = File.expand_path File.join dir, '../bin'
|
47
|
+
jar_glob = File.join bin_dir, '/**/plantuml*.jar'
|
43
48
|
first_jar = Dir[jar_glob].first
|
44
|
-
|
49
|
+
|
50
|
+
raise IOError, "No 'plantuml.jar' file could be found within the '#{bin_dir}' directory." if first_jar.nil?
|
51
|
+
|
52
|
+
File.expand_path first_jar
|
53
|
+
end
|
54
|
+
|
55
|
+
def debug_args
|
56
|
+
return ' -verbose' if @logger.debug?
|
57
|
+
|
58
|
+
' -nometadata'
|
45
59
|
end
|
46
60
|
end
|
47
61
|
end
|
@@ -0,0 +1,97 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'json'
|
4
|
+
require 'English'
|
5
|
+
require 'rexml/document'
|
6
|
+
require_relative 'log_wrapper'
|
7
|
+
require_relative 'diagram'
|
8
|
+
|
9
|
+
module Kramdown
|
10
|
+
module PlantUml
|
11
|
+
# Provides an instance of Jekyll if available.
|
12
|
+
module JekyllProvider
|
13
|
+
class << self
|
14
|
+
def jekyll
|
15
|
+
return @jekyll if defined? @jekyll
|
16
|
+
|
17
|
+
@jekyll = load_jekyll
|
18
|
+
end
|
19
|
+
|
20
|
+
def install
|
21
|
+
return @installed = false if jekyll.nil?
|
22
|
+
|
23
|
+
logger.debug 'Jekyll detected, hooking into :site:post_render'
|
24
|
+
|
25
|
+
Jekyll::Hooks.register :site, :post_render do |site|
|
26
|
+
logger.debug ':site:post_render triggered.'
|
27
|
+
|
28
|
+
site.pages.each do |page|
|
29
|
+
page.output = replace_needles(page.output)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
@installed = true
|
34
|
+
end
|
35
|
+
|
36
|
+
def installed?
|
37
|
+
@installed
|
38
|
+
end
|
39
|
+
|
40
|
+
def needle(plantuml, options)
|
41
|
+
hash = { 'plantuml' => plantuml, 'options' => options.to_h }
|
42
|
+
|
43
|
+
<<~NEEDLE
|
44
|
+
<!--#kramdown-plantuml.start#-->
|
45
|
+
#{hash.to_json}
|
46
|
+
<!--#kramdown-plantuml.end#-->
|
47
|
+
NEEDLE
|
48
|
+
rescue StandardError => e
|
49
|
+
raise e if options.raise_errors?
|
50
|
+
|
51
|
+
puts e
|
52
|
+
logger.error 'Error while placing needle.'
|
53
|
+
logger.error e.to_s
|
54
|
+
logger.debug_multiline plantuml
|
55
|
+
end
|
56
|
+
|
57
|
+
private
|
58
|
+
|
59
|
+
def replace_needles(html)
|
60
|
+
html.gsub(/<!--#kramdown-plantuml\.start#-->(?<json>.*?)<!--#kramdown-plantuml\.end#-->/m) do
|
61
|
+
json = $LAST_MATCH_INFO[:json]
|
62
|
+
return replace_needle(json)
|
63
|
+
rescue StandardError => e
|
64
|
+
raise e if options.raise_errors?
|
65
|
+
|
66
|
+
logger.error "Error while replacing needle: #{e.inspect}"
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def replace_needle(json)
|
71
|
+
hash = JSON.parse(json)
|
72
|
+
encoded_plantuml = hash['plantuml']
|
73
|
+
plantuml = decode_html_entities(encoded_plantuml)
|
74
|
+
options = ::Kramdown::PlantUml::Options.new({ plantuml: hash['options'] })
|
75
|
+
diagram = ::Kramdown::PlantUml::Diagram.new(plantuml, options)
|
76
|
+
diagram.convert_to_svg
|
77
|
+
end
|
78
|
+
|
79
|
+
def decode_html_entities(encoded_plantuml)
|
80
|
+
doc = REXML::Document.new "<plantuml>#{encoded_plantuml}</plantuml>"
|
81
|
+
doc.root.text
|
82
|
+
end
|
83
|
+
|
84
|
+
def load_jekyll
|
85
|
+
require 'jekyll'
|
86
|
+
::Jekyll
|
87
|
+
rescue LoadError
|
88
|
+
nil
|
89
|
+
end
|
90
|
+
|
91
|
+
def logger
|
92
|
+
@logger ||= ::Kramdown::PlantUml::LogWrapper.init
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
@@ -1,11 +1,12 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require_relative 'console_logger'
|
4
|
+
require_relative 'jekyll_provider'
|
4
5
|
|
5
6
|
module Kramdown
|
6
7
|
module PlantUml
|
7
|
-
#
|
8
|
-
class
|
8
|
+
# Logs stuff
|
9
|
+
class LogWrapper
|
9
10
|
def initialize(logger)
|
10
11
|
raise ArgumentError, 'logger cannot be nil' if logger.nil?
|
11
12
|
raise ArgumentError, 'logger must respond to #debug' unless logger.respond_to? :debug
|
@@ -17,46 +18,43 @@ module Kramdown
|
|
17
18
|
end
|
18
19
|
|
19
20
|
def debug(message)
|
20
|
-
|
21
|
+
write :debug, message
|
21
22
|
end
|
22
23
|
|
23
|
-
def
|
24
|
-
return if
|
24
|
+
def debug_multiline(multiline_string)
|
25
|
+
return if multiline_string.nil? || multiline_string.empty?
|
25
26
|
|
26
|
-
lines =
|
27
|
+
lines = multiline_string.lines
|
27
28
|
lines.each do |line|
|
28
|
-
|
29
|
+
write :debug, line.rstrip
|
29
30
|
end
|
30
31
|
end
|
31
32
|
|
32
33
|
def info(message)
|
33
|
-
|
34
|
+
write :info, message
|
34
35
|
end
|
35
36
|
|
36
37
|
def warn(message)
|
37
|
-
|
38
|
+
write :warn, message
|
38
39
|
end
|
39
40
|
|
40
41
|
def error(message)
|
41
|
-
|
42
|
+
write :error, message
|
42
43
|
end
|
43
44
|
|
44
45
|
def debug?
|
45
46
|
self.class.level == :debug
|
46
47
|
end
|
47
48
|
|
49
|
+
def level
|
50
|
+
@level ||= level_from_logger || self.class.env
|
51
|
+
end
|
52
|
+
|
48
53
|
class << self
|
49
54
|
def init
|
50
|
-
inner = nil
|
51
|
-
|
52
|
-
|
53
|
-
require 'jekyll'
|
54
|
-
inner = Jekyll.logger
|
55
|
-
rescue LoadError
|
56
|
-
inner = ConsoleLogger.new level
|
57
|
-
end
|
58
|
-
|
59
|
-
Logger.new inner
|
55
|
+
inner = JekyllProvider.jekyll ? JekyllProvider.jekyll.logger : nil
|
56
|
+
inner ||= ConsoleLogger.new(level)
|
57
|
+
new inner
|
60
58
|
end
|
61
59
|
|
62
60
|
def level
|
@@ -72,6 +70,18 @@ module Kramdown
|
|
72
70
|
:warn
|
73
71
|
end
|
74
72
|
end
|
73
|
+
|
74
|
+
private
|
75
|
+
|
76
|
+
def write(level, message)
|
77
|
+
@logger.public_send(level, " kramdown-plantuml: #{message}")
|
78
|
+
end
|
79
|
+
|
80
|
+
def level_from_logger
|
81
|
+
return @logger.level if @logger.respond_to? :level
|
82
|
+
|
83
|
+
nil
|
84
|
+
end
|
75
85
|
end
|
76
86
|
end
|
77
87
|
end
|
@@ -0,0 +1,91 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'log_wrapper'
|
4
|
+
|
5
|
+
module Kramdown
|
6
|
+
module PlantUml
|
7
|
+
# Options for PlantUML processing
|
8
|
+
class Options
|
9
|
+
attr_reader :theme_name, :theme_directory
|
10
|
+
|
11
|
+
def initialize(options_hash = {})
|
12
|
+
@logger = LogWrapper.init
|
13
|
+
@options = massage(options_hash)
|
14
|
+
@raise_errors = extract_raise_errors(@options)
|
15
|
+
extract_theme_options(@options)
|
16
|
+
end
|
17
|
+
|
18
|
+
def raise_errors?
|
19
|
+
@raise_errors
|
20
|
+
end
|
21
|
+
|
22
|
+
def to_h
|
23
|
+
@options
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def boolean(value, default_value)
|
29
|
+
return value if [true, false].include? value
|
30
|
+
return default_value if value.nil?
|
31
|
+
|
32
|
+
s = value.to_s.strip
|
33
|
+
return true if %w[true yes 1].select { |v| v.casecmp(s).zero? }.any?
|
34
|
+
return false if %w[false no 0].select { |v| v.casecmp(s).zero? }.any?
|
35
|
+
|
36
|
+
default_value
|
37
|
+
end
|
38
|
+
|
39
|
+
def extract_plantuml_options(options_hash)
|
40
|
+
return options_hash[:plantuml] if options_hash.key?(:plantuml)
|
41
|
+
return options_hash['plantuml'] if options_hash.key?('plantuml')
|
42
|
+
|
43
|
+
{}
|
44
|
+
end
|
45
|
+
|
46
|
+
def extract_theme_options(options)
|
47
|
+
return if options.empty? || !options.key?(:theme)
|
48
|
+
|
49
|
+
theme = options[:theme] || {}
|
50
|
+
|
51
|
+
unless theme.is_a?(Hash)
|
52
|
+
@logger.warn ":theme is not a Hash: #{theme}"
|
53
|
+
return
|
54
|
+
end
|
55
|
+
|
56
|
+
@theme_name = theme.key?(:name) ? theme[:name] : nil
|
57
|
+
@theme_directory = theme.key?(:directory) ? theme[:directory] : nil
|
58
|
+
end
|
59
|
+
|
60
|
+
def extract_raise_errors(options)
|
61
|
+
if options.key?(:raise_errors)
|
62
|
+
raise_errors = options[:raise_errors]
|
63
|
+
return boolean(raise_errors, true)
|
64
|
+
end
|
65
|
+
|
66
|
+
true
|
67
|
+
end
|
68
|
+
|
69
|
+
def massage(options_hash)
|
70
|
+
if options_hash.nil? || !options_hash.is_a?(Hash) || options_hash.empty?
|
71
|
+
@logger.debug 'No options provided'
|
72
|
+
return {}
|
73
|
+
end
|
74
|
+
|
75
|
+
plantuml_options = extract_plantuml_options(options_hash)
|
76
|
+
symbolize_keys(plantuml_options)
|
77
|
+
end
|
78
|
+
|
79
|
+
def symbolize_keys(options)
|
80
|
+
return options if options.nil? || options.empty?
|
81
|
+
|
82
|
+
array = options.map do |key, value|
|
83
|
+
value = value.is_a?(Hash) ? symbolize_keys(value) : value
|
84
|
+
[key.to_sym, value]
|
85
|
+
end
|
86
|
+
|
87
|
+
array.to_h
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
@@ -1,32 +1,69 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require_relative 'plantuml_result'
|
4
|
+
|
3
5
|
module Kramdown
|
4
6
|
module PlantUml
|
5
7
|
# PlantUML Error
|
6
8
|
class PlantUmlError < StandardError
|
7
|
-
def initialize(
|
9
|
+
def initialize(result)
|
10
|
+
raise ArgumentError, 'result cannot be nil' if result.nil?
|
11
|
+
raise ArgumentError, "result must be a #{PlantUmlResult}" unless result.is_a?(PlantUmlResult)
|
12
|
+
|
13
|
+
super create_message(result)
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def create_message(result)
|
19
|
+
header = header(result).gsub("\n", ' ').strip
|
20
|
+
plantuml = plantuml(result)
|
21
|
+
result = result(result)
|
8
22
|
message = <<~MESSAGE
|
9
|
-
|
23
|
+
#{header}
|
10
24
|
|
11
25
|
#{plantuml}
|
12
26
|
|
13
|
-
|
14
|
-
|
15
|
-
Exit code: #{exitcode}
|
16
|
-
#{stderr}
|
27
|
+
#{result}
|
17
28
|
MESSAGE
|
18
29
|
|
19
|
-
|
30
|
+
message.strip
|
20
31
|
end
|
21
32
|
|
22
|
-
def
|
23
|
-
|
33
|
+
def header(result)
|
34
|
+
if theme_not_found?(result) && !result.diagram.nil? && !result.diagram.theme.nil?
|
35
|
+
return <<~HEADER
|
36
|
+
Conversion of the following PlantUML result failed because the
|
37
|
+
theme '#{result.diagram.theme.name}' can't be found in the directory
|
38
|
+
'#{result.diagram.theme.directory}':
|
39
|
+
HEADER
|
40
|
+
end
|
41
|
+
|
42
|
+
'Conversion of the following PlantUML result failed:'
|
43
|
+
end
|
44
|
+
|
45
|
+
def theme_not_found?(result)
|
46
|
+
!result.nil? \
|
47
|
+
&& !result.stderr.nil? \
|
48
|
+
&& result.stderr.include?('NullPointerException') \
|
49
|
+
&& result.stderr.include?('getTheme')
|
50
|
+
end
|
51
|
+
|
52
|
+
def plantuml(result)
|
53
|
+
return nil if result.nil? || result.diagram.nil?
|
54
|
+
|
55
|
+
result.diagram.plantuml
|
56
|
+
end
|
57
|
+
|
58
|
+
def result(result)
|
59
|
+
return nil if result.nil?
|
60
|
+
|
61
|
+
<<~RESULT
|
62
|
+
The error received from PlantUML was:
|
24
63
|
|
25
|
-
|
26
|
-
#
|
27
|
-
|
28
|
-
# Circumvents https://bugs.openjdk.java.net/browse/JDK-8244621
|
29
|
-
!stderr.include?('CoreText note:')
|
64
|
+
Exit code: #{result.exitcode}
|
65
|
+
#{result.stderr}
|
66
|
+
RESULT
|
30
67
|
end
|
31
68
|
end
|
32
69
|
end
|
@@ -1,19 +1,26 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative '
|
3
|
+
require_relative 'log_wrapper'
|
4
4
|
require_relative 'plantuml_error'
|
5
|
+
require_relative 'diagram'
|
5
6
|
|
6
7
|
module Kramdown
|
7
8
|
module PlantUml
|
8
9
|
# Executes the PlantUML Java application.
|
9
10
|
class PlantUmlResult
|
10
|
-
attr_reader :stdout, :stderr, :exitcode
|
11
|
+
attr_reader :diagram, :stdout, :stderr, :exitcode
|
11
12
|
|
12
|
-
def initialize(stdout, stderr,
|
13
|
+
def initialize(diagram, stdout, stderr, exitcode)
|
14
|
+
raise ArgumentError, 'diagram cannot be nil' if diagram.nil?
|
15
|
+
raise ArgumentError, "diagram must be a #{Diagram}" unless diagram.is_a?(Diagram)
|
16
|
+
raise ArgumentError, 'exitcode cannot be nil' if exitcode.nil?
|
17
|
+
raise ArgumentError, "exitcode must be a #{Integer}" unless exitcode.is_a?(Integer)
|
18
|
+
|
19
|
+
@diagram = diagram
|
13
20
|
@stdout = stdout
|
14
21
|
@stderr = stderr
|
15
|
-
@exitcode =
|
16
|
-
@logger =
|
22
|
+
@exitcode = exitcode
|
23
|
+
@logger = LogWrapper.init
|
17
24
|
end
|
18
25
|
|
19
26
|
def without_xml_prologue
|
@@ -37,13 +44,22 @@ module Kramdown
|
|
37
44
|
@stdout
|
38
45
|
end
|
39
46
|
|
40
|
-
def
|
41
|
-
|
47
|
+
def valid?
|
48
|
+
return true if @exitcode.zero? || @stderr.nil? || @stderr.empty?
|
49
|
+
|
50
|
+
# If stderr is not empty, but contains the string 'CoreText note:',
|
51
|
+
# the error is caused by a bug in Java, and should be ignored.
|
52
|
+
# Circumvents https://bugs.openjdk.java.net/browse/JDK-8244621
|
53
|
+
@stderr.include?('CoreText note:')
|
54
|
+
end
|
55
|
+
|
56
|
+
def validate
|
57
|
+
raise PlantUmlError, self unless valid?
|
42
58
|
|
43
59
|
return if @stderr.nil? || @stderr.empty?
|
44
60
|
|
45
|
-
@logger.debug '
|
46
|
-
@logger.
|
61
|
+
@logger.debug 'PlantUML log:'
|
62
|
+
@logger.debug_multiline @stderr
|
47
63
|
end
|
48
64
|
end
|
49
65
|
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
# frozen_string_literal: false
|
2
|
+
|
3
|
+
require_relative 'options'
|
4
|
+
require_relative 'log_wrapper'
|
5
|
+
|
6
|
+
module Kramdown
|
7
|
+
module PlantUml
|
8
|
+
# Provides theming support for PlantUML
|
9
|
+
class Theme
|
10
|
+
attr_reader :name, :directory
|
11
|
+
|
12
|
+
def initialize(options)
|
13
|
+
raise ArgumentError, 'options cannot be nil' if options.nil?
|
14
|
+
raise ArgumentError, "options must be a '#{Options}'." unless options.is_a?(Options)
|
15
|
+
|
16
|
+
@logger = LogWrapper.init
|
17
|
+
@name = options.theme_name
|
18
|
+
@directory = options.theme_directory
|
19
|
+
end
|
20
|
+
|
21
|
+
def apply(plantuml)
|
22
|
+
if plantuml.nil? || !plantuml.is_a?(String) || plantuml.empty?
|
23
|
+
@logger.debug 'Empty diagram or not a String.'
|
24
|
+
return plantuml
|
25
|
+
end
|
26
|
+
|
27
|
+
if @name.nil? || @name.empty?
|
28
|
+
@logger.debug 'No theme to apply.'
|
29
|
+
return plantuml.strip
|
30
|
+
end
|
31
|
+
|
32
|
+
theme(plantuml)
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
def theme(plantuml)
|
38
|
+
startuml = '@startuml'
|
39
|
+
startuml_index = plantuml.index(startuml) + startuml.length
|
40
|
+
|
41
|
+
return plantuml if startuml_index.nil?
|
42
|
+
|
43
|
+
theme_string = "\n!theme #{@name}"
|
44
|
+
theme_string << " from #{@directory}" unless @directory.nil?
|
45
|
+
|
46
|
+
@logger.debug "Applying #{theme_string.strip}"
|
47
|
+
|
48
|
+
/@startuml.*/.match(plantuml) do |match|
|
49
|
+
return plantuml.insert match.end(0), theme_string
|
50
|
+
end
|
51
|
+
|
52
|
+
plantuml.strip
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
#
|
3
|
+
# Mimics the `which` Unix utility
|
4
4
|
class Which
|
5
5
|
def self.which(cmd)
|
6
6
|
exts = ENV['PATHEXT'] ? ENV['PATHEXT'].split(';') : ['']
|
@@ -10,6 +10,7 @@ class Which
|
|
10
10
|
return exe if File.executable?(exe) && !File.directory?(exe)
|
11
11
|
end
|
12
12
|
end
|
13
|
+
|
13
14
|
nil
|
14
15
|
end
|
15
16
|
end
|
data/lib/kramdown-plantuml.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative 'kramdown-plantuml/version'
|
4
|
-
require_relative 'kramdown-plantuml/converter'
|
5
3
|
require_relative 'kramdown_html'
|
4
|
+
require_relative 'kramdown-plantuml/jekyll_provider'
|
5
|
+
|
6
|
+
::Kramdown::PlantUml::JekyllProvider.install
|
data/lib/kramdown_html.rb
CHANGED
@@ -2,9 +2,11 @@
|
|
2
2
|
|
3
3
|
require 'kramdown'
|
4
4
|
require 'kramdown-parser-gfm'
|
5
|
-
require_relative 'kramdown-plantuml/
|
6
|
-
require_relative 'kramdown-plantuml/logger'
|
5
|
+
require_relative 'kramdown-plantuml/log_wrapper'
|
7
6
|
require_relative 'kramdown-plantuml/plantuml_error'
|
7
|
+
require_relative 'kramdown-plantuml/options'
|
8
|
+
require_relative 'kramdown-plantuml/diagram'
|
9
|
+
require_relative 'kramdown-plantuml/jekyll_provider'
|
8
10
|
|
9
11
|
module Kramdown
|
10
12
|
module Converter
|
@@ -14,13 +16,31 @@ module Kramdown
|
|
14
16
|
alias super_convert_codeblock convert_codeblock
|
15
17
|
|
16
18
|
def convert_codeblock(element, indent)
|
17
|
-
return super_convert_codeblock(element, indent)
|
19
|
+
return super_convert_codeblock(element, indent) unless plantuml?(element)
|
18
20
|
|
19
|
-
|
20
|
-
plantuml_options = @options.key?(:plantuml) ? @options[:plantuml] : {}
|
21
|
-
converter = ::Kramdown::PlantUml::Converter.new(plantuml_options || {})
|
21
|
+
jekyll = ::Kramdown::PlantUml::JekyllProvider
|
22
22
|
|
23
|
-
|
23
|
+
# If Jekyll is successfully loaded, we'll wait with converting the
|
24
|
+
# PlantUML diagram to SVG since a theme may be configured that needs to
|
25
|
+
# be copied to the assets directory before the PlantUML conversion can
|
26
|
+
# be performed. We therefore place a needle in the haystack that we will
|
27
|
+
# convert in the :site:pre_render hook.
|
28
|
+
options = ::Kramdown::PlantUml::Options.new(@options)
|
29
|
+
return jekyll.needle(element.value, options) if jekyll.installed?
|
30
|
+
|
31
|
+
convert_plantuml(element.value)
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def plantuml?(element)
|
37
|
+
element.attr['class'] == 'language-plantuml'
|
38
|
+
end
|
39
|
+
|
40
|
+
def convert_plantuml(plantuml)
|
41
|
+
options = ::Kramdown::PlantUml::Options.new(@options)
|
42
|
+
diagram = ::Kramdown::PlantUml::Diagram.new(plantuml, options)
|
43
|
+
diagram.convert_to_svg
|
24
44
|
end
|
25
45
|
end
|
26
46
|
end
|
data/pom.xml
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: kramdown-plantuml
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.1.
|
4
|
+
version: 1.1.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Swedbank Pay
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-
|
11
|
+
date: 2021-11-01 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: kramdown
|
@@ -166,21 +166,22 @@ files:
|
|
166
166
|
- LICENSE
|
167
167
|
- README.md
|
168
168
|
- Rakefile
|
169
|
-
- bin/net/sourceforge/plantuml/plantuml/1.2021.
|
169
|
+
- bin/net/sourceforge/plantuml/plantuml/1.2021.12/plantuml-1.2021.12.jar
|
170
170
|
- kramdown-plantuml.gemspec
|
171
171
|
- lib/kramdown-plantuml.rb
|
172
172
|
- lib/kramdown-plantuml/bool_env.rb
|
173
173
|
- lib/kramdown-plantuml/console_logger.rb
|
174
|
-
- lib/kramdown-plantuml/
|
174
|
+
- lib/kramdown-plantuml/diagram.rb
|
175
175
|
- lib/kramdown-plantuml/executor.rb
|
176
|
-
- lib/kramdown-plantuml/
|
177
|
-
- lib/kramdown-plantuml/
|
176
|
+
- lib/kramdown-plantuml/jekyll_provider.rb
|
177
|
+
- lib/kramdown-plantuml/log_wrapper.rb
|
178
|
+
- lib/kramdown-plantuml/options.rb
|
178
179
|
- lib/kramdown-plantuml/plantuml_error.rb
|
179
180
|
- lib/kramdown-plantuml/plantuml_result.rb
|
180
|
-
- lib/kramdown-plantuml/
|
181
|
+
- lib/kramdown-plantuml/theme.rb
|
181
182
|
- lib/kramdown-plantuml/version.rb
|
183
|
+
- lib/kramdown-plantuml/which.rb
|
182
184
|
- lib/kramdown_html.rb
|
183
|
-
- lib/which.rb
|
184
185
|
- pom.xml
|
185
186
|
homepage: https://github.com/SwedbankPay/kramdown-plantuml
|
186
187
|
licenses:
|
@@ -1,52 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require_relative 'version'
|
4
|
-
require_relative 'themer'
|
5
|
-
require_relative 'plantuml_error'
|
6
|
-
require_relative 'logger'
|
7
|
-
require_relative 'executor'
|
8
|
-
|
9
|
-
module Kramdown
|
10
|
-
module PlantUml
|
11
|
-
# Converts PlantUML markup to SVG
|
12
|
-
class Converter
|
13
|
-
def initialize(options = {})
|
14
|
-
@themer = Themer.new(options)
|
15
|
-
@logger = Logger.init
|
16
|
-
@executor = Executor.new
|
17
|
-
end
|
18
|
-
|
19
|
-
def convert_plantuml_to_svg(plantuml)
|
20
|
-
if plantuml.nil? || plantuml.empty?
|
21
|
-
@logger.warn 'kramdown-plantuml: PlantUML diagram is empty'
|
22
|
-
return plantuml
|
23
|
-
end
|
24
|
-
|
25
|
-
plantuml = @themer.apply_theme(plantuml)
|
26
|
-
plantuml = plantuml.strip
|
27
|
-
log(plantuml)
|
28
|
-
result = @executor.execute(plantuml)
|
29
|
-
result.validate(plantuml)
|
30
|
-
svg = result.without_xml_prologue
|
31
|
-
wrap(svg)
|
32
|
-
end
|
33
|
-
|
34
|
-
private
|
35
|
-
|
36
|
-
def wrap(svg)
|
37
|
-
theme_class = @themer.theme_name ? "theme-#{@themer.theme_name}" : ''
|
38
|
-
class_name = "plantuml #{theme_class}".strip
|
39
|
-
|
40
|
-
wrapper_element_start = "<div class=\"#{class_name}\">"
|
41
|
-
wrapper_element_end = '</div>'
|
42
|
-
|
43
|
-
"#{wrapper_element_start}#{svg}#{wrapper_element_end}"
|
44
|
-
end
|
45
|
-
|
46
|
-
def log(plantuml)
|
47
|
-
@logger.debug 'kramdown-plantuml: PlantUML converting diagram:'
|
48
|
-
@logger.debug_with_prefix 'kramdown-plantuml: ', plantuml
|
49
|
-
end
|
50
|
-
end
|
51
|
-
end
|
52
|
-
end
|
@@ -1,14 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
# Ruby's Hash class.
|
4
|
-
class ::Hash
|
5
|
-
# Via https://stackoverflow.com/a/25835016/2257038
|
6
|
-
def symbolize_keys
|
7
|
-
h = map do |k, v|
|
8
|
-
v_sym = v.instance_of?(Hash) ? v.symbolize_keys : v
|
9
|
-
[k.to_sym, v_sym]
|
10
|
-
end
|
11
|
-
|
12
|
-
h.to_h
|
13
|
-
end
|
14
|
-
end
|
@@ -1,64 +0,0 @@
|
|
1
|
-
# frozen_string_literal: false
|
2
|
-
|
3
|
-
require_relative 'hash'
|
4
|
-
require_relative 'logger'
|
5
|
-
|
6
|
-
module Kramdown
|
7
|
-
module PlantUml
|
8
|
-
# Provides theming support for PlantUML
|
9
|
-
class Themer
|
10
|
-
attr_reader :theme_name, :theme_directory
|
11
|
-
|
12
|
-
def initialize(options = {})
|
13
|
-
options = options.symbolize_keys unless options.nil?
|
14
|
-
@logger = Logger.init
|
15
|
-
@logger.debug "kramdown-plantuml: Options: #{options}"
|
16
|
-
@theme_name, @theme_directory = theme_options(options)
|
17
|
-
end
|
18
|
-
|
19
|
-
def apply_theme(plantuml)
|
20
|
-
if plantuml.nil? || plantuml.empty?
|
21
|
-
@logger.debug 'kramdown-plantuml: Empty diagram.'
|
22
|
-
return plantuml
|
23
|
-
end
|
24
|
-
|
25
|
-
if @theme_name.nil? || @theme_name.empty?
|
26
|
-
@logger.debug 'kramdown-plantuml: No theme to apply.'
|
27
|
-
return plantuml
|
28
|
-
end
|
29
|
-
|
30
|
-
theme(plantuml)
|
31
|
-
end
|
32
|
-
|
33
|
-
private
|
34
|
-
|
35
|
-
def theme_options(options)
|
36
|
-
return nil if options.nil? || !options.key?(:theme)
|
37
|
-
|
38
|
-
theme = options[:theme] || {}
|
39
|
-
theme_name = theme.key?(:name) ? theme[:name] : nil
|
40
|
-
theme_directory = theme.key?(:directory) ? theme[:directory] : nil
|
41
|
-
|
42
|
-
[theme_name, theme_directory]
|
43
|
-
end
|
44
|
-
|
45
|
-
def theme(plantuml)
|
46
|
-
startuml = '@startuml'
|
47
|
-
startuml_index = plantuml.index(startuml) + startuml.length
|
48
|
-
|
49
|
-
return plantuml if startuml_index.nil?
|
50
|
-
|
51
|
-
theme_string = "\n!theme #{@theme_name}"
|
52
|
-
theme_string << " from #{@theme_directory}" unless @theme_directory.nil?
|
53
|
-
|
54
|
-
@logger.debug "kramdown-plantuml: Applying #{theme_string}"
|
55
|
-
|
56
|
-
/@startuml.*/.match(plantuml) do |match|
|
57
|
-
return plantuml.insert match.end(0), theme_string
|
58
|
-
end
|
59
|
-
|
60
|
-
plantuml
|
61
|
-
end
|
62
|
-
end
|
63
|
-
end
|
64
|
-
end
|