bridgetown-core 1.0.0.alpha1 → 1.0.0.alpha5

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.
Files changed (72) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +35 -0
  3. data/Rakefile +5 -5
  4. data/lib/bridgetown-core/cache.rb +3 -5
  5. data/lib/bridgetown-core/cleaner.rb +2 -2
  6. data/lib/bridgetown-core/collection.rb +4 -6
  7. data/lib/bridgetown-core/commands/base.rb +4 -3
  8. data/lib/bridgetown-core/commands/build.rb +20 -19
  9. data/lib/bridgetown-core/commands/concerns/actions.rb +2 -2
  10. data/lib/bridgetown-core/commands/console.rb +3 -3
  11. data/lib/bridgetown-core/commands/doctor.rb +10 -8
  12. data/lib/bridgetown-core/commands/new.rb +5 -3
  13. data/lib/bridgetown-core/commands/plugins.rb +7 -9
  14. data/lib/bridgetown-core/commands/serve/servlet.rb +4 -4
  15. data/lib/bridgetown-core/commands/serve.rb +25 -27
  16. data/lib/bridgetown-core/commands/start.rb +6 -6
  17. data/lib/bridgetown-core/commands/webpack.rb +1 -1
  18. data/lib/bridgetown-core/component.rb +2 -6
  19. data/lib/bridgetown-core/concerns/liquid_renderable.rb +2 -2
  20. data/lib/bridgetown-core/concerns/site/configurable.rb +1 -6
  21. data/lib/bridgetown-core/concerns/site/content.rb +2 -2
  22. data/lib/bridgetown-core/concerns/site/extensible.rb +3 -4
  23. data/lib/bridgetown-core/concerns/site/localizable.rb +1 -1
  24. data/lib/bridgetown-core/concerns/site/ssr.rb +1 -1
  25. data/lib/bridgetown-core/concerns/site/writable.rb +1 -1
  26. data/lib/bridgetown-core/configuration.rb +1 -2
  27. data/lib/bridgetown-core/converter.rb +1 -0
  28. data/lib/bridgetown-core/converters/erb_templates.rb +6 -4
  29. data/lib/bridgetown-core/converters/liquid_templates.rb +2 -0
  30. data/lib/bridgetown-core/converters/markdown/kramdown_parser.rb +1 -1
  31. data/lib/bridgetown-core/converters/smartypants.rb +1 -0
  32. data/lib/bridgetown-core/drops/drop.rb +4 -4
  33. data/lib/bridgetown-core/entry_filter.rb +1 -0
  34. data/lib/bridgetown-core/filters/url_filters.rb +1 -1
  35. data/lib/bridgetown-core/filters.rb +11 -12
  36. data/lib/bridgetown-core/frontmatter_defaults.rb +5 -7
  37. data/lib/bridgetown-core/generated_page.rb +1 -3
  38. data/lib/bridgetown-core/generators/prototype_generator.rb +36 -37
  39. data/lib/bridgetown-core/helpers.rb +1 -1
  40. data/lib/bridgetown-core/hooks.rb +2 -2
  41. data/lib/bridgetown-core/liquid_renderer.rb +1 -3
  42. data/lib/bridgetown-core/log_adapter.rb +1 -1
  43. data/lib/bridgetown-core/log_writer.rb +1 -1
  44. data/lib/bridgetown-core/model/base.rb +2 -2
  45. data/lib/bridgetown-core/model/builder_origin.rb +3 -3
  46. data/lib/bridgetown-core/model/plugin_origin.rb +1 -1
  47. data/lib/bridgetown-core/plugin_manager.rb +2 -2
  48. data/lib/bridgetown-core/publisher.rb +1 -1
  49. data/lib/bridgetown-core/rack/boot.rb +8 -0
  50. data/lib/bridgetown-core/rack/routes.rb +1 -5
  51. data/lib/bridgetown-core/rack/static_indexes.rb +2 -2
  52. data/lib/bridgetown-core/readers/layout_reader.rb +2 -2
  53. data/lib/bridgetown-core/renderer.rb +1 -1
  54. data/lib/bridgetown-core/resource/base.rb +7 -7
  55. data/lib/bridgetown-core/resource/permalink_processor.rb +3 -2
  56. data/lib/bridgetown-core/resource/taxonomy_term.rb +1 -5
  57. data/lib/bridgetown-core/resource/transformer.rb +7 -5
  58. data/lib/bridgetown-core/ruby_template_view.rb +1 -3
  59. data/lib/bridgetown-core/static_file.rb +5 -7
  60. data/lib/bridgetown-core/tags/find.rb +6 -6
  61. data/lib/bridgetown-core/tags/highlight.rb +5 -5
  62. data/lib/bridgetown-core/tags/post_url.rb +6 -6
  63. data/lib/bridgetown-core/tags/render_content.rb +2 -2
  64. data/lib/bridgetown-core/tasks/bridgetown_tasks.rake +7 -1
  65. data/lib/bridgetown-core/url.rb +3 -3
  66. data/lib/bridgetown-core/utils.rb +7 -9
  67. data/lib/bridgetown-core/version.rb +1 -1
  68. data/lib/bridgetown-core/watcher.rb +2 -2
  69. data/lib/bridgetown-core.rb +2 -1
  70. data/lib/site_template/src/_layouts/default.liquid +1 -1
  71. metadata +3 -3
  72. data/lib/bridgetown-core/tags/include.rb +0 -213
