bridgetown-core 1.0.0.alpha3 → 1.0.0.alpha7

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/bridgetown-core.gemspec +1 -2
  3. data/lib/bridgetown-core/cache.rb +1 -1
  4. data/lib/bridgetown-core/collection.rb +1 -1
  5. data/lib/bridgetown-core/commands/configure.rb +7 -0
  6. data/lib/bridgetown-core/commands/new.rb +3 -2
  7. data/lib/bridgetown-core/commands/start.rb +10 -8
  8. data/lib/bridgetown-core/component.rb +2 -2
  9. data/lib/bridgetown-core/concerns/front_matter_importer.rb +1 -1
  10. data/lib/bridgetown-core/concerns/site/configurable.rb +6 -8
  11. data/lib/bridgetown-core/concerns/site/extensible.rb +2 -1
  12. data/lib/bridgetown-core/concerns/site/ssr.rb +38 -16
  13. data/lib/bridgetown-core/configuration.rb +77 -47
  14. data/lib/bridgetown-core/configurations/bt-postcss.rb +1 -3
  15. data/lib/bridgetown-core/configurations/cypress/cypress.json +4 -0
  16. data/lib/bridgetown-core/configurations/cypress/cypress_dir/fixtures/example.json +5 -0
  17. data/lib/bridgetown-core/configurations/cypress/cypress_dir/integration/navbar.spec.js +17 -0
  18. data/lib/bridgetown-core/configurations/cypress/cypress_dir/plugins/index.js +21 -0
  19. data/lib/bridgetown-core/configurations/cypress/cypress_dir/support/commands.js +25 -0
  20. data/lib/bridgetown-core/configurations/cypress/cypress_dir/support/index.js +20 -0
  21. data/lib/bridgetown-core/configurations/cypress/cypress_tasks +33 -0
  22. data/lib/bridgetown-core/configurations/cypress.rb +13 -0
  23. data/lib/bridgetown-core/configurations/minitesting.rb +19 -15
  24. data/lib/bridgetown-core/configurations/netlify/netlify.toml +2 -2
  25. data/lib/bridgetown-core/configurations/netlify.rb +2 -4
  26. data/lib/bridgetown-core/configurations/purgecss.rb +2 -2
  27. data/lib/bridgetown-core/configurations/render/render.yaml.erb +26 -0
  28. data/lib/bridgetown-core/configurations/render.rb +6 -0
  29. data/lib/bridgetown-core/configurations/tailwindcss.rb +3 -5
  30. data/lib/bridgetown-core/converters/markdown/kramdown_parser.rb +1 -1
  31. data/lib/bridgetown-core/core_ext/psych.rb +1 -5
  32. data/lib/bridgetown-core/frontmatter_defaults.rb +2 -2
  33. data/lib/bridgetown-core/liquid_renderer.rb +1 -1
  34. data/lib/bridgetown-core/model/base.rb +23 -26
  35. data/lib/bridgetown-core/model/builder_origin.rb +8 -6
  36. data/lib/bridgetown-core/model/origin.rb +10 -1
  37. data/lib/bridgetown-core/model/plugin_origin.rb +1 -1
  38. data/lib/bridgetown-core/plugin_manager.rb +7 -34
  39. data/lib/bridgetown-core/rack/boot.rb +54 -23
  40. data/lib/bridgetown-core/rack/roda.rb +2 -1
  41. data/lib/bridgetown-core/rack/routes.rb +2 -2
  42. data/lib/bridgetown-core/readers/layout_reader.rb +1 -1
  43. data/lib/bridgetown-core/readers/plugin_content_reader.rb +1 -1
  44. data/lib/bridgetown-core/renderer.rb +2 -2
  45. data/lib/bridgetown-core/resource/base.rb +3 -3
  46. data/lib/bridgetown-core/resource/relations.rb +1 -1
  47. data/lib/bridgetown-core/resource/taxonomy_term.rb +2 -2
  48. data/lib/bridgetown-core/resource/taxonomy_type.rb +2 -2
  49. data/lib/bridgetown-core/ruby_template_view.rb +2 -2
  50. data/lib/bridgetown-core/site.rb +15 -5
  51. data/lib/bridgetown-core/tasks/bridgetown_tasks.rake +6 -0
  52. data/lib/bridgetown-core/utils/loaders_manager.rb +72 -0
  53. data/lib/bridgetown-core/utils.rb +13 -14
  54. data/lib/bridgetown-core/version.rb +1 -1
  55. data/lib/bridgetown-core/watcher.rb +16 -7
  56. data/lib/bridgetown-core/yaml_parser.rb +1 -5
  57. data/lib/site_template/README.md +1 -1
  58. data/lib/site_template/Rakefile +3 -3
  59. data/lib/site_template/src/_layouts/default.liquid +1 -1
  60. metadata +16 -6
  61. data/lib/bridgetown-core/tags/include.rb +0 -216
