bridgetown-core 0.15.0.beta3 → 0.16.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (51) hide show
  1. checksums.yaml +4 -4
  2. data/Rakefile +14 -0
  3. data/bridgetown-core.gemspec +3 -0
  4. data/lib/bridgetown-core.rb +6 -1
  5. data/lib/bridgetown-core/commands/concerns/actions.rb +29 -23
  6. data/lib/bridgetown-core/commands/console.rb +12 -2
  7. data/lib/bridgetown-core/commands/serve.rb +5 -0
  8. data/lib/bridgetown-core/concerns/data_accessible.rb +19 -0
  9. data/lib/bridgetown-core/concerns/layout_placeable.rb +17 -0
  10. data/lib/bridgetown-core/concerns/liquid_renderable.rb +20 -0
  11. data/lib/bridgetown-core/concerns/publishable.rb +10 -0
  12. data/lib/bridgetown-core/concerns/site/configurable.rb +62 -31
  13. data/lib/bridgetown-core/concerns/site/content.rb +88 -29
  14. data/lib/bridgetown-core/concerns/site/extensible.rb +15 -12
  15. data/lib/bridgetown-core/concerns/site/processable.rb +12 -10
  16. data/lib/bridgetown-core/concerns/site/renderable.rb +22 -2
  17. data/lib/bridgetown-core/concerns/site/writable.rb +16 -2
  18. data/lib/bridgetown-core/concerns/validatable.rb +59 -0
  19. data/lib/bridgetown-core/configuration.rb +1 -0
  20. data/lib/bridgetown-core/converter.rb +34 -0
  21. data/lib/bridgetown-core/converters/erb_templates.rb +78 -0
  22. data/lib/bridgetown-core/converters/markdown.rb +6 -23
  23. data/lib/bridgetown-core/converters/smartypants.rb +0 -10
  24. data/lib/bridgetown-core/document.rb +8 -52
  25. data/lib/bridgetown-core/drops/document_drop.rb +9 -1
  26. data/lib/bridgetown-core/errors.rb +2 -0
  27. data/lib/bridgetown-core/excerpt.rb +1 -6
  28. data/lib/bridgetown-core/filters.rb +2 -0
  29. data/lib/bridgetown-core/layout.rb +24 -1
  30. data/lib/bridgetown-core/liquid_renderer/file_system.rb +1 -1
  31. data/lib/bridgetown-core/page.rb +34 -25
  32. data/lib/bridgetown-core/plugin_manager.rb +14 -5
  33. data/lib/bridgetown-core/regenerator.rb +1 -1
  34. data/lib/bridgetown-core/renderer.rb +38 -12
  35. data/lib/bridgetown-core/ruby_template_view.rb +98 -0
  36. data/lib/bridgetown-core/tags/class_map.rb +90 -0
  37. data/lib/bridgetown-core/tags/include.rb +2 -0
  38. data/lib/bridgetown-core/tags/render_content.rb +11 -1
  39. data/lib/bridgetown-core/tags/webpack_path.rb +19 -22
  40. data/lib/bridgetown-core/utils.rb +53 -0
  41. data/lib/bridgetown-core/version.rb +2 -2
  42. data/lib/site_template/bridgetown.config.yml +5 -3
  43. data/lib/site_template/src/_components/{footer.html → footer.liquid} +0 -0
  44. data/lib/site_template/src/_components/{head.html → head.liquid} +0 -0
  45. data/lib/site_template/src/_components/{navbar.html → navbar.liquid} +0 -0
  46. data/lib/site_template/src/_layouts/{default.html → default.liquid} +1 -1
  47. data/lib/site_template/src/_layouts/{home.html → home.liquid} +0 -0
  48. data/lib/site_template/src/_layouts/{page.html → page.liquid} +0 -0
  49. data/lib/site_template/src/_layouts/{post.html → post.liquid} +0 -0
  50. metadata +59 -10
  51. data/lib/bridgetown-core/concerns/convertible.rb +0 -235
@@ -2,8 +2,12 @@
2
2
 
3
3
  module Bridgetown
4
4
  class Document
