jekyll 4.0.0.pre.alpha1 → 4.1.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|