@@ -61,9 +61,9 @@ module Bridgetown
61
61
  @helpers ||= Helpers.new(self, site)
62
62
  end
63
63
 
64
- ruby2_keywords def method_missing(method_name, *args, &block)
64
+ def method_missing(method_name, *args, **kwargs, &block)
65
65
  if helpers.respond_to?(method_name.to_sym)
66
- helpers.send method_name.to_sym, *args, &block
66
+ helpers.send method_name.to_sym, *args, **kwargs, &block
67
67
  else
68
68
  super
69
69
  end
@@ -13,9 +13,10 @@ module Bridgetown
13
13
  include SSR
14
14
  include Writable
15
15
 
16
- attr_reader :root_dir, :source, :dest, :cache_dir, :config,
17
- :liquid_renderer, :components_load_paths,
18
- :includes_load_paths
16
+ attr_reader :root_dir, :source, :dest, :cache_dir, :config, :liquid_renderer
17
+
18
+ # @return [Bridgetown::Utils::LoadersManager]
19
+ attr_reader :loaders_manager
19
20
 
20
21
  # All files not pages/documents or structured data in the source folder
21
22
  # @return [Array<StaticFile>]
@@ -33,11 +34,20 @@ module Bridgetown
33
34
 
34
35
  # Initialize a new Site.
35
36
  #
36
- # config - A Hash containing site configuration details.
37
- def initialize(config)
37
+ # @param config [Bridgetown::Configuration]
38
+ # @param loaders_manager [Bridgetown::Utils::LoadersManager] initialized if none provided
39
+ def initialize(config, loaders_manager: nil)
38
40
  self.config = config
39
41
  locale
40
42
 
43
+ loaders_manager = if loaders_manager
44
+ loaders_manager.config = self.config
45
+ loaders_manager
46
+ else
47
+ Bridgetown::Utils::LoadersManager.new(self.config)
48
+ end
49
+ @loaders_manager = loaders_manager
50
+
41
51
  @plugin_manager = PluginManager.new(self)
42
52
  @cleaner = Cleaner.new(self)
43
53
  @reader = Reader.new(self)
