bridgetown-core 1.3.4 → 2.0.0.beta1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (140) hide show
  1. checksums.yaml +4 -4
  2. data/bin/bridgetown +0 -6
  3. data/bin/bt +6 -0
  4. data/bridgetown-core.gemspec +9 -6
  5. data/lib/bridgetown-core/cleaner.rb +1 -1
  6. data/lib/bridgetown-core/collection.rb +30 -18
  7. data/lib/bridgetown-core/commands/build.rb +9 -22
  8. data/lib/bridgetown-core/commands/concerns/actions.rb +15 -8
  9. data/lib/bridgetown-core/commands/concerns/configuration_overridable.rb +1 -1
  10. data/lib/bridgetown-core/commands/console.rb +3 -0
  11. data/lib/bridgetown-core/commands/doctor.rb +2 -4
  12. data/lib/bridgetown-core/commands/esbuild/esbuild.defaults.js.erb +1 -1
  13. data/lib/bridgetown-core/commands/esbuild/migrate-from-webpack.rb +1 -1
  14. data/lib/bridgetown-core/commands/esbuild/update.rb +2 -2
  15. data/lib/bridgetown-core/commands/esbuild.rb +3 -3
  16. data/lib/bridgetown-core/commands/new.rb +32 -39
  17. data/lib/bridgetown-core/commands/start.rb +76 -60
  18. data/lib/bridgetown-core/component.rb +19 -13
  19. data/lib/bridgetown-core/concerns/layout_placeable.rb +1 -1
  20. data/lib/bridgetown-core/concerns/prioritizable.rb +11 -1
  21. data/lib/bridgetown-core/concerns/site/configurable.rb +7 -18
  22. data/lib/bridgetown-core/concerns/site/content.rb +10 -9
  23. data/lib/bridgetown-core/concerns/site/extensible.rb +4 -6
  24. data/lib/bridgetown-core/concerns/site/fast_refreshable.rb +161 -0
  25. data/lib/bridgetown-core/concerns/site/processable.rb +1 -0
  26. data/lib/bridgetown-core/concerns/site/renderable.rb +31 -7
  27. data/lib/bridgetown-core/concerns/site/ssr.rb +23 -9
  28. data/lib/bridgetown-core/concerns/site/writable.rb +1 -1
  29. data/lib/bridgetown-core/concerns/transformable.rb +3 -5
  30. data/lib/bridgetown-core/configuration/configuration_dsl.rb +23 -14
  31. data/lib/bridgetown-core/configuration.rb +67 -114
  32. data/lib/bridgetown-core/configurations/bt-postcss.rb +1 -2
  33. data/lib/bridgetown-core/configurations/cypress/cypress_tasks +2 -2
  34. data/lib/bridgetown-core/configurations/cypress.rb +1 -1
  35. data/lib/bridgetown-core/configurations/gh-pages/gh-pages.yml +3 -3
  36. data/lib/bridgetown-core/configurations/is-land.rb +1 -1
  37. data/lib/bridgetown-core/configurations/lit.rb +1 -1
  38. data/lib/bridgetown-core/configurations/open-props.rb +1 -1
  39. data/lib/bridgetown-core/configurations/purgecss.rb +1 -1
  40. data/lib/bridgetown-core/configurations/ruby2js.rb +1 -1
  41. data/lib/bridgetown-core/configurations/shoelace.rb +8 -20
  42. data/lib/bridgetown-core/configurations/stimulus.rb +17 -36
  43. data/lib/bridgetown-core/configurations/turbo.rb +1 -2
  44. data/lib/bridgetown-core/converter.rb +38 -10
  45. data/lib/bridgetown-core/converters/erb_templates.rb +9 -26
  46. data/lib/bridgetown-core/converters/identity.rb +1 -1
  47. data/lib/bridgetown-core/converters/liquid_templates.rb +2 -20
  48. data/lib/bridgetown-core/converters/ruby_templates.rb +61 -3
  49. data/lib/bridgetown-core/converters/serbea_templates.rb +12 -24
  50. data/lib/bridgetown-core/current.rb +19 -17
  51. data/lib/bridgetown-core/drops/collection_drop.rb +1 -1
  52. data/lib/bridgetown-core/drops/drop.rb +3 -3
  53. data/lib/bridgetown-core/drops/relations_drop.rb +3 -2
  54. data/lib/bridgetown-core/drops/site_drop.rb +0 -5
  55. data/lib/bridgetown-core/entry_filter.rb +4 -6
  56. data/lib/bridgetown-core/errors.rb +2 -2
  57. data/lib/bridgetown-core/filters/from_liquid.rb +6 -10
  58. data/lib/bridgetown-core/filters/localization_filters.rb +1 -1
  59. data/lib/bridgetown-core/filters/translation_filters.rb +2 -2
  60. data/lib/bridgetown-core/filters.rb +3 -3
  61. data/lib/bridgetown-core/front_matter/defaults.rb +225 -0
  62. data/lib/bridgetown-core/front_matter/importer.rb +34 -0
  63. data/lib/bridgetown-core/front_matter/loaders/base.rb +29 -0
  64. data/lib/bridgetown-core/front_matter/loaders/ruby.rb +113 -0
  65. data/lib/bridgetown-core/front_matter/loaders/yaml.rb +42 -0
  66. data/lib/bridgetown-core/front_matter/loaders.rb +44 -0
  67. data/lib/bridgetown-core/{utils/ruby_front_matter.rb → front_matter/ruby.rb} +5 -5
  68. data/lib/bridgetown-core/front_matter.rb +11 -0
  69. data/lib/bridgetown-core/generated_page.rb +71 -31
  70. data/lib/bridgetown-core/generators/prototype_generator.rb +30 -18
  71. data/lib/bridgetown-core/helpers.rb +36 -47
  72. data/lib/bridgetown-core/hooks.rb +5 -5
  73. data/lib/bridgetown-core/inflector.rb +40 -0
  74. data/lib/bridgetown-core/kramdown/parser/gfm.rb +2 -2
  75. data/lib/bridgetown-core/layout.rb +3 -3
  76. data/lib/bridgetown-core/log_adapter.rb +12 -13
  77. data/lib/bridgetown-core/log_writer.rb +4 -4
  78. data/lib/bridgetown-core/model/base.rb +17 -17
  79. data/lib/bridgetown-core/model/builder_origin.rb +5 -3
  80. data/lib/bridgetown-core/model/origin.rb +1 -3
  81. data/lib/bridgetown-core/model/repo_origin.rb +12 -14
  82. data/lib/bridgetown-core/plugin.rb +0 -1
  83. data/lib/bridgetown-core/plugin_manager.rb +27 -84
  84. data/lib/bridgetown-core/rack/boot.rb +0 -15
  85. data/lib/bridgetown-core/rack/routes.rb +30 -90
  86. data/lib/bridgetown-core/reader.rb +6 -4
  87. data/lib/bridgetown-core/readers/layout_reader.rb +2 -2
  88. data/lib/bridgetown-core/readers/plugin_content_reader.rb +2 -2
  89. data/lib/bridgetown-core/resource/base.rb +112 -29
  90. data/lib/bridgetown-core/resource/destination.rb +1 -1
  91. data/lib/bridgetown-core/resource/relations.rb +11 -8
  92. data/lib/bridgetown-core/resource/taxonomy_type.rb +3 -1
  93. data/lib/bridgetown-core/resource/transformer.rb +4 -4
  94. data/lib/bridgetown-core/ruby_template_view.rb +44 -28
  95. data/lib/bridgetown-core/signals.rb +95 -0
  96. data/lib/bridgetown-core/site.rb +22 -4
  97. data/lib/bridgetown-core/slot.rb +5 -5
  98. data/lib/bridgetown-core/static_file.rb +5 -7
  99. data/lib/bridgetown-core/tags/asset_path.rb +11 -2
  100. data/lib/bridgetown-core/tags/find.rb +3 -5
  101. data/lib/bridgetown-core/tags/highlight.rb +3 -3
  102. data/lib/bridgetown-core/tags/post_url.rb +1 -1
  103. data/lib/bridgetown-core/tasks/bridgetown_tasks.rake +2 -2
  104. data/lib/bridgetown-core/utils/aux.rb +41 -41
  105. data/lib/bridgetown-core/utils/loaders_manager.rb +2 -21
  106. data/lib/bridgetown-core/utils/ruby_exec.rb +17 -0
  107. data/lib/bridgetown-core/utils.rb +46 -110
  108. data/lib/bridgetown-core/version.rb +2 -2
  109. data/lib/bridgetown-core/watcher.rb +21 -10
  110. data/lib/bridgetown-core.rb +35 -49
  111. data/lib/roda/plugins/bridgetown_server.rb +54 -12
  112. data/lib/roda/plugins/bridgetown_ssr.rb +13 -2
  113. data/lib/roda/plugins/ssg.rb +72 -0
  114. data/lib/site_template/.gitignore +9 -3
  115. data/lib/site_template/Gemfile.erb +3 -3
  116. data/lib/site_template/README.md +3 -4
  117. data/lib/site_template/Rakefile.erb +2 -15
  118. data/lib/site_template/TEMPLATES/erb/_partials/_head.erb +2 -2
  119. data/lib/site_template/TEMPLATES/serbea/_partials/_head.serb +2 -2
  120. data/lib/site_template/config/initializers.rb +60 -22
  121. data/lib/site_template/config/puma.rb +2 -0
  122. data/lib/site_template/package.json.erb +2 -27
  123. data/lib/site_template/src/index.md.erb +3 -3
  124. data/lib/site_template/tmp/pids/.keep +0 -0
  125. metadata +98 -63
  126. data/lib/bridgetown-core/commands/webpack/enable-postcss.rb +0 -12
  127. data/lib/bridgetown-core/commands/webpack/setup.rb +0 -4
  128. data/lib/bridgetown-core/commands/webpack/update.rb +0 -24
  129. data/lib/bridgetown-core/commands/webpack/webpack.config.js +0 -31
  130. data/lib/bridgetown-core/commands/webpack/webpack.defaults.js.erb +0 -135
  131. data/lib/bridgetown-core/commands/webpack.rb +0 -82
  132. data/lib/bridgetown-core/concerns/front_matter_importer.rb +0 -52
  133. data/lib/bridgetown-core/concerns/liquid_renderable.rb +0 -30
  134. data/lib/bridgetown-core/core_ext/psych.rb +0 -15
  135. data/lib/bridgetown-core/drops/url_drop.rb +0 -152
  136. data/lib/bridgetown-core/frontmatter_defaults.rb +0 -223
  137. data/lib/bridgetown-core/rack/static_indexes.rb +0 -31
  138. data/lib/bridgetown-core/url.rb +0 -166
  139. data/lib/bridgetown-core/utils/ansi.rb +0 -57
  140. data/lib/site_template/bridgetown.config.yml +0 -33
