bridgetown-core 0.14.1 → 0.15.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (52) hide show
  1. checksums.yaml +4 -4
  2. data/Rakefile +3 -1
  3. data/bin/bridgetown +9 -23
  4. data/bridgetown-core.gemspec +3 -1
  5. data/lib/bridgetown-core.rb +9 -2
  6. data/lib/bridgetown-core/commands/apply.rb +73 -0
  7. data/lib/bridgetown-core/commands/base.rb +45 -0
  8. data/lib/bridgetown-core/commands/build.rb +91 -86
  9. data/lib/bridgetown-core/commands/clean.rb +30 -29
  10. data/lib/bridgetown-core/commands/concerns/actions.rb +128 -0
  11. data/lib/bridgetown-core/commands/concerns/build_options.rb +76 -0
  12. data/lib/bridgetown-core/commands/concerns/configuration_overridable.rb +18 -0
  13. data/lib/bridgetown-core/commands/concerns/summarizable.rb +13 -0
  14. data/lib/bridgetown-core/commands/console.rb +57 -39
  15. data/lib/bridgetown-core/commands/doctor.rb +126 -126
  16. data/lib/bridgetown-core/commands/new.rb +120 -155
  17. data/lib/bridgetown-core/commands/plugins.rb +167 -130
  18. data/lib/bridgetown-core/commands/registrations.rb +16 -0
  19. data/lib/bridgetown-core/commands/serve.rb +219 -215
  20. data/lib/bridgetown-core/concerns/convertible.rb +1 -4
  21. data/lib/bridgetown-core/concerns/site/renderable.rb +1 -2
  22. data/lib/bridgetown-core/drops/document_drop.rb +9 -1
  23. data/lib/bridgetown-core/drops/page_drop.rb +1 -1
  24. data/lib/bridgetown-core/excerpt.rb +4 -1
  25. data/lib/bridgetown-core/generators/prototype_generator.rb +2 -0
  26. data/lib/bridgetown-core/liquid_renderer.rb +1 -0
  27. data/lib/bridgetown-core/liquid_renderer/file.rb +1 -4
  28. data/lib/bridgetown-core/liquid_renderer/file_system.rb +3 -1
  29. data/lib/bridgetown-core/page.rb +3 -18
  30. data/lib/bridgetown-core/plugin_manager.rb +31 -17
  31. data/lib/bridgetown-core/renderer.rb +31 -18
  32. data/lib/bridgetown-core/tags/include.rb +14 -0
  33. data/lib/bridgetown-core/tags/render_content.rb +39 -16
  34. data/lib/bridgetown-core/tags/with.rb +15 -0
  35. data/lib/bridgetown-core/utils.rb +44 -0
  36. data/lib/bridgetown-core/version.rb +2 -2
  37. data/lib/bridgetown-core/watcher.rb +17 -10
  38. data/lib/site_template/Gemfile.erb +19 -0
  39. data/lib/site_template/bridgetown.config.yml +5 -3
  40. data/lib/site_template/package.json +1 -0
  41. data/lib/site_template/src/_components/footer.liquid +3 -0
  42. data/lib/site_template/src/_components/head.liquid +9 -0
  43. data/lib/site_template/src/{_includes/navbar.html → _components/navbar.liquid} +0 -0
  44. data/lib/site_template/src/_layouts/default.html +3 -3
  45. data/lib/site_template/start.js +1 -1
  46. data/lib/site_template/webpack.config.js +3 -3
  47. metadata +53 -19
  48. data/lib/bridgetown-core/command.rb +0 -112
  49. data/lib/bridgetown-core/commands/help.rb +0 -34
  50. data/lib/site_template/src/_components/.keep +0 -0
  51. data/lib/site_template/src/_includes/footer.html +0 -3
  52. data/lib/site_template/src/_includes/head.html +0 -9
@@ -188,13 +188,10 @@ module Bridgetown
188
188
  #
189
189
  # Returns nothing.
190
190
  def do_layout(payload, layouts)
191
- self.output = _renderer.tap do |renderer|
191
+ _renderer.tap do |renderer|
192
192
  renderer.layouts = layouts
193
193
  renderer.payload = payload
194
194
  end.run
195
-
196
- Bridgetown.logger.debug "Post-Render Hooks:", relative_path
197
- Bridgetown::Hooks.trigger hook_owner, :post_render, self
198
195
  ensure
199
196
  @_renderer = nil # this will allow the modifications above to disappear
200
197
  end
@@ -43,8 +43,7 @@ module Bridgetown
43
43
  def render_regenerated(document, payload)