@@ -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|
@@ -0,0 +1,72 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Bridgetown
4
+ module Utils
5
+ class LoadersManager
6
+ attr_accessor :config
7
+
8
+ attr_reader :loaders, :root_dir
9
+
10
+ # @param config [Bridgetown::Configuration]
11
+ # @param root_dir [String] root of the current site
12
+ def initialize(config, root_dir = Dir.pwd)
13
+ @config = config
14
+ @loaders = {}
15
+ @root_dir = root_dir
16
+ end
17
+
18
+ def unload_loaders
19
+ return if @loaders.keys.empty?
20
+
21
+ @loaders.each do |_path, loader|
22
+ loader.unload
23
+ end
24
+ @loaders = {}
25
+ end
26
+
27
+ def reloading_enabled?(load_path)
28
+ load_path.start_with?(root_dir) && ENV["BRIDGETOWN_ENV"] != "production"
29
+ end
30
+
31
+ def setup_loaders(autoload_paths = []) # rubocop:todo Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity
32
+ (autoload_paths.presence || config.autoload_paths).each do |load_path|
33
+ if @loaders.key?(load_path)
34
+ raise "Zeitwerk loader already added for `#{load_path}'. Please check your config"
35
+ end
36
+
37
+ next unless Dir.exist? load_path
38
+
39
+ loader = Zeitwerk::Loader.new
40
+ begin
41
+ loader.push_dir(load_path)
42
+ rescue Zeitwerk::Error
43
+ next
44
+ end
45
+ loader.enable_reloading if reloading_enabled?(load_path)
46
+ loader.ignore(File.join(load_path, "**", "*.js.rb"))
47
+ config.autoloader_collapsed_paths.each do |collapsed_path|
48
+ next unless collapsed_path.starts_with?(load_path)
49
+
50
+ loader.collapse(collapsed_path)
51
+ end
52
+ Bridgetown::Hooks.trigger :loader, :pre_setup, loader, load_path
53
+ loader.setup
54
+ loader.eager_load if config.eager_load_paths.include?(load_path)
55
+ Bridgetown::Hooks.trigger :loader, :post_setup, loader, load_path
56
+ @loaders[load_path] = loader
57
+ end
58
+ end
59
+
60
+ def reload_loaders
61
+ @loaders.each do |load_path, loader|
62
+ next unless reloading_enabled?(load_path)
63
+
64
+ Bridgetown::Hooks.trigger :loader, :pre_reload, loader, load_path
65
+ loader.reload
66
+ loader.eager_load if config.eager_load_paths.include?(load_path)
67
+ Bridgetown::Hooks.trigger :loader, :post_reload, loader, load_path
68
+ end
69
+ end
70
+ end
71
+ end
72
+ end
@@ -5,6 +5,7 @@ module Bridgetown
5
5
  extend self
6
6
  autoload :Ansi, "bridgetown-core/utils/ansi"
7
7
  autoload :Aux, "bridgetown-core/utils/aux"
8
+ autoload :LoadersManager, "bridgetown-core/utils/loaders_manager"
8
9
  autoload :RequireGems, "bridgetown-core/utils/require_gems"
9
10
  autoload :RubyExec, "bridgetown-core/utils/ruby_exec"
10
11
  autoload :RubyFrontMatter, "bridgetown-core/utils/ruby_front_matter"
@@ -120,15 +121,11 @@ module Bridgetown
120
121
  # @return [Boolean] if the YAML front matter is present.
121
122
  # rubocop: disable Naming/PredicateName
122
123
  def has_yaml_header?(file)
123
- File.open(file, "rb", &:readline).match? Bridgetown::FrontMatterImporter::YAML_HEADER
124
- rescue EOFError
125
- false
124
+ File.open(file, "rb", &:gets)&.match?(Bridgetown::FrontMatterImporter::YAML_HEADER) || false
126
125
  end
127
126
 
128
127
  def has_rbfm_header?(file)
129
- File.open(file, "rb", &:readline).match? Bridgetown::FrontMatterImporter::RUBY_HEADER
130
- rescue EOFError
131
- false
128
+ File.open(file, "rb", &:gets)&.match?(Bridgetown::FrontMatterImporter::RUBY_HEADER) || false
132
129
  end
133
130
 
134
131
  # Determine whether the given content string contains Liquid Tags or Vaiables
@@ -354,7 +351,7 @@ module Bridgetown
354
351
  # @raise [WebpackAssetError] if unable to find css or js in the manifest
355
352
  # file
356
353
  def parse_webpack_manifest_file(site, asset_type)
357
- return log_webpack_asset_error("Webpack manifest") if site.frontend_manifest.nil?
354
+ return log_webpack_asset_error(site, "Webpack manifest") if site.frontend_manifest.nil?
358
355
 
359
356
  asset_path = if %w(js css).include?(asset_type)
360
357
  site.frontend_manifest["main.#{asset_type}"]
@@ -364,7 +361,7 @@ module Bridgetown
364
361
  end&.last
365
362
  end
366
363
 
367
- return log_webpack_asset_error(asset_type) if asset_path.nil?
364
+ return log_webpack_asset_error(site, asset_type) if asset_path.nil?
368
365
 
