jekyll 4.0.0.pre.alpha1 → 4.1.1
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/.rubocop.yml +58 -17
- data/lib/jekyll.rb +5 -1
- data/lib/jekyll/cache.rb +71 -64
- data/lib/jekyll/cleaner.rb +5 -5
- data/lib/jekyll/collection.rb +6 -4
- data/lib/jekyll/command.rb +4 -2
- data/lib/jekyll/commands/new.rb +4 -4
- data/lib/jekyll/commands/serve.rb +9 -1
- data/lib/jekyll/commands/serve/servlet.rb +13 -14
- data/lib/jekyll/commands/serve/websockets.rb +1 -1
- data/lib/jekyll/configuration.rb +40 -129
- data/lib/jekyll/converters/identity.rb +2 -2
- data/lib/jekyll/converters/markdown/kramdown_parser.rb +70 -9
- data/lib/jekyll/convertible.rb +21 -20
- data/lib/jekyll/document.rb +56 -31
- data/lib/jekyll/drops/document_drop.rb +12 -0
- data/lib/jekyll/drops/drop.rb +14 -8
- data/lib/jekyll/drops/site_drop.rb +11 -1
- data/lib/jekyll/drops/url_drop.rb +52 -1
- data/lib/jekyll/entry_filter.rb +38 -44
- data/lib/jekyll/excerpt.rb +3 -3
- data/lib/jekyll/filters.rb +140 -22
- data/lib/jekyll/filters/url_filters.rb +41 -14
- data/lib/jekyll/frontmatter_defaults.rb +15 -20
- data/lib/jekyll/hooks.rb +2 -5
- data/lib/jekyll/inclusion.rb +32 -0
- data/lib/jekyll/liquid_renderer.rb +18 -15
- data/lib/jekyll/liquid_renderer/file.rb +10 -0
- data/lib/jekyll/liquid_renderer/table.rb +18 -61
- data/lib/jekyll/mime.types +53 -11
- data/lib/jekyll/page.rb +26 -2
- data/lib/jekyll/page_excerpt.rb +25 -0
- data/lib/jekyll/path_manager.rb +31 -0
- data/lib/jekyll/profiler.rb +58 -0
- data/lib/jekyll/reader.rb +4 -1
- data/lib/jekyll/readers/collection_reader.rb +1 -0
- data/lib/jekyll/readers/data_reader.rb +1 -0
- data/lib/jekyll/readers/layout_reader.rb +1 -0
- data/lib/jekyll/readers/page_reader.rb +5 -5
- data/lib/jekyll/readers/post_reader.rb +2 -1
- data/lib/jekyll/readers/static_file_reader.rb +3 -3
- data/lib/jekyll/readers/theme_assets_reader.rb +1 -0
- data/lib/jekyll/renderer.rb +9 -15
- data/lib/jekyll/site.rb +21 -12
- data/lib/jekyll/static_file.rb +15 -10
- data/lib/jekyll/tags/highlight.rb +2 -4
- data/lib/jekyll/tags/include.rb +67 -11
- data/lib/jekyll/tags/post_url.rb +8 -5
- data/lib/jekyll/theme.rb +19 -10
- data/lib/jekyll/url.rb +7 -3
- data/lib/jekyll/utils.rb +14 -18
- data/lib/jekyll/utils/platforms.rb +1 -1
- data/lib/jekyll/utils/win_tz.rb +1 -1
- data/lib/jekyll/version.rb +1 -1
- data/lib/theme_template/theme.gemspec.erb +1 -4
- metadata +33 -36
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
module Jekyll
|
4
4
|
module Converters
|
5
|
-
#
|
5
|
+
# Identity converter. Returns same content as given.
|
6
6
|
# For more info on converters see https://jekyllrb.com/docs/plugins/converters/
|
7
7
|
class Identity < Converter
|
8
8
|
safe true
|
@@ -12,7 +12,7 @@ module Jekyll
|
|
12
12
|
# Public: Does the given extension match this converter's list of acceptable extensions?
|
13
13
|
# Takes one argument: the file's extension (including the dot).
|
14
14
|
#
|
15
|
-
#
|
15
|
+
# _ext - The String extension to check (not relevant here)
|
16
16
|
#
|
17
17
|
# Returns true since it always matches.
|
18
18
|
def matches(_ext)
|
@@ -1,5 +1,73 @@
|
|
1
1
|
# Frozen-string-literal: true
|
2
2
|
|
3
|
+
module Kramdown
|
4
|
+
# A Kramdown::Document subclass meant to optimize memory usage from initializing
|
5
|
+
# a kramdown document for parsing.
|
6
|
+
#
|
7
|
+
# The optimization is by using the same options Hash (and its derivatives) for
|
8
|
+
# converting all Markdown documents in a Jekyll site.
|
9
|
+
class JekyllDocument < Document
|
10
|
+
class << self
|
11
|
+
attr_reader :options, :parser
|
12
|
+
|
13
|
+
# The implementation is basically the core logic in +Kramdown::Document#initialize+
|
14
|
+
#
|
15
|
+
# rubocop:disable Naming/MemoizedInstanceVariableName
|
16
|
+
def setup(options)
|
17
|
+
@cache ||= {}
|
18
|
+
|
19
|
+
# reset variables on a subsequent set up with a different options Hash
|
20
|
+
unless @cache[:id] == options.hash
|
21
|
+
@options = @parser = nil
|
22
|
+
@cache[:id] = options.hash
|
23
|
+
end
|
24
|
+
|
25
|
+
@options ||= Options.merge(options).freeze
|
26
|
+
@parser ||= begin
|
27
|
+
parser_name = (@options[:input] || "kramdown").to_s
|
28
|
+
parser_name = parser_name[0..0].upcase + parser_name[1..-1]
|
29
|
+
try_require("parser", parser_name)
|
30
|
+
|
31
|
+
if Parser.const_defined?(parser_name)
|
32
|
+
Parser.const_get(parser_name)
|
33
|
+
else
|
34
|
+
raise Kramdown::Error, "kramdown has no parser to handle the specified " \
|
35
|
+
"input format: #{@options[:input]}"
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
# rubocop:enable Naming/MemoizedInstanceVariableName
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
def try_require(type, name)
|
44
|
+
require "kramdown/#{type}/#{Utils.snake_case(name)}"
|
45
|
+
rescue LoadError
|
46
|
+
false
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def initialize(source, options = {})
|
51
|
+
JekyllDocument.setup(options)
|
52
|
+
|
53
|
+
@options = JekyllDocument.options
|
54
|
+
@root, @warnings = JekyllDocument.parser.parse(source, @options)
|
55
|
+
end
|
56
|
+
|
57
|
+
# Use Kramdown::Converter::Html class to convert this document into HTML.
|
58
|
+
#
|
59
|
+
# The implementation is basically an optimized version of core logic in
|
60
|
+
# +Kramdown::Document#method_missing+ from kramdown-2.1.0.
|
61
|
+
def to_html
|
62
|
+
output, warnings = Kramdown::Converter::Html.convert(@root, @options)
|
63
|
+
@warnings.concat(warnings)
|
64
|
+
output
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
#
|
70
|
+
|
3
71
|
module Jekyll
|
4
72
|
module Converters
|
5
73
|
class Markdown
|
@@ -31,14 +99,14 @@ module Jekyll
|
|
31
99
|
def setup
|
32
100
|
@config["syntax_highlighter"] ||= highlighter
|
33
101
|
@config["syntax_highlighter_opts"] ||= {}
|
102
|
+
@config["syntax_highlighter_opts"]["default_lang"] ||= "plaintext"
|
34
103
|
@config["syntax_highlighter_opts"]["guess_lang"] = @config["guess_lang"]
|
35
104
|
@config["coderay"] ||= {} # XXX: Legacy.
|
36
105
|
modernize_coderay_config
|
37
|
-
make_accessible
|
38
106
|
end
|
39
107
|
|
40
108
|
def convert(content)
|
41
|
-
document = Kramdown::
|
109
|
+
document = Kramdown::JekyllDocument.new(content, @config)
|
42
110
|
html_output = document.to_html
|
43
111
|
if @config["show_warnings"]
|
44
112
|
document.warnings.each do |warning|
|
@@ -64,13 +132,6 @@ module Jekyll
|
|
64
132
|
end
|
65
133
|
end
|
66
134
|
|
67
|
-
def make_accessible(hash = @config)
|
68
|
-
hash.keys.each do |key|
|
69
|
-
hash[key.to_sym] = hash[key]
|
70
|
-
make_accessible(hash[key]) if hash[key].is_a?(Hash)
|
71
|
-
end
|
72
|
-
end
|
73
|
-
|
74
135
|
# config[kramdown][syntax_higlighter] >
|
75
136
|
# config[kramdown][enable_coderay] >
|
76
137
|
# config[highlighter]
|
data/lib/jekyll/convertible.rb
CHANGED
@@ -39,7 +39,7 @@ module Jekyll
|
|
39
39
|
|
40
40
|
begin
|
41
41
|
self.content = File.read(@path || site.in_source_dir(base, name),
|
42
|
-
Utils.merged_file_read_opts(site, opts))
|
42
|
+
**Utils.merged_file_read_opts(site, opts))
|
43
43
|
if content =~ Document::YAML_FRONT_MATTER_REGEXP
|
44
44
|
self.content = $POSTMATCH
|
45
45
|
self.data = SafeYAML.load(Regexp.last_match(1))
|
@@ -78,7 +78,7 @@ module Jekyll
|
|
78
78
|
#
|
79
79
|
# Returns the transformed contents.
|
80
80
|
def transform
|
81
|
-
|
81
|
+
renderer.convert(content)
|
82
82
|
end
|
83
83
|
|
84
84
|
# Determine the extension depending on content_type.
|
@@ -86,7 +86,7 @@ module Jekyll
|
|
86
86
|
# Returns the String extension for the output file.
|
87
87
|
# e.g. ".html" for an HTML output file.
|
88
88
|
def output_ext
|
89
|
-
|
89
|
+
renderer.output_ext
|
90
90
|
end
|
91
91
|
|
92
92
|
# Determine which converter to use based on this convertible's
|
@@ -94,7 +94,7 @@ module Jekyll
|
|
94
94
|
#
|
95
95
|
# Returns the Converter instance.
|
96
96
|
def converters
|
97
|
-
|
97
|
+
renderer.converters
|
98
98
|
end
|
99
99
|
|
100
100
|
# Render Liquid in the content
|
@@ -105,16 +105,17 @@ module Jekyll
|
|
105
105
|
#
|
106
106
|
# Returns the converted content
|
107
107
|
def render_liquid(content, payload, info, path)
|
108
|
-
|
108
|
+
renderer.render_liquid(content, payload, info, path)
|
109
109
|
end
|
110
110
|
|
111
111
|
# Convert this Convertible's data to a Hash suitable for use by Liquid.
|
112
112
|
#
|
113
113
|
# Returns the Hash representation of this Convertible.
|
114
114
|
def to_liquid(attrs = nil)
|
115
|
-
further_data =
|
116
|
-
|
117
|
-
|
115
|
+
further_data = \
|
116
|
+
(attrs || self.class::ATTRIBUTES_FOR_LIQUID).each_with_object({}) do |attribute, hsh|
|
117
|
+
hsh[attribute] = send(attribute)
|
118
|
+
end
|
118
119
|
|
119
120
|
defaults = site.frontmatter_defaults.all(relative_path, type)
|
120
121
|
Utils.deep_merge_hashes defaults, Utils.deep_merge_hashes(data, further_data)
|
@@ -146,7 +147,7 @@ module Jekyll
|
|
146
147
|
#
|
147
148
|
# Returns true if extname == .sass or .scss, false otherwise.
|
148
149
|
def sass_file?
|
149
|
-
|
150
|
+
Jekyll::Document::SASS_FILE_EXTS.include?(ext)
|
150
151
|
end
|
151
152
|
|
152
153
|
# Determine whether the document is a CoffeeScript file.
|
@@ -190,10 +191,10 @@ module Jekyll
|
|
190
191
|
#
|
191
192
|
# Returns nothing
|
192
193
|
def render_all_layouts(layouts, payload, info)
|
193
|
-
|
194
|
-
self.output =
|
194
|
+
renderer.layouts = layouts
|
195
|
+
self.output = renderer.place_in_layouts(output, payload, info)
|
195
196
|
ensure
|
196
|
-
@
|
197
|
+
@renderer = nil # this will allow the modifications above to disappear
|
197
198
|
end
|
198
199
|
|
199
200
|
# Add any necessary layouts to this convertible document.
|
@@ -203,15 +204,15 @@ module Jekyll
|
|
203
204
|
#
|
204
205
|
# Returns nothing.
|
205
206
|
def do_layout(payload, layouts)
|
206
|
-
self.output =
|
207
|
-
|
208
|
-
|
207
|
+
self.output = renderer.tap do |doc_renderer|
|
208
|
+
doc_renderer.layouts = layouts
|
209
|
+
doc_renderer.payload = payload
|
209
210
|
end.run
|
210
211
|
|
211
212
|
Jekyll.logger.debug "Post-Render Hooks:", relative_path
|
212
213
|
Jekyll::Hooks.trigger hook_owner, :post_render, self
|
213
214
|
ensure
|
214
|
-
@
|
215
|
+
@renderer = nil # this will allow the modifications above to disappear
|
215
216
|
end
|
216
217
|
|
217
218
|
# Write the generated page file to the destination directory.
|
@@ -240,12 +241,12 @@ module Jekyll
|
|
240
241
|
end
|
241
242
|
end
|
242
243
|
|
243
|
-
|
244
|
-
|
245
|
-
def _renderer
|
246
|
-
@_renderer ||= Jekyll::Renderer.new(site, self)
|
244
|
+
def renderer
|
245
|
+
@renderer ||= Jekyll::Renderer.new(site, self)
|
247
246
|
end
|
248
247
|
|
248
|
+
private
|
249
|
+
|
249
250
|
def no_layout?
|
250
251
|
data["layout"] == "none"
|
251
252
|
end
|
data/lib/jekyll/document.rb
CHANGED
@@ -5,7 +5,7 @@ module Jekyll
|
|
5
5
|
include Comparable
|
6
6
|
extend Forwardable
|
7
7
|
|
8
|
-
attr_reader :path, :site, :extname, :collection
|
8
|
+
attr_reader :path, :site, :extname, :collection, :type
|
9
9
|
attr_accessor :content, :output
|
10
10
|
|
11
11
|
def_delegator :self, :read_post_data, :post_read
|
@@ -14,6 +14,23 @@ module Jekyll
|
|
14
14
|
DATELESS_FILENAME_MATCHER = %r!^(?:.+/)*(.*)(\.[^.]+)$!.freeze
|
15
15
|
DATE_FILENAME_MATCHER = %r!^(?>.+/)*?(\d{2,4}-\d{1,2}-\d{1,2})-([^/]*)(\.[^.]+)$!.freeze
|
16
16
|
|
17
|
+
SASS_FILE_EXTS = %w(.sass .scss).freeze
|
18
|
+
YAML_FILE_EXTS = %w(.yaml .yml).freeze
|
19
|
+
|
20
|
+
#
|
21
|
+
|
22
|
+
# Class-wide cache to stash and retrieve regexp to detect "super-directories"
|
23
|
+
# of a particular Jekyll::Document object.
|
24
|
+
#
|
25
|
+
# dirname - The *special directory* for the Document.
|
26
|
+
# e.g. "_posts" or "_drafts" for Documents from the `site.posts` collection.
|
27
|
+
def self.superdirs_regex(dirname)
|
28
|
+
@superdirs_regex ||= {}
|
29
|
+
@superdirs_regex[dirname] ||= %r!#{dirname}.*!
|
30
|
+
end
|
31
|
+
|
32
|
+
#
|
33
|
+
|
17
34
|
# Create a new Document.
|
18
35
|
#
|
19
36
|
# path - the path to the file
|
@@ -27,6 +44,8 @@ module Jekyll
|
|
27
44
|
@path = path
|
28
45
|
@extname = File.extname(path)
|
29
46
|
@collection = relations[:collection]
|
47
|
+
@type = @collection.label.to_sym
|
48
|
+
|
30
49
|
@has_yaml_header = nil
|
31
50
|
|
32
51
|
if draft?
|
@@ -36,7 +55,7 @@ module Jekyll
|
|
36
55
|
end
|
37
56
|
|
38
57
|
data.default_proc = proc do |_, key|
|
39
|
-
site.frontmatter_defaults.find(relative_path,
|
58
|
+
site.frontmatter_defaults.find(relative_path, type, key)
|
40
59
|
end
|
41
60
|
|
42
61
|
trigger_hooks(:post_init)
|
@@ -97,7 +116,7 @@ module Jekyll
|
|
97
116
|
#
|
98
117
|
# Returns the output extension
|
99
118
|
def output_ext
|
100
|
-
|
119
|
+
renderer.output_ext
|
101
120
|
end
|
102
121
|
|
103
122
|
# The base filename of the document, without the file extname.
|
@@ -114,6 +133,10 @@ module Jekyll
|
|
114
133
|
@basename ||= File.basename(path)
|
115
134
|
end
|
116
135
|
|
136
|
+
def renderer
|
137
|
+
@renderer ||= Jekyll::Renderer.new(site, self)
|
138
|
+
end
|
139
|
+
|
117
140
|
# Produces a "cleaned" relative path.
|
118
141
|
# The "cleaned" relative path is the relative path without the extname
|
119
142
|
# and with the collection's directory removed as well.
|
@@ -138,7 +161,7 @@ module Jekyll
|
|
138
161
|
#
|
139
162
|
# Returns true if the extname is either .yml or .yaml, false otherwise.
|
140
163
|
def yaml_file?
|
141
|
-
|
164
|
+
YAML_FILE_EXTS.include?(extname)
|
142
165
|
end
|
143
166
|
|
144
167
|
# Determine whether the document is an asset file.
|
@@ -154,7 +177,7 @@ module Jekyll
|
|
154
177
|
#
|
155
178
|
# Returns true if extname == .sass or .scss, false otherwise.
|
156
179
|
def sass_file?
|
157
|
-
|
180
|
+
SASS_FILE_EXTS.include?(extname)
|
158
181
|
end
|
159
182
|
|
160
183
|
# Determine whether the document is a CoffeeScript file.
|
@@ -279,7 +302,7 @@ module Jekyll
|
|
279
302
|
else
|
280
303
|
begin
|
281
304
|
merge_defaults
|
282
|
-
read_content(opts)
|
305
|
+
read_content(**opts)
|
283
306
|
read_post_data
|
284
307
|
rescue StandardError => e
|
285
308
|
handle_read_error(e)
|
@@ -373,12 +396,6 @@ module Jekyll
|
|
373
396
|
@related_posts ||= Jekyll::RelatedPosts.new(self).build
|
374
397
|
end
|
375
398
|
|
376
|
-
# Override of normal respond_to? to match method_missing's logic for
|
377
|
-
# looking in @data.
|
378
|
-
def respond_to?(method, include_private = false)
|
379
|
-
data.key?(method.to_s) || super
|
380
|
-
end
|
381
|
-
|
382
399
|
# Override of method_missing to check in @data for the key.
|
383
400
|
def method_missing(method, *args, &blck)
|
384
401
|
if data.key?(method.to_s)
|
@@ -401,28 +418,33 @@ module Jekyll
|
|
401
418
|
#
|
402
419
|
# Returns nothing.
|
403
420
|
def categories_from_path(special_dir)
|
404
|
-
|
405
|
-
|
406
|
-
|
407
|
-
|
421
|
+
if relative_path.start_with?(special_dir)
|
422
|
+
superdirs = []
|
423
|
+
else
|
424
|
+
superdirs = relative_path.sub(Document.superdirs_regex(special_dir), "")
|
425
|
+
superdirs = superdirs.split(File::SEPARATOR)
|
426
|
+
superdirs.reject! { |c| c.empty? || c == special_dir || c == basename }
|
408
427
|
end
|
428
|
+
|
409
429
|
merge_data!({ "categories" => superdirs }, :source => "file path")
|
410
430
|
end
|
411
431
|
|
412
432
|
def populate_categories
|
413
|
-
|
414
|
-
"categories"
|
415
|
-
Array(data["categories"]) + Utils.pluralized_array_from_hash(
|
416
|
-
data, "category", "categories"
|
417
|
-
)
|
418
|
-
).map(&:to_s).flatten.uniq
|
433
|
+
categories = Array(data["categories"]) + Utils.pluralized_array_from_hash(
|
434
|
+
data, "category", "categories"
|
419
435
|
)
|
436
|
+
categories.map!(&:to_s)
|
437
|
+
categories.flatten!
|
438
|
+
categories.uniq!
|
439
|
+
|
440
|
+
merge_data!({ "categories" => categories })
|
420
441
|
end
|
421
442
|
|
422
443
|
def populate_tags
|
423
|
-
|
424
|
-
|
425
|
-
|
444
|
+
tags = Utils.pluralized_array_from_hash(data, "tag", "tags")
|
445
|
+
tags.flatten!
|
446
|
+
|
447
|
+
merge_data!({ "tags" => tags })
|
426
448
|
end
|
427
449
|
|
428
450
|
private
|
@@ -444,15 +466,12 @@ module Jekyll
|
|
444
466
|
end
|
445
467
|
|
446
468
|
def merge_defaults
|
447
|
-
defaults = @site.frontmatter_defaults.all(
|
448
|
-
relative_path,
|
449
|
-
collection.label.to_sym
|
450
|
-
)
|
469
|
+
defaults = @site.frontmatter_defaults.all(relative_path, type)
|
451
470
|
merge_data!(defaults, :source => "front matter defaults") unless defaults.empty?
|
452
471
|
end
|
453
472
|
|
454
|
-
def read_content(opts)
|
455
|
-
self.content = File.read(path, Utils.merged_file_read_opts(site, opts))
|
473
|
+
def read_content(**opts)
|
474
|
+
self.content = File.read(path, **Utils.merged_file_read_opts(site, opts))
|
456
475
|
if content =~ YAML_FRONT_MATTER_REGEXP
|
457
476
|
self.content = $POSTMATCH
|
458
477
|
data_file = SafeYAML.load(Regexp.last_match(1))
|
@@ -479,6 +498,7 @@ module Jekyll
|
|
479
498
|
end
|
480
499
|
end
|
481
500
|
|
501
|
+
# rubocop:disable Metrics/AbcSize
|
482
502
|
def populate_title
|
483
503
|
if relative_path =~ DATE_FILENAME_MATCHER
|
484
504
|
date, slug, ext = Regexp.last_match.captures
|
@@ -486,6 +506,10 @@ module Jekyll
|
|
486
506
|
elsif relative_path =~ DATELESS_FILENAME_MATCHER
|
487
507
|
slug, ext = Regexp.last_match.captures
|
488
508
|
end
|
509
|
+
# `slug` will be nil for documents without an extension since the regex patterns
|
510
|
+
# above tests for an extension as well.
|
511
|
+
# In such cases, assign `basename_without_ext` as the slug.
|
512
|
+
slug ||= basename_without_ext
|
489
513
|
|
490
514
|
# slugs shouldn't end with a period
|
491
515
|
# `String#gsub!` removes all trailing periods (in comparison to `String#chomp!`)
|
@@ -497,6 +521,7 @@ module Jekyll
|
|
497
521
|
data["slug"] ||= slug
|
498
522
|
data["ext"] ||= ext
|
499
523
|
end
|
524
|
+
# rubocop:enable Metrics/AbcSize
|
500
525
|
|
501
526
|
def modify_date(date)
|
502
527
|
if !data["date"] || data["date"].to_i == site.time.to_i
|
@@ -64,6 +64,18 @@ module Jekyll
|
|
64
64
|
result[key] = doc[key] unless NESTED_OBJECT_FIELD_BLACKLIST.include?(key)
|
65
65
|
end
|
66
66
|
end
|
67
|
+
|
68
|
+
def title
|
69
|
+
@obj.data["title"]
|
70
|
+
end
|
71
|
+
|
72
|
+
def categories
|
73
|
+
@obj.data["categories"]
|
74
|
+
end
|
75
|
+
|
76
|
+
def tags
|
77
|
+
@obj.data["tags"]
|
78
|
+
end
|
67
79
|
end
|
68
80
|
end
|
69
81
|
end
|