44
44
  return unless regenerator.regenerate?(document)
45
45
 
46
- document.output = Bridgetown::Renderer.new(self, document, payload).run
47
- document.trigger_hooks(:post_render)
46
+ Bridgetown::Renderer.new(self, document, payload).run
48
47
  end
49
48
  end
50
49
  end
@@ -12,7 +12,15 @@ module Bridgetown
12
12
  mutable false
13
13
 
14
14
  def_delegator :@obj, :relative_path, :path
15
- def_delegators :@obj, :id, :output, :content, :to_s, :relative_path, :url, :date
15
+ def_delegators :@obj,
16
+ :id,
17
+ :output,
18
+ :content,
19
+ :to_s,
20
+ :relative_path,
21
+ :url,
22
+ :date,
23
+ :related_posts
16
24
 
17
25
  private def_delegator :@obj, :data, :fallback_data
18
26
 
@@ -7,7 +7,7 @@ module Bridgetown
7
7
 
8
8
  mutable false
9
9
 
10
- def_delegators :@obj, :content, :dir, :name, :path, :url
10
+ def_delegators :@obj, :content, :dir, :name, :path, :url, :pager
11
11
  private def_delegator :@obj, :data, :fallback_data
12
12
  end
13
13
  end
@@ -81,7 +81,10 @@ module Bridgetown
81
81
  end
82
82
 
83
83
  def output
84
- @output ||= Renderer.new(doc.site, self, site.site_payload).run
84
+ @output || (
85
+ Renderer.new(doc.site, self, site.site_payload).run
86
+ @output
87
+ )
85
88
  end
86
89
 
87
90
  def place_in_layout?
@@ -63,6 +63,8 @@ module Bridgetown
63
63
  new_page
64
64
  end
65
65
 
66
+ # TODO: this would be a great use of .try
67
+ # document.try(:collection).try(:label) == @configured_collection
66
68
  def terms_matching_pages(search_term)
67
69
  selected_docs = @site.documents.select do |document|
68
70
  document.respond_to?(:collection) && document.collection.label == @configured_collection
@@ -26,6 +26,7 @@ module Bridgetown
26
26
  def reset
27
27
  @stats = {}
28
28
  @cache = {}
29
+ Renderer.cached_partials = {}
29
30
  end
30
31
 
31
32
  def file(filename)
@@ -10,11 +10,8 @@ module Bridgetown
10
10
 
11
11
  def parse(content)
12
12
  measure_time do