@@ -53,7 +53,7 @@ module Bridgetown
53
53
  @layout = site.layouts[data.layout].tap do |layout|
54
54
  unless layout
55
55
  Bridgetown.logger.warn "Resource:", "Layout '#{data.layout}' " \
56
- "requested via #{relative_path} does not exist."
56
+ "requested via #{relative_path} does not exist."
57
57
  end
58
58
  end
59
59
  end
@@ -267,7 +267,7 @@ module Bridgetown
267
267
  # Comparison is a comparison between the 2 dates or paths of the resources.
268
268
  #
269
269
  # @return [Integer] -1, 0, or +1
270
- def <=>(other) # rubocop:todo Metrics/AbcSize, Metrics/CyclomaticComplexity
270
+ def <=>(other) # rubocop:todo Metrics/AbcSize
271
271
  return nil unless other.respond_to?(:data)
272
272
 
273
273
  cmp = if data.date.respond_to?(:to_datetime) && other.data.date.respond_to?(:to_datetime)
@@ -293,7 +293,7 @@ module Bridgetown
293
293
 
294
294
  private
295
295
 
296
- def ensure_default_data
296
+ def ensure_default_data # rubocop:todo Metrics/AbcSize
297
297
  determine_locale
298
298
 
299
299
  slug = if matches = relative_path.to_s.match(DATE_FILENAME_MATCHER) # rubocop:disable Lint/AssignmentInCondition
@@ -337,14 +337,14 @@ module Bridgetown
337
337
  end
338
338
  end
339
339
 
340
- def determine_locale
340
+ def determine_locale # rubocop:todo Metrics/AbcSize
341
341
  unless data.locale
342
342
  data.locale = locale_from_alt_data_or_filename.presence || site.config.default_locale
343
343
  end
344
344
 
345
- if data.locale_overrides&.is_a?(Hash) && data.locale_overrides&.key?(data.locale)
346
- data.merge!(data.locale_overrides[data.locale])
347
- end
345
+ return unless data.locale_overrides.is_a?(Hash) && data.locale_overrides&.key?(data.locale)
346
+
347
+ data.merge!(data.locale_overrides[data.locale])
348
348
  end
349
349
 
350
350
  # Look for alternative front matter or look at the filename pattern: slug.locale.ext
@@ -46,9 +46,10 @@ module Bridgetown
46
46
  segment = segment.to_sym
47
47
  if self.class.placeholder_processors[segment]
48
48
  segment_value = self.class.placeholder_processors[segment].(resource)
49
- if segment_value.is_a?(Hash)
49
+ case segment_value
50
+ when Hash
50
51
  segment_value[:raw_value]
51
- elsif segment_value.is_a?(Array)
52
+ when Array
52
53
  segment_value.map do |subsegment|
53
54
  Utils.slugify(subsegment, mode: slugify_mode)
54
55
  end.join("/")
@@ -3,11 +3,7 @@
3
3
  module Bridgetown
4
4
  module Resource
5
5
  class TaxonomyTerm
6
- attr_reader :resource
7
-
8
- attr_reader :label
9
-
10
- attr_reader :type
6
+ attr_reader :resource, :label, :type
11
7
 
12
8
  def initialize(resource:, label:, type:)
13
9
  @resource = resource
@@ -103,10 +103,12 @@ module Bridgetown
103
103
  end
104
104
 