@@ -2,6 +2,7 @@
2
2
 
3
3
  module Bridgetown
4
4
  class StaticFile
5
+ using Bridgetown::Refinements
5
6
  extend Forwardable
6
7
 
7
8
  attr_reader :relative_path, :extname, :name, :data, :site, :collection
@@ -34,7 +35,7 @@ module Bridgetown
34
35
  @collection = collection
35
36
  @relative_path = File.join(*[@dir, @name].compact)
36
37
  @extname = File.extname(@name)
37
- @data = @site.frontmatter_defaults.all(relative_path, type).with_dot_access
38
+ @data = @site.frontmatter_defaults.all(relative_path, type).as_dots
38
39
  data.permalink ||= if collection && !collection.builtin?
39
40
  "#{collection.default_permalink.chomp("/").chomp(".*")}.*"
40
41
  else
@@ -58,7 +59,7 @@ module Bridgetown
58
59
  if site.base_path.present? && collection
59
60
  dest_url = dest_url.delete_prefix site.base_path(strip_slash_only: true)
60
61
  end
61
- site.in_dest_dir(dest, Bridgetown::URL.unescape_path(dest_url))
62
+ site.in_dest_dir(dest, Bridgetown::Utils.unencode_uri(dest_url))
62
63
  end
63
64
 