5
- include Comparable
6
5
  extend Forwardable
6
+ include DataAccessible
7
+ include Comparable
8
+ include LayoutPlaceable
9
+ include LiquidRenderable
10
+ include Publishable
7
11
 
8
12
  attr_reader :path, :site, :extname, :collection, :type
9
13
  attr_accessor :content, :output
@@ -95,6 +99,9 @@ module Bridgetown
95
99
  @relative_path ||= path.sub("#{site.collections_path}/", "")
96
100
  end
97
101
 
102
+ # FIXME: spinning up a new Renderer object just to get an extension
103
+ # seems excessive
104
+ #
98
105
  # The output extension of the document.
99
106
  #
100
107
  # Returns the output extension
@@ -143,38 +150,6 @@ module Bridgetown
143
150
  YAML_FILE_EXTS.include?(extname)
144
151
  end
145
152
 
146
- # TODO: Depricated
147
- # Used to determine CoffeeScript and Sass/SCSS files.
148
- def asset_file?
149
- false
150
- end
151
-
152
- # Determine whether the file should be rendered with Liquid.
153
- #
154
- # Returns false if the document is either an asset file or a yaml file,
155
- # or if the document doesn't contain any Liquid Tags or Variables,
156
- # true otherwise.
157
- def render_with_liquid?
158
- return false if data["render_with_liquid"] == false
159
-
160
- !(yaml_file? || !Utils.has_liquid_construct?(content))
161
- end
162
-
163
- # Determine whether the file should be rendered with a layout.
164
- #
165
- # Returns true if the Front Matter specifies that `layout` is set to `none`.
166
- def no_layout?
167
- data["layout"] == "none"
168
- end
169
-
170
- # Determine whether the file should be placed into layouts.
171
- #
172
- # Returns false if the document is set to `layouts: none`, or is either an
173
- # asset file or a yaml file. Returns true otherwise.
174
- def place_in_layout?
175
- !(asset_file? || yaml_file? || no_layout?)
176
- end
177
-
178
153
  # The URL template where the document would be accessible.
179
154
  #
180
155
  # Returns the URL template for the document.
@@ -209,10 +184,6 @@ module Bridgetown
209
184
  ).to_s
210
185
  end
211
186
 
212
- def [](key)
213
- data[key]
214
- end
215
-
216
187
  # The full path to the output file.
217
188
  #
218
189
  # base_directory - the base path of the output directory
@@ -243,14 +214,6 @@ module Bridgetown
243
214
  trigger_hooks(:post_write)
244
215
  end
245
216
 
246
- # Whether the file is published or not, as indicated in YAML front-matter
247
- #
248
- # Returns 'false' if the 'published' key is specified in the
249
- # YAML front-matter and is 'false'. Otherwise returns 'true'.
250
- def published?
251
- !(data.key?("published") && data["published"] == false)
252
- end
253
-
254
217
  # Read in the file and assign the content and data based on the file contents.
255
218
  # Merge the frontmatter of the file with the frontmatter default
256
219
  # values
@@ -287,13 +250,6 @@ module Bridgetown
287
250
  "#<#{self.class} #{relative_path} collection=#{collection.label}>"
288
251
  end
289
252
 
290
- # The string representation for this document.
291
- #
292
- # Returns the content of the document
293
- def to_s
294
- output || content || "NO CONTENT"
295
- end
296
-
297
253
  # Compare this document against another document.
298
254
  # Comparison is a comparison between the 2 paths of the documents.
299
255
  #
@@ -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
 
@@ -16,5 +16,7 @@ module Bridgetown
16
16
  PostURLError = Class.new(FatalException)
17
17
  InvalidURLError = Class.new(FatalException)
18
18
  InvalidConfigurationError = Class.new(FatalException)
19
+
20
+ WebpackAssetError = Class.new(FatalException)
19
21
  end
20
22
  end
@@ -3,6 +3,7 @@
3
3
  module Bridgetown
4
4
  class Excerpt
5
5
  extend Forwardable
6
+ include LiquidRenderable
6
7
 
7
8
  attr_accessor :doc
8
9
  attr_accessor :content, :ext