105
105
  def warn_on_missing_layout(layout, layout_name)
106
- if layout.nil? && layout_name
107
- Bridgetown.logger.warn "Build Warning:", "Layout '#{layout_name}' " \
108
- "requested via #{resource.relative_path} does not exist."
109
- end
106
+ return unless layout.nil? && layout_name
107
+
108
+ Bridgetown.logger.warn(
109
+ "Build Warning:",
110
+ "Layout '#{layout_name}' requested via #{resource.relative_path} does not exist."
111
+ )
110
112
  end
111
113
 
112
114
  ### Transformation Actions
@@ -152,7 +154,7 @@ module Bridgetown
152
154
  layout_input = layout.content.dup
153
155
 
154
156
  layout_converters.inject(layout_input) do |content, converter|
155
- next(content) unless [2, -2].include?(converter.method(:convert).arity)
157
+ next(content) unless [2, -2].include?(converter.method(:convert).arity) # rubocop:disable Performance/CollectionLiteralInLoop
156
158
 
157
159
  layout.current_document = resource
158
160
  layout.current_document_output = output
@@ -61,7 +61,6 @@ module Bridgetown
61
61
  @helpers ||= Helpers.new(self, site)
62
62
  end
63
63
 
64
- # rubocop:disable Style/MissingRespondToMissing
65
64
  ruby2_keywords def method_missing(method_name, *args, &block)
66
65
  if helpers.respond_to?(method_name.to_sym)
67
66
  helpers.send method_name.to_sym, *args, &block
@@ -73,7 +72,6 @@ module Bridgetown
73
72
  def respond_to_missing?(method_name, include_private = false)
74
73
  helpers.respond_to?(method_name.to_sym, include_private) || super
75
74
  end
76
- # rubocop:enable Style/MissingRespondToMissing
77
75
 
78
76
  private
79
77
 
@@ -84,7 +82,7 @@ module Bridgetown
84
82
  ["{% render \"#{component}\""]
85
83
  end
86
84
  unless options.empty?
87
- render_statement << ", " + options.keys.map { |k| "#{k}: #{k}" }.join(", ")
85
+ render_statement << ", #{options.keys.map { |k| "#{k}: #{k}" }.join(", ")}"
88
86
  end
89
87
  render_statement << " %}"
90
88
  if options[:_block_content]
@@ -36,7 +36,7 @@ module Bridgetown
36
36
  @extname = File.extname(@name)
37
37
  @data = @site.frontmatter_defaults.all(relative_path, type).with_dot_access
38
38
  data.permalink ||= if collection && !collection.builtin?
39
- collection.default_permalink.chomp("/").chomp(".*") + ".*"
39
+ "#{collection.default_permalink.chomp("/").chomp(".*")}.*"
40
40
  else
41
41
  "/:path.*"
42
42
  end
@@ -44,9 +44,7 @@ module Bridgetown
44
44
 
45
45
  # Returns source file path.
46
46
  def path
47
- @path ||= begin
48
- File.join(*[@base, @dir, @name].compact)
49
- end
47
+ @path ||= File.join(*[@base, @dir, @name].compact)
50
48
  end
51
49
 
52
50
  # Obtain destination path.
@@ -207,9 +205,9 @@ module Bridgetown
207
205
  def copy_file(dest_path)
208
206
  FileUtils.copy_entry(path, dest_path)
209
207
 
210
- unless File.symlink?(dest_path)
211
- File.utime(self.class.mtimes[path], self.class.mtimes[path], dest_path)
212
- end
208
+ return if File.symlink?(dest_path)
209
+
210
+ File.utime(self.class.mtimes[path], self.class.mtimes[path], dest_path)
213
211
  end
214
212
  end
215
213
  end
@@ -11,12 +11,7 @@ module Bridgetown
11
11
 
12
12
  def initialize(tag_name, markup, tokens)
13
13
  super
14
- if markup.strip =~ SYNTAX
15
- @new_var_name = Regexp.last_match(1).strip
16
- @single_or_group = Regexp.last_match(2)
17
- @arr_name = Regexp.last_match(3).strip
18
- @conditions = process_conditions(Regexp.last_match(4).strip)
19
- else
14
+ unless markup.strip =~ SYNTAX
20
15
  raise SyntaxError, <<~MSG
21
16
  Syntax Error in tag 'find' while parsing the following markup:
22
17
 
