middleman-commonmarker 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +4 -0
- data/README.md +24 -1
- data/features/commonmarker.feature +21 -0
- data/lib/middleman-commonmarker/commonmarker_template.rb +24 -2
- data/lib/middleman-commonmarker/version.rb +1 -1
- data/sig/middleman-commonmarker/commonmarker_template.rbs +2 -0
- data/test/commonmarker_template_test.rb +99 -4
- data/test/fixtures/test-theme.tmTheme +20 -0
- metadata +3 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: a84e082e8ec76cfb63d7acbde0e2fdd5ab6a2f4355e7fe322924b74ecaa81d16
|
|
4
|
+
data.tar.gz: 1d2ef217f0fe335f01c98d5e28292dfb98f3c56eca4e25c25fdf7d04e6e57022
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: babd88f6b95ea0b671f00d824bb3a1e5e3a16ebbd101b95de6ebac79740f8a1365c4b063fe5720ea4bf3a9ebe2a5ce2819f3fbeb52ae4826d56229f015e67573
|
|
7
|
+
data.tar.gz: 81b518c5818560624547091fab0da203dbf772c775af1079540f416ee82280f49ef8ef7d4ffb77b255bae13ed70c5bbea662ccc563ef27c6605a5e77fba1234a
|
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
|
@@ -46,6 +46,29 @@ Note that flat keys on `activate` (e.g. `activate :commonmarker, table: true`) a
|
|
|
46
46
|
|
|
47
47
|
These flat options are mapped onto commonmarker's `parse` / `render` / `extension` option groups (and `smartypants` maps to `parse.smart`).
|
|
48
48
|
|
|
49
|
+
### Syntax highlighting
|
|
50
|
+
|
|
51
|
+
By default, commonmarker highlights fenced code blocks with the `base16-ocean.dark` theme, writing the colors as inline `style` attributes.
|
|
52
|
+
|
|
53
|
+
Use the `plugins` option to change this. Its value is passed as-is to commonmarker's `plugins:` argument; see [commonmarker's README](https://github.com/gjtorikian/commonmarker#plugins) for the available values.
|
|
54
|
+
|
|
55
|
+
```ruby
|
|
56
|
+
# Use another built-in theme
|
|
57
|
+
set :markdown, plugins: {syntax_highlighter: {theme: "InspiredGitHub"}}
|
|
58
|
+
|
|
59
|
+
# Load syntax_themes/my-theme.tmTheme
|
|
60
|
+
set :markdown, plugins: {
|
|
61
|
+
syntax_highlighter: {theme: "my-theme", path: File.expand_path("syntax_themes", __dir__)}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
# Disable syntax highlighting
|
|
65
|
+
set :markdown, plugins: {syntax_highlighter: nil}
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
Give `path` as an absolute path; a relative path is resolved against the current working directory.
|
|
69
|
+
|
|
70
|
+
`plugins` can also be given through `activate :commonmarker, options: { plugins: ... }`. When both are set, the `activate` value replaces the `set :markdown` value entirely (no deep merge).
|
|
71
|
+
|
|
49
72
|
### Raw HTML is enabled during rendering
|
|
50
73
|
|
|
51
74
|
To emit the `<img>` HTML produced by `image_tag`, the renderer forces commonmarker's `unsafe: true` during transformation.
|
|
@@ -53,7 +76,7 @@ As a result, raw HTML in your Markdown is passed through (consistent with Redcar
|
|
|
53
76
|
|
|
54
77
|
## Scope
|
|
55
78
|
|
|
56
|
-
This extension covers helper integration (`image_tag` / `url_for`), `automatic_image_sizes`,
|
|
79
|
+
This extension covers helper integration (`image_tag` / `url_for`), `automatic_image_sizes`, commonmarker's native parse/render/extension options (`table`, `strikethrough`, `autolink`, `smartypants`, `tasklist`, …), and commonmarker plugins such as the syntax highlighter (`plugins`).
|
|
57
80
|
Redcarpet-specific options such as `no_images`, `no_links`, `link_attributes`, and `filter_html` are out of scope.
|
|
58
81
|
|
|
59
82
|
## Development
|
|
@@ -75,6 +75,27 @@ Feature: Markdown (Commonmarker) support
|
|
|
75
75
|
When I go to "/tables.html"
|
|
76
76
|
Then I should see "<table>"
|
|
77
77
|
|
|
78
|
+
Scenario: Commonmarker passes plugins through set :markdown
|
|
79
|
+
Given a fixture app "markdown-app"
|
|
80
|
+
And a file named "config.rb" with:
|
|
81
|
+
"""
|
|
82
|
+
activate :commonmarker
|
|
83
|
+
set :markdown, plugins: {syntax_highlighter: {theme: "InspiredGitHub"}}
|
|
84
|
+
"""
|
|
85
|
+
Given the Server is running at "markdown-app"
|
|
86
|
+
When I go to "/fenced_code_blocks.html"
|
|
87
|
+
Then I should see "background-color:#ffffff"
|
|
88
|
+
|
|
89
|
+
Scenario: Commonmarker passes plugins through activate
|
|
90
|
+
Given a fixture app "markdown-app"
|
|
91
|
+
And a file named "config.rb" with:
|
|
92
|
+
"""
|
|
93
|
+
activate :commonmarker, options: {plugins: {syntax_highlighter: {theme: "InspiredGitHub"}}}
|
|
94
|
+
"""
|
|
95
|
+
Given the Server is running at "markdown-app"
|
|
96
|
+
When I go to "/fenced_code_blocks.html"
|
|
97
|
+
Then I should see "background-color:#ffffff"
|
|
98
|
+
|
|
78
99
|
Scenario: Commonmarker uses our link_to and image_tag helpers
|
|
79
100
|
Given a fixture app "markdown-app"
|
|
80
101
|
And a file named "config.rb" with:
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
require "commonmarker"
|
|
4
4
|
require "active_support/core_ext/module/attribute_accessors"
|
|
5
|
+
require "active_support/core_ext/hash/keys"
|
|
5
6
|
|
|
6
7
|
module Middleman
|
|
7
8
|
module Renderers
|
|
@@ -21,6 +22,7 @@ module Middleman
|
|
|
21
22
|
|
|
22
23
|
def prepare
|
|
23
24
|
@context = options.delete(:context)
|
|
25
|
+
@commonmarker_plugins = build_commonmarker_plugins
|
|
24
26
|
@commonmarker_options = build_commonmarker_options
|
|
25
27
|
end
|
|
26
28
|
|
|
@@ -36,10 +38,10 @@ module Middleman
|
|
|
36
38
|
end
|
|
37
39
|
end
|
|
38
40
|
# Force unsafe so the injected raw <img> HTML is emitted.
|
|
39
|
-
return doc
|
|
41
|
+
return render_html(doc, render_options_with_unsafe)
|
|
40
42
|
end
|
|
41
43
|
|
|
42
|
-
doc
|
|
44
|
+
render_html(doc, @commonmarker_options)
|
|
43
45
|
end
|
|
44
46
|
|
|
45
47
|
private
|
|
@@ -77,12 +79,32 @@ module Middleman
|
|
|
77
79
|
nil
|
|
78
80
|
end
|
|
79
81
|
|
|
82
|
+
# Render with the user's `plugins` when given; otherwise let commonmarker
|
|
83
|
+
# apply its default plugins.
|
|
84
|
+
def render_html(doc, commonmarker_options)
|
|
85
|
+
doc.to_html(options: commonmarker_options, **@commonmarker_plugins)
|
|
86
|
+
end
|
|
87
|
+
|
|
80
88
|
def render_options_with_unsafe
|
|
81
89
|
@commonmarker_options.merge(
|
|
82
90
|
render: @commonmarker_options[:render].merge(unsafe: true)
|
|
83
91
|
)
|
|
84
92
|
end
|
|
85
93
|
|
|
94
|
+
# Take `plugins` out of the options as keyword arguments for to_html: {}
|
|
95
|
+
# when unset, {plugins: value} when set (a nil value disables the syntax
|
|
96
|
+
# highlighter). When both :plugins and "plugins" are present, the later
|
|
97
|
+
# one wins, as with the flat options, so `activate` overrides
|
|
98
|
+
# `set :markdown`.
|
|
99
|
+
def build_commonmarker_plugins
|
|
100
|
+
keys = options.keys.select { |key| key.to_s == "plugins" }
|
|
101
|
+
return {} if keys.empty?
|
|
102
|
+
|
|
103
|
+
value = keys.map { |key| options.delete(key) }.last
|
|
104
|
+
value = value.deep_symbolize_keys if value.is_a?(Hash)
|
|
105
|
+
{plugins: value}
|
|
106
|
+
end
|
|
107
|
+
|
|
86
108
|
# Distribute the flat `set :markdown, ...` options into the
|
|
87
109
|
# parse/render/extension nested structure, mapping `smartypants` to
|
|
88
110
|
# parse.smart.
|
|
@@ -16,7 +16,9 @@ module Middleman
|
|
|
16
16
|
def transform_link_node: (untyped node) -> void
|
|
17
17
|
def extract_text: (untyped node) -> String
|
|
18
18
|
def html_node_from: (String html) -> untyped
|
|
19
|
+
def render_html: (untyped doc, Hash[Symbol, untyped] commonmarker_options) -> String
|
|
19
20
|
def render_options_with_unsafe: () -> Hash[Symbol, untyped]
|
|
21
|
+
def build_commonmarker_plugins: () -> Hash[Symbol, untyped]
|
|
20
22
|
def build_commonmarker_options: () -> Hash[Symbol, untyped]
|
|
21
23
|
end
|
|
22
24
|
end
|
|
@@ -1,18 +1,29 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require "test_helper"
|
|
4
|
+
require "pathname"
|
|
4
5
|
|
|
5
6
|
class CommonmarkerTemplateTest < Minitest::Test
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
7
|
+
CODE_BLOCK = "```ruby\nputs 1\n```\n"
|
|
8
|
+
THEMES_DIR = File.expand_path("fixtures", __dir__)
|
|
9
|
+
|
|
10
|
+
# Build a template instance whose source is `body`; prepare runs on init
|
|
11
|
+
# and computes @commonmarker_plugins and @commonmarker_options from the
|
|
12
|
+
# given options.
|
|
13
|
+
def build(opts = {}, body = "")
|
|
14
|
+
Middleman::Renderers::CommonmarkerTemplate.new(nil, 1, opts) { body }
|
|
10
15
|
end
|
|
11
16
|
|
|
12
17
|
def options_for(opts)
|
|
13
18
|
build(opts).instance_variable_get(:@commonmarker_options)
|
|
14
19
|
end
|
|
15
20
|
|
|
21
|
+
# Render CODE_BLOCK with the given options. Tilt passes Object.new as the
|
|
22
|
+
# scope, so this goes through the scope branch of evaluate.
|
|
23
|
+
def html_for(opts)
|
|
24
|
+
build(opts, CODE_BLOCK).render
|
|
25
|
+
end
|
|
26
|
+
|
|
16
27
|
def image_node(markdown)
|
|
17
28
|
node = Commonmarker.parse(markdown)
|
|
18
29
|
found = nil
|
|
@@ -53,4 +64,88 @@ class CommonmarkerTemplateTest < Minitest::Test
|
|
|
53
64
|
def test_html_node_from_returns_nil_when_no_html_present
|
|
54
65
|
assert_nil build.send(:html_node_from, "just plain text")
|
|
55
66
|
end
|
|
67
|
+
|
|
68
|
+
def test_plugins_unset_matches_commonmarker_default
|
|
69
|
+
template = build({}, CODE_BLOCK)
|
|
70
|
+
opts = template.send(:render_options_with_unsafe)
|
|
71
|
+
expected = Commonmarker.parse(CODE_BLOCK, options: opts).to_html(options: opts)
|
|
72
|
+
assert_equal expected, template.render
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def test_plugins_with_builtin_theme
|
|
76
|
+
html = html_for(plugins: {syntax_highlighter: {theme: "InspiredGitHub"}})
|
|
77
|
+
assert_includes html, "background-color:#ffffff"
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def test_plugins_with_theme_from_path
|
|
81
|
+
html = html_for(plugins: {syntax_highlighter: {theme: "test-theme", path: THEMES_DIR}})
|
|
82
|
+
assert_includes html, "background-color:#123456"
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def test_plugins_with_path_only_keeps_default_theme
|
|
86
|
+
assert_equal html_for({}), html_for(plugins: {syntax_highlighter: {path: THEMES_DIR}})
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def test_plugins_with_empty_theme_outputs_classes
|
|
90
|
+
html = html_for(plugins: {syntax_highlighter: {theme: ""}})
|
|
91
|
+
assert_includes html, %(<pre class="syntax-highlighting">)
|
|
92
|
+
refute_includes html, "style="
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def test_plugins_disabling_highlighter
|
|
96
|
+
[{syntax_highlighter: nil}, {}, nil].each do |plugins|
|
|
97
|
+
refute_includes html_for(plugins:), "style=", "plugins: #{plugins.inspect}"
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def test_plugins_with_misspelled_key_disables_highlighter
|
|
102
|
+
refute_includes html_for(plugins: {syntax_highlight: {theme: "InspiredGitHub"}}), "style="
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def test_plugins_with_string_keys
|
|
106
|
+
assert_equal html_for(plugins: {syntax_highlighter: {theme: "InspiredGitHub"}}),
|
|
107
|
+
html_for(plugins: {"syntax_highlighter" => {"theme" => "InspiredGitHub"}})
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
def test_later_plugins_key_takes_precedence
|
|
111
|
+
inspired = {syntax_highlighter: {theme: "InspiredGitHub"}}
|
|
112
|
+
assert_equal html_for(plugins: inspired), html_for({:plugins => nil, "plugins" => inspired})
|
|
113
|
+
assert_equal html_for(plugins: nil), html_for({"plugins" => inspired, :plugins => nil})
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
def test_plugins_with_unknown_theme_raises
|
|
117
|
+
assert_raises(ArgumentError) { html_for(plugins: {syntax_highlighter: {theme: "no-such-theme"}}) }
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
def test_plugins_with_empty_highlighter_raises
|
|
121
|
+
assert_raises(TypeError) { html_for(plugins: {syntax_highlighter: {}}) }
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
def test_plugins_with_nil_theme_raises
|
|
125
|
+
assert_raises(TypeError) { html_for(plugins: {syntax_highlighter: {theme: nil}}) }
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
def test_plugins_with_non_hash_value_raises
|
|
129
|
+
{"x" => NoMethodError, [1] => TypeError}.each do |plugins, error|
|
|
130
|
+
assert_raises(error, "plugins: #{plugins.inspect}") { html_for(plugins:) }
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
def test_plugins_with_pathname_path_raises
|
|
135
|
+
assert_raises(TypeError) do
|
|
136
|
+
html_for(plugins: {syntax_highlighter: {theme: "test-theme", path: Pathname(THEMES_DIR)}})
|
|
137
|
+
end
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
def test_plugins_are_not_mixed_into_commonmarker_options
|
|
141
|
+
opts = options_for(plugins: {syntax_highlighter: {theme: "InspiredGitHub"}})
|
|
142
|
+
refute opts[:parse].key?(:plugins)
|
|
143
|
+
refute opts[:render].key?(:plugins)
|
|
144
|
+
refute opts[:extension].key?(:plugins)
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
def test_plugins_apply_without_scope
|
|
148
|
+
template = build({plugins: {syntax_highlighter: {theme: "InspiredGitHub"}}}, CODE_BLOCK)
|
|
149
|
+
assert_includes template.send(:evaluate, nil, {}), "background-color:#ffffff"
|
|
150
|
+
end
|
|
56
151
|
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
3
|
+
<plist version="1.0">
|
|
4
|
+
<dict>
|
|
5
|
+
<key>name</key>
|
|
6
|
+
<string>test-theme</string>
|
|
7
|
+
<key>settings</key>
|
|
8
|
+
<array>
|
|
9
|
+
<dict>
|
|
10
|
+
<key>settings</key>
|
|
11
|
+
<dict>
|
|
12
|
+
<key>background</key>
|
|
13
|
+
<string>#123456</string>
|
|
14
|
+
<key>foreground</key>
|
|
15
|
+
<string>#abcdef</string>
|
|
16
|
+
</dict>
|
|
17
|
+
</dict>
|
|
18
|
+
</array>
|
|
19
|
+
</dict>
|
|
20
|
+
</plist>
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: middleman-commonmarker
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.2.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Yusuke Nakamura
|
|
@@ -85,6 +85,7 @@ files:
|
|
|
85
85
|
- sig/middleman-commonmarker/extension.rbs
|
|
86
86
|
- sig/middleman-commonmarker/version.rbs
|
|
87
87
|
- test/commonmarker_template_test.rb
|
|
88
|
+
- test/fixtures/test-theme.tmTheme
|
|
88
89
|
- test/test_helper.rb
|
|
89
90
|
homepage: https://github.com/unasuke/middleman-commonmarker
|
|
90
91
|
licenses:
|
|
@@ -109,7 +110,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
109
110
|
- !ruby/object:Gem::Version
|
|
110
111
|
version: '0'
|
|
111
112
|
requirements: []
|
|
112
|
-
rubygems_version: 4.0.
|
|
113
|
+
rubygems_version: 4.0.20
|
|
113
114
|
specification_version: 4
|
|
114
115
|
summary: Commonmarker (CommonMark) markdown engine extension for Middleman
|
|
115
116
|
test_files: []
|