@@ -91,12 +92,6 @@ module Bridgetown
91
92
  false
92
93
  end
93
94
 
94
- def render_with_liquid?
95
- return false if data["render_with_liquid"] == false
96
-
97
- !(yaml_file? || !Utils.has_liquid_construct?(content))
98
- end
99
-
100
95
  protected
101
96
 
102
97
  # Internal: Extract excerpt from the content
@@ -30,6 +30,7 @@ module Bridgetown
30
30
  ).convert(input.to_s)
31
31
  end
32
32
 
33
+ # TODO: This should be removed, there is no Sass converter
33
34
  # Convert a Sass string into CSS output.
34
35
  #
35
36
  # input - The Sass String to convert.
@@ -41,6 +42,7 @@ module Bridgetown
41
42
  ).convert(input)
42
43
  end
43
44
 
45
+ # TODO: This should be removed, there is no Scss converter
44
46
  # Convert a Scss string into CSS output.
45
47
  #
46
48
  # input - The Scss String to convert.
@@ -2,7 +2,9 @@
2
2
 
3
3
  module Bridgetown
4
4
  class Layout
5
- include Convertible
5
+ include DataAccessible
6
+ include LiquidRenderable
7
+ include Validatable
6
8
 
7
9
  # Gets the Site object.
8
10
  attr_reader :site
@@ -25,6 +27,12 @@ module Bridgetown
25
27
  # Gets/Sets the content of this layout.
26
28
  attr_accessor :content
27
29
 
30
+ # Gets/Sets the current document (for layout-compatible converters)
31
+ attr_accessor :current_document
32
+
33
+ # Gets/Sets the document output (for layout-compatible converters)
34
+ attr_accessor :current_document_output
35
+
28
36
  # Initialize a new Layout.
29
37
  #
30
38
  # site - The Site.
@@ -51,6 +59,14 @@ module Bridgetown
51
59
  read_yaml(base, name)
52
60
  end
53
61
 
62
+ # The inspect string for this document.
63
+ # Includes the relative path and the collection label.
64
+ #
65
+ # Returns the inspect string for this document.
66
+ def inspect
67
+ "#<#{self.class} #{@path}>"
68
+ end
69
+
54
70
  # Extract information from the layout filename.
55
71
  #
56
72
  # name - The String filename of the layout file.
@@ -59,5 +75,12 @@ module Bridgetown
59
75
  def process(name)
60
76
  self.ext = File.extname(name)
61
77
  end
78
+
79
+ # Provide this Layout's data to a Hash suitable for use by Liquid.
80
+ #
81
+ # Returns the Hash representation of this Layout.
82
+ def to_liquid
83
+ data
84
+ end
62
85
  end
63
86
  end
@@ -32,7 +32,7 @@ module Bridgetown
32
32
 
33
33
  # Last path in the list wins
34
34
  LiquidComponent.parse(
35
- ::File.read(found_paths.last, site.file_read_opts)
35
+ ::File.read(found_paths.last, **site.file_read_opts)
36
36
  ).content
37
37
  end
38
38
  end
@@ -2,7 +2,11 @@
2
2
 
3
3
  module Bridgetown
4
4
  class Page
5
- include Convertible
5
+ include DataAccessible
6
+ include LayoutPlaceable
7
+ include LiquidRenderable
8
+ include Publishable
9
+ include Validatable
6
10
 
7
11
  attr_writer :dir
8
12
  attr_accessor :site, :pager
@@ -11,15 +15,6 @@ module Bridgetown
11
15
 
12
16
  alias_method :extname, :ext
13
17
 
14
- # Attributes for Liquid templates
15
- ATTRIBUTES_FOR_LIQUID = %w(
16
- content
17
- dir
18
- name
19
- path
20
- url
21
- ).freeze
22
-
23
18
  # A set of extensions that are considered HTML or HTML-like so we
24
19
  # should not alter them, this includes .xhtml through XHTM5.
25
20
 
@@ -143,19 +138,6 @@ module Bridgetown
143
138
  self.basename = name[0..-ext.length - 1].gsub(%r!\.*\z!, "")