@@ -25,6 +20,11 @@ module Bridgetown
25
20
  Valid syntax: find <varname> where|in <array>, <condition(s)>
26
21
  MSG
27
22
  end
23
+
24
+ @new_var_name = Regexp.last_match(1).strip
25
+ @single_or_group = Regexp.last_match(2)
26
+ @arr_name = Regexp.last_match(3).strip
27
+ @conditions = process_conditions(Regexp.last_match(4).strip)
28
28
  end
29
29
 
30
30
  def render(context)
@@ -14,10 +14,7 @@ module Bridgetown
14
14
 
15
15
  def initialize(tag_name, markup, tokens)
16
16
  super
17
- if markup.strip =~ SYNTAX
18
- @lang = Regexp.last_match(1).downcase
19
- @highlight_options = parse_options(Regexp.last_match(2))
20
- else
17
+ unless markup.strip =~ SYNTAX
21
18
  raise SyntaxError, <<~MSG
22
19
  Syntax Error in tag 'highlight' while parsing the following markup:
23
20
 
@@ -26,6 +23,9 @@ module Bridgetown
26
23
  Valid syntax: highlight <lang> [linenos]
27
24
  MSG
28
25
  end
26
+
27
+ @lang = Regexp.last_match(1).downcase
28
+ @highlight_options = parse_options(Regexp.last_match(2))
29
29
  end
30
30
 
31
31
  LEADING_OR_TRAILING_LINE_TERMINATORS = %r!\A(\n|\r)+|(\n|\r)+\z!.freeze
@@ -89,7 +89,7 @@ module Bridgetown
89
89
  "data-lang=\"#{@lang}\"",
90
90
  ].join(" ")
91
91
  "<figure class=\"highlight\"><pre><code #{code_attributes}>"\
92
- "#{code.chomp}</code></pre></figure>"
92
+ "#{code.chomp}</code></pre></figure>"
93
93
  end
94
94
  end
95
95
  end
@@ -74,19 +74,19 @@ module Bridgetown
74
74
 
75
75
  site.collections.posts.resources.each do |document|
76
76
  return relative_url(document) if @post == document
77
- end
78
-
79
- # New matching method did not match, fall back to old method
80
- # with deprecation warning if this matches
81
77
 
82
- site.collections.posts.resources.each do |document|
78
+ # New matching method did not match, fall back to old method
79
+ # with deprecation warning if this matches
83
80
  next unless @post.deprecated_equality document
84
81
 
85
- Bridgetown::Deprecator.deprecation_message "A call to "\
82
+ Bridgetown::Deprecator.deprecation_message(
83
+ "A call to "\
86
84
  "'{% post_url #{@post.name} %}' did not match " \
87
85
  "a post using the new matching method of checking name " \
88
86
  "(path-date-slug) equality. Please make sure that you " \
89
87
  "change this tag to match the post's name exactly."
88
+ )
89
+
90
90
  return relative_url(document)
91
91
  end
92
92
 
@@ -3,7 +3,7 @@
3
3
  module Bridgetown
4
4
  module Tags
5
5
  class BlockRenderTag < Liquid::Block
6
- # rubocop:disable Metrics/MethodLength
6
+ # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
7
7
  def render(context)
8
8
  context.stack({}) do
9
9
  # unindent the incoming text
@@ -37,7 +37,7 @@ module Bridgetown
37
37
  .render_tag(context, +"")
38
38
  end
39
39
  end
40
- # rubocop:enable Metrics/MethodLength
40
+ # rubocop:enable Metrics/MethodLength, Metrics/AbcSize
41
41
 
42
42
  private
43
43
 
@@ -1,5 +1,11 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ desc "Generate a secret key for use in sessions, token generation, and beyond"
4
+ task :secret do
5
+ require "securerandom"
6
+ puts SecureRandom.hex(64) # rubocop:disable Bridgetown/NoPutsAllowed
7
+ end
8
+
3
9
  namespace :frontend do
4
10
  desc "Run frontend bundler independently"
5
11
  task :watcher, :sidecar do |_task, args|
@@ -23,7 +29,7 @@ end
23
29
 
24
30
  desc "Prerequisite task which loads site and provides automation"
25
31
  task :environment do
26
- class HammerActions < Thor
32
+ class HammerActions < Thor # rubocop:disable Lint/ConstantDefinitionInBlock
27
33
  include Thor::Actions
28
34
  include Bridgetown::Commands::Actions
29
35
 
