bridgetown-core 1.0.0.alpha3 → 1.0.0.alpha7

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 (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)