144
139
  end
145
140
 
146
- # Add any necessary layouts to this post
147
- #
148
- # layouts - The Hash of {"name" => "layout"}.
149
- # site_payload - The site payload Hash.
150
- #
151
- # Returns String rendered page.
152
- def render(layouts, site_payload)
153
- site_payload["page"] = to_liquid
154
- site_payload["paginator"] = pager.to_liquid
155
-
156
- do_layout(site_payload, layouts)
157
- end
158
-
159
141
  # The path to the source file
160
142
  #
161
143
  # Returns the path to the source file
@@ -165,7 +147,17 @@ module Bridgetown
165
147
 
166
148
  # The path to the page source file, relative to the site source
167
149
  def relative_path
168
- @relative_path ||= File.join(*[@dir, @name].map(&:to_s).reject(&:empty?)).sub(%r!\A\/!, "")
150
+ @relative_path ||= File.join(*[@dir, @name].map(&:to_s).reject(&:empty?)).delete_prefix("/")
151
+ end
152
+
153
+ # FIXME: spinning up a new Renderer object just to get an extension
154
+ # seems excessive
155
+ #
156
+ # The output extension of the page.
157
+ #
158
+ # Returns the output extension
159
+ def output_ext
160
+ @output_ext ||= Bridgetown::Renderer.new(site, self).output_ext
169
161
  end
170
162
 
171
163
  # Obtain destination path.
@@ -180,9 +172,22 @@ module Bridgetown
180
172
  path
181
173
  end
182
174
 
175
+ # Write the generated page file to the destination directory.
176
+ #
177
+ # dest - The String path to the destination dir.
178
+ #
179
+ # Returns nothing.
180
+ def write(dest)
181
+ path = destination(dest)
182
+ FileUtils.mkdir_p(File.dirname(path))
183
+ Bridgetown.logger.debug "Writing:", path
184
+ File.write(path, output, mode: "wb")
185
+ Bridgetown::Hooks.trigger :pages, :post_write, self
186
+ end
187
+
183
188
  # Returns the object as a debug String.
184
189
  def inspect
185
- "#<#{self.class} @relative_path=#{relative_path.inspect}>"
190
+ "#<#{self.class} #{relative_path}>"
186
191
  end
187
192
 
188
193
  # Returns the Boolean of whether this Page is HTML or not.
@@ -199,6 +204,10 @@ module Bridgetown
199
204
  Bridgetown::Hooks.trigger :pages, hook_name, self, *args
200
205
  end
201
206
 
207
+ def type
208
+ :pages
209
+ end
210
+
202
211
  def write?
203
212
  true
204
213
  end
@@ -3,6 +3,7 @@
3
3
  module Bridgetown
4
4
  class PluginManager
5
5
  PLUGINS_GROUP = :bridgetown_plugins
6
+ YARN_DEPENDENCY_REGEXP = %r!(.+)@([^@]*)$!.freeze
6
7
 
7
8
  attr_reader :site
8
9
 
@@ -67,12 +68,20 @@ module Bridgetown
67
68
  # If that exact package hasn't been installed, execute yarn add
68
69
  #
69
70
  # Returns nothing.
70
- def self.install_yarn_dependencies(required_gems)
71
+ def self.install_yarn_dependencies(required_gems, single_gemname = nil)
71
72
  return unless File.exist?("package.json")
72
73
 
73
74
  package_json = JSON.parse(File.read("package.json"))
74
75
 
75
- required_gems.each do |loaded_gem|
76
+ gems_to_search = if single_gemname
77
+ required_gems.select do |loaded_gem|
78
+ loaded_gem.to_spec&.name == single_gemname.to_s
79
+ end
80
+ else
81
+ required_gems
82
+ end
83
+
84
+ gems_to_search.each do |loaded_gem|
76
85
  yarn_dependency = find_yarn_dependency(loaded_gem)
77
86
  next unless add_yarn_dependency?(yarn_dependency, package_json)
78
87
 
@@ -83,10 +92,10 @@ module Bridgetown
83
92
  end
84
93
 
85
94
  def self.find_yarn_dependency(loaded_gem)