@@ -28,9 +28,9 @@ module Bridgetown
28
28
  @placeholders = options[:placeholders] || {}
29
29
  @permalink = options[:permalink]
30
30
 
31
- if (@template || @permalink).nil?
32
- raise ArgumentError, "One of :template or :permalink must be supplied."
33
- end
31
+ return unless (@template || @permalink).nil?
32
+
33
+ raise ArgumentError, "One of :template or :permalink must be supplied."
34
34
  end
35
35
 
36
36
  # The generated relative URL of the resource
@@ -12,7 +12,7 @@ module Bridgetown
12
12
 
13
13
  # Constants for use in #slugify
14
14
  SLUGIFY_MODES = %w(raw default pretty simple ascii latin).freeze
15
- SLUGIFY_RAW_REGEXP = Regexp.new('\\s+').freeze
15
+ SLUGIFY_RAW_REGEXP = Regexp.new("\\s+").freeze
16
16
  SLUGIFY_DEFAULT_REGEXP = Regexp.new("[^\\p{M}\\p{L}\\p{Nd}]+").freeze
17
17
  SLUGIFY_PRETTY_REGEXP = Regexp.new("[^\\p{M}\\p{L}\\p{Nd}._~!$&'()+,;=@]+").freeze
18
18
  SLUGIFY_ASCII_REGEXP = Regexp.new("[^[A-Za-z0-9]]+").freeze
@@ -203,7 +203,7 @@ module Bridgetown
203
203
  slug = replace_character_sequence_with_hyphen(string, mode: mode)
204
204
 
205
205
  # Remove leading/trailing hyphen
206
- slug.gsub!(%r!^\-|\-$!i, "")
206
+ slug.gsub!(%r!^-|-$!i, "")
207
207
 
208
208
  slug.downcase! unless cased
209
209
 
@@ -316,9 +316,7 @@ module Bridgetown
316
316
  lines.map do |line|
317
317
  continue_processing = !skip_pre_lines
318
318
 
319
- if skip_pre_lines
320
- skip_pre_lines = false if line.include?("</pre>")
321
- end
319
+ skip_pre_lines = false if skip_pre_lines && line.include?("</pre>")
322
320
  if line.include?("<pre")
323
321
  skip_pre_lines = true
324
322
  continue_processing = false
@@ -340,7 +338,7 @@ module Bridgetown
340
338
  else
341
339
  line
342
340
  end
343
- end.join("")
341
+ end.join
344
342
  end
345
343
  # rubocop:enable Metrics/AbcSize, Metrics/MethodLength, Metrics/PerceivedComplexity
346
344
 
@@ -448,9 +446,9 @@ module Bridgetown
448
446
  end
449
447
 
450
448
  def merge_default_proc(target, overwrite)
451
- if target.is_a?(Hash) && overwrite.is_a?(Hash) && target.default_proc.nil?
452
- target.default_proc = overwrite.default_proc
453
- end
449
+ return unless target.is_a?(Hash) && overwrite.is_a?(Hash) && target.default_proc.nil?
450
+
451
+ target.default_proc = overwrite.default_proc
454
452
  end
455
453
 
456
454
  def duplicate_frozen_values(target)
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Bridgetown
4
- VERSION = "1.0.0.alpha1"
4
+ VERSION = "1.0.0.alpha5"
5
5
  CODE_NAME = "Pearl"
6
6
  end
@@ -116,7 +116,7 @@ module Bridgetown
116
116
  rescue ArgumentError
117
117
  # Could not find a relative path
118
118
  end
119
- end.compact + [%r!^\.bridgetown\-metadata!]
119
+ end.compact + [%r!^\.bridgetown-metadata!]
120
120
  end
121
121
 
122
122
  def sleep_forever
@@ -132,7 +132,7 @@ module Bridgetown
132
132
  site.plugin_manager.reload_component_loaders
133
133
  site.process
134
134
  Bridgetown.logger.info "Done! 🎉", "#{"Completed".green} in less than" \
135
- " #{(Time.now - time).ceil(2)} seconds."
135
+ " #{(Time.now - time).ceil(2)} seconds."
136
136
  rescue Exception => e
137
137
  Bridgetown.logger.error "Error:", e.message
138
138
 
@@ -249,12 +249,13 @@ end
249
249
 
250
250
  module Bridgetown
251
251
  module Model; end
252
+
252
253
  module Resource
