jekyll-mentioji 0.1.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 +7 -0
- data/LICENSE +21 -0
- data/README.md +56 -0
- data/lib/jekyll-mentioji.rb +181 -0
- metadata +146 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 2f7969c91c7033c67e9327d2cb3dac8687bc30bd
|
4
|
+
data.tar.gz: a61f334384fc26db61b2adf0a9996768f55a02c9
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 6ecf13698e63ef1cd5ce1565108e0d678b5f3610086456202fcb9091594706ae79467e0cd750200ade2d7a6344f029be16ddf0ecbb517a773b9fb6409fad39f6
|
7
|
+
data.tar.gz: 8b04cc659afae2e1f9666c9b5ca9be95444351da0e5b38ca3260b757be43310219f0717f630524222daf65518c1072600b75bef623d841533dcb769d25f2f4be
|
data/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
MIT LICENSE
|
2
|
+
|
3
|
+
Copyright (c) 2018 Ashwin Maroli
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
# Jekyll Mentioji
|
2
|
+
|
3
|
+
If your site uses both [`jekyll-mentions`](https://github.com/jekyll/jekyll-mentions) and [`jemoji`](https://github.com/jekyll/jemoji), then
|
4
|
+
using `jekyll-mentioji` *instead*, is going to improve your build times.
|
5
|
+
|
6
|
+
Internally, this plugin combines the code & logic behind the above two plugins and adapts the associated code in
|
7
|
+
[`html-pipeline`](https://github.com/jch/html-pipeline), which the above two plugins wrap around, to emerge as *the faster implementation*
|
8
|
+
in comparison to using the two plugins together in a site.
|
9
|
+
|
10
|
+
## Usage
|
11
|
+
|
12
|
+
Replace the two plugins in your `Gemfile` and/or `_config.yml` with this plugin:
|
13
|
+
|
14
|
+
```diff
|
15
|
+
# Gemfile
|
16
|
+
|
17
|
+
group :jekyll_plugins do
|
18
|
+
- gem "jekyll-mentions"
|
19
|
+
- gem "jemoji"
|
20
|
+
+ gem "jekyll-mentioji"
|
21
|
+
end
|
22
|
+
```
|
23
|
+
```sh
|
24
|
+
bundle install
|
25
|
+
```
|
26
|
+
```diff
|
27
|
+
# _config.yml
|
28
|
+
|
29
|
+
plugins:
|
30
|
+
- - jekyll-mentions
|
31
|
+
- - jemoji
|
32
|
+
+ - jekyll-mentioji
|
33
|
+
```
|
34
|
+
|
35
|
+
## Other Notes:
|
36
|
+
|
37
|
+
- This plugin aims to be a zero-config replacement for the two plugins and therefore should be compatible with existing configuration
|
38
|
+
for the two plugins. `jekyll-mentioji` will read both existing `jekyll-mentions:` and `emoji:` settings in your config file.
|
39
|
+
- A few diversions from the two official plugins:
|
40
|
+
- `@mention` can currently include the underscore (`_`) along with alphanumeric characters and hyphen (`-`)
|
41
|
+
- `@mention` will not be rendered within `<script></script>`
|
42
|
+
- configuration for emoji assets-path mirror that of `jekyll-mentions`: the value can be both a string or a dictionary
|
43
|
+
|
44
|
+
### Build times comparison
|
45
|
+
|
46
|
+
rvm | jmentions+jemoji | *jmentioji*
|
47
|
+
:---: | :----: | :------:
|
48
|
+
2.2.9 | 15.482 | *13.671*
|
49
|
+
2.3.6 | 13.798 | *11.988*
|
50
|
+
2.4.3 | 14.225 | *12.848*
|
51
|
+
2.5.0 | 14.560 | *12.771*
|
52
|
+
|
53
|
+
(built using `jekyll:master@c7f006`)
|
54
|
+
|
55
|
+
*Disclaimer: The no.s above are averages of 3 restarted jobs on two separate Travis CI build-commits and therefore cannot be considered as
|
56
|
+
solid evidence. However, tests run locally do show an improvement of approx. 2s with `jekyll-mentioji` over the combo.*
|
@@ -0,0 +1,181 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "gemoji"
|
4
|
+
require "nokogiri"
|
5
|
+
|
6
|
+
module Jekyll
|
7
|
+
class Mentioji
|
8
|
+
MENTIONPATTERNS = %r~(?:^|\B)@((?>[\w][\w-]*))(?!/)(?=\.+[ \t\W]|\.+$|[^\w.]|$)~i
|
9
|
+
|
10
|
+
OPENING_BODY_TAG_REGEX = %r!<body(.*?)>\s*!
|
11
|
+
|
12
|
+
IGNORE_MENTION_PARENTS = %w(pre code a script style).freeze
|
13
|
+
IGNORE_EMOJI_PARENTS = %w(pre code tt).freeze
|
14
|
+
|
15
|
+
class << self
|
16
|
+
def transform(doc)
|
17
|
+
content = doc.output
|
18
|
+
return unless content.include?("@") || content.include?(":")
|
19
|
+
setup_transformer(doc.site.config)
|
20
|
+
doc.output = if content.include?("<body")
|
21
|
+
process_html_body(content)
|
22
|
+
else
|
23
|
+
process(content)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def transformable?(doc)
|
28
|
+
(doc.is_a?(Jekyll::Page) || doc.write?) &&
|
29
|
+
doc.output_ext == ".html" || (doc.permalink&.end_with?("/"))
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
def process_html_body(content)
|
35
|
+
head, opener, tail = content.partition(OPENING_BODY_TAG_REGEX)
|
36
|
+
body_content, *rest = tail.partition("</body>")
|
37
|
+
|
38
|
+
String.new(head) << opener << process(body_content) << rest.join
|
39
|
+
end
|
40
|
+
|
41
|
+
def process(body_content)
|
42
|
+
return body_content unless body_content =~ prelim_check_regex
|
43
|
+
parsed_body = Nokogiri::HTML::DocumentFragment.parse(body_content)
|
44
|
+
parsed_body.search(".//text()").each do |node|
|
45
|
+
content = node.text
|
46
|
+
next if !content.include?("@") && !content.include?(":")
|
47
|
+
node.replace(
|
48
|
+
mention_renderer(
|
49
|
+
node, emoji_renderer(node, content)
|
50
|
+
)
|
51
|
+
)
|
52
|
+
end
|
53
|
+
parsed_body.to_html
|
54
|
+
end
|
55
|
+
|
56
|
+
# rubocop:disable Naming/MemoizedInstanceVariableName
|
57
|
+
def setup_transformer(config)
|
58
|
+
@transconfig ||= {
|
59
|
+
"mention_base" => compute_base(
|
60
|
+
config, "jekyll-mentions", "base_url", default_mention_base
|
61
|
+
),
|
62
|
+
"emoji_source" => compute_base(
|
63
|
+
config, "emoji", "src", default_asset_root
|
64
|
+
),
|
65
|
+
}
|
66
|
+
end
|
67
|
+
# rubocop:enable Naming/MemoizedInstanceVariableName
|
68
|
+
|
69
|
+
def compute_base(config, key, subkey, default_value)
|
70
|
+
subject = config[key]
|
71
|
+
case subject
|
72
|
+
when nil, NilClass
|
73
|
+
default_value
|
74
|
+
when String
|
75
|
+
subject
|
76
|
+
when Hash
|
77
|
+
subject.fetch(subkey, default_value)
|
78
|
+
else
|
79
|
+
raise TypeError, "Your #{key} config has to either be a string or a hash. It's a " \
|
80
|
+
"kind of #{subject.class} right now."
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
def default_mention_base
|
85
|
+
if !ENV["SSL"].to_s.empty? && !ENV["GITHUB_HOSTNAME"].to_s.empty?
|
86
|
+
scheme = ENV["SSL"] == "true" ? "https://" : "http://"
|
87
|
+
"#{scheme}#{ENV["GITHUB_HOSTNAME"].chomp("/")}"
|
88
|
+
else
|
89
|
+
"https://github.com"
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def default_asset_root
|
94
|
+
if ENV["ASSET_HOST_URL"].to_s.empty?
|
95
|
+
File.join("https://assets-cdn.github.com", "/images/icons")
|
96
|
+
else
|
97
|
+
File.join(ENV["ASSET_HOST_URL"], "/images/icons")
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
def mention_markup(username)
|
102
|
+
mention_stash[username] ||= begin
|
103
|
+
"<a href='#{@transconfig["mention_base"]}/#{username}' " \
|
104
|
+
"class='user-mention'>@#{username}</a>"
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
def mention_renderer(node, text)
|
109
|
+
return text unless text.include?("@")
|
110
|
+
return text if has_ancestor?(node, IGNORE_MENTION_PARENTS)
|
111
|
+
text.gsub(MENTIONPATTERNS) { mention_markup(Regexp.last_match(1)) }
|
112
|
+
end
|
113
|
+
|
114
|
+
def emoji_renderer(node, text)
|
115
|
+
return text unless text.include?(":")
|
116
|
+
return text if has_ancestor?(node, IGNORE_EMOJI_PARENTS)
|
117
|
+
text.gsub(emoji_pattern) { emoji_markup(Regexp.last_match(1)) }
|
118
|
+
end
|
119
|
+
|
120
|
+
def emoji_url(name)
|
121
|
+
File.join(
|
122
|
+
@transconfig["emoji_source"], "emoji",
|
123
|
+
::Emoji.find_by_alias(name).image_filename
|
124
|
+
)
|
125
|
+
end
|
126
|
+
|
127
|
+
def emoji_markup(name)
|
128
|
+
emoji_stash[name] ||= begin
|
129
|
+
attrs = []
|
130
|
+
img_attrs(name).each do |key, value|
|
131
|
+
attrs << "#{key}='#{value}'"
|
132
|
+
end
|
133
|
+
"<img #{attrs.join(" ")}>"
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
def img_attrs(name)
|
138
|
+
{
|
139
|
+
"class" => "emoji",
|
140
|
+
"title" => ":#{name}:",
|
141
|
+
"alt" => ":#{name}:",
|
142
|
+
"src" => emoji_url(name).to_s,
|
143
|
+
"height" => "20",
|
144
|
+
"width" => "20",
|
145
|
+
}
|
146
|
+
end
|
147
|
+
|
148
|
+
def mention_stash
|
149
|
+
@mention_stash ||= {}
|
150
|
+
end
|
151
|
+
|
152
|
+
def emoji_stash
|
153
|
+
@emoji_stash ||= {}
|
154
|
+
end
|
155
|
+
|
156
|
+
def emoji_names
|
157
|
+
::Emoji.all.flat_map(&:aliases).sort!.map! { |name| Regexp.escape(name) }
|
158
|
+
end
|
159
|
+
|
160
|
+
def emoji_pattern
|
161
|
+
@emoji_pattern ||= %r!:(#{emoji_names.join('|')}):!
|
162
|
+
end
|
163
|
+
|
164
|
+
def prelim_check_regex
|
165
|
+
@prelim_check_regex ||= %r!#{MENTIONPATTERNS}|#{emoji_pattern}!
|
166
|
+
end
|
167
|
+
|
168
|
+
# rubocop:disable Naming/PredicateName
|
169
|
+
def has_ancestor?(node, tags)
|
170
|
+
while (node = node.respond_to?(:parent) && node.parent)
|
171
|
+
break true if tags.include?(node.name.downcase)
|
172
|
+
end
|
173
|
+
end
|
174
|
+
# rubocop:enable Naming/PredicateName
|
175
|
+
end
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
Jekyll::Hooks.register([:pages, :documents], :post_render) do |doc|
|
180
|
+
Jekyll::Mentioji.transform(doc) if Jekyll::Mentioji.transformable?(doc)
|
181
|
+
end
|
metadata
ADDED
@@ -0,0 +1,146 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: jekyll-mentioji
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Ashwin Maroli
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2018-08-15 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: gemoji
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '3.0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '3.0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: jekyll
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '3.5'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '3.5'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: nokogiri
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '1.4'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '1.4'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: cucumber
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '3.0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '3.0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: jekyll-mentions
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '1.0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '1.0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: jemoji
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0.9'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - "~>"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0.9'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: rubocop-jekyll
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - "~>"
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0.1'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - "~>"
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0.1'
|
111
|
+
description: Improve build times for sites using both 'jekyll-mentions and 'jemoji'
|
112
|
+
plugins
|
113
|
+
email:
|
114
|
+
- ashmaroli@gmail.com
|
115
|
+
executables: []
|
116
|
+
extensions: []
|
117
|
+
extra_rdoc_files: []
|
118
|
+
files:
|
119
|
+
- LICENSE
|
120
|
+
- README.md
|
121
|
+
- lib/jekyll-mentioji.rb
|
122
|
+
homepage: https://github.com/ashmaroli/jekyll-mentioji
|
123
|
+
licenses:
|
124
|
+
- MIT
|
125
|
+
metadata: {}
|
126
|
+
post_install_message:
|
127
|
+
rdoc_options: []
|
128
|
+
require_paths:
|
129
|
+
- lib
|
130
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
131
|
+
requirements:
|
132
|
+
- - ">="
|
133
|
+
- !ruby/object:Gem::Version
|
134
|
+
version: 2.3.0
|
135
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
136
|
+
requirements:
|
137
|
+
- - ">="
|
138
|
+
- !ruby/object:Gem::Version
|
139
|
+
version: '0'
|
140
|
+
requirements: []
|
141
|
+
rubyforge_project:
|
142
|
+
rubygems_version: 2.6.14
|
143
|
+
signing_key:
|
144
|
+
specification_version: 4
|
145
|
+
summary: Faster version of the 'Jekyll::Mentions + Jekyll::Emoji' combo
|
146
|
+
test_files: []
|