jekyll 3.7.4 → 3.8.0.pre.rc1
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/lib/jekyll/cleaner.rb +4 -4
- data/lib/jekyll/collection.rb +5 -6
- data/lib/jekyll/commands/doctor.rb +13 -0
- data/lib/jekyll/commands/new.rb +3 -2
- data/lib/jekyll/configuration.rb +3 -1
- data/lib/jekyll/convertible.rb +3 -2
- data/lib/jekyll/document.rb +10 -8
- data/lib/jekyll/drops/collection_drop.rb +2 -3
- data/lib/jekyll/drops/document_drop.rb +2 -3
- data/lib/jekyll/drops/site_drop.rb +12 -3
- data/lib/jekyll/drops/static_file_drop.rb +2 -1
- data/lib/jekyll/entry_filter.rb +3 -6
- data/lib/jekyll/excerpt.rb +37 -1
- data/lib/jekyll/filters.rb +2 -61
- data/lib/jekyll/filters/date_filters.rb +107 -0
- data/lib/jekyll/liquid_renderer.rb +17 -5
- data/lib/jekyll/reader.rb +9 -3
- data/lib/jekyll/regenerator.rb +1 -0
- data/lib/jekyll/related_posts.rb +1 -1
- data/lib/jekyll/renderer.rb +26 -17
- data/lib/jekyll/site.rb +14 -10
- data/lib/jekyll/static_file.rb +1 -1
- data/lib/jekyll/tags/include.rb +8 -5
- data/lib/jekyll/theme.rb +7 -4
- data/lib/jekyll/theme_builder.rb +1 -1
- data/lib/jekyll/url.rb +4 -4
- data/lib/jekyll/utils.rb +8 -0
- data/lib/jekyll/version.rb +1 -1
- metadata +6 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3d8b3cb33faecac197557dfc43ba3a5e6b24053ecc42c9bb9ea3a733553f7eb4
|
4
|
+
data.tar.gz: 3af6b03a6c04a694adac3507d1e82048046d791ce6254d1b827fccea97db4367
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6d2dbd4a413268950af60bb1cb3219bb48a6fcdaefdc76e0035e97fb20852759d6d293b0b1a10bb39ab40e8527befaec5f63d028f01056fabf6c88fe9e4e99a4
|
7
|
+
data.tar.gz: dc435a723327de90ff63432a53db4fca2f11e2240c1f661fc66f6871610f737aa9eb2947a7434dbddd148443afb69e01c17044104bf9a185ddbdff4697b41fec
|
data/lib/jekyll/cleaner.rb
CHANGED
@@ -57,9 +57,9 @@ module Jekyll
|
|
57
57
|
#
|
58
58
|
# Returns a Set with the file paths
|
59
59
|
def new_files
|
60
|
-
|
61
|
-
|
62
|
-
|
60
|
+
@new_files ||= Set.new.tap do |files|
|
61
|
+
site.each_site_file { |item| files << item.destination(site.dest) }
|
62
|
+
end
|
63
63
|
end
|
64
64
|
|
65
65
|
# Private: The list of directories to be created when site is built.
|
@@ -67,7 +67,7 @@ module Jekyll
|
|
67
67
|
#
|
68
68
|
# Returns a Set with the directory paths
|
69
69
|
def new_dirs
|
70
|
-
new_files.map { |file| parent_dirs(file) }.flatten.to_set
|
70
|
+
@new_dirs ||= new_files.map { |file| parent_dirs(file) }.flatten.to_set
|
71
71
|
end
|
72
72
|
|
73
73
|
# Private: The list of parent directories of a given file
|
data/lib/jekyll/collection.rb
CHANGED
@@ -210,12 +210,11 @@ module Jekyll
|
|
210
210
|
private
|
211
211
|
|
212
212
|
def read_document(full_path)
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
Jekyll.logger.debug "Skipped Publishing:", doc.relative_path
|
213
|
+
docs << Document.new(full_path, :site => site, :collection => self).tap do |doc|
|
214
|
+
doc.read
|
215
|
+
if !site.publisher.publish?(doc) && site.publisher.hidden_in_the_future?(doc)
|
216
|
+
Jekyll.logger.debug "Skip Publishing:", "#{doc.relative_path} has a future date"
|
217
|
+
end
|
219
218
|
end
|
220
219
|
end
|
221
220
|
|
@@ -41,9 +41,22 @@ module Jekyll
|
|
41
41
|
!conflicting_urls(site),
|
42
42
|
!urls_only_differ_by_case(site),
|
43
43
|
proper_site_url?(site),
|
44
|
+
properly_gathered_posts?(site),
|
44
45
|
].all?
|
45
46
|
end
|
46
47
|
|
48
|
+
def properly_gathered_posts?(site)
|
49
|
+
return true if site.config["collections_dir"].empty?
|
50
|
+
posts_at_root = site.in_source_dir("_posts")
|
51
|
+
return true unless File.directory?(posts_at_root)
|
52
|
+
Jekyll.logger.warn "Warning:",
|
53
|
+
"Detected '_posts' directory outside custom `collections_dir`!"
|
54
|
+
Jekyll.logger.warn "",
|
55
|
+
"Please move '#{posts_at_root}' into the custom directory at " \
|
56
|
+
"'#{site.in_source_dir(site.config["collections_dir"])}'"
|
57
|
+
false
|
58
|
+
end
|
59
|
+
|
47
60
|
def deprecated_relative_permalinks(site)
|
48
61
|
if site.config["relative_permalinks"]
|
49
62
|
Jekyll::Deprecator.deprecation_message "Your site still uses relative" \
|
data/lib/jekyll/commands/new.rb
CHANGED
@@ -27,8 +27,9 @@ module Jekyll
|
|
27
27
|
new_blog_path = File.expand_path(args.join(" "), Dir.pwd)
|
28
28
|
FileUtils.mkdir_p new_blog_path
|
29
29
|
if preserve_source_location?(new_blog_path, options)
|
30
|
-
Jekyll.logger.
|
31
|
-
|
30
|
+
Jekyll.logger.error "Conflict:", "#{new_blog_path} exists and is not empty."
|
31
|
+
Jekyll.logger.abort_with "", "Ensure #{new_blog_path} is empty or else " \
|
32
|
+
"try again with `--force` to proceed and overwrite any files."
|
32
33
|
end
|
33
34
|
|
34
35
|
if options["blank"]
|
data/lib/jekyll/configuration.rb
CHANGED
data/lib/jekyll/convertible.rb
CHANGED
@@ -165,9 +165,9 @@ module Jekyll
|
|
165
165
|
|
166
166
|
# Determine whether the file should be rendered with Liquid.
|
167
167
|
#
|
168
|
-
#
|
168
|
+
# Returns true if the file has Liquid Tags or Variables, false otherwise.
|
169
169
|
def render_with_liquid?
|
170
|
-
|
170
|
+
Jekyll::Utils.has_liquid_construct?(content)
|
171
171
|
end
|
172
172
|
|
173
173
|
# Determine whether the file should be placed into layouts.
|
@@ -227,6 +227,7 @@ module Jekyll
|
|
227
227
|
def write(dest)
|
228
228
|
path = destination(dest)
|
229
229
|
FileUtils.mkdir_p(File.dirname(path))
|
230
|
+
Jekyll.logger.debug "Writing:", path
|
230
231
|
File.write(path, output, :mode => "wb")
|
231
232
|
Jekyll::Hooks.trigger hook_owner, :post_write, self
|
232
233
|
end
|
data/lib/jekyll/document.rb
CHANGED
@@ -83,15 +83,14 @@ module Jekyll
|
|
83
83
|
# Returns a String path which represents the relative path from the collections_dir
|
84
84
|
# to this document.
|
85
85
|
def relative_path
|
86
|
-
@relative_path ||=
|
87
|
-
Pathutil.new(path).relative_path_from(site.collections_path).to_s
|
86
|
+
@relative_path ||= path.sub("#{site.collections_path}/", "")
|
88
87
|
end
|
89
88
|
|
90
89
|
# The output extension of the document.
|
91
90
|
#
|
92
91
|
# Returns the output extension
|
93
92
|
def output_ext
|
94
|
-
Jekyll::Renderer.new(site, self).output_ext
|
93
|
+
@output_ext ||= Jekyll::Renderer.new(site, self).output_ext
|
95
94
|
end
|
96
95
|
|
97
96
|
# The base filename of the document, without the file extname.
|
@@ -157,9 +156,10 @@ module Jekyll
|
|
157
156
|
# Determine whether the file should be rendered with Liquid.
|
158
157
|
#
|
159
158
|
# Returns false if the document is either an asset file or a yaml file,
|
159
|
+
# or if the document doesn't contain any Liquid Tags or Variables,
|
160
160
|
# true otherwise.
|
161
161
|
def render_with_liquid?
|
162
|
-
!(coffeescript_file? || yaml_file?)
|
162
|
+
!(coffeescript_file? || yaml_file? || !Utils.has_liquid_construct?(content))
|
163
163
|
end
|
164
164
|
|
165
165
|
# Determine whether the file should be rendered with a layout.
|
@@ -239,6 +239,7 @@ module Jekyll
|
|
239
239
|
def write(dest)
|
240
240
|
path = destination(dest)
|
241
241
|
FileUtils.mkdir_p(File.dirname(path))
|
242
|
+
Jekyll.logger.debug "Writing:", path
|
242
243
|
File.write(path, output, :mode => "wb")
|
243
244
|
|
244
245
|
trigger_hooks(:post_write)
|
@@ -311,9 +312,10 @@ module Jekyll
|
|
311
312
|
# Based on the Collection to which it belongs.
|
312
313
|
#
|
313
314
|
# True if the document has a collection and if that collection's #write?
|
314
|
-
#
|
315
|
+
# method returns true, and if the site's Publisher will publish the document.
|
316
|
+
# False otherwise.
|
315
317
|
def write?
|
316
|
-
collection && collection.write?
|
318
|
+
collection && collection.write? && site.publisher.publish?(self)
|
317
319
|
end
|
318
320
|
|
319
321
|
# The Document excerpt_separator, from the YAML Front-Matter or site
|
@@ -358,7 +360,7 @@ module Jekyll
|
|
358
360
|
#
|
359
361
|
# Returns an Array of related Posts.
|
360
362
|
def related_posts
|
361
|
-
Jekyll::RelatedPosts.new(self).build
|
363
|
+
@related_posts ||= Jekyll::RelatedPosts.new(self).build
|
362
364
|
end
|
363
365
|
|
364
366
|
# Override of normal respond_to? to match method_missing's logic for
|
@@ -417,7 +419,7 @@ module Jekyll
|
|
417
419
|
def merge_categories!(other)
|
418
420
|
if other.key?("categories") && !other["categories"].nil?
|
419
421
|
if other["categories"].is_a?(String)
|
420
|
-
other["categories"] = other["categories"].split
|
422
|
+
other["categories"] = other["categories"].split
|
421
423
|
end
|
422
424
|
other["categories"] = (data["categories"] || []) | other["categories"]
|
423
425
|
end
|
@@ -11,12 +11,11 @@ module Jekyll
|
|
11
11
|
def_delegators :@obj, :label, :docs, :files, :directory,
|
12
12
|
:relative_directory
|
13
13
|
|
14
|
+
private def_delegator :@obj, :metadata, :fallback_data
|
15
|
+
|
14
16
|
def to_s
|
15
17
|
docs.to_s
|
16
18
|
end
|
17
|
-
|
18
|
-
private
|
19
|
-
def_delegator :@obj, :metadata, :fallback_data
|
20
19
|
end
|
21
20
|
end
|
22
21
|
end
|
@@ -14,6 +14,8 @@ module Jekyll
|
|
14
14
|
def_delegator :@obj, :relative_path, :path
|
15
15
|
def_delegators :@obj, :id, :output, :content, :to_s, :relative_path, :url
|
16
16
|
|
17
|
+
private def_delegator :@obj, :data, :fallback_data
|
18
|
+
|
17
19
|
def collection
|
18
20
|
@obj.collection.label
|
19
21
|
end
|
@@ -61,9 +63,6 @@ module Jekyll
|
|
61
63
|
result[key] = doc[key] unless NESTED_OBJECT_FIELD_BLACKLIST.include?(key)
|
62
64
|
end
|
63
65
|
end
|
64
|
-
|
65
|
-
private
|
66
|
-
def_delegator :@obj, :data, :fallback_data
|
67
66
|
end
|
68
67
|
end
|
69
68
|
end
|
@@ -11,6 +11,8 @@ module Jekyll
|
|
11
11
|
def_delegators :@obj, :time, :pages, :static_files, :documents,
|
12
12
|
:tags, :categories
|
13
13
|
|
14
|
+
private def_delegator :@obj, :config, :fallback_data
|
15
|
+
|
14
16
|
def [](key)
|
15
17
|
if @obj.collections.key?(key) && key != "posts"
|
16
18
|
@obj.collections[key].docs
|
@@ -37,11 +39,18 @@ module Jekyll
|
|
37
39
|
@site_collections ||= @obj.collections.values.sort_by(&:label).map(&:to_liquid)
|
38
40
|
end
|
39
41
|
|
42
|
+
# `{{ site.related_posts }}` is how posts can get posts related to
|
43
|
+
# them, either through LSI if it's enabled, or through the most
|
44
|
+
# recent posts.
|
45
|
+
# We should remove this in 4.0 and switch to `{{ post.related_posts }}`.
|
46
|
+
def related_posts
|
47
|
+
return nil unless @current_document.is_a?(Jekyll::Document)
|
48
|
+
@current_document.related_posts
|
49
|
+
end
|
50
|
+
attr_writer :current_document
|
51
|
+
|
40
52
|
# return nil for `{{ site.config }}` even if --config was passed via CLI
|
41
53
|
def config; end
|
42
|
-
|
43
|
-
private
|
44
|
-
def_delegator :@obj, :config, :fallback_data
|
45
54
|
end
|
46
55
|
end
|
47
56
|
end
|
@@ -6,8 +6,9 @@ module Jekyll
|
|
6
6
|
extend Forwardable
|
7
7
|
def_delegators :@obj, :name, :extname, :modified_time, :basename
|
8
8
|
def_delegator :@obj, :relative_path, :path
|
9
|
-
def_delegator :@obj, :data, :fallback_data
|
10
9
|
def_delegator :@obj, :type, :collection
|
10
|
+
|
11
|
+
private def_delegator :@obj, :data, :fallback_data
|
11
12
|
end
|
12
13
|
end
|
13
14
|
end
|
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
|
|
data/lib/jekyll/excerpt.rb
CHANGED
@@ -8,7 +8,7 @@ module Jekyll
|
|
8
8
|
attr_accessor :content, :ext
|
9
9
|
attr_writer :output
|
10
10
|
|
11
|
-
def_delegators :@doc, :site, :name, :ext, :
|
11
|
+
def_delegators :@doc, :site, :name, :ext, :extname,
|
12
12
|
:render_with_liquid?, :collection, :related_posts,
|
13
13
|
:url, :next_doc, :previous_doc
|
14
14
|
|
@@ -41,6 +41,13 @@ module Jekyll
|
|
41
41
|
File.join(doc.path, "#excerpt")
|
42
42
|
end
|
43
43
|
|
44
|
+
# 'Relative Path' of the excerpt.
|
45
|
+
#
|
46
|
+
# Returns the relative_path for the doc this excerpt belongs to with #excerpt appended
|
47
|
+
def relative_path
|
48
|
+
File.join(doc.relative_path, "#excerpt")
|
49
|
+
end
|
50
|
+
|
44
51
|
# Check if excerpt includes a string
|
45
52
|
#
|
46
53
|
# Returns true if the string passed in
|
@@ -116,11 +123,40 @@ module Jekyll
|
|
116
123
|
def extract_excerpt(doc_content)
|
117
124
|
head, _, tail = doc_content.to_s.partition(doc.excerpt_separator)
|
118
125
|
|
126
|
+
# append appropriate closing tag (to a Liquid block), to the "head" if the
|
127
|
+
# partitioning resulted in leaving the closing tag somewhere in the "tail"
|
128
|
+
# partition.
|
129
|
+
if head.include?("{%")
|
130
|
+
head =~ %r!{%\s*(\w+).+\s*%}!
|
131
|
+
tag_name = Regexp.last_match(1)
|
132
|
+
|
133
|
+
if liquid_block?(tag_name) && head.match(%r!{%\s*end#{tag_name}\s*%}!).nil?
|
134
|
+
print_build_warning
|
135
|
+
head << "\n{% end#{tag_name} %}"
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
119
139
|
if tail.empty?
|
120
140
|
head
|
121
141
|
else
|
122
142
|
head.to_s.dup << "\n\n" << tail.scan(%r!^ {0,3}\[[^\]]+\]:.+$!).join("\n")
|
123
143
|
end
|
124
144
|
end
|
145
|
+
|
146
|
+
private
|
147
|
+
|
148
|
+
def liquid_block?(tag_name)
|
149
|
+
Liquid::Template.tags[tag_name].superclass == Liquid::Block
|
150
|
+
end
|
151
|
+
|
152
|
+
def print_build_warning
|
153
|
+
Jekyll.logger.warn "Warning:", "Excerpt modified in #{doc.relative_path}!"
|
154
|
+
Jekyll.logger.warn "",
|
155
|
+
"Found a Liquid block containing separator '#{doc.excerpt_separator}' and has " \
|
156
|
+
"been modified with the appropriate closing tag."
|
157
|
+
Jekyll.logger.warn "",
|
158
|
+
"Feel free to define a custom excerpt or excerpt_separator in the document's " \
|
159
|
+
"Front Matter if the generated excerpt is unsatisfactory."
|
160
|
+
end
|
125
161
|
end
|
126
162
|
end
|
data/lib/jekyll/filters.rb
CHANGED
@@ -2,7 +2,6 @@
|
|
2
2
|
|
3
3
|
require "addressable/uri"
|
4
4
|
require "json"
|
5
|
-
require "date"
|
6
5
|
require "liquid"
|
7
6
|
|
8
7
|
require_all "jekyll/filters"
|
@@ -11,6 +10,7 @@ module Jekyll
|
|
11
10
|
module Filters
|
12
11
|
include URLFilters
|
13
12
|
include GroupingFilters
|
13
|
+
include DateFilters
|
14
14
|
|
15
15
|
# Convert a Markdown string into HTML output.
|
16
16
|
#
|
@@ -67,55 +67,6 @@ module Jekyll
|
|
67
67
|
Utils.slugify(input, :mode => mode)
|
68
68
|
end
|
69
69
|
|
70
|
-
# Format a date in short format e.g. "27 Jan 2011".
|
71
|
-
#
|
72
|
-
# date - the Time to format.
|
73
|
-
#
|
74
|
-
# Returns the formatting String.
|
75
|
-
def date_to_string(date)
|
76
|
-
time(date).strftime("%d %b %Y")
|
77
|
-
end
|
78
|
-
|
79
|
-
# Format a date in long format e.g. "27 January 2011".
|
80
|
-
#
|
81
|
-
# date - The Time to format.
|
82
|
-
#
|
83
|
-
# Returns the formatted String.
|
84
|
-
def date_to_long_string(date)
|
85
|
-
return date if date.to_s.empty?
|
86
|
-
time(date).strftime("%d %B %Y")
|
87
|
-
end
|
88
|
-
|
89
|
-
# Format a date for use in XML.
|
90
|
-
#
|
91
|
-
# date - The Time to format.
|
92
|
-
#
|
93
|
-
# Examples
|
94
|
-
#
|
95
|
-
# date_to_xmlschema(Time.now)
|
96
|
-
# # => "2011-04-24T20:34:46+08:00"
|
97
|
-
#
|
98
|
-
# Returns the formatted String.
|
99
|
-
def date_to_xmlschema(date)
|
100
|
-
return date if date.to_s.empty?
|
101
|
-
time(date).xmlschema
|
102
|
-
end
|
103
|
-
|
104
|
-
# Format a date according to RFC-822
|
105
|
-
#
|
106
|
-
# date - The Time to format.
|
107
|
-
#
|
108
|
-
# Examples
|
109
|
-
#
|
110
|
-
# date_to_rfc822(Time.now)
|
111
|
-
# # => "Sun, 24 Apr 2011 12:34:46 +0000"
|
112
|
-
#
|
113
|
-
# Returns the formatted String.
|
114
|
-
def date_to_rfc822(date)
|
115
|
-
return date if date.to_s.empty?
|
116
|
-
time(date).rfc822
|
117
|
-
end
|
118
|
-
|
119
70
|
# XML escape a string for use. Replaces any special characters with
|
120
71
|
# appropriate HTML entity replacements.
|
121
72
|
#
|
@@ -223,7 +174,7 @@ module Jekyll
|
|
223
174
|
return input unless input.respond_to?(:select)
|
224
175
|
input = input.values if input.is_a?(Hash)
|
225
176
|
input.select do |object|
|
226
|
-
Array(item_property(object, property)).map(&:to_s).include?(value.to_s)
|
177
|
+
Array(item_property(object, property)).map!(&:to_s).include?(value.to_s)
|
227
178
|
end || []
|
228
179
|
end
|
229
180
|
|
@@ -357,16 +308,6 @@ module Jekyll
|
|
357
308
|
.map!(&:last)
|
358
309
|
end
|
359
310
|
|
360
|
-
private
|
361
|
-
def time(input)
|
362
|
-
date = Liquid::Utils.to_date(input)
|
363
|
-
unless date.respond_to?(:to_time)
|
364
|
-
raise Errors::InvalidDateError,
|
365
|
-
"Invalid Date: '#{input.inspect}' is not a valid datetime."
|
366
|
-
end
|
367
|
-
date.to_time.dup.localtime
|
368
|
-
end
|
369
|
-
|
370
311
|
private
|
371
312
|
def item_property(item, property)
|
372
313
|
if item.respond_to?(:to_liquid)
|
@@ -0,0 +1,107 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Jekyll
|
4
|
+
module Filters
|
5
|
+
module DateFilters
|
6
|
+
# Format a date in short format e.g. "27 Jan 2011".
|
7
|
+
# Ordinal format is also supported, in both the UK
|
8
|
+
# (e.g. "27th Jan 2011") and US ("e.g. Jan 27th, 2011") formats.
|
9
|
+
# UK format is the default.
|
10
|
+
#
|
11
|
+
# date - the Time to format.
|
12
|
+
# type - if "ordinal" the returned String will be in ordinal format
|
13
|
+
# style - if "US" the returned String will be in US format.
|
14
|
+
# Otherwise it will be in UK format.
|
15
|
+
#
|
16
|
+
# Returns the formatting String.
|
17
|
+
def date_to_string(date, type = nil, style = nil)
|
18
|
+
stringify_date(date, "%b", type, style)
|
19
|
+
end
|
20
|
+
|
21
|
+
# Format a date in long format e.g. "27 January 2011".
|
22
|
+
# Ordinal format is also supported, in both the UK
|
23
|
+
# (e.g. "27th January 2011") and US ("e.g. January 27th, 2011") formats.
|
24
|
+
# UK format is the default.
|
25
|
+
#
|
26
|
+
# date - the Time to format.
|
27
|
+
# type - if "ordinal" the returned String will be in ordinal format
|
28
|
+
# style - if "US" the returned String will be in US format.
|
29
|
+
# Otherwise it will be in UK format.
|
30
|
+
#
|
31
|
+
# Returns the formatted String.
|
32
|
+
def date_to_long_string(date, type = nil, style = nil)
|
33
|
+
stringify_date(date, "%B", type, style)
|
34
|
+
end
|
35
|
+
|
36
|
+
# Format a date for use in XML.
|
37
|
+
#
|
38
|
+
# date - The Time to format.
|
39
|
+
#
|
40
|
+
# Examples
|
41
|
+
#
|
42
|
+
# date_to_xmlschema(Time.now)
|
43
|
+
# # => "2011-04-24T20:34:46+08:00"
|
44
|
+
#
|
45
|
+
# Returns the formatted String.
|
46
|
+
def date_to_xmlschema(date)
|
47
|
+
return date if date.to_s.empty?
|
48
|
+
time(date).xmlschema
|
49
|
+
end
|
50
|
+
|
51
|
+
# Format a date according to RFC-822
|
52
|
+
#
|
53
|
+
# date - The Time to format.
|
54
|
+
#
|
55
|
+
# Examples
|
56
|
+
#
|
57
|
+
# date_to_rfc822(Time.now)
|
58
|
+
# # => "Sun, 24 Apr 2011 12:34:46 +0000"
|
59
|
+
#
|
60
|
+
# Returns the formatted String.
|
61
|
+
def date_to_rfc822(date)
|
62
|
+
return date if date.to_s.empty?
|
63
|
+
time(date).rfc822
|
64
|
+
end
|
65
|
+
|
66
|
+
private
|
67
|
+
# month_type: Notations that evaluate to 'Month' via `Time#strftime` ("%b", "%B")
|
68
|
+
# type: nil (default) or "ordinal"
|
69
|
+
# style: nil (default) or "US"
|
70
|
+
#
|
71
|
+
# Returns a stringified date or the empty input.
|
72
|
+
def stringify_date(date, month_type, type = nil, style = nil)
|
73
|
+
return date if date.to_s.empty?
|
74
|
+
time = time(date)
|
75
|
+
if type == "ordinal"
|
76
|
+
day = time.day
|
77
|
+
ordinal_day = "#{day}#{ordinal(day)}"
|
78
|
+
return time.strftime("#{month_type} #{ordinal_day}, %Y") if style == "US"
|
79
|
+
return time.strftime("#{ordinal_day} #{month_type} %Y")
|
80
|
+
end
|
81
|
+
time.strftime("%d #{month_type} %Y")
|
82
|
+
end
|
83
|
+
|
84
|
+
private
|
85
|
+
def ordinal(number)
|
86
|
+
return "th" if (11..13).cover?(number)
|
87
|
+
|
88
|
+
case number % 10
|
89
|
+
when 1 then "st"
|
90
|
+
when 2 then "nd"
|
91
|
+
when 3 then "rd"
|
92
|
+
else "th"
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
private
|
97
|
+
def time(input)
|
98
|
+
date = Liquid::Utils.to_date(input)
|
99
|
+
unless date.respond_to?(:to_time)
|
100
|
+
raise Errors::InvalidDateError,
|
101
|
+
"Invalid Date: '#{input.inspect}' is not a valid datetime."
|
102
|
+
end
|
103
|
+
date.to_time.dup.localtime
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
@@ -5,6 +5,11 @@ require_relative "liquid_renderer/table"
|
|
5
5
|
|
6
6
|
module Jekyll
|
7
7
|
class LiquidRenderer
|
8
|
+
extend Forwardable
|
9
|
+
|
10
|
+
def_delegator :@site, :in_source_dir, :source_dir
|
11
|
+
def_delegator :@site, :in_theme_dir, :theme_dir
|
12
|
+
|
8
13
|
def initialize(site)
|
9
14
|
@site = site
|
10
15
|
Liquid::Template.error_mode = @site.config["liquid"]["error_mode"].to_sym
|
@@ -16,11 +21,13 @@ module Jekyll
|
|
16
21
|
end
|
17
22
|
|
18
23
|
def file(filename)
|
19
|
-
filename
|
20
|
-
|
21
|
-
""
|
22
|
-
|
23
|
-
|
24
|
+
filename.match(filename_regex)
|
25
|
+
filename =
|
26
|
+
if Regexp.last_match(1) == theme_dir("")
|
27
|
+
::File.join(Regexp.last_match(1).split("/")[-1], Regexp.last_match(2))
|
28
|
+
else
|
29
|
+
Regexp.last_match(2)
|
30
|
+
end
|
24
31
|
LiquidRenderer::File.new(self, filename).tap do
|
25
32
|
@stats[filename] ||= new_profile_hash
|
26
33
|
@stats[filename][:count] += 1
|
@@ -44,6 +51,11 @@ module Jekyll
|
|
44
51
|
end
|
45
52
|
|
46
53
|
private
|
54
|
+
|
55
|
+
def filename_regex
|
56
|
+
%r!\A(#{source_dir}/|#{theme_dir}/|\W*)(.*)!oi
|
57
|
+
end
|
58
|
+
|
47
59
|
def new_profile_hash
|
48
60
|
Hash.new { |hash, key| hash[key] = 0 }
|
49
61
|
end
|
data/lib/jekyll/reader.rb
CHANGED
@@ -63,8 +63,8 @@ module Jekyll
|
|
63
63
|
# Returns nothing.
|
64
64
|
def retrieve_posts(dir)
|
65
65
|
return if outside_configured_directory?(dir)
|
66
|
-
site.posts.docs.concat(
|
67
|
-
site.posts.docs.concat(
|
66
|
+
site.posts.docs.concat(post_reader.read_posts(dir))
|
67
|
+
site.posts.docs.concat(post_reader.read_drafts(dir)) if site.show_drafts
|
68
68
|
end
|
69
69
|
|
70
70
|
# Recursively traverse directories with the read_directories function.
|
@@ -78,7 +78,7 @@ module Jekyll
|
|
78
78
|
dot_dirs.each do |file|
|
79
79
|
dir_path = site.in_source_dir(dir, file)
|
80
80
|
rel_path = File.join(dir, file)
|
81
|
-
unless @site.dest.
|
81
|
+
unless @site.dest.chomp("/") == dir_path
|
82
82
|
@site.reader.read_directories(rel_path)
|
83
83
|
end
|
84
84
|
end
|
@@ -146,5 +146,11 @@ module Jekyll
|
|
146
146
|
collections_dir = site.config["collections_dir"]
|
147
147
|
!collections_dir.empty? && !dir.start_with?("/#{collections_dir}")
|
148
148
|
end
|
149
|
+
|
150
|
+
# Create a single PostReader instance to retrieve drafts and posts from all valid
|
151
|
+
# directories in current site.
|
152
|
+
def post_reader
|
153
|
+
@post_reader ||= PostReader.new(site)
|
154
|
+
end
|
149
155
|
end
|
150
156
|
end
|
data/lib/jekyll/regenerator.rb
CHANGED
data/lib/jekyll/related_posts.rb
CHANGED
data/lib/jekyll/renderer.rb
CHANGED
@@ -52,7 +52,7 @@ module Jekyll
|
|
52
52
|
Jekyll.logger.debug "Rendering:", document.relative_path
|
53
53
|
|
54
54
|
assign_pages!
|
55
|
-
|
55
|
+
assign_current_document!
|
56
56
|
assign_highlighter_options!
|
57
57
|
assign_layout_data!
|
58
58
|
|
@@ -68,8 +68,11 @@ module Jekyll
|
|
68
68
|
# rubocop: disable AbcSize
|
69
69
|
def render_document
|
70
70
|
info = {
|
71
|
-
:registers
|
71
|
+
:registers => { :site => site, :page => payload["page"] },
|
72
|
+
:strict_filters => liquid_options["strict_filters"],
|
73
|
+
:strict_variables => liquid_options["strict_variables"],
|
72
74
|
}
|
75
|
+
|
73
76
|
output = document.content
|
74
77
|
if document.render_with_liquid?
|
75
78
|
Jekyll.logger.debug "Rendering Liquid:", document.relative_path
|
@@ -77,7 +80,7 @@ module Jekyll
|
|
77
80
|
end
|
78
81
|
|
79
82
|
Jekyll.logger.debug "Rendering Markup:", document.relative_path
|
80
|
-
output = convert(output)
|
83
|
+
output = convert(output.to_s)
|
81
84
|
document.content = output
|
82
85
|
|
83
86
|
if document.place_in_layout?
|
@@ -169,12 +172,16 @@ module Jekyll
|
|
169
172
|
# Returns nothing
|
170
173
|
private
|
171
174
|
def validate_layout(layout)
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
175
|
+
if invalid_layout?(layout)
|
176
|
+
Jekyll.logger.warn(
|
177
|
+
"Build Warning:",
|
178
|
+
"Layout '#{document.data["layout"]}' requested "\
|
179
|
+
"in #{document.relative_path} does not exist."
|
180
|
+
)
|
181
|
+
elsif !layout.nil?
|
182
|
+
layout_source = layout.path.start_with?(site.source) ? :site : :theme
|
183
|
+
Jekyll.logger.debug "Layout source:", layout_source
|
184
|
+
end
|
178
185
|
end
|
179
186
|
|
180
187
|
# Render layout content into document.output
|
@@ -217,12 +224,8 @@ module Jekyll
|
|
217
224
|
#
|
218
225
|
# Returns nothing
|
219
226
|
private
|
220
|
-
def
|
221
|
-
|
222
|
-
payload["site"]["related_posts"] = document.related_posts
|
223
|
-
else
|
224
|
-
payload["site"]["related_posts"] = nil
|
225
|
-
end
|
227
|
+
def assign_current_document!
|
228
|
+
payload["site"].current_document = document
|
226
229
|
end
|
227
230
|
|
228
231
|
# Set highlighter prefix and suffix
|
@@ -244,8 +247,9 @@ module Jekyll
|
|
244
247
|
|
245
248
|
private
|
246
249
|
def permalink_ext
|
247
|
-
|
248
|
-
|
250
|
+
document_permalink = document.permalink
|
251
|
+
if document_permalink && !document_permalink.end_with?("/")
|
252
|
+
permalink_ext = File.extname(document_permalink)
|
249
253
|
permalink_ext unless permalink_ext.empty?
|
250
254
|
end
|
251
255
|
end
|
@@ -265,5 +269,10 @@ module Jekyll
|
|
265
269
|
c.output_ext(document.extname)
|
266
270
|
end.compact
|
267
271
|
end
|
272
|
+
|
273
|
+
private
|
274
|
+
def liquid_options
|
275
|
+
@liquid_options ||= site.config["liquid"]
|
276
|
+
end
|
268
277
|
end
|
269
278
|
end
|
data/lib/jekyll/site.rb
CHANGED
@@ -93,9 +93,12 @@ module Jekyll
|
|
93
93
|
self.pages = []
|
94
94
|
self.static_files = []
|
95
95
|
self.data = {}
|
96
|
+
@site_data = nil
|
96
97
|
@collections = nil
|
98
|
+
@docs_to_write = nil
|
97
99
|
@regenerator.clear_cache
|
98
100
|
@liquid_renderer.reset
|
101
|
+
@site_cleaner = nil
|
99
102
|
|
100
103
|
if limit_posts < 0
|
101
104
|
raise ArgumentError, "limit_posts must be a non-negative number"
|
@@ -252,7 +255,7 @@ module Jekyll
|
|
252
255
|
#
|
253
256
|
# Returns the Hash to be hooked to site.data.
|
254
257
|
def site_data
|
255
|
-
config["data"] || data
|
258
|
+
@site_data ||= (config["data"] || data)
|
256
259
|
end
|
257
260
|
|
258
261
|
# The Hash payload containing site-wide data.
|
@@ -311,7 +314,7 @@ module Jekyll
|
|
311
314
|
#
|
312
315
|
# Returns an Array of Documents which should be written
|
313
316
|
def docs_to_write
|
314
|
-
documents.select(&:write?)
|
317
|
+
@docs_to_write ||= documents.select(&:write?)
|
315
318
|
end
|
316
319
|
|
317
320
|
# Get all the documents
|
@@ -458,10 +461,7 @@ module Jekyll
|
|
458
461
|
def render_docs(payload)
|
459
462
|
collections.each_value do |collection|
|
460
463
|
collection.docs.each do |document|
|
461
|
-
|
462
|
-
document.output = Jekyll::Renderer.new(self, document, payload).run
|
463
|
-
document.trigger_hooks(:post_render)
|
464
|
-
end
|
464
|
+
render_regenerated(document, payload)
|
465
465
|
end
|
466
466
|
end
|
467
467
|
end
|
@@ -469,11 +469,15 @@ module Jekyll
|
|
469
469
|
private
|
470
470
|
def render_pages(payload)
|
471
471
|
pages.flatten.each do |page|
|
472
|
-
|
473
|
-
page.output = Jekyll::Renderer.new(self, page, payload).run
|
474
|
-
page.trigger_hooks(:post_render)
|
475
|
-
end
|
472
|
+
render_regenerated(page, payload)
|
476
473
|
end
|
477
474
|
end
|
475
|
+
|
476
|
+
private
|
477
|
+
def render_regenerated(document, payload)
|
478
|
+
return unless regenerator.regenerate?(document)
|
479
|
+
document.output = Jekyll::Renderer.new(self, document, payload).run
|
480
|
+
document.trigger_hooks(:post_render)
|
481
|
+
end
|
478
482
|
end
|
479
483
|
end
|
data/lib/jekyll/static_file.rb
CHANGED
data/lib/jekyll/tags/include.rb
CHANGED
@@ -19,7 +19,11 @@ module Jekyll
|
|
19
19
|
VARIABLE_SYNTAX = %r!
|
20
20
|
(?<variable>[^{]*(\{\{\s*[\w\-\.]+\s*(\|.*)?\}\}[^\s{}]*)+)
|
21
21
|
(?<params>.*)
|
22
|
-
!
|
22
|
+
!mx
|
23
|
+
|
24
|
+
FULL_VALID_SYNTAX = %r!\A\s*(?:#{VALID_SYNTAX}(?=\s|\z)\s*)*\z!
|
25
|
+
VALID_FILENAME_CHARS = %r!^[\w/\.-]+$!
|
26
|
+
INVALID_SEQUENCES = %r![./]{2,}!
|
23
27
|
|
24
28
|
def initialize(tag_name, markup, tokens)
|
25
29
|
super
|
@@ -59,7 +63,7 @@ module Jekyll
|
|
59
63
|
end
|
60
64
|
|
61
65
|
def validate_file_name(file)
|
62
|
-
if file
|
66
|
+
if file =~ INVALID_SEQUENCES || file !~ VALID_FILENAME_CHARS
|
63
67
|
raise ArgumentError, <<-MSG
|
64
68
|
Invalid syntax for include tag. File contains invalid characters or sequences:
|
65
69
|
|
@@ -74,8 +78,7 @@ MSG
|
|
74
78
|
end
|
75
79
|
|
76
80
|
def validate_params
|
77
|
-
|
78
|
-
unless @params =~ full_valid_syntax
|
81
|
+
unless @params =~ FULL_VALID_SYNTAX
|
79
82
|
raise ArgumentError, <<-MSG
|
80
83
|
Invalid syntax for include tag:
|
81
84
|
|
@@ -96,7 +99,7 @@ MSG
|
|
96
99
|
|
97
100
|
# Render the variable if required
|
98
101
|
def render_variable(context)
|
99
|
-
if @file
|
102
|
+
if @file =~ VARIABLE_SYNTAX
|
100
103
|
partial = context.registers[:site]
|
101
104
|
.liquid_renderer
|
102
105
|
.file("(variable)")
|
data/lib/jekyll/theme.rb
CHANGED
@@ -8,6 +8,8 @@ module Jekyll
|
|
8
8
|
|
9
9
|
def initialize(name)
|
10
10
|
@name = name.downcase.strip
|
11
|
+
Jekyll.logger.debug "Theme:", name
|
12
|
+
Jekyll.logger.debug "Theme source:", root
|
11
13
|
configure_sass
|
12
14
|
end
|
13
15
|
|
@@ -21,19 +23,19 @@ module Jekyll
|
|
21
23
|
end
|
22
24
|
|
23
25
|
def includes_path
|
24
|
-
path_for "_includes".freeze
|
26
|
+
@includes_path ||= path_for "_includes".freeze
|
25
27
|
end
|
26
28
|
|
27
29
|
def layouts_path
|
28
|
-
path_for "_layouts".freeze
|
30
|
+
@layouts_path ||= path_for "_layouts".freeze
|
29
31
|
end
|
30
32
|
|
31
33
|
def sass_path
|
32
|
-
path_for "_sass".freeze
|
34
|
+
@sass_path ||= path_for "_sass".freeze
|
33
35
|
end
|
34
36
|
|
35
37
|
def assets_path
|
36
|
-
path_for "assets".freeze
|
38
|
+
@assets_path ||= path_for "assets".freeze
|
37
39
|
end
|
38
40
|
|
39
41
|
def configure_sass
|
@@ -56,6 +58,7 @@ module Jekyll
|
|
56
58
|
def realpath_for(folder)
|
57
59
|
File.realpath(Jekyll.sanitized_path(root, folder.to_s))
|
58
60
|
rescue Errno::ENOENT, Errno::EACCES, Errno::ELOOP
|
61
|
+
Jekyll.logger.warn "Invalid theme folder:", folder
|
59
62
|
nil
|
60
63
|
end
|
61
64
|
|
data/lib/jekyll/theme_builder.rb
CHANGED
@@ -8,7 +8,7 @@ class Jekyll::ThemeBuilder
|
|
8
8
|
attr_reader :name, :path, :code_of_conduct
|
9
9
|
|
10
10
|
def initialize(theme_name, opts)
|
11
|
-
@name = theme_name.to_s.tr(" ", "_").
|
11
|
+
@name = theme_name.to_s.tr(" ", "_").squeeze("_")
|
12
12
|
@path = Pathname.new(File.expand_path(name, Dir.pwd))
|
13
13
|
@code_of_conduct = !!opts["code_of_conduct"]
|
14
14
|
end
|
data/lib/jekyll/url.rb
CHANGED
@@ -72,9 +72,9 @@ module Jekyll
|
|
72
72
|
break result if result.index(":").nil?
|
73
73
|
if token.last.nil?
|
74
74
|
# Remove leading "/" to avoid generating urls with `//`
|
75
|
-
result.gsub(
|
75
|
+
result.gsub("/:#{token.first}", "")
|
76
76
|
else
|
77
|
-
result.gsub(
|
77
|
+
result.gsub(":#{token.first}", self.class.escape_path(token.last))
|
78
78
|
end
|
79
79
|
end
|
80
80
|
end
|
@@ -109,14 +109,14 @@ module Jekyll
|
|
109
109
|
replacement = self.class.escape_path(value)
|
110
110
|
|
111
111
|
match.sub(":#{winner}", replacement)
|
112
|
-
end.
|
112
|
+
end.squeeze("/")
|
113
113
|
end
|
114
114
|
|
115
115
|
# Returns a sanitized String URL, stripping "../../" and multiples of "/",
|
116
116
|
# as well as the beginning "/" so we can enforce and ensure it.
|
117
117
|
|
118
118
|
def sanitize_url(str)
|
119
|
-
"
|
119
|
+
"/#{str}".gsub("..", "/").gsub("./", "").squeeze("/")
|
120
120
|
end
|
121
121
|
|
122
122
|
# Escapes a path to be a valid URL path segment
|
data/lib/jekyll/utils.rb
CHANGED
@@ -147,6 +147,14 @@ module Jekyll
|
|
147
147
|
rescue EOFError
|
148
148
|
false
|
149
149
|
end
|
150
|
+
|
151
|
+
# Determine whether the given content string contains Liquid Tags or Vaiables
|
152
|
+
#
|
153
|
+
# Returns true is the string contains sequences of `{%` or `{{`
|
154
|
+
def has_liquid_construct?(content)
|
155
|
+
return false if content.nil? || content.empty?
|
156
|
+
content.include?("{%") || content.include?("{{")
|
157
|
+
end
|
150
158
|
# rubocop: enable PredicateName
|
151
159
|
|
152
160
|
# Slugify a filename or title.
|
data/lib/jekyll/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: jekyll
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.
|
4
|
+
version: 3.8.0.pre.rc1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Tom Preston-Werner
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-
|
11
|
+
date: 2018-04-03 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: addressable
|
@@ -237,6 +237,7 @@ files:
|
|
237
237
|
- lib/jekyll/excerpt.rb
|
238
238
|
- lib/jekyll/external.rb
|
239
239
|
- lib/jekyll/filters.rb
|
240
|
+
- lib/jekyll/filters/date_filters.rb
|
240
241
|
- lib/jekyll/filters/grouping_filters.rb
|
241
242
|
- lib/jekyll/filters/url_filters.rb
|
242
243
|
- lib/jekyll/frontmatter_defaults.rb
|
@@ -322,12 +323,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
322
323
|
version: 2.1.0
|
323
324
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
324
325
|
requirements:
|
325
|
-
- - "
|
326
|
+
- - ">"
|
326
327
|
- !ruby/object:Gem::Version
|
327
|
-
version:
|
328
|
+
version: 1.3.1
|
328
329
|
requirements: []
|
329
330
|
rubyforge_project:
|
330
|
-
rubygems_version: 2.7.
|
331
|
+
rubygems_version: 2.7.3
|
331
332
|
signing_key:
|
332
333
|
specification_version: 2
|
333
334
|
summary: A simple, blog aware, static site generator.
|