jekyll 4.0.0.pre.beta1 → 4.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (61) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +204 -18
  3. data/README.markdown +2 -6
  4. data/lib/blank_template/_layouts/default.html +1 -1
  5. data/lib/jekyll.rb +6 -17
  6. data/lib/jekyll/cleaner.rb +3 -3
  7. data/lib/jekyll/collection.rb +2 -2
  8. data/lib/jekyll/command.rb +4 -2
  9. data/lib/jekyll/commands/doctor.rb +19 -15
  10. data/lib/jekyll/commands/new.rb +4 -4
  11. data/lib/jekyll/commands/new_theme.rb +0 -2
  12. data/lib/jekyll/commands/serve.rb +12 -1
  13. data/lib/jekyll/configuration.rb +18 -19
  14. data/lib/jekyll/converters/identity.rb +2 -2
  15. data/lib/jekyll/converters/markdown/kramdown_parser.rb +70 -1
  16. data/lib/jekyll/convertible.rb +30 -23
  17. data/lib/jekyll/document.rb +41 -19
  18. data/lib/jekyll/drops/collection_drop.rb +3 -3
  19. data/lib/jekyll/drops/document_drop.rb +4 -3
  20. data/lib/jekyll/drops/drop.rb +98 -20
  21. data/lib/jekyll/drops/site_drop.rb +3 -3
  22. data/lib/jekyll/drops/static_file_drop.rb +4 -4
  23. data/lib/jekyll/drops/url_drop.rb +11 -3
  24. data/lib/jekyll/entry_filter.rb +18 -7
  25. data/lib/jekyll/excerpt.rb +1 -1
  26. data/lib/jekyll/filters.rb +112 -28
  27. data/lib/jekyll/filters/url_filters.rb +45 -15
  28. data/lib/jekyll/frontmatter_defaults.rb +14 -19
  29. data/lib/jekyll/hooks.rb +22 -21
  30. data/lib/jekyll/inclusion.rb +32 -0
  31. data/lib/jekyll/layout.rb +5 -0
  32. data/lib/jekyll/liquid_renderer.rb +18 -15
  33. data/lib/jekyll/liquid_renderer/file.rb +10 -0
  34. data/lib/jekyll/liquid_renderer/table.rb +1 -64
  35. data/lib/jekyll/page.rb +42 -11
  36. data/lib/jekyll/page_excerpt.rb +25 -0
  37. data/lib/jekyll/path_manager.rb +53 -10
  38. data/lib/jekyll/profiler.rb +58 -0
  39. data/lib/jekyll/reader.rb +11 -6
  40. data/lib/jekyll/readers/collection_reader.rb +1 -0
  41. data/lib/jekyll/readers/data_reader.rb +4 -0
  42. data/lib/jekyll/readers/layout_reader.rb +1 -0
  43. data/lib/jekyll/readers/page_reader.rb +1 -0
  44. data/lib/jekyll/readers/post_reader.rb +2 -1
  45. data/lib/jekyll/readers/static_file_reader.rb +1 -0
  46. data/lib/jekyll/readers/theme_assets_reader.rb +1 -0
  47. data/lib/jekyll/related_posts.rb +1 -1
  48. data/lib/jekyll/renderer.rb +15 -17
  49. data/lib/jekyll/site.rb +34 -10
  50. data/lib/jekyll/static_file.rb +17 -12
  51. data/lib/jekyll/tags/include.rb +82 -33
  52. data/lib/jekyll/tags/link.rb +2 -1
  53. data/lib/jekyll/tags/post_url.rb +3 -4
  54. data/lib/jekyll/theme.rb +6 -8
  55. data/lib/jekyll/url.rb +8 -5
  56. data/lib/jekyll/utils.rb +5 -5
  57. data/lib/jekyll/utils/platforms.rb +34 -49
  58. data/lib/jekyll/utils/win_tz.rb +1 -1
  59. data/lib/jekyll/version.rb +1 -1
  60. data/lib/theme_template/theme.gemspec.erb +1 -4
  61. metadata +34 -39
@@ -67,6 +67,8 @@ module Jekyll
67
67
  cmd.option "show_drafts", "-D", "--drafts", "Render posts in the _drafts folder"