86
- yarn_dependency = loaded_gem.to_spec&.metadata&.dig("yarn-add")&.split("@")
87
- return nil if yarn_dependency&.length != 2
95
+ yarn_dependency = loaded_gem.to_spec&.metadata&.dig("yarn-add")&.match(YARN_DEPENDENCY_REGEXP)
96
+ return nil if yarn_dependency&.length != 3 || yarn_dependency[2] == ""
88
97
 
89
- yarn_dependency
98
+ yarn_dependency[1..2]
90
99
  end
91
100
 
92
101
  def self.add_yarn_dependency?(yarn_dependency, package_json)
@@ -163,7 +163,7 @@ module Bridgetown
163
163
  end
164
164
 
165
165
  def regenerate_page?(document)
166
- document.asset_file? || document.data["regenerate"] ||
166
+ document.data["regenerate"] ||
167
167
  source_modified_or_dest_missing?(
168
168
  site.in_source_dir(document.relative_path), document.destination(@site.dest)
169
169
  )
@@ -58,6 +58,7 @@ module Bridgetown
58
58
  Bridgetown.logger.debug "Rendering:", document.relative_path
59
59
 
60
60
  assign_pages!
61
+ # TODO: this can be eliminated I think:
61
62
  assign_current_document!
62
63
  assign_highlighter_options!
63
64
  assign_layout_data!
@@ -83,7 +84,7 @@ module Bridgetown
83
84
  end
84
85
 
85
86
  Bridgetown.logger.debug "Rendering Markup:", document.relative_path
86
- output = convert(output.to_s)
87
+ output = convert(output.to_s, document)
87
88
  document.content = output
88
89
 
89
90
  if document.place_in_layout?
@@ -140,9 +141,13 @@ module Bridgetown
140
141
  # Convert the document using the converters which match this renderer's document.
141
142
  #
142
143
  # Returns String the converted content.
143
- def convert(content)
144
+ def convert(content, document)
144
145
  converters.reduce(content) do |output, converter|
145
- converter.convert output
146
+ if converter.method(:convert).arity == 1
147
+ converter.convert output
148
+ else
149
+ converter.convert output, document
150
+ end
146
151
  rescue StandardError => e
147
152
  Bridgetown.logger.error "Conversion error:",
148
153
  "#{converter.class} encountered an error while "\
@@ -202,17 +207,38 @@ module Bridgetown
202
207
  # Render layout content into document.output
203
208
  #
204
209
  # Returns String rendered content
210
+ # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
205
211
  def render_layout(output, layout, liquid_context)
206
- payload["content"] = output
207
- payload["layout"] = Utils.deep_merge_hashes(layout.data, payload["layout"] || {})
208
-
209
- render_liquid(
210
- layout.content,
211
- payload,
212
- liquid_context,
213
- layout.path
214
- )
212
+ if layout.render_with_liquid?
213
+ payload["content"] = output
214
+ payload["layout"] = Utils.deep_merge_hashes(layout.data, payload["layout"] || {})
215
+
216
+ render_liquid(
217
+ layout.content,
218
+ payload,
219
+ liquid_context,
220
+ layout.path
221
+ )
222
+ else
223
+ layout_converters ||= site.converters.select { |c| c.matches(layout.ext) }.sort
224
+
225
+ layout_content = layout.content.dup
226
+ layout_converters.reduce(layout_content) do |layout_output, converter|
227
+ next(layout_output) unless converter.method(:convert).arity == 2
228
+
229
+ layout.current_document = document
230
+ layout.current_document_output = output
231
+ converter.convert layout_output, layout
232
+ rescue StandardError => e
233
+ Bridgetown.logger.error "Conversion error:",
234
+ "#{converter.class} encountered an error while "\
235
+ "converting '#{document.relative_path}':"
236
+ Bridgetown.logger.error("", e.to_s)
237
+ raise e
238
+ end
239
+ end
215
240
  end
241
+ # rubocop:enable Metrics/AbcSize, Metrics/MethodLength
216
242
 
217
243
  def add_regenerator_dependencies(layout)
218
244
  return unless document.write?