jekyll 3.8.7 → 4.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 +4 -4
- data/.rubocop.yml +71 -62
- data/LICENSE +1 -1
- data/README.markdown +46 -17
- data/lib/blank_template/_config.yml +3 -0
- data/lib/blank_template/_layouts/default.html +12 -0
- data/lib/blank_template/_sass/main.scss +9 -0
- data/lib/blank_template/assets/css/main.scss +4 -0
- data/lib/blank_template/index.md +8 -0
- data/lib/jekyll.rb +10 -1
- data/lib/jekyll/cache.rb +190 -0
- data/lib/jekyll/cleaner.rb +5 -4
- data/lib/jekyll/collection.rb +82 -10
- data/lib/jekyll/command.rb +33 -6
- data/lib/jekyll/commands/build.rb +11 -20
- data/lib/jekyll/commands/clean.rb +2 -0
- data/lib/jekyll/commands/doctor.rb +15 -8
- data/lib/jekyll/commands/help.rb +1 -1
- data/lib/jekyll/commands/new.rb +37 -35
- data/lib/jekyll/commands/new_theme.rb +30 -28
- data/lib/jekyll/commands/serve.rb +55 -81
- data/lib/jekyll/commands/serve/live_reload_reactor.rb +6 -10
- data/lib/jekyll/commands/serve/servlet.rb +22 -25
- data/lib/jekyll/commands/serve/websockets.rb +1 -1
- data/lib/jekyll/configuration.rb +61 -149
- data/lib/jekyll/converters/identity.rb +18 -0
- data/lib/jekyll/converters/markdown.rb +49 -40
- data/lib/jekyll/converters/markdown/kramdown_parser.rb +84 -11
- data/lib/jekyll/converters/smartypants.rb +34 -14
- data/lib/jekyll/convertible.rb +30 -31
- data/lib/jekyll/deprecator.rb +1 -3
- data/lib/jekyll/document.rb +89 -61
- data/lib/jekyll/drops/collection_drop.rb +2 -3
- data/lib/jekyll/drops/document_drop.rb +14 -1
- data/lib/jekyll/drops/drop.rb +17 -14
- data/lib/jekyll/drops/excerpt_drop.rb +4 -0
- data/lib/jekyll/drops/page_drop.rb +18 -0
- data/lib/jekyll/drops/site_drop.rb +6 -5
- data/lib/jekyll/drops/unified_payload_drop.rb +1 -0
- data/lib/jekyll/drops/url_drop.rb +53 -1
- data/lib/jekyll/entry_filter.rb +42 -45
- data/lib/jekyll/excerpt.rb +45 -34
- data/lib/jekyll/external.rb +10 -5
- data/lib/jekyll/filters.rb +200 -40
- data/lib/jekyll/filters/date_filters.rb +6 -3
- data/lib/jekyll/filters/grouping_filters.rb +1 -2
- data/lib/jekyll/filters/url_filters.rb +46 -14
- data/lib/jekyll/frontmatter_defaults.rb +46 -35
- data/lib/jekyll/hooks.rb +4 -8
- data/lib/jekyll/inclusion.rb +32 -0
- data/lib/jekyll/liquid_extensions.rb +0 -2
- data/lib/jekyll/liquid_renderer.rb +31 -16
- data/lib/jekyll/liquid_renderer/file.rb +24 -3
- data/lib/jekyll/liquid_renderer/table.rb +36 -77
- data/lib/jekyll/log_adapter.rb +5 -1
- data/lib/jekyll/mime.types +53 -11
- data/lib/jekyll/page.rb +54 -12
- data/lib/jekyll/page_excerpt.rb +26 -0
- data/lib/jekyll/page_without_a_file.rb +0 -4
- data/lib/jekyll/path_manager.rb +31 -0
- data/lib/jekyll/plugin.rb +5 -11
- data/lib/jekyll/plugin_manager.rb +2 -0
- data/lib/jekyll/profiler.rb +58 -0
- data/lib/jekyll/reader.rb +42 -9
- data/lib/jekyll/readers/collection_reader.rb +1 -0
- data/lib/jekyll/readers/data_reader.rb +8 -9
- data/lib/jekyll/readers/layout_reader.rb +3 -12
- data/lib/jekyll/readers/page_reader.rb +5 -5
- data/lib/jekyll/readers/post_reader.rb +31 -18
- data/lib/jekyll/readers/static_file_reader.rb +4 -4
- data/lib/jekyll/readers/theme_assets_reader.rb +8 -5
- data/lib/jekyll/regenerator.rb +4 -12
- data/lib/jekyll/renderer.rb +23 -40
- data/lib/jekyll/site.rb +91 -38
- data/lib/jekyll/static_file.rb +62 -21
- data/lib/jekyll/stevenson.rb +2 -3
- data/lib/jekyll/tags/highlight.rb +19 -51
- data/lib/jekyll/tags/include.rb +82 -42
- data/lib/jekyll/tags/link.rb +11 -7
- data/lib/jekyll/tags/post_url.rb +25 -21
- data/lib/jekyll/theme.rb +16 -18
- data/lib/jekyll/theme_builder.rb +91 -89
- data/lib/jekyll/url.rb +10 -5
- data/lib/jekyll/utils.rb +18 -21
- data/lib/jekyll/utils/ansi.rb +1 -1
- data/lib/jekyll/utils/exec.rb +0 -1
- data/lib/jekyll/utils/internet.rb +2 -4
- data/lib/jekyll/utils/platforms.rb +8 -8
- data/lib/jekyll/utils/thread_event.rb +1 -5
- data/lib/jekyll/utils/win_tz.rb +2 -2
- data/lib/jekyll/version.rb +1 -1
- data/lib/site_template/.gitignore +2 -0
- data/lib/site_template/404.html +1 -0
- data/lib/site_template/_config.yml +17 -5
- data/lib/site_template/_posts/0000-00-00-welcome-to-jekyll.markdown.erb +5 -1
- data/lib/site_template/{about.md → about.markdown} +0 -0
- data/lib/site_template/{index.md → index.markdown} +0 -0
- data/lib/theme_template/gitignore.erb +1 -0
- data/lib/theme_template/theme.gemspec.erb +1 -4
- data/rubocop/jekyll/assert_equal_literal_actual.rb +149 -0
- metadata +69 -31
- data/lib/jekyll/converters/markdown/rdiscount_parser.rb +0 -37
- data/lib/jekyll/converters/markdown/redcarpet_parser.rb +0 -112
- data/lib/jekyll/utils/rouge.rb +0 -22
data/lib/jekyll/static_file.rb
CHANGED
|
@@ -4,7 +4,7 @@ module Jekyll
|
|
|
4
4
|
class StaticFile
|
|
5
5
|
extend Forwardable
|
|
6
6
|
|
|
7
|
-
attr_reader :relative_path, :extname, :name
|
|
7
|
+
attr_reader :relative_path, :extname, :name
|
|
8
8
|
|
|
9
9
|
def_delegator :to_liquid, :to_json, :to_json
|
|
10
10
|
|
|
@@ -25,7 +25,7 @@ module Jekyll
|
|
|
25
25
|
# base - The String path to the <source>.
|
|
26
26
|
# dir - The String path between <source> and the file.
|
|
27
27
|
# name - The String filename of the file.
|
|
28
|
-
# rubocop: disable ParameterLists
|
|
28
|
+
# rubocop: disable Metrics/ParameterLists
|
|
29
29
|
def initialize(site, base, dir, name, collection = nil)
|
|
30
30
|
@site = site
|
|
31
31
|
@base = base
|
|
@@ -34,17 +34,18 @@ module Jekyll
|
|
|
34
34
|
@collection = collection
|
|
35
35
|
@relative_path = File.join(*[@dir, @name].compact)
|
|
36
36
|
@extname = File.extname(@name)
|
|
37
|
-
@data = @site.frontmatter_defaults.all(relative_path, type)
|
|
38
37
|
end
|
|
39
|
-
# rubocop: enable ParameterLists
|
|
38
|
+
# rubocop: enable Metrics/ParameterLists
|
|
40
39
|
|
|
41
40
|
# Returns source file path.
|
|
42
41
|
def path
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
42
|
+
@path ||= begin
|
|
43
|
+
# Static file is from a collection inside custom collections directory
|
|
44
|
+
if !@collection.nil? && !@site.config["collections_dir"].empty?
|
|
45
|
+
File.join(*[@base, @site.config["collections_dir"], @dir, @name].compact)
|
|
46
|
+
else
|
|
47
|
+
File.join(*[@base, @dir, @name].compact)
|
|
48
|
+
end
|
|
48
49
|
end
|
|
49
50
|
end
|
|
50
51
|
|
|
@@ -54,7 +55,8 @@ module Jekyll
|
|
|
54
55
|
#
|
|
55
56
|
# Returns destination file path.
|
|
56
57
|
def destination(dest)
|
|
57
|
-
@site.in_dest_dir(
|
|
58
|
+
dest = @site.in_dest_dir(dest)
|
|
59
|
+
@site.in_dest_dir(dest, Jekyll::URL.unescape_path(url))
|
|
58
60
|
end
|
|
59
61
|
|
|
60
62
|
def destination_rel_dir
|
|
@@ -86,7 +88,10 @@ module Jekyll
|
|
|
86
88
|
# Returns true unless the defaults for the destination path from
|
|
87
89
|
# _config.yml contain `published: false`.
|
|
88
90
|
def write?
|
|
89
|
-
defaults.fetch("published", true)
|
|
91
|
+
publishable = defaults.fetch("published", true)
|
|
92
|
+
return publishable unless @collection
|
|
93
|
+
|
|
94
|
+
publishable && @collection.write?
|
|
90
95
|
end
|
|
91
96
|
|
|
92
97
|
# Write the static file to the destination directory (if modified).
|
|
@@ -96,8 +101,8 @@ module Jekyll
|
|
|
96
101
|
# Returns false if the file was not modified since last time (no-op).
|
|
97
102
|
def write(dest)
|
|
98
103
|
dest_path = destination(dest)
|
|
99
|
-
|
|
100
104
|
return false if File.exist?(dest_path) && !modified?
|
|
105
|
+
|
|
101
106
|
self.class.mtimes[path] = mtime
|
|
102
107
|
|
|
103
108
|
FileUtils.mkdir_p(File.dirname(dest_path))
|
|
@@ -107,37 +112,66 @@ module Jekyll
|
|
|
107
112
|
true
|
|
108
113
|
end
|
|
109
114
|
|
|
115
|
+
def data
|
|
116
|
+
@data ||= @site.frontmatter_defaults.all(relative_path, type)
|
|
117
|
+
end
|
|
118
|
+
|
|
110
119
|
def to_liquid
|
|
111
120
|
@to_liquid ||= Drops::StaticFileDrop.new(self)
|
|
112
121
|
end
|
|
113
122
|
|
|
123
|
+
# Generate "basename without extension" and strip away any trailing periods.
|
|
124
|
+
# NOTE: `String#gsub` removes all trailing periods (in comparison to `String#chomp`)
|
|
114
125
|
def basename
|
|
115
|
-
File.basename(name, extname)
|
|
126
|
+
@basename ||= File.basename(name, extname).gsub(%r!\.*\z!, "")
|
|
116
127
|
end
|
|
117
128
|
|
|
118
129
|
def placeholders
|
|
119
130
|
{
|
|
120
131
|
:collection => @collection.label,
|
|
121
|
-
:path =>
|
|
122
|
-
@collection.relative_directory.size..relative_path.size],
|
|
132
|
+
:path => cleaned_relative_path,
|
|
123
133
|
:output_ext => "",
|
|
124
|
-
:name =>
|
|
134
|
+
:name => basename,
|
|
125
135
|
:title => "",
|
|
126
136
|
}
|
|
127
137
|
end
|
|
128
138
|
|
|
139
|
+
# Similar to Jekyll::Document#cleaned_relative_path.
|
|
140
|
+
# Generates a relative path with the collection's directory removed when applicable
|
|
141
|
+
# and additionally removes any multiple periods in the string.
|
|
142
|
+
#
|
|
143
|
+
# NOTE: `String#gsub!` removes all trailing periods (in comparison to `String#chomp!`)
|
|
144
|
+
#
|
|
145
|
+
# Examples:
|
|
146
|
+
# When `relative_path` is "_methods/site/my-cool-avatar...png":
|
|
147
|
+
# cleaned_relative_path
|
|
148
|
+
# # => "/site/my-cool-avatar"
|
|
149
|
+
#
|
|
150
|
+
# Returns the cleaned relative path of the static file.
|
|
151
|
+
def cleaned_relative_path
|
|
152
|
+
@cleaned_relative_path ||= begin
|
|
153
|
+
cleaned = relative_path[0..-extname.length - 1]
|
|
154
|
+
cleaned.gsub!(%r!\.*\z!, "")
|
|
155
|
+
cleaned.sub!(@collection.relative_directory, "") if @collection
|
|
156
|
+
cleaned
|
|
157
|
+
end
|
|
158
|
+
end
|
|
159
|
+
|
|
129
160
|
# Applies a similar URL-building technique as Jekyll::Document that takes
|
|
130
161
|
# the collection's URL template into account. The default URL template can
|
|
131
162
|
# be overriden in the collection's configuration in _config.yml.
|
|
132
163
|
def url
|
|
133
|
-
@url ||=
|
|
134
|
-
|
|
164
|
+
@url ||= begin
|
|
165
|
+
base = if @collection.nil?
|
|
166
|
+
cleaned_relative_path
|
|
135
167
|
else
|
|
136
|
-
|
|
168
|
+
Jekyll::URL.new(
|
|
137
169
|
:template => @collection.url_template,
|
|
138
|
-
:placeholders => placeholders
|
|
139
|
-
|
|
170
|
+
:placeholders => placeholders
|
|
171
|
+
)
|
|
140
172
|
end.to_s.chomp("/")
|
|
173
|
+
base << extname
|
|
174
|
+
end
|
|
141
175
|
end
|
|
142
176
|
|
|
143
177
|
# Returns the type of the collection if present, nil otherwise.
|
|
@@ -151,7 +185,14 @@ module Jekyll
|
|
|
151
185
|
@defaults ||= @site.frontmatter_defaults.all url, type
|
|
152
186
|
end
|
|
153
187
|
|
|
188
|
+
# Returns a debug string on inspecting the static file.
|
|
189
|
+
# Includes only the relative path of the object.
|
|
190
|
+
def inspect
|
|
191
|
+
"#<#{self.class} @relative_path=#{relative_path.inspect}>"
|
|
192
|
+
end
|
|
193
|
+
|
|
154
194
|
private
|
|
195
|
+
|
|
155
196
|
def copy_file(dest_path)
|
|
156
197
|
if @site.safe || Jekyll.env == "production"
|
|
157
198
|
FileUtils.cp(path, dest_path)
|
data/lib/jekyll/stevenson.rb
CHANGED
|
@@ -16,9 +16,8 @@ module Jekyll
|
|
|
16
16
|
severity ||= UNKNOWN
|
|
17
17
|
@logdev = logdevice(severity)
|
|
18
18
|
|
|
19
|
-
if @logdev.nil? || severity < @level
|
|
20
|
-
|
|
21
|
-
end
|
|
19
|
+
return true if @logdev.nil? || severity < @level
|
|
20
|
+
|
|
22
21
|
progname ||= @progname
|
|
23
22
|
if message.nil?
|
|
24
23
|
if block_given?
|
|
@@ -10,7 +10,7 @@ module Jekyll
|
|
|
10
10
|
# forms: name, name=value, or name="<quoted list>"
|
|
11
11
|
#
|
|
12
12
|
# <quoted list> is a space-separated list of numbers
|
|
13
|
-
SYNTAX = %r!^([a-zA-Z0-9.+#_-]+)((\s+\w+(=(\w+|"([0-9]+\s)*[0-9]+"))?)*)
|
|
13
|
+
SYNTAX = %r!^([a-zA-Z0-9.+#_-]+)((\s+\w+(=(\w+|"([0-9]+\s)*[0-9]+"))?)*)$!.freeze
|
|
14
14
|
|
|
15
15
|
def initialize(tag_name, markup, tokens)
|
|
16
16
|
super
|
|
@@ -18,29 +18,29 @@ module Jekyll
|
|
|
18
18
|
@lang = Regexp.last_match(1).downcase
|
|
19
19
|
@highlight_options = parse_options(Regexp.last_match(2))
|
|
20
20
|
else
|
|
21
|
-
raise SyntaxError,
|
|
22
|
-
Syntax Error in tag 'highlight' while parsing the following markup:
|
|
21
|
+
raise SyntaxError, <<~MSG
|
|
22
|
+
Syntax Error in tag 'highlight' while parsing the following markup:
|
|
23
23
|
|
|
24
|
-
|
|
24
|
+
#{markup}
|
|
25
25
|
|
|
26
|
-
Valid syntax: highlight <lang> [linenos]
|
|
27
|
-
MSG
|
|
26
|
+
Valid syntax: highlight <lang> [linenos]
|
|
27
|
+
MSG
|
|
28
28
|
end
|
|
29
29
|
end
|
|
30
30
|
|
|
31
|
+
LEADING_OR_TRAILING_LINE_TERMINATORS = %r!\A(\n|\r)+|(\n|\r)+\z!.freeze
|
|
32
|
+
|
|
31
33
|
def render(context)
|
|
32
34
|
prefix = context["highlighter_prefix"] || ""
|
|
33
35
|
suffix = context["highlighter_suffix"] || ""
|
|
34
|
-
code = super.to_s.gsub(
|
|
35
|
-
|
|
36
|
-
is_safe = !!context.registers[:site].safe
|
|
36
|
+
code = super.to_s.gsub(LEADING_OR_TRAILING_LINE_TERMINATORS, "")
|
|
37
37
|
|
|
38
38
|
output =
|
|
39
39
|
case context.registers[:site].highlighter
|
|
40
|
-
when "pygments"
|
|
41
|
-
render_pygments(code, is_safe)
|
|
42
40
|
when "rouge"
|
|
43
41
|
render_rouge(code)
|
|
42
|
+
when "pygments"
|
|
43
|
+
render_pygments(code, context)
|
|
44
44
|
else
|
|
45
45
|
render_codehighlighter(code)
|
|
46
46
|
end
|
|
@@ -49,23 +49,9 @@ MSG
|
|
|
49
49
|
prefix + rendered_output + suffix
|
|
50
50
|
end
|
|
51
51
|
|
|
52
|
-
def sanitized_opts(opts, is_safe)
|
|
53
|
-
if is_safe
|
|
54
|
-
Hash[[
|
|
55
|
-
[:startinline, opts.fetch(:startinline, nil)],
|
|
56
|
-
[:hl_lines, opts.fetch(:hl_lines, nil)],
|
|
57
|
-
[:linenos, opts.fetch(:linenos, nil)],
|
|
58
|
-
[:encoding, opts.fetch(:encoding, "utf-8")],
|
|
59
|
-
[:cssclass, opts.fetch(:cssclass, nil)],
|
|
60
|
-
].reject { |f| f.last.nil? }]
|
|
61
|
-
else
|
|
62
|
-
opts
|
|
63
|
-
end
|
|
64
|
-
end
|
|
65
|
-
|
|
66
52
|
private
|
|
67
53
|
|
|
68
|
-
OPTIONS_REGEX = %r!(?:\w="[^"]*"|\w=\w|\w)
|
|
54
|
+
OPTIONS_REGEX = %r!(?:\w="[^"]*"|\w=\w|\w)+!.freeze
|
|
69
55
|
|
|
70
56
|
def parse_options(input)
|
|
71
57
|
options = {}
|
|
@@ -75,7 +61,7 @@ MSG
|
|
|
75
61
|
input.scan(OPTIONS_REGEX) do |opt|
|
|
76
62
|
key, value = opt.split("=")
|
|
77
63
|
# If a quoted list, convert to array
|
|
78
|
-
if value
|
|
64
|
+
if value&.include?('"')
|
|
79
65
|
value.delete!('"')
|
|
80
66
|
value = value.split
|
|
81
67
|
end
|
|
@@ -86,33 +72,15 @@ MSG
|
|
|
86
72
|
options
|
|
87
73
|
end
|
|
88
74
|
|
|
89
|
-
def render_pygments(code,
|
|
90
|
-
Jekyll
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
code,
|
|
94
|
-
:lexer => @lang,
|
|
95
|
-
:options => sanitized_opts(@highlight_options, is_safe)
|
|
96
|
-
)
|
|
97
|
-
|
|
98
|
-
if highlighted_code.nil?
|
|
99
|
-
Jekyll.logger.error <<-MSG
|
|
100
|
-
There was an error highlighting your code:
|
|
101
|
-
|
|
102
|
-
#{code}
|
|
103
|
-
|
|
104
|
-
While attempting to convert the above code, Pygments.rb returned an unacceptable value.
|
|
105
|
-
This is usually a timeout problem solved by running `jekyll build` again.
|
|
106
|
-
MSG
|
|
107
|
-
raise ArgumentError, "Pygments.rb returned an unacceptable value "\
|
|
108
|
-
"when attempting to highlight some code."
|
|
109
|
-
end
|
|
110
|
-
|
|
111
|
-
highlighted_code.sub('<div class="highlight"><pre>', "").sub("</pre></div>", "")
|
|
75
|
+
def render_pygments(code, _context)
|
|
76
|
+
Jekyll.logger.warn "Warning:", "Highlight Tag no longer supports rendering with Pygments."
|
|
77
|
+
Jekyll.logger.warn "", "Using the default highlighter, Rouge, instead."
|
|
78
|
+
render_rouge(code)
|
|
112
79
|
end
|
|
113
80
|
|
|
114
81
|
def render_rouge(code)
|
|
115
|
-
|
|
82
|
+
require "rouge"
|
|
83
|
+
formatter = ::Rouge::Formatters::HTMLLegacy.new(
|
|
116
84
|
:line_numbers => @highlight_options[:linenos],
|
|
117
85
|
:wrap => false,
|
|
118
86
|
:css_class => "highlight",
|
data/lib/jekyll/tags/include.rb
CHANGED
|
@@ -2,37 +2,29 @@
|
|
|
2
2
|
|
|
3
3
|
module Jekyll
|
|
4
4
|
module Tags
|
|
5
|
-
class IncludeTagError < StandardError
|
|
6
|
-
attr_accessor :path
|
|
7
|
-
|
|
8
|
-
def initialize(msg, path)
|
|
9
|
-
super(msg)
|
|
10
|
-
@path = path
|
|
11
|
-
end
|
|
12
|
-
end
|
|
13
|
-
|
|
14
5
|
class IncludeTag < Liquid::Tag
|
|
15
6
|
VALID_SYNTAX = %r!
|
|
16
7
|
([\w-]+)\s*=\s*
|
|
17
8
|
(?:"([^"\\]*(?:\\.[^"\\]*)*)"|'([^'\\]*(?:\\.[^'\\]*)*)'|([\w\.-]+))
|
|
18
|
-
!x
|
|
9
|
+
!x.freeze
|
|
19
10
|
VARIABLE_SYNTAX = %r!
|
|
20
11
|
(?<variable>[^{]*(\{\{\s*[\w\-\.]+\s*(\|.*)?\}\}[^\s{}]*)+)
|
|
21
12
|
(?<params>.*)
|
|
22
|
-
!mx
|
|
13
|
+
!mx.freeze
|
|
23
14
|
|
|
24
|
-
FULL_VALID_SYNTAX = %r!\A\s*(?:#{VALID_SYNTAX}(?=\s|\z)\s*)*\z
|
|
25
|
-
VALID_FILENAME_CHARS = %r!^[\w/\.-]
|
|
26
|
-
INVALID_SEQUENCES = %r![./]{2,}
|
|
15
|
+
FULL_VALID_SYNTAX = %r!\A\s*(?:#{VALID_SYNTAX}(?=\s|\z)\s*)*\z!.freeze
|
|
16
|
+
VALID_FILENAME_CHARS = %r!^[\w/\.-]+$!.freeze
|
|
17
|
+
INVALID_SEQUENCES = %r![./]{2,}!.freeze
|
|
27
18
|
|
|
28
19
|
def initialize(tag_name, markup, tokens)
|
|
29
20
|
super
|
|
30
|
-
|
|
21
|
+
markup = markup.strip
|
|
22
|
+
matched = markup.match(VARIABLE_SYNTAX)
|
|
31
23
|
if matched
|
|
32
24
|
@file = matched["variable"].strip
|
|
33
25
|
@params = matched["params"].strip
|
|
34
26
|
else
|
|
35
|
-
@file, @params = markup.
|
|
27
|
+
@file, @params = markup.split(%r!\s+!, 2)
|
|
36
28
|
end
|
|
37
29
|
validate_params if @params
|
|
38
30
|
@tag_name = tag_name
|
|
@@ -50,9 +42,9 @@ module Jekyll
|
|
|
50
42
|
markup = markup[match.end(0)..-1]
|
|
51
43
|
|
|
52
44
|
value = if match[2]
|
|
53
|
-
match[2].gsub(
|
|
45
|
+
match[2].gsub('\\"', '"')
|
|
54
46
|
elsif match[3]
|
|
55
|
-
match[3].gsub(
|
|
47
|
+
match[3].gsub("\\'", "'")
|
|
56
48
|
elsif match[4]
|
|
57
49
|
context[match[4]]
|
|
58
50
|
end
|
|
@@ -63,32 +55,32 @@ module Jekyll
|
|
|
63
55
|
end
|
|
64
56
|
|
|
65
57
|
def validate_file_name(file)
|
|
66
|
-
if file
|
|
67
|
-
raise ArgumentError,
|
|
68
|
-
Invalid syntax for include tag. File contains invalid characters or sequences:
|
|
58
|
+
if INVALID_SEQUENCES.match?(file) || !VALID_FILENAME_CHARS.match?(file)
|
|
59
|
+
raise ArgumentError, <<~MSG
|
|
60
|
+
Invalid syntax for include tag. File contains invalid characters or sequences:
|
|
69
61
|
|
|
70
|
-
|
|
62
|
+
#{file}
|
|
71
63
|
|
|
72
|
-
Valid syntax:
|
|
64
|
+
Valid syntax:
|
|
73
65
|
|
|
74
|
-
|
|
66
|
+
#{syntax_example}
|
|
75
67
|
|
|
76
|
-
MSG
|
|
68
|
+
MSG
|
|
77
69
|
end
|
|
78
70
|
end
|
|
79
71
|
|
|
80
72
|
def validate_params
|
|
81
|
-
unless @params
|
|
82
|
-
raise ArgumentError,
|
|
83
|
-
Invalid syntax for include tag:
|
|
73
|
+
unless FULL_VALID_SYNTAX.match?(@params)
|
|
74
|
+
raise ArgumentError, <<~MSG
|
|
75
|
+
Invalid syntax for include tag:
|
|
84
76
|
|
|
85
|
-
|
|
77
|
+
#{@params}
|
|
86
78
|
|
|
87
|
-
Valid syntax:
|
|
79
|
+
Valid syntax:
|
|
88
80
|
|
|
89
|
-
|
|
81
|
+
#{syntax_example}
|
|
90
82
|
|
|
91
|
-
MSG
|
|
83
|
+
MSG
|
|
92
84
|
end
|
|
93
85
|
end
|
|
94
86
|
|
|
@@ -99,13 +91,7 @@ MSG
|
|
|
99
91
|
|
|
100
92
|
# Render the variable if required
|
|
101
93
|
def render_variable(context)
|
|
102
|
-
|
|
103
|
-
partial = context.registers[:site]
|
|
104
|
-
.liquid_renderer
|
|
105
|
-
.file("(variable)")
|
|
106
|
-
.parse(@file)
|
|
107
|
-
partial.render!(context)
|
|
108
|
-
end
|
|
94
|
+
Liquid::Template.parse(@file).render(context) if VARIABLE_SYNTAX.match?(@file)
|
|
109
95
|
end
|
|
110
96
|
|
|
111
97
|
def tag_includes_dirs(context)
|
|
@@ -115,7 +101,7 @@ MSG
|
|
|
115
101
|
def locate_include_file(context, file, safe)
|
|
116
102
|
includes_dirs = tag_includes_dirs(context)
|
|
117
103
|
includes_dirs.each do |dir|
|
|
118
|
-
path =
|
|
104
|
+
path = PathManager.join(dir, file)
|
|
119
105
|
return path if valid_include_file?(path, dir.to_s, safe)
|
|
120
106
|
end
|
|
121
107
|
raise IOError, could_not_locate_message(file, includes_dirs, safe)
|
|
@@ -147,7 +133,7 @@ MSG
|
|
|
147
133
|
end
|
|
148
134
|
|
|
149
135
|
def add_include_to_dependency(site, path, context)
|
|
150
|
-
if context.registers[:page]
|
|
136
|
+
if context.registers[:page]&.key?("path")
|
|
151
137
|
site.regenerator.add_dependency(
|
|
152
138
|
site.in_source_dir(context.registers[:page]["path"]),
|
|
153
139
|
path
|
|
@@ -207,6 +193,60 @@ MSG
|
|
|
207
193
|
end
|
|
208
194
|
end
|
|
209
195
|
|
|
196
|
+
# Do not inherit from this class.
|
|
197
|
+
# TODO: Merge into the `Jekyll::Tags::IncludeTag` in v5.0
|
|
198
|
+
class OptimizedIncludeTag < IncludeTag
|
|
199
|
+
def render(context)
|
|
200
|
+
@site ||= context.registers[:site]
|
|
201
|
+
|
|
202
|
+
file = render_variable(context) || @file
|
|
203
|
+
validate_file_name(file)
|
|
204
|
+
|
|
205
|
+
@site.inclusions[file] ||= locate_include_file(file)
|
|
206
|
+
inclusion = @site.inclusions[file]
|
|
207
|
+
|
|
208
|
+
add_include_to_dependency(inclusion, context) if @site.incremental?
|
|
209
|
+
|
|
210
|
+
context.stack do
|
|
211
|
+
context["include"] = parse_params(context) if @params
|
|
212
|
+
inclusion.render(context)
|
|
213
|
+
end
|
|
214
|
+
end
|
|
215
|
+
|
|
216
|
+
private
|
|
217
|
+
|
|
218
|
+
def locate_include_file(file)
|
|
219
|
+
@site.includes_load_paths.each do |dir|
|
|
220
|
+
path = PathManager.join(dir, file)
|
|
221
|
+
return Inclusion.new(@site, dir, file) if valid_include_file?(path, dir)
|
|
222
|
+
end
|
|
223
|
+
raise IOError, could_not_locate_message(file, @site.includes_load_paths, @site.safe)
|
|
224
|
+
end
|
|
225
|
+
|
|
226
|
+
def valid_include_file?(path, dir)
|
|
227
|
+
File.file?(path) && !outside_scope?(path, dir)
|
|
228
|
+
end
|
|
229
|
+
|
|
230
|
+
def outside_scope?(path, dir)
|
|
231
|
+
@site.safe && !realpath_prefixed_with?(path, dir)
|
|
232
|
+
end
|
|
233
|
+
|
|
234
|
+
def realpath_prefixed_with?(path, dir)
|
|
235
|
+
File.realpath(path).start_with?(dir)
|
|
236
|
+
rescue StandardError
|
|
237
|
+
false
|
|
238
|
+
end
|
|
239
|
+
|
|
240
|
+
def add_include_to_dependency(inclusion, context)
|
|
241
|
+
return unless context.registers[:page]&.key?("path")
|
|
242
|
+
|
|
243
|
+
@site.regenerator.add_dependency(
|
|
244
|
+
@site.in_source_dir(context.registers[:page]["path"]),
|
|
245
|
+
inclusion.path
|
|
246
|
+
)
|
|
247
|
+
end
|
|
248
|
+
end
|
|
249
|
+
|
|
210
250
|
class IncludeRelativeTag < IncludeTag
|
|
211
251
|
def tag_includes_dirs(context)
|
|
212
252
|
Array(page_path(context)).freeze
|
|
@@ -232,5 +272,5 @@ MSG
|
|
|
232
272
|
end
|
|
233
273
|
end
|
|
234
274
|
|
|
235
|
-
Liquid::Template.register_tag("include", Jekyll::Tags::
|
|
275
|
+
Liquid::Template.register_tag("include", Jekyll::Tags::OptimizedIncludeTag)
|
|
236
276
|
Liquid::Template.register_tag("include_relative", Jekyll::Tags::IncludeRelativeTag)
|