253
254
  def self.register_extension(mod)
254
255
  if mod.const_defined?(:LiquidResource)
255
256
  Bridgetown::Drops::ResourceDrop.include mod.const_get(:LiquidResource)
256
257
  end
257
- if mod.const_defined?(:RubyResource)
258
+ if mod.const_defined?(:RubyResource) # rubocop:disable Style/GuardClause
258
259
  Bridgetown::Resource::Base.include mod.const_get(:RubyResource)
259
260
  end
260
261
  end
@@ -1,5 +1,5 @@
1
1
  <!doctype html>
2
- <html lang="en">
2
+ <html lang="{{ site.locale }}">
3
3
  <head>
4
4
  {% render "head", metadata: site.metadata, title: page.title %}
5
5
  </head>
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bridgetown-core
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0.alpha1
4
+ version: 1.0.0.alpha5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Bridgetown Team
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-10-16 00:00:00.000000000 Z
11
+ date: 2021-10-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activemodel
@@ -340,6 +340,7 @@ executables:
340
340
  extensions: []
341
341
  extra_rdoc_files: []
342
342
  files:
343
+ - ".rubocop.yml"
343
344
  - ".yardopts"
344
345
  - Rakefile
345
346
  - bin/bridgetown
@@ -475,7 +476,6 @@ files:
475
476
  - lib/bridgetown-core/tags/class_map.rb
476
477
  - lib/bridgetown-core/tags/find.rb
477
478
  - lib/bridgetown-core/tags/highlight.rb
478
- - lib/bridgetown-core/tags/include.rb
479
479
  - lib/bridgetown-core/tags/link.rb
480
480
  - lib/bridgetown-core/tags/live_reload_dev_js.rb
481
481
  - lib/bridgetown-core/tags/post_url.rb