13
- # Remove extraneous indentation for rendercontent tags
14
- processed_content = content.gsub(%r!^[ \t]+{%-? rendercontent!, "{% rendercontent")
15
-
16
13
  @renderer.cache[@filename] ||= Liquid::Template.parse(
17
- processed_content, line_numbers: true
14
+ content, line_numbers: true
18
15
  )
19
16
  end
20
17
  @template = @renderer.cache[@filename]
@@ -31,7 +31,9 @@ module Bridgetown
31
31
  raise Liquid::FileSystemError, "No such template '#{template_path}'" if found_paths.empty?
32
32
 
33
33
  # Last path in the list wins
34
- ::File.read(found_paths.last, site.file_read_opts)
34
+ LiquidComponent.parse(
35
+ ::File.read(found_paths.last, site.file_read_opts)
36
+ ).content
35
37
  end
36
38
  end
37
39
  end
@@ -73,18 +73,6 @@ module Bridgetown
73
73
  end
74
74
  end
75
75
 
76
- # For backwards-compatibility in subclasses that do not redefine
77
- # the `:to_liquid` method, stash existing definition under a new name
78
- #
79
- # TODO: Remove in Bridgetown 5.0
80
- alias_method :legacy_to_liquid, :to_liquid
81
- private :legacy_to_liquid
82
-
83
- # Private
84
- # Subclasses can choose to optimize their `:to_liquid` method by wrapping
85
- # it around this definition.
86
- #
87
- # TODO: Remove in Bridgetown 5.0
88
76
  def liquid_drop
89
77
  @liquid_drop ||= begin
90
78
  defaults = site.frontmatter_defaults.all(relative_path, type)
@@ -94,15 +82,12 @@ module Bridgetown
94
82
  Drops::PageDrop.new(self)
95
83
  end
96
84
  end
97
- private :liquid_drop
98
85
 
99
86
  # Public
100
87
  #
101
88
  # Liquid representation of current page
102
- #
103
- # TODO: Remove optional parameter in Bridgetown 5.0
104
- def to_liquid(attrs = nil)
105
- self.class == Bridgetown::Page ? liquid_drop : legacy_to_liquid(attrs)
89
+ def to_liquid
90
+ liquid_drop
106
91
  end
107
92
 
108
93
  # The full path and filename of the post. Defined in the YAML of the post
@@ -180,7 +165,7 @@ module Bridgetown
180
165
 
181
166
  # The path to the page source file, relative to the site source
182
167
  def relative_path
183
- @relative_path ||= File.join(*[@dir, @name].map(&:to_s).reject(&:empty?)).sub(%r!\A\/!, "")
168
+ @relative_path ||= File.join(*[@dir, @name].map(&:to_s).reject(&:empty?)).delete_prefix("/")
184
169
  end
185
170
 
186
171
  # Obtain destination path.
@@ -2,6 +2,9 @@
2
2
 
3
3
  module Bridgetown
4
4
  class PluginManager
5
+ PLUGINS_GROUP = :bridgetown_plugins
6
+ YARN_DEPENDENCY_REGEXP = %r!(.+)@([^@]*)$!.freeze
7
+
5
8
  attr_reader :site
6
9
 
7
10
  @source_manifests = Set.new
@@ -40,11 +43,9 @@ module Bridgetown
40
43
  if !ENV["BRIDGETOWN_NO_BUNDLER_REQUIRE"] && File.file?("Gemfile")
41
44
  require "bundler"
42
45
 
43
- group_name = :bridgetown_plugins
44
-
45
- required_gems = Bundler.require group_name
46
+ required_gems = Bundler.require PLUGINS_GROUP
46
47
  required_gems.select! do |dep|
47
- (dep.groups & [group_name]).any? && dep.should_include?
48
+ (dep.groups & [PLUGINS_GROUP]).any? && dep.should_include?
48
49
  end
49
50
 
50
51
  install_yarn_dependencies(required_gems)
@@ -67,30 +68,43 @@ module Bridgetown
67
68
  # If that exact package hasn't been installed, execute yarn add
68
69
  #
69
70
  # Returns nothing.
70
- # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity
71
71
  def self.install_yarn_dependencies(required_gems)
72
72
  return unless File.exist?("package.json")
73
73
 
74
74
  package_json = JSON.parse(File.read("package.json"))
75
75
 
76
76
  required_gems.each do |loaded_gem|
77
- next unless loaded_gem.to_spec&.metadata&.dig("yarn-add")
78
-
79
- yarn_add_dependency = loaded_gem.to_spec.metadata["yarn-add"].split("@")
80
- next unless yarn_add_dependency.length == 2
81
-
82
- # check matching version number is see if it's already installed
83
- if package_json["dependencies"]
84
- current_package = package_json["dependencies"].dig(yarn_add_dependency.first)
85
- next unless current_package.nil? || current_package != yarn_add_dependency.last
86
- end
77
+ yarn_dependency = find_yarn_dependency(loaded_gem)
78
+ next unless add_yarn_dependency?(yarn_dependency, package_json)
87
79
 
88
80
  # all right, time to install the package
89
- cmd = "yarn add #{yarn_add_dependency.join("@")}"
81
+ cmd = "yarn add #{yarn_dependency.join("@")}"
90
82
  system cmd
91
83
  end
92
84
  end
93
- # rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity
85
+
86
+ def self.find_yarn_dependency(loaded_gem)
87
+ yarn_dependency = loaded_gem.to_spec&.metadata&.dig("yarn-add")&.match(YARN_DEPENDENCY_REGEXP)
88
+ return nil if yarn_dependency&.length != 3 || yarn_dependency[2] == ""
89
+
90
+ yarn_dependency[1..2]
91
+ end
92
+
93
+ def self.add_yarn_dependency?(yarn_dependency, package_json)
94
+ return false if yarn_dependency.nil?
95
+
96
+ # check matching version number is see if it's already installed
97
+ if package_json["dependencies"]
98
+ current_version = package_json["dependencies"].dig(yarn_dependency.first)
99
+ package_requires_updating?(current_version, yarn_dependency.last)
100
+ else
101
+ true
102
+ end
103
+ end
104
+
105
+ def self.package_requires_updating?(current_version, dep_version)
106
+ current_version.nil? || current_version != dep_version && !current_version.include?("/")
107
+ end
94
108
 
95
109
  # Require all .rb files
96
110
  #
@@ -5,11 +5,16 @@ module Bridgetown
5
5
  attr_reader :document, :site
6
6
  attr_writer :layouts, :payload
7
7
 
8
+ class << self
9
+ attr_accessor :cached_partials
10
+ end
11
+
8
12
  def initialize(site, document, site_payload = nil)
9
13
  @site = site
10
14
  @document = document
11
15
  @payload = site_payload
12
16
  @layouts = nil
17
+ self.class.cached_partials ||= {}
13
18
  end
14
19
 
15
20
  # Fetches the payload used in Liquid rendering.
@@ -48,7 +53,7 @@ module Bridgetown
48
53
 
49
54
  # Prepare payload and render the document
50
55
  #
51
- # Returns String rendered document output
56
+ # Returns nothing
52
57
  def run
53
58
  Bridgetown.logger.debug "Rendering:", document.relative_path
54
59
 
@@ -58,8 +63,8 @@ module Bridgetown
58
63
  assign_layout_data!
59
64
 
60
65
  document.trigger_hooks(:pre_render, payload)
61
-
62
- render_document
66
+ document.output = render_document
67
+ document.trigger_hooks(:post_render)
63
68
  end
64
69
 
65
70
  # Render the document.
@@ -67,18 +72,14 @@ module Bridgetown
67
72
  # Returns String rendered document output
68
73
  # rubocop: disable Metrics/AbcSize
69
74
  def render_document
70
- info = {
71
- registers: { site: site, page: payload["page"] },
72
- strict_filters: liquid_options["strict_filters"],
73
- strict_variables: liquid_options["strict_variables"],
74
- }
75
+ liquid_context = provide_liquid_context
75
76
 
76
77
  execute_inline_ruby!
77
78
 
78
79
  output = document.content
79
80
  if document.render_with_liquid?
80
81
  Bridgetown.logger.debug "Rendering Liquid:", document.relative_path
81
- output = render_liquid(output, payload, info, document.path)
82
+ output = render_liquid(output, payload, liquid_context, document.path)
82
83
  end
83
84
 
84
85
  Bridgetown.logger.debug "Rendering Markup:", document.relative_path
@@ -87,12 +88,24 @@ module Bridgetown
87
88
 
88
89
  if document.place_in_layout?
89
90
  Bridgetown.logger.debug "Rendering Layout:", document.relative_path
90
- output = place_in_layouts(output, payload, info)
91
+ output = place_in_layouts(output, payload, liquid_context)
91
92
  end
92
93
 
93
94
  output
94
95
  end
95
96
 
97
+ def provide_liquid_context
98
+ {
99
+ registers: {
100
+ site: site,
101
+ page: payload["page"],
102
+ cached_partials: self.class.cached_partials,
103
+ },
104
+ strict_filters: liquid_options["strict_filters"],
105
+ strict_variables: liquid_options["strict_variables"],
106
+ }
107
+ end
108
+
96
109
  def execute_inline_ruby!
97
110
  return unless site.config.should_execute_inline_ruby?
98
111
 
@@ -101,21 +114,21 @@ module Bridgetown
101
114
 
102
115
  # rubocop: enable Metrics/AbcSize
103
116
 
104
- # Render the given content with the payload and info
117
+ # Render the given content with the payload and context
105
118
  #
106
119
  # content -
107
120
  # payload -
108
- # info -
121
+ # context -
109
122
  # path - (optional) the path to the file, for use in ex
110
123
  #
111
124
  # Returns String the content, rendered by Liquid.
112
- def render_liquid(content, payload, info, path = nil)
125
+ def render_liquid(content, payload, liquid_context, path = nil)
113
126
  template = site.liquid_renderer.file(path).parse(content)
114
127
  template.warnings.each do |e|
115
128
  Bridgetown.logger.warn "Liquid Warning:",
116
129
  LiquidRenderer.format_error(e, path || document.relative_path)
117
130
  end
118
- template.render!(payload, info)
131
+ template.render!(payload, liquid_context)
119
132
  # rubocop: disable Lint/RescueException
120
133
  rescue Exception => e
121
134
  Bridgetown.logger.error "Liquid Exception:",
@@ -151,7 +164,7 @@ module Bridgetown
151
164
  # Render layouts and place document content inside.
152
165
  #
153
166
  # Returns String rendered content
154
- def place_in_layouts(content, payload, info)
167
+ def place_in_layouts(content, payload, liquid_context)
155
168
  output = content.dup
156
169
  layout = layouts[document.data["layout"].to_s]
157
170
  validate_layout(layout)
@@ -162,7 +175,7 @@ module Bridgetown
162
175
  payload["layout"] = nil
163
176
 
164
177
  while layout
165
- output = render_layout(output, layout, info)
178
+ output = render_layout(output, layout, liquid_context)
166
179
  add_regenerator_dependencies(layout)
167
180
 
168
181
  next unless (layout = site.layouts[layout.data["layout"]])
@@ -189,14 +202,14 @@ module Bridgetown
189
202
  # Render layout content into document.output
190
203
  #
191
204
  # Returns String rendered content
192
- def render_layout(output, layout, info)
205
+ def render_layout(output, layout, liquid_context)
193
206
  payload["content"] = output
194
207
  payload["layout"] = Utils.deep_merge_hashes(layout.data, payload["layout"] || {})
195
208
 
196
209
  render_liquid(
197
210
  layout.content,
198
211
  payload,
199
- info,
212
+ liquid_context,
200
213
  layout.path
201
214
  )
202
215
  end
@@ -3,6 +3,10 @@
3
3
  module Bridgetown
4
4
  module Tags
5
5
  class IncludeTag < Liquid::Tag
6
+ class << self
7
+ attr_accessor :deprecation_message_shown
8
+ end
9
+
6
10
  VALID_SYNTAX = %r!
7
11
  ([\w-]+)\s*=\s*
8
12
  (?:"([^"\\]*(?:\\.[^"\\]*)*)"|'([^'\\]*(?:\\.[^'\\]*)*)'|([\w\.-]+))
@@ -18,6 +22,14 @@ module Bridgetown
18
22
 
19
23
  def initialize(tag_name, markup, tokens)
20
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
+
21
33
  matched = markup.strip.match(VARIABLE_SYNTAX)
22
34
  if matched
23
35
  @file = matched["variable"].strip
@@ -200,7 +212,9 @@ module Bridgetown
200
212
  else
201
213
  File.join(site.config["collections_dir"], page_payload["path"])
202
214
  end
215
+ # rubocop:disable Performance/DeleteSuffix
203
216
  resource_path.sub!(%r!/#excerpt\z!, "")
217
+ # rubocop:enable Performance/DeleteSuffix
204
218
  site.in_source_dir File.dirname(resource_path)
205
219
  end
206
220
  end
@@ -3,28 +3,51 @@
3
3
  module Bridgetown
4
4
  module Tags
5
5
  class BlockRenderTag < Liquid::Block
6
- def initialize(tag_name, markup, options)
7
- super
6
+ # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
7
+ def render(context)
8
+ context.stack({}) do
9
+ # unindent the incoming text
10
+ content = Bridgetown::Utils.reindent_for_markdown(super)
8
11
 
9
- @tag = tag_name
10
- @markup = markup
11
- @options = options
12
- end
12
+ regions = gather_content_regions(context)
13
13
 
14
- def render(context)
15
- content = super.gsub(%r!^[ \t]+!, "") # unindent the incoming text
14
+ site = context.registers[:site]
15
+ converter = site.find_converter_instance(Bridgetown::Converters::Markdown)
16
+ markdownified_content = converter.convert(content)
17
+ context["processed_component_content"] = markdownified_content
16
18
 
17
- site = context.registers[:site]
18
- converter = site.find_converter_instance(Bridgetown::Converters::Markdown)
19
- markdownified_content = converter.convert(content)
19
+ render_params = [@markup, "content: processed_component_content"]
20
+ unless regions.empty?
21
+ regions.each do |region_name, region_content|
22
+ region_name = region_name.sub("content_with_region_", "")
20
23
 
21
- context.stack do
22
- context["componentcontent"] = markdownified_content
23
- render_params = "#{@markup}, content: componentcontent"
24
- render_tag = Liquid::Render.parse("render", render_params, @options, @parse_context)
25
- render_tag.render_tag(context, +"")
24
+ if region_name.end_with? ":markdown"
25
+ region_name.sub!(%r!:markdown$!, "")
26
+ context[region_name] = converter.convert(
27
+ Bridgetown::Utils.reindent_for_markdown(region_content)
28
+ )
29
+ else
30
+ context[region_name] = region_content
31
+ end
32
+ render_params.push "#{region_name}: #{region_name}"
33
+ end
34
+ end
35
+
36
+ Liquid::Render.parse("render", render_params.join(","), nil, @parse_context)
37
+ .render_tag(context, +"")
26
38
  end
27
39
  end
40
+ # rubocop:enable Metrics/AbcSize, Metrics/MethodLength
41
+
42
+ private
43
+
44
+ def gather_content_regions(context)
45
+ unless context.scopes[0].keys.find { |k| k.to_s.start_with? "content_with_region_" }
46
+ return {}
47
+ end
48
+
49
+ context.scopes[0].select { |k| k.to_s.start_with? "content_with_region_" }
50
+ end
28
51
  end
29
52
  end
30
53
  end