369
366
  static_frontend_path site, ["js", asset_path]
370
367
  end
@@ -379,12 +376,14 @@ module Bridgetown
379
376
  Addressable::URI.parse(path_parts.join("/")).normalize.to_s
380
377
  end
381
378
 
382
- def log_webpack_asset_error(asset_type)
383
- Bridgetown.logger.warn(
384
- "Webpack:",
385
- "There was an error parsing your #{asset_type} file. \
386
- Please check your #{asset_type} file for any errors."
387
- )
379
+ def log_webpack_asset_error(site, asset_type)
380
+ site.data[:__webpack_asset_errors] ||= {}
381
+ site.data[:__webpack_asset_errors][asset_type] ||=
382
+ Bridgetown.logger.warn(
383
+ "Webpack:",
384
+ "There was an error parsing your #{asset_type} file. \
385
+ Please check your #{asset_type} file for any errors."
386
+ )
388
387
 
389
388
  "MISSING_WEBPACK_MANIFEST_FILE"
390
389
  end
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Bridgetown
4
- VERSION = "1.0.0.alpha3"
4
+ VERSION = "1.0.0.alpha7"
5
5
  CODE_NAME = "Pearl"
6
6
  end
@@ -41,10 +41,12 @@ module Bridgetown
41
41
  Dir.exist?(path)
42
42
  end
43
43
 