68
68
  cmd.option "unpublished", "--unpublished",
69
69
  "Render posts that were marked as unpublished"
70
+ cmd.option "disable_disk_cache", "--disable-disk-cache",
71
+ "Disable caching to disk in non-safe mode"
70
72
  cmd.option "quiet", "-q", "--quiet", "Silence output."
71
73
  cmd.option "verbose", "-V", "--verbose", "Print verbose output."
72
74
  cmd.option "incremental", "-I", "--incremental", "Enable incremental rebuild."
@@ -84,7 +86,7 @@ module Jekyll
84
86
  # klass - an array of Jekyll::Command subclasses associated with the command
85
87
  #
86
88
  # Note that all exceptions are rescued..
87
- # rubocop: disable RescueException
89
+ # rubocop: disable Lint/RescueException
88
90
  def process_with_graceful_fail(cmd, options, *klass)
89
91
  klass.each { |k| k.process(options) if k.respond_to?(:process) }
90
92
  rescue Exception => e
@@ -97,7 +99,7 @@ module Jekyll
97
99
  Jekyll.logger.error "", " for any additional information or backtrace. "
98
100
  Jekyll.logger.abort_with "", dashes
99
101
  end
100
- # rubocop: enable RescueException
102
+ # rubocop: enable Lint/RescueException
101
103
  end
102
104
  end
103
105
  end
@@ -67,15 +67,16 @@ module Jekyll
67
67
 
68
68
  def conflicting_urls(site)
69
69
  conflicting_urls = false
70
- urls = {}
71
- urls = collect_urls(urls, site.pages, site.dest)
72
- urls = collect_urls(urls, site.posts.docs, site.dest)
73
- urls.each do |url, paths|
70
+ destination_map(site).each do |dest, paths|
74
71
  next unless paths.size > 1
75
72
 
76
73
  conflicting_urls = true
77
- Jekyll.logger.warn "Conflict:", "The URL '#{url}' is the destination" \
78
- " for the following pages: #{paths.join(", ")}"
74
+ Jekyll.logger.warn "Conflict:",
75
+ "The following destination is shared by multiple files."
76
+ Jekyll.logger.warn "", "The written file may end up with unexpected contents."
77
+ Jekyll.logger.warn "", dest.to_s.cyan
78
+ paths.each { |path| Jekyll.logger.warn "", " - #{path}" }
79
+ Jekyll.logger.warn ""
79
80
  end
80
81
  conflicting_urls
81
82
  end
@@ -84,7 +85,7 @@ module Jekyll
84
85
  return true unless Utils::Platforms.osx?
85
86
 
86
87
  if Dir.pwd != `pwd`.strip
87
- Jekyll.logger.error " " + <<-STR.strip.gsub(%r!\n\s+!, "\n ")
88
+ Jekyll.logger.error <<~STR
88
89
  We have detected that there might be trouble using fsevent on your
89
90
  operating system, you can read https://github.com/thibaudgg/rb-fsevent/wiki/no-fsevents-fired-(OSX-bug)
90
91
  for possible work arounds or you can work around it immediately
@@ -122,16 +123,19 @@ module Jekyll
122
123
 
123
124
  private
124
125
 
125
- def collect_urls(urls, things, destination)
126
- things.each do |thing|
127
- dest = thing.destination(destination)
128
- if urls[dest]
129
- urls[dest] << thing.path
130
- else
131
- urls[dest] = [thing.path]
126
+ def destination_map(site)
127
+ {}.tap do |result|
128
+ site.each_site_file do |thing|
129
+ next if allow_used_permalink?(thing)
130
+
131
+ dest_path = thing.destination(site.dest)
132
+ (result[dest_path] ||= []) << thing.path
132
133
  end
133
134
  end
134
- urls
135
+ end
136
+
137
+ def allow_used_permalink?(item)
138
+ defined?(JekyllRedirectFrom) && item.is_a?(JekyllRedirectFrom::RedirectPage)
135
139
  end
136
140
 
137
141
  def case_insensitive_urls(things, destination)