@@ -1,213 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Bridgetown
4
- module Tags
5
- class IncludeTag < Liquid::Tag
6
- class << self
7
- attr_accessor :deprecation_message_shown
8
- end
9
-
10
- VALID_SYNTAX = %r!
11
- ([\w-]+)\s*=\s*
12
- (?:"([^"\\]*(?:\\.[^"\\]*)*)"|'([^'\\]*(?:\\.[^'\\]*)*)'|([\w\.-]+))
13
- !x.freeze
14
- VARIABLE_SYNTAX = %r!
15
- (?<variable>[^{]*(\{\{\s*[\w\-\.]+\s*(\|.*)?\}\}[^\s{}]*)+)
16
- (?<params>.*)
17
- !mx.freeze
18
-
19
- FULL_VALID_SYNTAX = %r!\A\s*(?:#{VALID_SYNTAX}(?=\s|\z)\s*)*\z!.freeze
20
- VALID_FILENAME_CHARS = %r!^[\w/\.-]+$!.freeze
21
- INVALID_SEQUENCES = %r![./]{2,}!.freeze
22
-
23
- def initialize(tag_name, markup, tokens)
24
- super
25
-
26
- unless self.class.deprecation_message_shown
27
- Bridgetown.logger.warn "NOTICE: the {% include %} tag is deprecated and" \
28
- " will be removed in Bridgetown 1.0. You should" \
29
- " use the {% render %} tag instead."
30
- self.class.deprecation_message_shown = true
31
- end
32
-
33
- matched = markup.strip.match(VARIABLE_SYNTAX)
34
- if matched
35
- @file = matched["variable"].strip
36
- @params = matched["params"].strip
37
- else
38
- @file, @params = markup.strip.split(%r!\s+!, 2)
39
- end
40
- validate_params if @params
41
- @tag_name = tag_name
42
- end
43
-
44
- def syntax_example
45
- "{% #{@tag_name} file.ext param='value' param2='value' %}"
46
- end
47
-
48
- def parse_params(context)
49
- params = {}
50
- markup = @params
51
-
52
- while (match = VALID_SYNTAX.match(markup))
53
- markup = markup[match.end(0)..-1]
54
-
55
- value = if match[2]
56
- match[2].gsub('\\"', '"')
57
- elsif match[3]
58
- match[3].gsub("\\'", "'")
59
- elsif match[4]
60
- context[match[4]]
61
- end
62
-
63
- params[match[1]] = value
64
- end
65
- params
66
- end
67
-
68
- def validate_file_name(file)
69
- if INVALID_SEQUENCES.match?(file) || !VALID_FILENAME_CHARS.match?(file)
70
- raise ArgumentError, <<~MSG
71
- Invalid syntax for include tag. File contains invalid characters or sequences:
72
-
73
- #{file}
74
-
75
- Valid syntax:
76
-
77
- #{syntax_example}
78
-
79
- MSG
80
- end
81
- end
82
-
83
- def validate_params
84
- unless FULL_VALID_SYNTAX.match?(@params)
85
- raise ArgumentError, <<~MSG
86
- Invalid syntax for include tag:
87
-
88
- #{@params}
89
-
90
- Valid syntax:
91
-
92
- #{syntax_example}
93
-
94
- MSG
95
- end
96
- end
97
-
98
- # Grab file read opts in the context
99
- def file_read_opts(context)
100
- context.registers[:site].file_read_opts
101
- end
102
-
103
- # Render the variable if required
104
- def render_variable(context)
105
- Liquid::Template.parse(@file).render(context) if VARIABLE_SYNTAX.match?(@file)
106
- end
107
-
108
- def tag_includes_dirs(context)
109
- context.registers[:site].includes_load_paths.freeze
110
- end
111
-
112
- def locate_include_file(context, file)
113
- includes_dirs = tag_includes_dirs(context)
114
- includes_dirs.each do |dir|
115
- path = File.join(dir, file)
116
- return path if valid_include_file?(path, dir.to_s)
117
- end
118
- raise IOError, could_not_locate_message(file, includes_dirs)
119
- end
120
-
121
- def render(context)
122
- file = render_variable(context) || @file
123
- validate_file_name(file)
124
-
125
- path = locate_include_file(context, file)
126
- return unless path
127
-
128
- partial = load_cached_partial(path, context)
129
-
130
- context.stack do
131
- context["include"] = parse_params(context) if @params
132
- begin
133
- partial.render!(context)
134
- rescue Liquid::Error => e
135
- e.template_name = path
136
- e.markup_context = "included " if e.markup_context.nil?
137
- raise e
138
- end
139
- end
140
- end
141
-
142
- def load_cached_partial(path, context)
143
- context.registers[:cached_partials] ||= {}
144
- cached_partial = context.registers[:cached_partials]
145
-
146
- if cached_partial.key?(path)
147
- cached_partial[path]
148
- else
149
- unparsed_file = context.registers[:site]
150
- .liquid_renderer
151
- .file(path)
152
- begin
153
- cached_partial[path] = unparsed_file.parse(read_file(path, context))
154
- rescue Liquid::Error => e
155
- e.template_name = path
156
- e.markup_context = "included " if e.markup_context.nil?
157
- raise e
158
- end
159
- end
160
- end
161
-
162
- def valid_include_file?(path, _dir)
163
- File.file?(path)
164
- end
165
-
166
- def realpath_prefixed_with?(path, dir)
167
- File.exist?(path) && File.realpath(path).start_with?(dir)
168
- rescue StandardError
169
- false
170
- end
171
-
172
- # This method allows to modify the file content by inheriting from the class.
173
- def read_file(file, context)
174
- File.read(file, **file_read_opts(context))
175
- end
176
-
177
- private
178
-
179
- def could_not_locate_message(file, includes_dirs)
180
- "Could not locate the included file '#{file}' in any of #{includes_dirs}." \
181
- " Ensure it exists in one of those directories."
182
- end
183
- end
184
-
185
- class IncludeRelativeTag < IncludeTag
186
- def tag_includes_dirs(context)
187
- Array(page_path(context)).freeze
188
- end
189
-
190
- def page_path(context)
191
- if context.registers[:page].nil?
192
- context.registers[:site].source
193
- else
194
- site = context.registers[:site]
195
- page_payload = context.registers[:page]
196
- resource_path = \
197
- if page_payload["collection"].nil?
198
- page_payload["path"]
199
- else
200
- File.join(site.config["collections_dir"], page_payload["path"])
201
- end
202
- # rubocop:disable Performance/DeleteSuffix
203
- resource_path.sub!(%r!/#excerpt\z!, "")
204
- # rubocop:enable Performance/DeleteSuffix
205
- site.in_source_dir File.dirname(resource_path)
206
- end
207
- end
208
- end
209
- end
210
- end
211
-
212
- Liquid::Template.register_tag("include", Bridgetown::Tags::IncludeTag)
213
- Liquid::Template.register_tag("include_relative", Bridgetown::Tags::IncludeRelativeTag)