44
+ paths_to_watch = (plugin_paths_to_watch + options.autoload_paths).uniq
45
+
44
46
  Listen.to(
45
47
  options["source"],
46
48
  webpack_path,
47
- *plugin_paths_to_watch,
49
+ *paths_to_watch,
48
50
  ignore: listen_ignore_paths(options),
49
51
  force_polling: options["force_polling"],
50
52
  &listen_handler(site, options)
@@ -57,10 +59,12 @@ module Bridgetown
57
59
  c = modified + added + removed
58
60
  n = c.length
59
61
 
60
- Bridgetown.logger.info "Regenerating…"
61
- Bridgetown.logger.info "", "#{n} file(s) changed at #{t.strftime("%Y-%m-%d %H:%M:%S")}"
62
+ unless site.ssr?
63
+ Bridgetown.logger.info "Regenerating…"
64
+ Bridgetown.logger.info "", "#{n} file(s) changed at #{t.strftime("%Y-%m-%d %H:%M:%S")}"
65
+ c.each { |path| Bridgetown.logger.info "", path["#{site.root_dir}/".length..] }
66
+ end
62
67
 
63
- c.each { |path| Bridgetown.logger.info "", path["#{site.root_dir}/".length..-1] }
64
68
  process(site, t, options)
65
69
  end
66
70
  end
@@ -101,7 +105,7 @@ module Bridgetown
101
105
  source = Pathname.new(options["source"]).expand_path
102
106
  paths = to_exclude(options)
103
107
 
104
- paths.map do |p|
108
+ paths.filter_map do |p|
105
109
  absolute_path = Pathname.new(normalize_encoding(p, options["source"].encoding)).expand_path
106
110
  next unless absolute_path.exist?
107
111
 
@@ -116,20 +120,25 @@ module Bridgetown
116
120
  rescue ArgumentError
117
121
  # Could not find a relative path
118
122
  end
119
- end.compact + [%r!^\.bridgetown-metadata!]
123
+ end + [%r!^\.bridgetown-metadata!]
120
124
  end
121
125
 
122
126
  def sleep_forever
123
127
  loop { sleep 1000 }
124
128
  end
125
129
 
130
+ # @param site [Bridgetown::Site]
126
131
  def process(site, time, options)
127
132
  begin
128
133
  I18n.reload! # make sure any locale files get read again
134
+ Bridgetown::Current.site = site # needed in SSR mode apparently
129
135
  Bridgetown::Hooks.trigger :site, :pre_reload, site
130
136
  Bridgetown::Hooks.clear_reloadable_hooks
131
137
  site.plugin_manager.reload_plugin_files
132
- site.plugin_manager.reload_component_loaders
138
+ site.loaders_manager.reload_loaders
139
+
140
+ return site.ssr_reload if site.ssr?
141
+
133
142
  site.process
134
143
  Bridgetown.logger.info "Done! 🎉", "#{"Completed".green} in less than" \
135
144
  " #{(Time.now - time).ceil(2)} seconds."
@@ -11,11 +11,7 @@ module Bridgetown
11
11
  end
12
12
 
13
13
  def load(yaml)
14
- if RUBY_VERSION.start_with?("2.5")
15
- YAML.safe_load yaml, PERMITTED_CLASSES
16
- else
17
- YAML.safe_load yaml, permitted_classes: PERMITTED_CLASSES
18
- end
14
+ YAML.safe_load yaml, permitted_classes: PERMITTED_CLASSES
19
15
  end
20
16
  end
21
17
  end
@@ -16,7 +16,7 @@ Welcome to your new Bridgetown website! You can update this README file to provi
16
16
  - [GCC](https://gcc.gnu.org/install/)
17
17
  - [Make](https://www.gnu.org/software/make/)
18
18
  - [Ruby](https://www.ruby-lang.org/en/downloads/)
19
- - `>= 2.5`
19
+ - `>= 2.7`
20
20
  - [Bridgetown Gem](https://rubygems.org/gems/bridgetown)
21
21
  - `gem install bridgetown -N`
22
22
  - [Node](https://nodejs.org)
@@ -2,6 +2,9 @@ require "bridgetown"
2
2
 
3
3
  Bridgetown.load_tasks
4
4
 
5
+ # Run rake without specifying any command to execute a deploy build by default.
6
+ task default: :deploy
7
+
5
8
  #
6
9
  # Standard set of tasks, which you can customize if you wish:
7
10
  #
@@ -44,6 +47,3 @@ end
44
47
  # say_status :rake, "I'm a Rake tast =) #{site.config.url}"
45
48
  # end
46
49
  # end
47
-
48
- # Run rake without specifying any command to execute a deploy build by default.
49
- task default: :deploy
@@ -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.alpha3
4
+ version: 1.0.0.alpha7
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-18 00:00:00.000000000 Z
11
+ date: 2021-11-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activemodel
@@ -390,11 +390,21 @@ files:
390
390
  - lib/bridgetown-core/configurations/.keep
391
391
  - lib/bridgetown-core/configurations/bt-postcss.rb
392
392
  - lib/bridgetown-core/configurations/bt-postcss/postcss.config.js
393
+ - lib/bridgetown-core/configurations/cypress.rb
394
+ - lib/bridgetown-core/configurations/cypress/cypress.json
395
+ - lib/bridgetown-core/configurations/cypress/cypress_dir/fixtures/example.json
396
+ - lib/bridgetown-core/configurations/cypress/cypress_dir/integration/navbar.spec.js
397
+ - lib/bridgetown-core/configurations/cypress/cypress_dir/plugins/index.js
398
+ - lib/bridgetown-core/configurations/cypress/cypress_dir/support/commands.js
399
+ - lib/bridgetown-core/configurations/cypress/cypress_dir/support/index.js
400
+ - lib/bridgetown-core/configurations/cypress/cypress_tasks
393
401
  - lib/bridgetown-core/configurations/minitesting.rb
394
402
  - lib/bridgetown-core/configurations/netlify.rb
395
403
  - lib/bridgetown-core/configurations/netlify/netlify.sh
396
404
  - lib/bridgetown-core/configurations/netlify/netlify.toml
397
405
  - lib/bridgetown-core/configurations/purgecss.rb
406
+ - lib/bridgetown-core/configurations/render.rb
407
+ - lib/bridgetown-core/configurations/render/render.yaml.erb
398
408
  - lib/bridgetown-core/configurations/stimulus.rb
399
409
  - lib/bridgetown-core/configurations/swup.rb
400
410
  - lib/bridgetown-core/configurations/tailwindcss.rb
@@ -476,7 +486,6 @@ files:
476
486
  - lib/bridgetown-core/tags/class_map.rb
477
487
  - lib/bridgetown-core/tags/find.rb
478
488
  - lib/bridgetown-core/tags/highlight.rb
479
- - lib/bridgetown-core/tags/include.rb
480
489
  - lib/bridgetown-core/tags/link.rb
481
490
  - lib/bridgetown-core/tags/live_reload_dev_js.rb
482
491
  - lib/bridgetown-core/tags/post_url.rb
@@ -489,6 +498,7 @@ files:
489
498
  - lib/bridgetown-core/utils.rb
490
499
  - lib/bridgetown-core/utils/ansi.rb
491
500
  - lib/bridgetown-core/utils/aux.rb
501
+ - lib/bridgetown-core/utils/loaders_manager.rb
492
502
  - lib/bridgetown-core/utils/require_gems.rb
493
503
  - lib/bridgetown-core/utils/ruby_exec.rb
494
504
  - lib/bridgetown-core/utils/ruby_front_matter.rb
@@ -543,12 +553,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
543
553
  requirements:
544
554
  - - ">="
545
555
  - !ruby/object:Gem::Version
546
- version: 2.5.0
556
+ version: 2.7.0
547
557
  required_rubygems_version: !ruby/object:Gem::Requirement
548
558
  requirements:
549
- - - ">="
559
+ - - ">"
550
560
  - !ruby/object:Gem::Version
551
- version: 2.7.0
561
+ version: 1.3.1
552
562
  requirements: []
553
563
  rubygems_version: 3.1.4
554
564
  signing_key:
@@ -1,216 +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
-
15
- # rubocop:disable Lint/MixedRegexpCaptureTypes
16
- VARIABLE_SYNTAX = %r!
17
- (?<variable>[^{]*(\{\{\s*[\w\-.]+\s*(\|.*)?\}\}[^\s{}]*)+)
18
- (?<params>.*)
19
- !mx.freeze
20
- # rubocop:enable Lint/MixedRegexpCaptureTypes
21
-
22
- FULL_VALID_SYNTAX = %r!\A\s*(?:#{VALID_SYNTAX}(?=\s|\z)\s*)*\z!.freeze
23
- VALID_FILENAME_CHARS = %r!^[\w/.-]+$!.freeze
24
- INVALID_SEQUENCES = %r![./]{2,}!.freeze
25
-
26
- def initialize(tag_name, markup, tokens)
27
- super
28
-
29
- unless self.class.deprecation_message_shown
30
- Bridgetown.logger.warn "NOTICE: the {% include %} tag is deprecated and" \
31
- " will be removed in Bridgetown 1.0. You should" \
32
- " use the {% render %} tag instead."
33
- self.class.deprecation_message_shown = true
34
- end
35
-
36
- matched = markup.strip.match(VARIABLE_SYNTAX)
37
- if matched
38
- @file = matched["variable"].strip
39
- @params = matched["params"].strip
40
- else
41
- @file, @params = markup.strip.split(%r!\s+!, 2)
42
- end
43
- validate_params if @params
44
- @tag_name = tag_name
45
- end
46
-
47
- def syntax_example
48
- "{% #{@tag_name} file.ext param='value' param2='value' %}"
49
- end
50
-
51
- def parse_params(context)
52
- params = {}
53
- markup = @params
54
-
55
- while (match = VALID_SYNTAX.match(markup))
56
- markup = markup[match.end(0)..-1]
57
-
58
- value = if match[2]
59
- match[2].gsub('\\"', '"')
60
- elsif match[3]
61
- match[3].gsub("\\'", "'")
62
- elsif match[4]
63
- context[match[4]]
64
- end
65
-
66
- params[match[1]] = value
67
- end
68
- params
69
- end
70
-
71
- def validate_file_name(file)
72
- return unless INVALID_SEQUENCES.match?(file) || !VALID_FILENAME_CHARS.match?(file)
73
-
74
- raise ArgumentError, <<~MSG
75
- Invalid syntax for include tag. File contains invalid characters or sequences:
76
-
77
- #{file}
78
-
79
- Valid syntax:
80
-
81
- #{syntax_example}
82
-
83
- MSG
84
- end
85
-
86
- def validate_params
87
- return if FULL_VALID_SYNTAX.match?(@params)
88
-
89
- raise ArgumentError, <<~MSG
90
- Invalid syntax for include tag:
91
-
92
- #{@params}
93
-
94
- Valid syntax:
95
-
96
- #{syntax_example}
97
-
98
- MSG
99
- end
100
-
101
- # Grab file read opts in the context
102
- def file_read_opts(context)
103
- context.registers[:site].file_read_opts
104
- end
105
-
106
- # Render the variable if required
107
- def render_variable(context)
108
- Liquid::Template.parse(@file).render(context) if VARIABLE_SYNTAX.match?(@file)
109
- end
110
-
111
- def tag_includes_dirs(context)
112
- context.registers[:site].includes_load_paths.freeze
113
- end
114
-
115
- def locate_include_file(context, file)
116
- includes_dirs = tag_includes_dirs(context)
117
- includes_dirs.each do |dir|
118
- path = File.join(dir, file)
119
- return path if valid_include_file?(path, dir.to_s)
120
- end
121
- raise IOError, could_not_locate_message(file, includes_dirs)
122
- end
123
-
124
- def render(context)
125
- file = render_variable(context) || @file
126
- validate_file_name(file)
127
-
128
- path = locate_include_file(context, file)
129
- return unless path
130
-
131
- partial = load_cached_partial(path, context)
132
-
133
- context.stack do
134
- context["include"] = parse_params(context) if @params
135
- begin
136
- partial.render!(context)
137
- rescue Liquid::Error => e
138
- e.template_name = path
139
- e.markup_context = "included " if e.markup_context.nil?
140
- raise e
141
- end
142
- end
143
- end
144
-
145
- def load_cached_partial(path, context)
146
- context.registers[:cached_partials] ||= {}
147
- cached_partial = context.registers[:cached_partials]
148
-
149
- if cached_partial.key?(path)
150
- cached_partial[path]
151
- else
152
- unparsed_file = context.registers[:site]
153
- .liquid_renderer
154
- .file(path)
155
- begin
156
- cached_partial[path] = unparsed_file.parse(read_file(path, context))
157
- rescue Liquid::Error => e
158
- e.template_name = path
159
- e.markup_context = "included " if e.markup_context.nil?
160
- raise e
161
- end
162
- end
163
- end
164
-
165
- def valid_include_file?(path, _dir)
166
- File.file?(path)
167
- end
168
-
169
- def realpath_prefixed_with?(path, dir)
170
- File.exist?(path) && File.realpath(path).start_with?(dir)
171
- rescue StandardError
172
- false
173
- end
174
-
175
- # This method allows to modify the file content by inheriting from the class.
176
- def read_file(file, context)
177
- File.read(file, **file_read_opts(context))
178
- end
179
-
180
- private
181
-
182
- def could_not_locate_message(file, includes_dirs)
183
- "Could not locate the included file '#{file}' in any of #{includes_dirs}." \
184
- " Ensure it exists in one of those directories."
185
- end
186
- end
187
-
188
- class IncludeRelativeTag < IncludeTag
189
- def tag_includes_dirs(context)
190
- Array(page_path(context)).freeze
191
- end
192
-
193
- def page_path(context)
194
- if context.registers[:page].nil?
195
- context.registers[:site].source
196
- else
197
- site = context.registers[:site]
198
- page_payload = context.registers[:page]
199
- resource_path = \
200
- if page_payload["collection"].nil?
201
- page_payload["path"]
202
- else
203
- File.join(site.config["collections_dir"], page_payload["path"])
204
- end
205
- # rubocop:disable Performance/DeleteSuffix
206
- resource_path.sub!(%r!/#excerpt\z!, "")
207
- # rubocop:enable Performance/DeleteSuffix
208
- site.in_source_dir File.dirname(resource_path)
209
- end
210
- end
211
- end
212
- end
213
- end
214
-
215
- Liquid::Template.register_tag("include", Bridgetown::Tags::IncludeTag)
216
- Liquid::Template.register_tag("include_relative", Bridgetown::Tags::IncludeRelativeTag)