@@ -80,24 +80,24 @@ module Jekyll
80
80
  # Happy Jekylling!
81
81
  gem "jekyll", "~> #{Jekyll::VERSION}"
82
82
  # This is the default theme for new Jekyll sites. You may change this to anything you like.
83
- gem "minima", "~> 2.0"
83
+ gem "minima", "~> 2.5"
84
84
  # If you want to use GitHub Pages, remove the "gem "jekyll"" above and
85
85
  # uncomment the line below. To upgrade, run `bundle update github-pages`.
86
86
  # gem "github-pages", group: :jekyll_plugins
87
87
  # If you have any plugins, put them here!
88
88
  group :jekyll_plugins do
89
- gem "jekyll-feed", "~> 0.6"
89
+ gem "jekyll-feed", "~> 0.12"
90
90
  end
91
91
 
92
92
  # Windows and JRuby does not include zoneinfo files, so bundle the tzinfo-data gem
93
93
  # and associated library.
94
- install_if -> { RUBY_PLATFORM =~ %r!mingw|mswin|java! } do
94
+ platforms :mingw, :x64_mingw, :mswin, :jruby do
95
95
  gem "tzinfo", "~> 1.2"
96
96
  gem "tzinfo-data"
97
97
  end
98
98
 
99
99
  # Performance-booster for watching directories on Windows
100
- gem "wdm", "~> 0.1.1", :install_if => Gem.win_platform?
100
+ gem "wdm", "~> 0.1.1", :platforms => [:mingw, :x64_mingw, :mswin]
101
101
 
102
102
  RUBY
103
103
  end
@@ -20,7 +20,6 @@ module Jekyll
20
20
  end
21
21
  end
22
22
 
23
- # rubocop:disable Metrics/AbcSize
24
23
  def process(args, opts)
25
24
  if !args || args.empty?
26
25
  raise Jekyll::Errors::InvalidThemeName, "You must specify a theme name."
@@ -35,7 +34,6 @@ module Jekyll
35
34
  " is ready for you in #{theme.path.to_s.cyan}!"
36
35
  Jekyll.logger.info "For help getting started, read #{theme.path}/README.md."
37
36
  end
38
- # rubocop:enable Metrics/AbcSize
39
37
  end
40
38
  end
41
39
  end
@@ -249,6 +249,9 @@ module Jekyll
249
249
 
250
250
  def default_url(opts)
251
251
  config = configuration_from_options(opts)