64
65
  def destination_rel_dir
@@ -146,7 +147,6 @@ module Bridgetown
146
147
  }
147
148
  end
148
149
 
149
- # Similar to Bridgetown::Document#cleaned_relative_path.
150
150
  # Generates a relative path with the collection's directory removed when applicable
151
151
  # and additionally removes any multiple periods in the string.
152
152
  #
@@ -167,15 +167,13 @@ module Bridgetown
167
167
  end
168
168
  end
169
169
 
170
- # Applies a similar URL-building technique as Bridgetown::Document that takes
170
+ # Applies a similar URL-building technique as resources that takes
171
171
  # the collection's URL template into account. The default URL template can
172
172
  # be overriden in the collection's configuration in bridgetown.config.yml.
173
173
  def url
174
174
  @url ||= begin
175
175
  newly_processed = false
176
- special_posts_case = @collection&.label == "posts" &&
177
- site.config.content_engine != "resource"
178
- base = if @collection.nil? || special_posts_case
176
+ base = if @collection.nil?
179
177
  cleaned_relative_path
180
178
  else
181
179
  newly_processed = true
@@ -2,7 +2,7 @@
2
2
 
3
3
  module Bridgetown
4
4
  module Tags
5
- # A helper class to help find the path to assets inside of a webpack or esbuild
5
+ # A helper class to help find the path to assets inside of an esbuild
6
6
  # manifest file.
7
7
  class AssetPath < Liquid::Tag
8
8
  # @param tag_name [String] Name of the tag
@@ -20,13 +20,22 @@ module Bridgetown
20
20
  # Render an asset path based on the frontend manifest file
21
21
  # @param context [Liquid::Context] Context passed to the tag
22
22
  #
23
- # @return [String] Returns "MISSING_WEBPACK_MANIFEST" if the manifest
23
+ # @return [String] Returns "MISSING_ESBUILD_MANIFEST" if the manifest
24
24
  # file isn't found
25
25
  # @return [String] Returns a blank string if the asset isn't found
26
26
  # @return [String] Returns the path to the asset if no issues parsing
27
27
  def render(context)
28
28
  @context = context
29
29
  site = context.registers[:site]
30
+ if tag_name == "webpack_path"
31
+ source_file =
32
+ "#{context.registers.static[:file_system].root.last}/#{context.template_name}.liquid"
33
+ raise(
34
+ Bridgetown::Errors::FatalException,
35
+ "🚨 Oops, you'll need to change `webpack_path' to `asset_path' in:\n#{source_file}\n"
36
+ )
37
+ end
38
+
30
39
  Bridgetown::Utils.parse_frontend_manifest_file(site, @asset_type) || ""
31
40
  end
32
41
  end
@@ -6,7 +6,7 @@ module Bridgetown
6
6
  include Bridgetown::Filters::ConditionHelpers
7
7
  include Bridgetown::LiquidExtensions
8
8
 
9
- SYNTAX = %r!^(.*?) (where|in) (.*?),(.*)$!.freeze
9
+ SYNTAX = %r!^(.*?) (where|in) (.*?),(.*)$!
10
10
  CONDITIONS_SEP = "~FINDSEP~"
11
11
 
