jekyll-kroki 0.2.1 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 22cd7bfae1fa5a37266559c800563db4352a1f7323a65ce15a8058ddae6a7e55
4
- data.tar.gz: d76013092f50d163ab83efde344705ec02e8252043d5cd90eadd68903aec472e
3
+ metadata.gz: 7f3956d6144278bdd3448613552e1bb2c3db31eaec49333d20a038ca4240205f
4
+ data.tar.gz: 809c19f518fc91ae2f44e02c573d86b32bb9875f48d7165a80f7263a00218b25
5
5
  SHA512:
6
- metadata.gz: eeeeb8d251bcdbaa85429189d11c5ab3aae798b34a28fc4b7742fb195e5ba50af9d450f33dc14db629dc901b5a4e632da77d48abb599ed97b16ae2aa80cd5fee
7
- data.tar.gz: 1d2bf0763f3551576b8e1d0f47b4aa8d62f14b01fe25698bd7ad1d043f4dad1a0c723f7ec607db4cae11bb4c4183be4018ae62b56a7803e8622ad83ac57aa12d
6
+ metadata.gz: 7c97db5828301a44fe1db39f97e9a424c826675bc6949e1a2291aba0f271b52a51407f3e517b2c19977ab7c4da6027d7aa055a81880fb980600404846558d9aa
7
+ data.tar.gz: 8880e382989ebb202ca4d2f92ffea94c43053b41a78eacb2a9281263a7ccac52fc7a1f2485b0ac8252d16f3f9057c83e62604f78d2b374c02d360991e785d6f8
@@ -0,0 +1,11 @@
1
+ {
2
+ "name": "Ruby",
3
+ "image": "mcr.microsoft.com/devcontainers/ruby:3.0-bullseye",
4
+ "customizations": {
5
+ "vscode": {
6
+ "extensions": [
7
+ "streetsidesoftware.code-spell-checker"
8
+ ]
9
+ }
10
+ }
11
+ }
data/.rubocop.yml CHANGED
@@ -12,4 +12,4 @@ Style/StringLiteralsInInterpolation:
12
12
  Layout/LineLength:
13
13
  Max: 120
14
14
  Metrics/MethodLength:
15
- Max: 12
15
+ Max: 14
@@ -0,0 +1,7 @@
1
+ {
2
+ "editor.formatOnSave": true,
3
+ "editor.rulers": [
4
+ 120
5
+ ],
6
+ "rubyLsp.formatter": "rubocop"
7
+ }
data/README.md CHANGED
@@ -1,8 +1,10 @@
1
+ ![Main Workflow](https://github.com/felixvanoost/jekyll-kroki/actions/workflows/main.yml/badge.svg)
2
+ [![Gem Version](https://badge.fury.io/rb/jekyll-kroki.svg)](https://badge.fury.io/rb/jekyll-kroki)
3
+
1
4
  # jekyll-kroki
2
- A Jekyll plugin to convert diagram descriptions into images using Kroki
5
+ A [Jekyll](https://jekyllrb.com/) plugin to convert diagram descriptions into images using [Kroki](https://kroki.io/).
3
6
 
4
7
  ## Installation
5
-
6
8
  Add the `jekyll-kroki` Gem to the `:jekyll_plugins` group of your site's Gemfile:
7
9
 
8
10
  ```ruby
@@ -12,10 +14,9 @@ end
12
14
  ```
13
15
 
14
16
  ## Usage
17
+ Kroki supports over 25 popular diagram scripting languages, including Blockdiag, D2, GraphViz, Mermaid, and PlantUML. The [examples](https://kroki.io/examples.html) page and complete list of [supported diagram languages](https://kroki.io/#support) provide a taste of what's possible.
15
18
 
16
- [Kroki](https://github.com/yuzutech/kroki) supports over 20 popular diagram languages spanning several dozen diagram types. The [examples](https://kroki.io/examples.html) page provides a taste of what's possible.
17
-
18
- In Markdown, simply write your diagram description inside a fenced code block with the language specified:
19
+ In Markdown, simply write your diagram descriptions inside a fenced code block with the language specified:
19
20
 
20
21
  ````
21
22
  ```plantuml
@@ -27,16 +28,27 @@ Kroki --> Jekyll: Rendered diagram in SVG format
27
28
  ```
28
29
  ````
29
30
 
30
- When Jekyll builds your site, the `jekyll-kroki` plugin will encode the diagram, send it to the Kroki server for rendering, then replace the diagram description in the generated HTML with the rendered diagram in SVG format:
31
+ When Jekyll builds your site, the `jekyll-kroki` plugin will encode the diagrams, send them to the Kroki server for rendering, then replace the diagram descriptions in the generated HTML with the rendered images in SVG format:
31
32
 
32
33
  ![sample-diagram](https://github.com/felixvanoost/jekyll-kroki/assets/10233016/244d2ec4-b09b-4a5f-8164-3851574c3dd2)
33
34
 
34
- The site remains truly static as the SVG is directly embedded in the HTML files that Jekyll serves. Jekyll only depends on the Kroki server (which can also be run locally) during the build stage, and all of the client-side processing that is normally used to render diagrams into images is eliminated.
35
+ The site remains truly static as the images are directly embedded in the HTML files served by Jekyll. Jekyll only depends on the Kroki server (which can also be run locally) during the build stage, and all of the client-side processing that is normally used to render diagrams into images is eliminated.
35
36
 
36
- `jekyll-kroki` uses the same Markdown fenced code syntax as the [GitLab Kroki integration](https://docs.gitlab.com/ee/administration/integration/kroki.html), allowing diagram descriptions in Markdown files to be displayed seamlessly in both the GitLab UI and on GitLab Pages sites generated using Jekyll.
37
+ ### Advantages
37
38
 
38
- ### Configuration
39
+ #### Consistent syntax
40
+ Instead of using Liquid tags, `jekyll-kroki` leverages the same Markdown fenced code block syntax used by both [GitLab](https://docs.gitlab.com/ee/user/markdown.html#diagrams-and-flowcharts) and [GitHub](https://docs.github.com/en/get-started/writing-on-github/working-with-advanced-formatting/creating-diagrams) to display diagrams. Besides being more consistent, this means that diagram descriptions in Markdown files can be displayed consistently as images across the GitLab/GitHub UI and on GitLab/GitHub Pages sites generated using Jekyll. GitLab currently supports Mermaid and PlantUML, while GitHub only supports Mermaid.
41
+
42
+ #### Seamless GitLab integration
43
+ Self-managed GitLab instances can additionally enable the [Kroki integration](https://docs.gitlab.com/ee/administration/integration/kroki.html), which adds support for all the same diagram scripting languages used by `jekyll-kroki`. Furthermore, by pointing both GitLab and `jekyll-kroki` to the same Kroki instance, you can guarantee that diagrams are generated using identical versions of the diagram libraries.
39
44
 
45
+ #### Speed
46
+ The server-side nature of Kroki means that you don't have to deal with installing or updating any diagram library dependencies on your machine. Jekyll sites that are generated in CI/CD pipelines will thus build faster.
47
+
48
+ #### Flexibility
49
+ Kroki is available either as a free service or self-hosted using Docker. Organisations that frequently build large Jekyll sites with many diagrams or want maximum control over their data have the option of running their own Kroki instance to provide consistency and use compute resources efficiently.
50
+
51
+ ### Configuration
40
52
  You can specify the URL of the Kroki instance to use in the Jekyll `_config.yml` file:
41
53
 
42
54
  ```yaml
@@ -44,10 +56,9 @@ kroki:
44
56
  url: "https://my-kroki.server"
45
57
  ```
46
58
 
47
- This is useful if you want to run a Kroki instance locally or your organisation maintains its own private Kroki server. `jekyll-kroki` will use the public Kroki instance https://kroki.io by default if a URL is not specified.
59
+ This is useful if you want to run a Kroki instance locally or your organisation maintains its own private Kroki server. The public Kroki instance https://kroki.io is used by default.
48
60
 
49
61
  ### Security
50
-
51
62
  Embedding diagrams as SVGs directly within HTML files can be dangerous. You should only use a Kroki instance that you trust (or run your own!). For additional security, you can configure a [Content Security Policy (CSP)](https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP) using custom Webrick headers in the Jekyll `_config.yml` file:
52
63
 
53
64
  ```yaml
@@ -57,5 +68,4 @@ webrick:
57
68
  ```
58
69
 
59
70
  ## Contributing
60
-
61
71
  Bug reports and pull requests are welcome! For major changes, please open an issue first to discuss what you would like to change.
data/jekyll-kroki.gemspec CHANGED
@@ -8,8 +8,8 @@ Gem::Specification.new do |spec|
8
8
  spec.authors = ["Felix van Oost"]
9
9
 
10
10
  spec.summary = "A Jekyll plugin to convert diagram descriptions into images using Kroki"
11
- spec.description = "Replaces diagram descriptions written in any Kroki-supported language in HTML files generated by
12
- Jekyll with their visual representation in SVG format."
11
+ spec.description = "A Jekyll plugin to convert diagram descriptions written in over 25 popular diagram scripting
12
+ languages into images using Kroki"
13
13
  spec.homepage = "https://github.com/felixvanoost/jekyll-kroki"
14
14
  spec.license = "MIT"
15
15
  spec.required_ruby_version = ">= 2.6.0"
@@ -30,6 +30,7 @@ Gem::Specification.new do |spec|
30
30
 
31
31
  spec.add_runtime_dependency "faraday", ["~> 2.7"]
32
32
  spec.add_runtime_dependency "faraday-retry", ["~> 2.2"]
33
+ spec.add_runtime_dependency "httpx", ["~> 1.1"]
33
34
  spec.add_runtime_dependency "jekyll", ["~> 4"]
34
35
  spec.add_runtime_dependency "nokogiri", ["~> 1.15"]
35
36
 
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Jekyll
4
4
  class Kroki
5
- VERSION = "0.2.1"
5
+ VERSION = "0.3.0"
6
6
  end
7
7
  end
data/lib/jekyll/kroki.rb CHANGED
@@ -5,6 +5,7 @@ require_relative "kroki/version"
5
5
  require "base64"
6
6
  require "faraday"
7
7
  require "faraday/retry"
8
+ require "httpx/adapters/faraday"
8
9
  require "jekyll"
9
10
  require "nokogiri"
10
11
  require "zlib"
@@ -13,45 +14,59 @@ module Jekyll
13
14
  # Converts diagram descriptions into images using Kroki
14
15
  class Kroki
15
16
  KROKI_DEFAULT_URL = "https://kroki.io"
17
+ SUPPORTED_LANGUAGES = %w[actdiag blockdiag bpmn bytefield c4plantuml d2 dbml diagramsnet ditaa erd excalidraw
18
+ graphviz mermaid nomnoml nwdiag packetdiag pikchr plantuml rackdiag seqdiag structurizr
19
+ svgbob symbolator tikz umlet vega vegalite wavedrom wireviz].freeze
16
20
  HTTP_MAX_RETRIES = 3
17
21
 
18
22
  class << self
19
- # Renders all diagram descriptions in any Kroki-supported language and embeds them throughout a Jekyll site.
23
+ # Renders and embeds all diagram descriptions in a Jekyll site using Kroki.
20
24
  #
21
- # @param [Jekyll::Site] The site to embed diagrams in
25
+ # @param [Jekyll::Site] The Jekyll site to embed diagrams in
22
26
  def embed_site(site)
23
27
  # Get the URL of the Kroki instance
24
28
  kroki_url = kroki_url(site.config)
25
- puts "[jekyll-kroki] Rendering diagrams using Kroki instance at '#{kroki_url}'"
26
-
27
- # Set up a Faraday connection
28
29
  connection = setup_connection(kroki_url)
29
30
 
30
- # Parse the page, render and embed the diagrams, then convert it back into HTML
31
- site.pages.each do |page|
32
- next unless embeddable?(page)
31
+ rendered_diag = 0
32
+ (site.pages + site.documents).each do |doc|
33
+ next unless embeddable?(doc)
34
+
35
+ # Render all supported diagram descriptions in the document
36
+ rendered_diag += embed_doc(connection, doc)
37
+ end
33
38
 
34
- parsed_page = Nokogiri::HTML(page.output)
35
- embed_page(connection, parsed_page)
36
- page.output = parsed_page.to_html
39
+ unless rendered_diag.zero?
40
+ puts "[jekyll-kroki] Rendered #{rendered_diag} diagrams using Kroki instance at '#{kroki_url}'"
37
41
  end
42
+ rescue StandardError => e
43
+ exit(e)
38
44
  end
39
45
 
40
- # Renders all diagram descriptions in any Kroki-supported language and embeds them in an HTML document.
46
+ # Renders all supported diagram descriptions in a document and embeds them as inline SVGs in the HTML source.
41
47
  #
42
48
  # @param [Faraday::Connection] The Faraday connection to use
43
49
  # @param [Nokogiri::HTML4::Document] The parsed HTML document
44
- def embed_page(connection, parsed_doc)
45
- # Iterate through every diagram description in each of the supported languages
46
- get_supported_languages(connection).each do |language|
50
+ # @param [Integer] The number of rendered diagrams
51
+ def embed_doc(connection, doc)
52
+ # Parse the HTML document
53
+ parsed_doc = Nokogiri::HTML(doc.output)
54
+
55
+ rendered_diag = 0
56
+ SUPPORTED_LANGUAGES.each do |language|
47
57
  parsed_doc.css("code[class~='language-#{language}']").each do |diagram_desc|
48
58
  # Replace the diagram description with the SVG representation rendered by Kroki
49
59
  diagram_desc.replace(render_diagram(connection, diagram_desc, language))
60
+ rendered_diag += 1
50
61
  end
51
62
  end
63
+
64
+ # Convert the document back to HTML
65
+ doc.output = parsed_doc.to_html
66
+ rendered_diag
52
67
  end
53
68
 
54
- # Renders a diagram description using Kroki.
69
+ # Renders a single diagram description using Kroki.
55
70
  #
56
71
  # @param [Faraday::Connection] The Faraday connection to use
57
72
  # @param [String] The diagram description
@@ -61,6 +76,8 @@ module Jekyll
61
76
  begin
62
77
  response = connection.get("#{language}/svg/#{encode_diagram(diagram_desc.text)}")
63
78
  rescue Faraday::Error => e
79
+ raise "'#{connection.url_prefix}' does not point to a valid Kroki instance" if e.response.nil?
80
+
64
81
  raise e.response[:body]
65
82
  end
66
83
  expected_content_type = "image/svg+xml"
@@ -74,10 +91,10 @@ module Jekyll
74
91
  end
75
92
 
76
93
  # Sanitises a rendered diagram. Only <script> elements are removed, which is the most minimal / naive
77
- # implementation possible and is definitely not secure.
94
+ # implementation possible.
78
95
  #
79
96
  # @param [String] The diagram to santise in SVG format
80
- # @return [String] The sanitized diagram in SVG format
97
+ # @return [String] The sanitised diagram
81
98
  def sanitise_diagram(diagram_svg)
82
99
  parsed_svg = Nokogiri::XML(diagram_svg)
83
100
  parsed_svg.xpath('//*[name()="script"]').each(&:remove)
@@ -93,23 +110,6 @@ module Jekyll
93
110
  Base64.urlsafe_encode64(Zlib.deflate(diagram_desc))
94
111
  end
95
112
 
96
- # Gets an array of supported diagram languages from the Kroki '/health' endpoint.
97
- #
98
- # This only shows which languages the Kroki project supports, not which ones are currently available from the
99
- # configured Kroki instance. For example, Mermaid will still show up as a supported language even if the Mermaid
100
- # companion container is not running.
101
- #
102
- # @param [Faraday::Connection] The Faraday connection to use
103
- # @return [Array] The supported diagram languages
104
- def get_supported_languages(connection)
105
- begin
106
- response = connection.get("health")
107
- rescue Faraday::Error => e
108
- raise e.response[:body]
109
- end
110
- response.body["version"].keys
111
- end
112
-
113
113
  # Sets up a new Faraday connection.
114
114
  #
115
115
  # @param [URI::HTTP] The URL of the Kroki instance
@@ -118,7 +118,8 @@ module Jekyll
118
118
  retry_options = { max: HTTP_MAX_RETRIES, interval: 0.1, interval_randomness: 0.5, backoff_factor: 2,
119
119
  exceptions: [Faraday::RequestTimeoutError, Faraday::ServerError] }
120
120
 
121
- Faraday.new(url: kroki_url) do |builder|
121
+ Faraday.new(url: kroki_url, request: { timeout: 5 }) do |builder|
122
+ builder.adapter :httpx, persistent: true
122
123
  builder.request :retry, retry_options
123
124
  builder.response :json, content_type: /\bjson$/
124
125
  builder.response :raise_error
@@ -147,10 +148,27 @@ module Jekyll
147
148
  def embeddable?(doc)
148
149
  doc.output_ext == ".html" && (doc.is_a?(Jekyll::Page) || doc.write?)
149
150
  end
151
+
152
+ # Exits the Jekyll process without returning a stack trace. This method does not return because the process is
153
+ # abruptly terminated.
154
+ #
155
+ # @param [StandardError] The error to display in the termination message
156
+ # @param [int] The caller index to display in the termination message. The default index is 1, which means the
157
+ # calling method. To specify the calling method's caller, pass in 2.
158
+ #
159
+ # Source: https://www.mslinn.com/ruby/2200-crash-exit.html
160
+ def exit(error, caller_index = 1)
161
+ raise error
162
+ rescue StandardError => e
163
+ file, line_number, caller = e.backtrace[caller_index].split(":")
164
+ caller = caller.tr("`", "'")
165
+ warn %([jekyll-kroki] "#{error.message}" #{caller} on line #{line_number} of #{file}).red
166
+ exec "echo ''"
167
+ end
150
168
  end
151
169
  end
152
170
  end
153
171
 
154
- Jekyll::Hooks.register :site, :post_render do |doc|
155
- Jekyll::Kroki.embed_site(doc)
172
+ Jekyll::Hooks.register :site, :post_render do |site|
173
+ Jekyll::Kroki.embed_site(site)
156
174
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jekyll-kroki
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.1
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Felix van Oost
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2023-10-23 00:00:00.000000000 Z
11
+ date: 2023-12-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: faraday
@@ -38,6 +38,20 @@ dependencies:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
40
  version: '2.2'
41
+ - !ruby/object:Gem::Dependency
42
+ name: httpx
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '1.1'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '1.1'
41
55
  - !ruby/object:Gem::Dependency
42
56
  name: jekyll
43
57
  requirement: !ruby/object:Gem::Requirement
@@ -109,14 +123,16 @@ dependencies:
109
123
  - !ruby/object:Gem::Version
110
124
  version: '1.21'
111
125
  description: |-
112
- Replaces diagram descriptions written in any Kroki-supported language in HTML files generated by
113
- Jekyll with their visual representation in SVG format.
126
+ A Jekyll plugin to convert diagram descriptions written in over 25 popular diagram scripting
127
+ languages into images using Kroki
114
128
  email:
115
129
  executables: []
116
130
  extensions: []
117
131
  extra_rdoc_files: []
118
132
  files:
133
+ - ".devcontainer/devcontainer.json"
119
134
  - ".rubocop.yml"
135
+ - ".vscode/settings.json"
120
136
  - LICENSE
121
137
  - README.md
122
138
  - Rakefile
@@ -144,7 +160,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
144
160
  - !ruby/object:Gem::Version
145
161
  version: '0'
146
162
  requirements: []
147
- rubygems_version: 3.3.5
163
+ rubygems_version: 3.2.33
148
164
  signing_key:
149
165
  specification_version: 4
150
166
  summary: A Jekyll plugin to convert diagram descriptions into images using Kroki