jekyll 3.6.3 → 3.7.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of jekyll might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/.rubocop.yml +0 -9
- data/LICENSE +1 -1
- data/README.markdown +1 -1
- data/lib/jekyll.rb +3 -0
- data/lib/jekyll/cleaner.rb +3 -1
- data/lib/jekyll/collection.rb +7 -3
- data/lib/jekyll/commands/clean.rb +1 -1
- data/lib/jekyll/commands/doctor.rb +3 -1
- data/lib/jekyll/commands/new.rb +5 -2
- data/lib/jekyll/commands/serve.rb +183 -41
- data/lib/jekyll/commands/serve/live_reload_reactor.rb +127 -0
- data/lib/jekyll/commands/serve/livereload_assets/livereload.js +1183 -0
- data/lib/jekyll/commands/serve/servlet.rb +142 -1
- data/lib/jekyll/commands/serve/websockets.rb +80 -0
- data/lib/jekyll/configuration.rb +9 -17
- data/lib/jekyll/converters/markdown.rb +1 -1
- data/lib/jekyll/converters/markdown/kramdown_parser.rb +8 -2
- data/lib/jekyll/converters/smartypants.rb +14 -2
- data/lib/jekyll/convertible.rb +10 -4
- data/lib/jekyll/document.rb +2 -2
- data/lib/jekyll/entry_filter.rb +3 -6
- data/lib/jekyll/filters/url_filters.rb +6 -1
- data/lib/jekyll/frontmatter_defaults.rb +18 -3
- data/lib/jekyll/hooks.rb +3 -0
- data/lib/jekyll/liquid_renderer.rb +8 -6
- data/lib/jekyll/page.rb +1 -1
- data/lib/jekyll/page_without_a_file.rb +18 -0
- data/lib/jekyll/regenerator.rb +1 -1
- data/lib/jekyll/renderer.rb +2 -2
- data/lib/jekyll/site.rb +1 -3
- data/lib/jekyll/tags/highlight.rb +2 -2
- data/lib/jekyll/tags/include.rb +1 -1
- data/lib/jekyll/tags/post_url.rb +1 -1
- data/lib/jekyll/theme.rb +3 -2
- data/lib/jekyll/theme_builder.rb +8 -8
- data/lib/jekyll/utils.rb +41 -22
- data/lib/jekyll/utils/ansi.rb +0 -2
- data/lib/jekyll/utils/internet.rb +39 -0
- data/lib/jekyll/utils/thread_event.rb +35 -0
- data/lib/jekyll/version.rb +1 -1
- metadata +41 -7
@@ -5,6 +5,128 @@ require "webrick"
|
|
5
5
|
module Jekyll
|
6
6
|
module Commands
|
7
7
|
class Serve
|
8
|
+
# This class is used to determine if the Servlet should modify a served file
|
9
|
+
# to insert the LiveReload script tags
|
10
|
+
class SkipAnalyzer
|
11
|
+
BAD_USER_AGENTS = [%r!MSIE!].freeze
|
12
|
+
|
13
|
+
def self.skip_processing?(request, response, options)
|
14
|
+
new(request, response, options).skip_processing?
|
15
|
+
end
|
16
|
+
|
17
|
+
def initialize(request, response, options)
|
18
|
+
@options = options
|
19
|
+
@request = request
|
20
|
+
@response = response
|
21
|
+
end
|
22
|
+
|
23
|
+
def skip_processing?
|
24
|
+
!html? || chunked? || inline? || bad_browser?
|
25
|
+
end
|
26
|
+
|
27
|
+
def chunked?
|
28
|
+
@response["Transfer-Encoding"] == "chunked"
|
29
|
+
end
|
30
|
+
|
31
|
+
def inline?
|
32
|
+
@response["Content-Disposition"] =~ %r!^inline!
|
33
|
+
end
|
34
|
+
|
35
|
+
def bad_browser?
|
36
|
+
BAD_USER_AGENTS.any? { |pattern| @request["User-Agent"] =~ pattern }
|
37
|
+
end
|
38
|
+
|
39
|
+
def html?
|
40
|
+
@response["Content-Type"] =~ %r!text/html!
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
# This class inserts the LiveReload script tags into HTML as it is served
|
45
|
+
class BodyProcessor
|
46
|
+
HEAD_TAG_REGEX = %r!<head>|<head[^(er)][^<]*>!
|
47
|
+
|
48
|
+
attr_reader :content_length, :new_body, :livereload_added
|
49
|
+
|
50
|
+
def initialize(body, options)
|
51
|
+
@body = body
|
52
|
+
@options = options
|
53
|
+
@processed = false
|
54
|
+
end
|
55
|
+
|
56
|
+
def processed?
|
57
|
+
@processed
|
58
|
+
end
|
59
|
+
|
60
|
+
# rubocop:disable Metrics/MethodLength
|
61
|
+
def process!
|
62
|
+
@new_body = []
|
63
|
+
# @body will usually be a File object but Strings occur in rare cases
|
64
|
+
if @body.respond_to?(:each)
|
65
|
+
begin
|
66
|
+
@body.each { |line| @new_body << line.to_s }
|
67
|
+
ensure
|
68
|
+
@body.close
|
69
|
+
end
|
70
|
+
else
|
71
|
+
@new_body = @body.lines
|
72
|
+
end
|
73
|
+
|
74
|
+
@content_length = 0
|
75
|
+
@livereload_added = false
|
76
|
+
|
77
|
+
@new_body.each do |line|
|
78
|
+
if !@livereload_added && line["<head"]
|
79
|
+
line.gsub!(HEAD_TAG_REGEX) do |match|
|
80
|
+
%(#{match}#{template.result(binding)})
|
81
|
+
end
|
82
|
+
|
83
|
+
@livereload_added = true
|
84
|
+
end
|
85
|
+
|
86
|
+
@content_length += line.bytesize
|
87
|
+
@processed = true
|
88
|
+
end
|
89
|
+
@new_body = @new_body.join
|
90
|
+
end
|
91
|
+
|
92
|
+
def template
|
93
|
+
# Unclear what "snipver" does. Doc at
|
94
|
+
# https://github.com/livereload/livereload-js states that the recommended
|
95
|
+
# setting is 1.
|
96
|
+
|
97
|
+
# Complicated JavaScript to ensure that livereload.js is loaded from the
|
98
|
+
# same origin as the page. Mostly useful for dealing with the browser's
|
99
|
+
# distinction between 'localhost' and 127.0.0.1
|
100
|
+
template = <<-TEMPLATE
|
101
|
+
<script>
|
102
|
+
document.write(
|
103
|
+
'<script src="http://' +
|
104
|
+
(location.host || 'localhost').split(':')[0] +
|
105
|
+
':<%=@options["livereload_port"] %>/livereload.js?snipver=1<%= livereload_args %>"' +
|
106
|
+
'></' +
|
107
|
+
'script>');
|
108
|
+
</script>
|
109
|
+
TEMPLATE
|
110
|
+
ERB.new(Jekyll::Utils.strip_heredoc(template))
|
111
|
+
end
|
112
|
+
|
113
|
+
def livereload_args
|
114
|
+
# XHTML standard requires ampersands to be encoded as entities when in
|
115
|
+
# attributes. See http://stackoverflow.com/a/2190292
|
116
|
+
src = ""
|
117
|
+
if @options["livereload_min_delay"]
|
118
|
+
src += "&mindelay=#{@options["livereload_min_delay"]}"
|
119
|
+
end
|
120
|
+
if @options["livereload_max_delay"]
|
121
|
+
src += "&maxdelay=#{@options["livereload_max_delay"]}"
|
122
|
+
end
|
123
|
+
if @options["livereload_port"]
|
124
|
+
src += "&port=#{@options["livereload_port"]}"
|
125
|
+
end
|
126
|
+
src
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
8
130
|
class Servlet < WEBrick::HTTPServlet::FileHandler
|
9
131
|
DEFAULTS = {
|
10
132
|
"Cache-Control" => "private, max-age=0, proxy-revalidate, " \
|
@@ -18,18 +140,37 @@ module Jekyll
|
|
18
140
|
super
|
19
141
|
end
|
20
142
|
|
143
|
+
def search_index_file(req, res)
|
144
|
+
super || search_file(req, res, ".html")
|
145
|
+
end
|
146
|
+
|
21
147
|
# Add the ability to tap file.html the same way that Nginx does on our
|
22
148
|
# Docker images (or on GitHub Pages.) The difference is that we might end
|
23
149
|
# up with a different preference on which comes first.
|
24
150
|
|
25
151
|
def search_file(req, res, basename)
|
26
152
|
# /file.* > /file/index.html > /file.html
|
27
|
-
super || super(req, res, "
|
153
|
+
super || super(req, res, "#{basename}.html")
|
28
154
|
end
|
29
155
|
|
30
156
|
# rubocop:disable Naming/MethodName
|
31
157
|
def do_GET(req, res)
|
32
158
|
rtn = super
|
159
|
+
|
160
|
+
if @jekyll_opts["livereload"]
|
161
|
+
return rtn if SkipAnalyzer.skip_processing?(req, res, @jekyll_opts)
|
162
|
+
|
163
|
+
processor = BodyProcessor.new(res.body, @jekyll_opts)
|
164
|
+
processor.process!
|
165
|
+
res.body = processor.new_body
|
166
|
+
res.content_length = processor.content_length.to_s
|
167
|
+
|
168
|
+
if processor.livereload_added
|
169
|
+
# Add a header to indicate that the page content has been modified
|
170
|
+
res["X-Rack-LiveReload"] = "1"
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
33
174
|
validate_and_ensure_charset(req, res)
|
34
175
|
res.header.merge!(@headers)
|
35
176
|
rtn
|
@@ -0,0 +1,80 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "http/parser"
|
4
|
+
|
5
|
+
module Jekyll
|
6
|
+
module Commands
|
7
|
+
class Serve
|
8
|
+
# The LiveReload protocol requires the server to serve livereload.js over HTTP
|
9
|
+
# despite the fact that the protocol itself uses WebSockets. This custom connection
|
10
|
+
# class addresses the dual protocols that the server needs to understand.
|
11
|
+
class HttpAwareConnection < EventMachine::WebSocket::Connection
|
12
|
+
attr_reader :reload_body, :reload_size
|
13
|
+
|
14
|
+
def initialize(_opts)
|
15
|
+
# If EventMachine SSL support on Windows ever gets better, the code below will
|
16
|
+
# set up the reactor to handle SSL
|
17
|
+
#
|
18
|
+
# @ssl_enabled = opts["ssl_cert"] && opts["ssl_key"]
|
19
|
+
# if @ssl_enabled
|
20
|
+
# em_opts[:tls_options] = {
|
21
|
+
# :private_key_file => Jekyll.sanitized_path(opts["source"], opts["ssl_key"]),
|
22
|
+
# :cert_chain_file => Jekyll.sanitized_path(opts["source"], opts["ssl_cert"])
|
23
|
+
# }
|
24
|
+
# em_opts[:secure] = true
|
25
|
+
# end
|
26
|
+
|
27
|
+
# This is too noisy even for --verbose, but uncomment if you need it for
|
28
|
+
# a specific WebSockets issue. Adding ?LR-verbose=true onto the URL will
|
29
|
+
# enable logging on the client side.
|
30
|
+
# em_opts[:debug] = true
|
31
|
+
|
32
|
+
em_opts = {}
|
33
|
+
super(em_opts)
|
34
|
+
|
35
|
+
reload_file = File.join(Serve.singleton_class::LIVERELOAD_DIR, "livereload.js")
|
36
|
+
|
37
|
+
@reload_body = File.read(reload_file)
|
38
|
+
@reload_size = @reload_body.bytesize
|
39
|
+
end
|
40
|
+
|
41
|
+
# rubocop:disable Metrics/MethodLength
|
42
|
+
def dispatch(data)
|
43
|
+
parser = Http::Parser.new
|
44
|
+
parser << data
|
45
|
+
|
46
|
+
# WebSockets requests will have a Connection: Upgrade header
|
47
|
+
if parser.http_method != "GET" || parser.upgrade?
|
48
|
+
super
|
49
|
+
elsif parser.request_url =~ %r!^\/livereload.js!
|
50
|
+
headers = [
|
51
|
+
"HTTP/1.1 200 OK",
|
52
|
+
"Content-Type: application/javascript",
|
53
|
+
"Content-Length: #{reload_size}",
|
54
|
+
"",
|
55
|
+
"",
|
56
|
+
].join("\r\n")
|
57
|
+
send_data(headers)
|
58
|
+
|
59
|
+
# stream_file_data would free us from keeping livereload.js in memory
|
60
|
+
# but JRuby blocks on that call and never returns
|
61
|
+
send_data(reload_body)
|
62
|
+
close_connection_after_writing
|
63
|
+
else
|
64
|
+
body = "This port only serves livereload.js over HTTP.\n"
|
65
|
+
headers = [
|
66
|
+
"HTTP/1.1 400 Bad Request",
|
67
|
+
"Content-Type: text/plain",
|
68
|
+
"Content-Length: #{body.bytesize}",
|
69
|
+
"",
|
70
|
+
"",
|
71
|
+
].join("\r\n")
|
72
|
+
send_data(headers)
|
73
|
+
send_data(body)
|
74
|
+
close_connection_after_writing
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
data/lib/jekyll/configuration.rb
CHANGED
@@ -8,6 +8,7 @@ module Jekyll
|
|
8
8
|
# Where things are
|
9
9
|
"source" => Dir.pwd,
|
10
10
|
"destination" => File.join(Dir.pwd, "_site"),
|
11
|
+
"collections_dir" => "",
|
11
12
|
"plugins_dir" => "_plugins",
|
12
13
|
"layouts_dir" => "_layouts",
|
13
14
|
"data_dir" => "_data",
|
@@ -79,6 +80,7 @@ module Jekyll
|
|
79
80
|
"input" => "GFM",
|
80
81
|
"hard_wrap" => false,
|
81
82
|
"footnote_nr" => 1,
|
83
|
+
"show_warnings" => false,
|
82
84
|
},
|
83
85
|
}.map { |k, v| [k, v.freeze] }].freeze
|
84
86
|
|
@@ -95,7 +97,7 @@ module Jekyll
|
|
95
97
|
# problems and backwards-compatibility.
|
96
98
|
def from(user_config)
|
97
99
|
Utils.deep_merge_hashes(DEFAULTS, Configuration[user_config].stringify_keys)
|
98
|
-
.
|
100
|
+
.add_default_collections
|
99
101
|
end
|
100
102
|
end
|
101
103
|
|
@@ -132,8 +134,8 @@ module Jekyll
|
|
132
134
|
def safe_load_file(filename)
|
133
135
|
case File.extname(filename)
|
134
136
|
when %r!\.toml!i
|
135
|
-
Jekyll::External.require_with_graceful_fail("
|
136
|
-
|
137
|
+
Jekyll::External.require_with_graceful_fail("tomlrb") unless defined?(Tomlrb)
|
138
|
+
Tomlrb.load_file(filename)
|
137
139
|
when %r!\.ya?ml!i
|
138
140
|
SafeYAML.load_file(filename) || {}
|
139
141
|
else
|
@@ -163,8 +165,7 @@ module Jekyll
|
|
163
165
|
config_files = Jekyll.sanitized_path(source(override), "_config.#{default}")
|
164
166
|
@default_config_file = true
|
165
167
|
end
|
166
|
-
config_files
|
167
|
-
config_files
|
168
|
+
Array(config_files)
|
168
169
|
end
|
169
170
|
|
170
171
|
# Public: Read configuration and return merged Hash
|
@@ -209,7 +210,7 @@ module Jekyll
|
|
209
210
|
warn err
|
210
211
|
end
|
211
212
|
|
212
|
-
configuration.
|
213
|
+
configuration.backwards_compatibilize.add_default_collections
|
213
214
|
end
|
214
215
|
|
215
216
|
# Public: Split a CSV string into an array containing its values
|
@@ -245,18 +246,9 @@ module Jekyll
|
|
245
246
|
config
|
246
247
|
end
|
247
248
|
|
249
|
+
# DEPRECATED.
|
248
250
|
def fix_common_issues
|
249
|
-
|
250
|
-
|
251
|
-
if config.key?("paginate") && (!config["paginate"].is_a?(Integer) ||
|
252
|
-
config["paginate"] < 1)
|
253
|
-
|
254
|
-
Jekyll.logger.warn "Config Warning:", "The `paginate` key must be a positive" \
|
255
|
-
" integer or nil. It's currently set to '#{config["paginate"].inspect}'."
|
256
|
-
config["paginate"] = nil
|
257
|
-
end
|
258
|
-
|
259
|
-
config
|
251
|
+
self
|
260
252
|
end
|
261
253
|
|
262
254
|
def add_default_collections
|
@@ -44,7 +44,7 @@ module Jekyll
|
|
44
44
|
# are not in safe mode.)
|
45
45
|
|
46
46
|
def valid_processors
|
47
|
-
%
|
47
|
+
%w(rdiscount kramdown redcarpet) + third_party_processors
|
48
48
|
end
|
49
49
|
|
50
50
|
# Public: A list of processors that you provide via plugins.
|
@@ -1,5 +1,4 @@
|
|
1
1
|
# Frozen-string-literal: true
|
2
|
-
# Encoding: utf-8
|
3
2
|
|
4
3
|
module Jekyll
|
5
4
|
module Converters
|
@@ -38,7 +37,14 @@ module Jekyll
|
|
38
37
|
end
|
39
38
|
|
40
39
|
def convert(content)
|
41
|
-
Kramdown::Document.new(content, @config)
|
40
|
+
document = Kramdown::Document.new(content, @config)
|
41
|
+
html_output = document.to_html
|
42
|
+
if @config["show_warnings"]
|
43
|
+
document.warnings.each do |warning|
|
44
|
+
Jekyll.logger.warn "Kramdown warning:", warning
|
45
|
+
end
|
46
|
+
end
|
47
|
+
html_output
|
42
48
|
end
|
43
49
|
|
44
50
|
private
|
@@ -3,9 +3,14 @@
|
|
3
3
|
class Kramdown::Parser::SmartyPants < Kramdown::Parser::Kramdown
|
4
4
|
def initialize(source, options)
|
5
5
|
super
|
6
|
-
@block_parsers = [:block_html]
|
6
|
+
@block_parsers = [:block_html, :content]
|
7
7
|
@span_parsers = [:smart_quotes, :html_entity, :typographic_syms, :span_html]
|
8
8
|
end
|
9
|
+
|
10
|
+
def parse_content
|
11
|
+
add_text @src.scan(%r!\A.*\n!)
|
12
|
+
end
|
13
|
+
define_parser(:content, %r!\A!)
|
9
14
|
end
|
10
15
|
|
11
16
|
module Jekyll
|
@@ -29,7 +34,14 @@ module Jekyll
|
|
29
34
|
end
|
30
35
|
|
31
36
|
def convert(content)
|
32
|
-
Kramdown::Document.new(content, @config)
|
37
|
+
document = Kramdown::Document.new(content, @config)
|
38
|
+
html_output = document.to_html.chomp
|
39
|
+
if @config["show_warnings"]
|
40
|
+
document.warnings.each do |warning|
|
41
|
+
Jekyll.logger.warn "Kramdown warning:", warning.sub(%r!^Warning:\s+!, "")
|
42
|
+
end
|
43
|
+
end
|
44
|
+
html_output
|
33
45
|
end
|
34
46
|
end
|
35
47
|
end
|
data/lib/jekyll/convertible.rb
CHANGED
@@ -46,10 +46,10 @@ module Jekyll
|
|
46
46
|
self.content = $POSTMATCH
|
47
47
|
self.data = SafeYAML.load(Regexp.last_match(1))
|
48
48
|
end
|
49
|
-
rescue SyntaxError => e
|
49
|
+
rescue Psych::SyntaxError => e
|
50
50
|
Jekyll.logger.warn "YAML Exception reading #{filename}: #{e.message}"
|
51
51
|
raise e if self.site.config["strict_front_matter"]
|
52
|
-
rescue => e
|
52
|
+
rescue StandardError => e
|
53
53
|
Jekyll.logger.warn "Error reading file #{filename}: #{e.message}"
|
54
54
|
raise e if self.site.config["strict_front_matter"]
|
55
55
|
end
|
@@ -172,9 +172,10 @@ module Jekyll
|
|
172
172
|
|
173
173
|
# Determine whether the file should be placed into layouts.
|
174
174
|
#
|
175
|
-
# Returns false if the document is an asset file
|
175
|
+
# Returns false if the document is an asset file or if the front matter
|
176
|
+
# specifies `layout: none`
|
176
177
|
def place_in_layout?
|
177
|
-
!asset_file?
|
178
|
+
!(asset_file? || no_layout?)
|
178
179
|
end
|
179
180
|
|
180
181
|
# Checks if the layout specified in the document actually exists
|
@@ -244,8 +245,13 @@ module Jekyll
|
|
244
245
|
end
|
245
246
|
|
246
247
|
private
|
248
|
+
|
247
249
|
def _renderer
|
248
250
|
@_renderer ||= Jekyll::Renderer.new(site, self)
|
249
251
|
end
|
252
|
+
|
253
|
+
def no_layout?
|
254
|
+
data["layout"] == "none"
|
255
|
+
end
|
250
256
|
end
|
251
257
|
end
|
data/lib/jekyll/document.rb
CHANGED
@@ -266,7 +266,7 @@ module Jekyll
|
|
266
266
|
merge_defaults
|
267
267
|
read_content(opts)
|
268
268
|
read_post_data
|
269
|
-
rescue => e
|
269
|
+
rescue StandardError => e
|
270
270
|
handle_read_error(e)
|
271
271
|
end
|
272
272
|
end
|
@@ -463,7 +463,7 @@ module Jekyll
|
|
463
463
|
|
464
464
|
private
|
465
465
|
def handle_read_error(error)
|
466
|
-
if error.is_a? SyntaxError
|
466
|
+
if error.is_a? Psych::SyntaxError
|
467
467
|
Jekyll.logger.error "Error:", "YAML Exception reading #{path}: #{error.message}"
|
468
468
|
else
|
469
469
|
Jekyll.logger.error "Error:", "could not read file #{path}: #{error.message}"
|
data/lib/jekyll/entry_filter.rb
CHANGED
@@ -31,12 +31,9 @@ module Jekyll
|
|
31
31
|
|
32
32
|
def filter(entries)
|
33
33
|
entries.reject do |e|
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
next false if included?(e)
|
38
|
-
# Reject this entry if it is special, a backup file, or excluded.
|
39
|
-
special?(e) || backup?(e) || excluded?(e)
|
34
|
+
unless included?(e)
|
35
|
+
special?(e) || backup?(e) || excluded?(e) || symlink?(e)
|
36
|
+
end
|
40
37
|
end
|
41
38
|
end
|
42
39
|
|