12
12
  def initialize(tag_name, markup, tokens)
@@ -38,11 +38,9 @@ module Bridgetown
38
38
  end.join(" and ")
39
39
  @liquid_condition = parse_condition(expression)
40
40
 
41
- context[@new_var_name] = if @single_or_group == "where"
42
- group_evaluate(context)
43
- else
41
+ context[@new_var_name] = @single_or_group == "where" ?
42
+ group_evaluate(context) :
44
43
  single_evaluate(context)
45
- end
46
44
 
47
45
  ""
48
46
  end
@@ -10,7 +10,7 @@ module Bridgetown
10
10
  # forms: name, name=value, or name="<quoted list>"
11
11
  #
12
12
  # <quoted list> is a space-separated list of numbers
13
- SYNTAX = %r!^([a-zA-Z0-9.+#_-]+)((\s+\w+(=(\w+|"([0-9]+\s)*[0-9]+"))?)*)$!.freeze
13
+ SYNTAX = %r!^([a-zA-Z0-9.+#_-]+)((\s+\w+(=(\w+|"([0-9]+\s)*[0-9]+"))?)*)$!
14
14
 
15
15
  def initialize(tag_name, markup, tokens)
16
16
  super
@@ -28,7 +28,7 @@ module Bridgetown
28
28
  @highlight_options = parse_options(Regexp.last_match(2))
29
29
  end
30
30
 
31
- LEADING_OR_TRAILING_LINE_TERMINATORS = %r!\A(\n|\r)+|(\n|\r)+\z!.freeze
31
+ LEADING_OR_TRAILING_LINE_TERMINATORS = %r!\A(\n|\r)+|(\n|\r)+\z!
32
32
 
33
33
  def render(context)
34
34
  prefix = context["highlighter_prefix"] || ""
@@ -49,7 +49,7 @@ module Bridgetown
49
49
 
50
50
  private
51
51
 
52
- OPTIONS_REGEX = %r!(?:\w="[^"]*"|\w=\w|\w)+!.freeze
52
+ OPTIONS_REGEX = %r!(?:\w="[^"]*"|\w=\w|\w)+!
53
53
 
54
54
  def parse_options(input)
55
55
  options = {}
@@ -3,7 +3,7 @@
3
3
  module Bridgetown
4
4
  module Tags
5
5
  class PostComparer
6
- MATCHER = %r!^(.+/)*(\d+-\d+-\d+)-(.*)$!.freeze
6
+ MATCHER = %r!^(.+/)*(\d+-\d+-\d+)-(.*)$!
7
7
 
8
8
  attr_reader :path, :date, :slug, :name
9
9
 
@@ -32,7 +32,7 @@ namespace :roda do
32
32
  task :routes do
33
33
  require "bridgetown-core/rack/boot"
34
34
 
35
- Bridgetown::Rack::Roda.print_routes
35
+ Bridgetown::Rack::Routes.print_routes
36
36
  end
37
37
  end
38
38
 
@@ -55,7 +55,7 @@ task :environment do # rubocop:todo Metrics/BlockLength
55
55
  def site(context: :rake)
56
56
  @site ||= begin
57
57
  config = Bridgetown::Current.preloaded_configuration
58
- config.run_initializers! context: context
58
+ config.run_initializers!(context:)
59
59
  Bridgetown::Site.new(config)
60
60
  end
61
61
  end
@@ -3,57 +3,57 @@
3
3
  module Bridgetown
4
4
  module Utils
5
5
  module Aux
6
- def self.with_color(name, message)
7
- return message unless !name.nil? && Bridgetown::Utils::Ansi::COLORS[name.to_sym]
6
+ class << self
7
+ extend Inclusive::Class
8
8
 
9
- Bridgetown::Utils::Ansi.send(name, message)
10
- end
9
+ # @return
10
+ # [Bridgetown::Foundation::Packages::Ansi, Bridgetown::Foundation::Packages::PidTracker]
11
+ packages def utils = [
12
+ Bridgetown::Foundation::Packages::Ansi,
13
+ Bridgetown::Foundation::Packages::PidTracker,
14
+ ]
11
15
 
12
- def self.running_pids
13
- @running_pids ||= []
14
- end
16
+ def with_color(name, message)
17
+ return message unless !name.nil? && utils.colors[name.to_sym]
15
18
 
16
- def self.add_pid(pid)
17
- running_pids << pid
18
- end
19
+ utils.send(name, message)
20
+ end
19
21
 
20
- def self.run_process(name, color, cmd, env: {})
21
- @mutex ||= Thread::Mutex.new
22
-
23
- Thread.new do
24
- rd, wr = IO.pipe("BINARY")
25
- pid = Process.spawn({ "BRIDGETOWN_NO_BUNDLER_REQUIRE" => nil }.merge(env),
26
- cmd, out: wr, err: wr, pgroup: true)
27
- @mutex.synchronize { add_pid(pid) }
28
-
29
- loop do
30
- line = rd.gets
31
- line.to_s.lines.map(&:chomp).each do |message|
32
- next if name == "Frontend" && %r{ELIFECYCLE.*?Command failed}.match?(message)
33
-
34
- output = +""
35
- output << with_color(color, "[#{name}] ") if color
36
- output << message
37
- @mutex.synchronize do
38
- $stdout.puts output
39
- $stdout.flush
22
+ def run_process(name, color, cmd, env: {}) # rubocop:disable Metrics/AbcSize
23
+ @mutex ||= Thread::Mutex.new
24
+
25
+ Thread.new do
26
+ rd, wr = IO.pipe("BINARY")
27
+ pid = Process.spawn({ "BRIDGETOWN_NO_BUNDLER_REQUIRE" => nil }.merge(env),
28
+ cmd, out: wr, err: wr, pgroup: true)
29
+ @mutex.synchronize { utils.add_pid(pid, file: :aux) }
30
+
31
+ loop do
32
+ line = rd.gets
33
+ line.to_s.lines.map(&:chomp).each do |message|
34
+ next if name == "Frontend" && %r{ELIFECYCLE.*?Command failed}.match?(message)
35
+
36
+ output = +""
37
+ output << with_color(color, "[#{name}] ") if color
38
+ output << message
39
+ @mutex.synchronize do
40
+ $stdout.puts output
41
+ $stdout.flush
42
+ end
40
43
  end
41
44
  end
42
45
  end
43
46
  end
44
- end
45
47
 
46
- def self.group(&block)
47
- Bridgetown::Deprecator.deprecation_message "Bridgetown::Aux.group method will be removed" \
48
- "in a future version, use run_process"
49
- instance_exec(&block)
50
- end
48
+ def kill_processes
49
+ Bridgetown.logger.info "Stopping auxiliary processes..."
51
50
 
52
- def self.kill_processes
53
- Bridgetown.logger.info "Stopping auxiliary processes..."
54
- running_pids.each do |pid|
55
- Process.kill("SIGTERM", -Process.getpgid(pid))
56
- rescue Errno::ESRCH, Errno::EPERM, Errno::ECHILD # rubocop:disable Lint/SuppressedException
51
+ utils.read_pidfile(:aux).each do |pid|
52
+ Process.kill("SIGTERM", -Process.getpgid(pid.to_i))
53
+ rescue Errno::ESRCH, Errno::EPERM, Errno::ECHILD # rubocop:disable Lint/SuppressedException
54
+ ensure
55
+ utils.remove_pidfile :aux
56
+ end
57
57
  end
58
58
  end
59
59
  end
@@ -28,26 +28,8 @@ module Bridgetown
28
28
  load_path.start_with?(root_dir) && ENV["BRIDGETOWN_ENV"] != "production"
29
29
  end
30
30
 
31
- def clear_descendants_for_reload(_cpath, value, _abspath)
32
- unless value.is_a?(Class) && value.singleton_class < ActiveSupport::DescendantsTracker
33
- return
34
- end
35
-
36
- if defined?(ActiveSupport::RubyFeatures) && ActiveSupport::RubyFeatures::CLASS_SUBCLASSES
37
- ActiveSupport::DescendantsTracker.clear([value.superclass])
38
- return
39
- end
40
-
41
- # TODO: this could probably be refactored to work like the above
42
- if ActiveSupport::DescendantsTracker.class_variables.include?(:@@direct_descendants)
43
- ActiveSupport::DescendantsTracker.class_variable_get(
44
- :@@direct_descendants
45
- )[value.superclass]&.reject! { _1 == value }
46
- end
47
- end
48
-
49
31
  def setup_loaders(autoload_paths = []) # rubocop:todo Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity
50
- (autoload_paths.presence || config.autoload_paths).each do |load_path| # rubocop:todo Metrics/BlockLength
32
+ (autoload_paths.presence || config.autoload_paths).each do |load_path|
51
33
  if @loaders.key?(load_path)
52
34
  raise "Zeitwerk loader already added for `#{load_path}'. Please check your config"
53
35
  end
@@ -64,14 +46,13 @@ module Bridgetown
64
46
  loader.enable_reloading if reloading_enabled?(load_path)
65
47
  loader.ignore(File.join(load_path, "**", "*.js.rb"))
66
48
  loader.ignore(
67
- File.join(File.expand_path(config[:islands_dir], config[:source]), "routes")
49
+ File.join(File.expand_path(config[:islands_dir], config[:source]), "**", "routes")
68
50
  )
69
51
  config.autoloader_collapsed_paths.each do |collapsed_path|
70
52
  next unless collapsed_path.starts_with?(load_path)
71
53
 
72
54
  loader.collapse(collapsed_path)
73
55
  end
74
- loader.on_unload(&method(:clear_descendants_for_reload)) # rubocop:disable Performance/MethodObjectAsBlock
75
56
  Bridgetown::Hooks.trigger :loader, :pre_setup, loader, load_path
76
57
  loader.setup
77
58
  loader.eager_load if config.eager_load_paths.include?(load_path)
@@ -3,6 +3,23 @@
3
3
  module Bridgetown
4
4
  module Utils
5
5
  module RubyExec
6
+ # @param context [Layout, Model::RepoOrigin] the execution context (i.e.
7
+ # `self` for the Ruby code)
8
+ # @param ruby_code [String] the Ruby code to execute
9
+ # @param file_path [String] the absolute path to the file
10
+ # @param starting_line [Integer] the number to list as the starting line
11
+ # for compilation errors
12
+ # @return [Hash]
13
+ def self.process_ruby_data(context, ruby_code, file_path, starting_line)
14
+ ruby_data = context.instance_eval(ruby_code, file_path.to_s, starting_line)
15
+ ruby_data.is_a?(Array) ? { rows: ruby_data } : ruby_data.to_h
16
+ rescue StandardError => e
17
+ raise(
18
+ "Ruby code isn't returning an array, or object which " \
19
+ "responds to `to_h' (#{e.message})"
20
+ )
21
+ end
22
+
6
23
  def self.search_data_for_ruby_code(convertible)
7
24
  return if convertible.data.empty?
8
25
 
@@ -2,15 +2,11 @@
2
2
 
3
3
  module Bridgetown
4
4
  module Utils # rubocop:todo Metrics/ModuleLength
5
- extend Gem::Deprecate
6
5
  extend self
7
- autoload :Ansi, "bridgetown-core/utils/ansi"
8
6
  autoload :Aux, "bridgetown-core/utils/aux"
9
7
  autoload :LoadersManager, "bridgetown-core/utils/loaders_manager"
10
8
  autoload :RequireGems, "bridgetown-core/utils/require_gems"
11
9
  autoload :RubyExec, "bridgetown-core/utils/ruby_exec"
12
- autoload :RubyFrontMatter, "bridgetown-core/utils/ruby_front_matter"
13
- autoload :RubyFrontMatterDSL, "bridgetown-core/utils/ruby_front_matter"
14
10
  autoload :SmartyPantsConverter, "bridgetown-core/utils/smarty_pants_converter"
15
11
 
16
12
  # Constants for use in #slugify
@@ -39,6 +35,13 @@ module Bridgetown
39
35
  input.to_s.encode(xml: :attr).gsub(%r!\A"|"\Z!, "")
40
36
  end
41
37
 
38
+ def unencode_uri(path)
39
+ path = path.encode("utf-8")
40
+ return path unless path.include?("%")
41
+
42
+ Addressable::URI.unencode(path)
43
+ end
44
+
42
45
  # Non-destructive version of deep_merge_hashes! See that method.
43
46
  #
44
47
  # Returns the merged hashes.
@@ -66,8 +69,6 @@ module Bridgetown
66
69
  def mergeable?(value)
67
70
  value.is_a?(Hash) || value.is_a?(Drops::Drop)
68
71
  end
69
- alias_method :mergable?, :mergeable?
70
- deprecate :mergable?, :mergeable?, 2023, 7
71
72
 
72
73
  def duplicable?(obj)
73
74
  case obj
@@ -123,24 +124,21 @@ module Bridgetown
123
124
  # Determines whether a given file has
124
125
  #
125
126
  # @return [Boolean] if the YAML front matter is present.
126
- # rubocop: disable Naming/PredicateName
127
- def has_yaml_header?(file)
128
- File.open(file, "rb", &:gets)&.match?(Bridgetown::FrontMatterImporter::YAML_HEADER) || false
129
- end
130
-
131
- def has_rbfm_header?(file)
132
- File.open(file, "rb", &:gets)&.match?(Bridgetown::FrontMatterImporter::RUBY_HEADER) || false
127
+ def has_yaml_header?(file) # rubocop: disable Naming/PredicateName
128
+ Bridgetown::Deprecator.deprecation_message(
129
+ "Bridgetown::Utils.has_yaml_header? is deprecated, use " \
130
+ "Bridgetown::FrontMatter::Loaders::YAML.header? instead"
131
+ )
132
+ FrontMatter::Loaders::YAML.header?(file)
133
133
  end
134
134
 
135
- # Determine whether the given content string contains Liquid Tags or Vaiables
136
- #
137
- # @return [Boolean] if the string contains sequences of `{%` or `{{`
138
- def has_liquid_construct?(content)
139
- return false if content.nil? || content.empty?
140
-
141
- content.include?("{%") || content.include?("{{")
135
+ def has_rbfm_header?(file) # rubocop: disable Naming/PredicateName
136
+ Bridgetown::Deprecator.deprecation_message(
137
+ "Bridgetown::Utils.has_rbfm_header? is deprecated, use " \
138
+ "Bridgetown::FrontMatter::Loaders::Ruby.header? instead"
139
+ )
140
+ FrontMatter::Loaders::Ruby.header?(file)
142
141
  end
143
- # rubocop: enable Naming/PredicateName
144
142
 
145
143
  # Slugify a filename or title.
146
144
  #
@@ -201,7 +199,7 @@ module Bridgetown
201
199
  string = I18n.transliterate(string)
202
200
  end
203
201
 
204
- slug = replace_character_sequence_with_hyphen(string, mode: mode)
202
+ slug = replace_character_sequence_with_hyphen(string, mode:)
205
203
 
206
204
  # Remove leading/trailing hyphen
207
205
  slug.gsub!(%r!^-|-$!i, "")
@@ -211,49 +209,6 @@ module Bridgetown
211
209
  slug
212
210
  end
213
211
 
214
- # Add an appropriate suffix to template so that it matches the specified
215
- # permalink style.
216
- #
217
- # template - permalink template without trailing slash or file extension
218
- # permalink_style - permalink style, either built-in or custom
219
- #
220
- # The returned permalink template will use the same ending style as
221
- # specified in permalink_style. For example, if permalink_style contains a
222
- # trailing slash (or is :pretty, which indirectly has a trailing slash),
223
- # then so will the returned template. If permalink_style has a trailing
224
- # ":output_ext" (or is :none, :date, or :ordinal) then so will the returned
225
- # template. Otherwise, template will be returned without modification.
226
- #
227
- # Examples:
228
- # add_permalink_suffix("/:basename", :pretty)
229
- # # => "/:basename/"
230
- #
231
- # add_permalink_suffix("/:basename", :date)
232
- # # => "/:basename:output_ext"
233
- #
234
- # add_permalink_suffix("/:basename", "/:year/:month/:title/")
235
- # # => "/:basename/"
236
- #
237
- # add_permalink_suffix("/:basename", "/:year/:month/:title")
238
- # # => "/:basename"
239
- #
240
- # Returns the updated permalink template
241
- def add_permalink_suffix(template, permalink_style)
242
- template = template.dup
243
-
244
- case permalink_style
245
- when :pretty, :simple
246
- template << "/"
247
- when :date, :ordinal, :none
248
- template << ":output_ext"
249
- else
250
- template << "/" if permalink_style.to_s.end_with?("/")
251
- template << ":output_ext" if permalink_style.to_s.end_with?(":output_ext")
252
- end
253
-
254
- template
255
- end
256
-
257
212
  # Work the same way as Dir.glob but seperating the input into two parts
258
213
  # ('dir' + '/' + 'pattern') to make sure the first part('dir') does not act
259
214
  # as a pattern.
@@ -350,8 +305,6 @@ module Bridgetown
350
305
  # @return [String, nil]
351
306
  def parse_frontend_manifest_file(site, asset_type)
352
307
  case frontend_bundler_type(site.root_dir)
353
- when :webpack
354
- parse_webpack_manifest_file(site, asset_type)
355
308
  when :esbuild
356
309
  parse_esbuild_manifest_file(site, asset_type)
357
310
  else
@@ -363,35 +316,11 @@ module Bridgetown
363
316
  end
364
317
  end
365
318
 
366
- # Return an asset path based on the Webpack manifest file
367
- # @param site [Bridgetown::Site] The current site object
368
- # @param asset_type [String] js or css, or filename in manifest
369
- #
370
- # @return [String] Returns "MISSING_WEBPACK_MANIFEST" if the manifest
371
- # file isnt found
372
- # @return [nil] Returns nil if the asset isnt found
373
- # @return [String] Returns the path to the asset if no issues parsing
374
- def parse_webpack_manifest_file(site, asset_type)
375
- return log_frontend_asset_error(site, "Webpack manifest") if site.frontend_manifest.nil?
376
-
377
- asset_path = if %w(js css).include?(asset_type)
378
- site.frontend_manifest["main.#{asset_type}"]
379
- else
380
- site.frontend_manifest.find do |item, _|
381
- item.sub(%r{^../(frontend/|src/)?}, "") == asset_type
382
- end&.last
383
- end
384
-
385
- return log_frontend_asset_error(site, asset_type) if asset_path.nil?
386
-
387
- static_frontend_path site, ["js", asset_path]
388
- end
389
-
390
319
  # Return an asset path based on the esbuild manifest file
391
320
  # @param site [Bridgetown::Site] The current site object
392
321
  # @param asset_type [String] js or css, or filename in manifest
393
322
  #
394
- # @return [String] Returns "MISSING_WEBPACK_MANIFEST" if the manifest
323
+ # @return [String] Returns "MISSING_ESBUILD_MANIFEST" if the manifest
395
324
  # file isnt found
396
325
  # @return [nil] Returns nil if the asset isnt found
397
326
  # @return [String] Returns the path to the asset if no issues parsing
@@ -442,9 +371,7 @@ module Bridgetown
442
371
  end
443
372
 
444
373
  def frontend_bundler_type(cwd = Dir.pwd)
445
- if File.exist?(File.join(cwd, "webpack.config.js"))
446
- :webpack
447
- elsif File.exist?(File.join(cwd, "esbuild.config.js"))
374
+ if File.exist?(File.join(cwd, "esbuild.config.js"))
448
375
  :esbuild
449
376
  else
450
377
  :unknown
@@ -484,11 +411,15 @@ module Bridgetown
484
411
  def live_reload_js(site) # rubocop:disable Metrics/MethodLength
485
412
  return "" unless Bridgetown.env.development? && !site.config.skip_live_reload
486
413
 
414
+ path = File.join(site.base_path, "/_bridgetown/live_reload")
487
415
  code = <<~JAVASCRIPT
488
416
  let lastmod = 0
489
- function startReloadConnection() {
490
- const evtSource = new EventSource("#{site.base_path(strip_slash_only: true)}/_bridgetown/live_reload")
491
- evtSource.onmessage = event => {
417
+ let reconnectAttempts = 0
418
+ function startLiveReload() {
419
+ const connection = new EventSource("#{path}")
420
+
421
+ connection.addEventListener("message", event => {
422
+ reconnectAttempts = 0
492
423
  if (document.querySelector("#bridgetown-build-error")) document.querySelector("#bridgetown-build-error").close()
493
424
  if (event.data == "reloaded!") {
494
425
  location.reload()
@@ -500,8 +431,9 @@ module Bridgetown
500
431
  lastmod = newmod
501
432
  }
502
433
  }
503
- }
504
- evtSource.addEventListener("builderror", event => {
434
+ })
435
+
436
+ connection.addEventListener("builderror", event => {
505
437
  let dialog = document.querySelector("#bridgetown-build-error")
506
438
  if (!dialog) {
507
439
  dialog = document.createElement("dialog")
@@ -518,19 +450,23 @@ module Bridgetown
518
450
  }
519
451
  dialog.querySelector("pre").textContent = JSON.parse(event.data)
520
452
  })
521
- evtSource.onerror = event => {
522
- if (evtSource.readyState === 2) {
523
- // reconnect with new object
524
- evtSource.close()
525
- console.warn("Live reload: attempting to reconnect in 3 seconds...")
526
453
 
527
- setTimeout(() => startReloadConnection(), 3000)
454
+ connection.addEventListener("error", () => {
455
+ if (connection.readyState === 2) {
456
+ // reconnect with new object
457
+ connection.close()
458
+ reconnectAttempts++
459
+ if (reconnectAttempts < 25) {
460
+ console.warn("Live reload: attempting to reconnect in 3 seconds...")
461
+ setTimeout(() => startLiveReload(), 3000)
462
+ } else {
463
+ console.error("Too many live reload connections failed. Refresh the page to try again.")
464
+ }
528
465
  }
529
- }
466
+ })
530
467
  }
531
- setTimeout(() => {
532
- startReloadConnection()
533
- }, 500)
468
+
469
+ startLiveReload()
534
470
  JAVASCRIPT
535
471
 
536
472
  %(<script type="module">#{code}</script>).html_safe
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Bridgetown
4
- VERSION = "1.3.4"
5
- CODE_NAME = "Kelly Butte"
4
+ VERSION = "2.0.0.beta1"
5
+ CODE_NAME = "(TBD!)"
6
6
  end
@@ -25,11 +25,11 @@ module Bridgetown
25
25
  Bridgetown::Hooks.trigger :site, :post_read, site
26
26
  block&.call(site)
27
27
  end
28
- end
29
28
 
30
- Bridgetown.logger.info "Watcher:", "enabled." unless options[:using_puma]
29
+ return
30
+ end
31
31
 
32
- return if options[:serving]
32
+ Bridgetown.logger.info "Watcher:", "enabled." unless options[:start_command]
33
33
 
34
34
  trap("INT") do
35
35
  self.shutdown = true
@@ -81,7 +81,12 @@ module Bridgetown
81
81
  c.each { |path| Bridgetown.logger.info "", "- #{path["#{site.root_dir}/".length..]}" }
82
82
  end
83
83
 
84
- reload_site(site, options, paths: c)
84
+ reload_site(
85
+ site,
86
+ options,
87
+ paths: c,
88
+ fast_refreshable: site.config.fast_refresh && (added + removed).empty?
89
+ )
85
90
  end.start
86
91
  end
87
92
 
@@ -90,23 +95,29 @@ module Bridgetown
90
95
  # @param site [Bridgetown::Site] the current site instance
91
96
  # @param options [Bridgetown::Configuration] the site configuration
92
97
  # @param paths Array<String>
93
- def reload_site(site, options, paths: []) # rubocop:todo Metrics/MethodLength
98
+ def reload_site(site, options, paths: [], fast_refreshable: false) # rubocop:todo Metrics/MethodLength
94
99
  begin
95
100
  time = Time.now
96
101
  I18n.reload! # make sure any locale files get read again
97
102
  Bridgetown::Current.sites[site.label] = site # needed in SSR mode apparently
98
103
  catch :halt do
99
- Bridgetown::Hooks.trigger :site, :pre_reload, site, paths
100
- Bridgetown::Hooks.clear_reloadable_hooks
101
- site.loaders_manager.reload_loaders
102
- Bridgetown::Hooks.trigger :site, :post_reload, site, paths
104
+ unless fast_refreshable
105
+ Bridgetown::Hooks.trigger :site, :pre_reload, site, paths
106
+ Bridgetown::Hooks.clear_reloadable_hooks
107
+ site.loaders_manager.reload_loaders
108
+ Bridgetown::Hooks.trigger :site, :post_reload, site, paths
109
+ end
103
110
 
104
111
  if site.ssr?
105
112
  site.reset(soft: true)
106
113
  return
107
114
  end
108
115
 
109
- site.process
116
+ if fast_refreshable
117
+ site.fast_refresh(paths, reload_if_needed: true)
118
+ else
119
+ site.process
120
+ end
110
121
  end
111
122
  Bridgetown.logger.info "Done! 🎉", "#{"Completed".bold.green} in less than " \
112
123
  "#{(Time.now - time).ceil(2)} seconds."