252
+ auth = config.values_at("host", "port").join(":")
253
+ return config["url"] if auth == "127.0.0.1:4000"
254
+
252
255
  format_url(
253
256
  config["ssl_cert"] && config["ssl_key"],
254
257
  config["host"] == "127.0.0.1" ? "localhost" : config["host"],
@@ -307,7 +310,15 @@ module Jekyll
307
310
  require "webrick/https"
308
311
 
309
312
  opts[:SSLCertificate] = OpenSSL::X509::Certificate.new(read_file(src, cert))
310
- opts[:SSLPrivateKey] = OpenSSL::PKey::RSA.new(read_file(src, key))
313
+ begin
314
+ opts[:SSLPrivateKey] = OpenSSL::PKey::RSA.new(read_file(src, key))
315
+ rescue StandardError
316
+ if defined?(OpenSSL::PKey::EC)
317
+ opts[:SSLPrivateKey] = OpenSSL::PKey::EC.new(read_file(src, key))
318
+ else
319
+ raise
320
+ end
321
+ end
311
322
  opts[:SSLEnable] = true
312
323
  end
313
324
 
@@ -4,7 +4,7 @@ module Jekyll
4
4
  class Configuration < Hash
5
5
  # Default options. Overridden by values in _config.yml.
6
6
  # Strings rather than symbols are used for compatibility with YAML.
7
- DEFAULTS = Configuration[{
7
+ DEFAULTS = {
8
8
  # Where things are
9
9
  "source" => Dir.pwd,
10
10
  "destination" => File.join(Dir.pwd, "_site"),
@@ -66,7 +66,7 @@ module Jekyll
66
66
 
67
67
  "kramdown" => {
68
68
  "auto_ids" => true,
69
- "toc_levels" => "1..6",
69
+ "toc_levels" => (1..6).to_a,
70
70
  "entity_output" => "as_char",
71
71
  "smart_quotes" => "lsquo,rsquo,ldquo,rdquo",
72
72
  "input" => "GFM",
@@ -75,7 +75,7 @@ module Jekyll
75
75
  "footnote_nr" => 1,
76
76
  "show_warnings" => false,
77
77
  },
78
- }.map { |k, v| [k, v.freeze] }].freeze
78
+ }.each_with_object(Configuration.new) { |(k, v), hsh| hsh[k] = v.freeze }.freeze
79
79
 
80
80
  class << self
81
81
  # Static: Produce a Configuration ready for use in a Site.
@@ -94,7 +94,7 @@ module Jekyll
94
94
  #
95
95
  # Return a copy of the hash where all its keys are strings
96
96
  def stringify_keys
97
- reduce({}) { |hsh, (k, v)| hsh.merge(k.to_s => v) }
97
+ each_with_object({}) { |(k, v), hsh| hsh[k.to_s] = v }
98
98
  end
99
99
 
100
100
  def get_config_value_with_override(config_key, override)
@@ -235,7 +235,9 @@ module Jekyll
235
235
 
236
236
  # Ensure we have a hash.
237
237
  if config["collections"].is_a?(Array)
238
- config["collections"] = Hash[config["collections"].map { |c| [c, {}] }]
238
+ config["collections"] = config["collections"].each_with_object({}) do |collection, hash|
239
+ hash[collection] = {}
240
+ end
239
241
  end
240
242
 
241
243
  config["collections"] = Utils.deep_merge_hashes(
@@ -267,21 +269,18 @@ module Jekyll
267
269
 
268
270
  private
269
271
 
272
+ STYLE_TO_PERMALINK = {
273
+ :none => "/:categories/:title:output_ext",
274
+ :date => "/:categories/:year/:month/:day/:title:output_ext",
275
+ :ordinal => "/:categories/:year/:y_day/:title:output_ext",
276
+ :pretty => "/:categories/:year/:month/:day/:title/",
277
+ :weekdate => "/:categories/:year/W:week/:short_day/:title:output_ext",
278
+ }.freeze
279
+
280
+ private_constant :STYLE_TO_PERMALINK
281
+
270
282
  def style_to_permalink(permalink_style)
271
- case permalink_style.to_sym
272
- when :pretty
273
- "/:categories/:year/:month/:day/:title/"
274
- when :none
275
- "/:categories/:title:output_ext"
276
- when :date
277
- "/:categories/:year/:month/:day/:title:output_ext"
278
- when :ordinal
279
- "/:categories/:year/:y_day/:title:output_ext"
280
- when :weekdate
281
- "/:categories/:year/W:week/:short_day/:title:output_ext"
282
- else
283
- permalink_style.to_s
284
- end
283
+ STYLE_TO_PERMALINK[permalink_style.to_sym] || permalink_style.to_s
285
284
  end
286
285
 
287
286
  def check_include_exclude(config)
@@ -2,7 +2,7 @@
2
2
 
3
3
  module Jekyll
4
4
  module Converters
5
- # Identify converter. Returns same content as given.
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
- # ext - The String extension to check (not relevant here)
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,13 +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
106
  end
38
107
 
39
108
  def convert(content)
40
- document = Kramdown::Document.new(content, @config)
109
+ document = Kramdown::JekyllDocument.new(content, @config)
41
110
  html_output = document.to_html
42
111
  if @config["show_warnings"]
43
112
  document.warnings.each do |warning|
@@ -35,13 +35,13 @@ module Jekyll
35
35
  # Returns nothing.
36
36
  # rubocop:disable Metrics/AbcSize
37
37
  def read_yaml(base, name, opts = {})
38
- filename = File.join(base, name)
38
+ filename = @path || site.in_source_dir(base, name)
39
+ Jekyll.logger.debug "Reading:", relative_path
39
40
 
40
41
  begin
41
- self.content = File.read(@path || site.in_source_dir(base, name),
42
- Utils.merged_file_read_opts(site, opts))
42
+ self.content = File.read(filename, **Utils.merged_file_read_opts(site, opts))
43
43
  if content =~ Document::YAML_FRONT_MATTER_REGEXP
44
- self.content = $POSTMATCH
44
+ self.content = Regexp.last_match.post_match
45
45
  self.data = SafeYAML.load(Regexp.last_match(1))
46
46
  end
47
47
  rescue Psych::SyntaxError => e
@@ -69,7 +69,7 @@ module Jekyll
69
69
  end
70
70
 
71
71
  def validate_permalink!(filename)
72
- if self.data["permalink"]&.to_s&.empty?
72
+ if self.data["permalink"] == ""
73
73
  raise Errors::InvalidPermalinkError, "Invalid permalink in #{filename}"
74
74
  end
75
75
  end
@@ -78,7 +78,7 @@ module Jekyll
78
78
  #
79
79
  # Returns the transformed contents.
80
80
  def transform
81
- _renderer.convert(content)
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
- _renderer.output_ext
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
- _renderer.converters
97
+ renderer.converters
98
98
  end
99
99
 
100
100
  # Render Liquid in the content
@@ -105,18 +105,14 @@ module Jekyll
105
105
  #
106
106
  # Returns the converted content
107
107
  def render_liquid(content, payload, info, path)
108
- _renderer.render_liquid(content, payload, info, path)
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 = Hash[(attrs || self.class::ATTRIBUTES_FOR_LIQUID).map do |attribute|
116
- [attribute, send(attribute)]
117
- end]
118
-
119
- defaults = site.frontmatter_defaults.all(relative_path, type)
115
+ further_data = attribute_hash(attrs || self.class::ATTRIBUTES_FOR_LIQUID)
120
116
  Utils.deep_merge_hashes defaults, Utils.deep_merge_hashes(data, further_data)
121
117
  end
122
118
 
@@ -190,10 +186,10 @@ module Jekyll
190
186
  #
191
187
  # Returns nothing
192
188
  def render_all_layouts(layouts, payload, info)
193
- _renderer.layouts = layouts
194
- self.output = _renderer.place_in_layouts(output, payload, info)
189
+ renderer.layouts = layouts
190
+ self.output = renderer.place_in_layouts(output, payload, info)
195
191
  ensure
196
- @_renderer = nil # this will allow the modifications above to disappear
192
+ @renderer = nil # this will allow the modifications above to disappear
197
193
  end
198
194
 
199
195
  # Add any necessary layouts to this convertible document.
@@ -203,15 +199,15 @@ module Jekyll
203
199
  #
204
200
  # Returns nothing.
205
201
  def do_layout(payload, layouts)
206
- self.output = _renderer.tap do |renderer|
207
- renderer.layouts = layouts
208
- renderer.payload = payload
202
+ self.output = renderer.tap do |doc_renderer|
203
+ doc_renderer.layouts = layouts
204
+ doc_renderer.payload = payload
209
205
  end.run
210
206
 
211
207
  Jekyll.logger.debug "Post-Render Hooks:", relative_path
212
208
  Jekyll::Hooks.trigger hook_owner, :post_render, self
213
209
  ensure
214
- @_renderer = nil # this will allow the modifications above to disappear
210
+ @renderer = nil # this will allow the modifications above to disappear
215
211
  end
216
212
 
217
213
  # Write the generated page file to the destination directory.
@@ -240,10 +236,21 @@ module Jekyll
240
236
  end
241
237
  end
242
238
 
239
+ def renderer
240
+ @renderer ||= Jekyll::Renderer.new(site, self)
241
+ end
242
+
243
243
  private
244
244
 
245
- def _renderer
246
- @_renderer ||= Jekyll::Renderer.new(site, self)
245
+ def defaults
246
+ @defaults ||= site.frontmatter_defaults.all(relative_path, type)
247
+ end
248
+
249
+ def attribute_hash(attrs)
250
+ @attribute_hash ||= {}
251
+ @attribute_hash[attrs] ||= attrs.each_with_object({}) do |attribute, hsh|
252
+ hsh[attribute] = send(attribute)
253
+ end
247
254
  end
248
255
 
249
256
  def no_layout?