bridgetown-core 0.19.3 → 0.20.0

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 (67) hide show
  1. checksums.yaml +4 -4
  2. data/bridgetown-core.gemspec +1 -1
  3. data/lib/bridgetown-core.rb +30 -11
  4. data/lib/bridgetown-core/cleaner.rb +7 -1
  5. data/lib/bridgetown-core/collection.rb +173 -77
  6. data/lib/bridgetown-core/commands/base.rb +9 -0
  7. data/lib/bridgetown-core/commands/configure.rb +4 -0
  8. data/lib/bridgetown-core/commands/console.rb +4 -0
  9. data/lib/bridgetown-core/concerns/data_accessible.rb +1 -0
  10. data/lib/bridgetown-core/concerns/site/configurable.rb +7 -3
  11. data/lib/bridgetown-core/concerns/site/content.rb +57 -15
  12. data/lib/bridgetown-core/concerns/site/processable.rb +1 -0
  13. data/lib/bridgetown-core/concerns/site/renderable.rb +26 -0
  14. data/lib/bridgetown-core/concerns/site/writable.rb +11 -1
  15. data/lib/bridgetown-core/concerns/validatable.rb +1 -0
  16. data/lib/bridgetown-core/configuration.rb +39 -19
  17. data/lib/bridgetown-core/converter.rb +14 -0
  18. data/lib/bridgetown-core/converters/identity.rb +0 -9
  19. data/lib/bridgetown-core/converters/markdown.rb +14 -4
  20. data/lib/bridgetown-core/converters/markdown/kramdown_parser.rb +3 -0
  21. data/lib/bridgetown-core/current.rb +10 -0
  22. data/lib/bridgetown-core/document.rb +6 -14
  23. data/lib/bridgetown-core/drops/collection_drop.rb +1 -1
  24. data/lib/bridgetown-core/drops/page_drop.rb +4 -0
  25. data/lib/bridgetown-core/drops/resource_drop.rb +81 -0
  26. data/lib/bridgetown-core/drops/site_drop.rb +33 -8
  27. data/lib/bridgetown-core/drops/unified_payload_drop.rb +4 -0
  28. data/lib/bridgetown-core/entry_filter.rb +10 -23
  29. data/lib/bridgetown-core/errors.rb +0 -2
  30. data/lib/bridgetown-core/filters.rb +2 -1
  31. data/lib/bridgetown-core/generators/prototype_generator.rb +37 -19
  32. data/lib/bridgetown-core/layout.rb +2 -2
  33. data/lib/bridgetown-core/liquid_renderer/file.rb +1 -0
  34. data/lib/bridgetown-core/liquid_renderer/table.rb +1 -0
  35. data/lib/bridgetown-core/model/base.rb +138 -0
  36. data/lib/bridgetown-core/model/builder_origin.rb +40 -0
  37. data/lib/bridgetown-core/model/file_origin.rb +119 -0
  38. data/lib/bridgetown-core/model/origin.rb +38 -0
  39. data/lib/bridgetown-core/page.rb +9 -1
  40. data/lib/bridgetown-core/plugin_manager.rb +0 -2
  41. data/lib/bridgetown-core/publisher.rb +7 -1
  42. data/lib/bridgetown-core/reader.rb +25 -12
  43. data/lib/bridgetown-core/readers/data_reader.rb +3 -4
  44. data/lib/bridgetown-core/readers/post_reader.rb +1 -1
  45. data/lib/bridgetown-core/regenerator.rb +8 -1
  46. data/lib/bridgetown-core/related_posts.rb +1 -1
  47. data/lib/bridgetown-core/renderer.rb +5 -12
  48. data/lib/bridgetown-core/resource/base.rb +275 -0
  49. data/lib/bridgetown-core/resource/destination.rb +49 -0
  50. data/lib/bridgetown-core/resource/permalink_processor.rb +179 -0
  51. data/lib/bridgetown-core/resource/taxonomy_term.rb +25 -0
  52. data/lib/bridgetown-core/resource/taxonomy_type.rb +47 -0
  53. data/lib/bridgetown-core/resource/transformer.rb +173 -0
  54. data/lib/bridgetown-core/ruby_template_view.rb +4 -0
  55. data/lib/bridgetown-core/site.rb +9 -1
  56. data/lib/bridgetown-core/static_file.rb +33 -10
  57. data/lib/bridgetown-core/url.rb +1 -0
  58. data/lib/bridgetown-core/utils.rb +40 -40
  59. data/lib/bridgetown-core/utils/platforms.rb +1 -0
  60. data/lib/bridgetown-core/version.rb +2 -2
  61. data/lib/site_template/webpack.config.js.erb +8 -6
  62. metadata +28 -21
  63. data/lib/bridgetown-core/page_without_a_file.rb +0 -17
  64. data/lib/bridgetown-core/readers/collection_reader.rb +0 -23
  65. data/lib/bridgetown-core/utils/exec.rb +0 -26
  66. data/lib/bridgetown-core/utils/internet.rb +0 -37
  67. data/lib/bridgetown-core/utils/win_tz.rb +0 -75
@@ -25,6 +25,15 @@ module Bridgetown
25
25
  end
26
26
  end
27
27
 
28
+ desc "dream", "There's a place where that idea still exists as a reality"
29
+ def dream
30
+ puts ""
31
+ puts "🎶 The Dream of the 90s is Alive in Portland... ✨"
32
+ puts " https://youtu.be/U4hShMEk1Ew"
33
+ puts " https://youtu.be/0_HGqPGp9iY"
34
+ puts ""
35
+ end
36
+
28
37
  desc "help <command>", "Show detailed command usage information and exit"
29
38
  def help(subcommand = nil)
30
39
  if subcommand && respond_to?(subcommand)
@@ -50,6 +50,10 @@ module Bridgetown
50
50
  configuration = set_color configuration, :blue, :bold
51
51
  say configuration
52
52
  end
53
+ say "\n"
54
+
55
+ docs_url = "https://www.bridgetownrb.com/docs/bundled-configurations".yellow.bold
56
+ say "For more info, check out the docs at: #{docs_url}"
53
57
  end
54
58
 
55
59
  def configurations
@@ -28,6 +28,7 @@ module Bridgetown
28
28
 
29
29
  def console
30
30
  require "irb"
31
+ require "irb/ext/save-history"
31
32
  require "amazing_print" unless options[:"bypass-ap"]
32
33
 
33
34
  Bridgetown.logger.info "Starting:", "Bridgetown v#{Bridgetown::VERSION.magenta}" \
@@ -50,6 +51,7 @@ module Bridgetown
50
51
  IRB.setup(nil)
51
52
  workspace = IRB::WorkSpace.new
52
53
  irb = IRB::Irb.new(workspace)
54
+ IRB.conf[:IRB_RC]&.call(irb.context)
53
55
  IRB.conf[:MAIN_CONTEXT] = irb.context
54
56
  eval("site = $BRIDGETOWN_SITE", workspace.binding, __FILE__, __LINE__)
55
57
  Bridgetown.logger.info "Console:", "Now loaded as " + "site".cyan + " variable."
@@ -68,6 +70,8 @@ module Bridgetown
68
70
  end
69
71
  irb.eval_input
70
72
  end
73
+ ensure
74
+ IRB.conf[:AT_EXIT].each(&:call)
71
75
  end
72
76
  end
73
77
  end
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Bridgetown
4
+ # TODO: to be retired once the Resource engine is made official
4
5
  module DataAccessible
5
6
  # Returns the contents as a String.
6
7
  def to_s
@@ -30,11 +30,15 @@ class Bridgetown::Site
30
30
  configure_include_paths
31
31
  configure_file_read_opts
32
32
 
33
- self.permalink_style = config["permalink"].to_sym
33
+ self.permalink_style = (config["permalink"] || "pretty").to_sym
34
34
 
35
35
  @config
36
36
  end
37
37
 
38
+ def uses_resource?
39
+ config[:content_engine] == "resource"
40
+ end
41
+
38
42
  def defaults_reader
39
43
  @defaults_reader ||= Bridgetown::DefaultsReader.new(self)
40
44
  end
@@ -78,7 +82,7 @@ class Bridgetown::Site
78
82
  # @return [Array<String>] Return an array of updated paths if multiple paths given.
79
83
  def in_root_dir(*paths)
80
84
  paths.reduce(root_dir) do |base, path|
81
- Bridgetown.sanitized_path(base, path)
85
+ Bridgetown.sanitized_path(base, path.to_s)
82
86
  end
83
87
  end
84
88
 
@@ -91,7 +95,7 @@ class Bridgetown::Site
91
95
  # @return [Array<String>] Return an array of updated paths if multiple paths given.
92
96
  def in_source_dir(*paths)
93
97
  paths.reduce(source) do |base, path|
94
- Bridgetown.sanitized_path(base, path)
98
+ Bridgetown.sanitized_path(base, path.to_s)
95
99
  end
96
100
  end
97
101
 
@@ -32,6 +32,18 @@ class Bridgetown::Site
32
32
  end
33
33
  end
34
34
 
35
+ def resources_grouped_by_taxonomy(taxonomy)
36
+ @post_attr_hash[taxonomy.label] ||= begin
37
+ taxonomy.terms.transform_values { |terms| terms.map(&:resource).sort.reverse }
38
+ end
39
+ end
40
+
41
+ def taxonomies
42
+ taxonomy_types.transform_values do |taxonomy|
43
+ resources_grouped_by_taxonomy(taxonomy)
44
+ end
45
+ end
46
+
35
47
  # Returns a hash of "tags" using {#post_attr_hash} where each tag is a key
36
48
  # and each value is a post which contains the key.
37
49
  # @example
@@ -41,7 +53,7 @@ class Bridgetown::Site
41
53
  # @return [Hash{String, Array<Post>}] Returns a hash of all tags and their corresponding posts
42
54
  # @see post_attr_hash
43
55
  def tags
44
- post_attr_hash("tags")
56
+ uses_resource? ? taxonomies.tag : post_attr_hash("tags")
45
57
  end
46
58
 
47
59
  # Returns a hash of "categories" using {#post_attr_hash} where each tag is
@@ -54,7 +66,7 @@ class Bridgetown::Site
54
66
  # their corresponding posts
55
67
  # @see post_attr_hash
56
68
  def categories
57
- post_attr_hash("categories")
69
+ uses_resource? ? taxonomies.category : post_attr_hash("categories")
58
70
  end
59
71
 
60
72
  # Returns the value of `data["site_metadata"]` or creates a new instance of
@@ -121,19 +133,25 @@ class Bridgetown::Site
121
133
  # An array of collection names.
122
134
  # @return [Array<String>] an array of collection names from the configuration,
123
135
  # or an empty array if the `config["collections"]` key is not set.
124
- # @raise ArgumentError Raise an error if `config["collections"]` is not
125
- # an Array or a Hash
126
136
  def collection_names
127
- case config["collections"]
128
- when Hash
129
- config["collections"].keys
130
- when Array
131
- config["collections"]
132
- when nil
133
- []
134
- else
135
- raise ArgumentError, "Your `collections` key must be a hash or an array."
136
- end
137
+ Array(config.collections&.keys)
138
+ end
139
+
140
+ # @return [Array<Bridgetown::Resource::TaxonomyType>]
141
+ def taxonomy_types
142
+ @taxonomy_types ||= config.taxonomies.map do |label, key_or_metadata|
143
+ key = key_or_metadata
144
+ tax_metadata = if key_or_metadata.is_a? Hash
145
+ key = key_or_metadata["key"]
146
+ key_or_metadata.reject { |k| k == "key" }
147
+ else
148
+ HashWithDotAccess::Hash.new
149
+ end
150
+
151
+ [label, Bridgetown::Resource::TaxonomyType.new(
152
+ site: self, label: label, key: key, metadata: tax_metadata
153
+ ),]
154
+ end.to_h.with_dot_access
137
155
  end
138
156
 
139
157
  # Get all documents.
@@ -155,11 +173,29 @@ class Bridgetown::Site
155
173
  documents.select(&:write?)
156
174
  end
157
175
 
158
- # Get all posts.
176
+ # Get all documents.
177
+ # @return [Array<Document>] an array of documents from the
178
+ # configuration
179
+ def resources
180
+ collections.each_with_object(Set.new) do |(_, collection), set|
181
+ set.merge(collection.resources)
182
+ end.to_a
183
+ end
184
+
185
+ def resources_to_write
186
+ resources.select(&:write?)
187
+ end
188
+
189
+ # Get all posts. Deprecated, to be removed in v1.0.
159
190
  #
160
191
  # @return [Collection] Returns {#collections}`["posts"]`, creating it if need be
161
192
  # @see Collection
162
193
  def posts
194
+ unless @wrote_deprecation_msg
195
+ Bridgetown::Deprecator.deprecation_message "Call site.collections.posts " \
196
+ "instead of site.posts (Ruby code)"
197
+ end
198
+ @wrote_deprecation_msg ||= true
163
199
  collections["posts"] ||= Bridgetown::Collection.new(self, "posts")
164
200
  end
165
201
 
@@ -177,7 +213,13 @@ class Bridgetown::Site
177
213
  #
178
214
  # @return [Array]
179
215
  def contents
216
+ return resources if uses_resource?
217
+
180
218
  pages + documents
181
219
  end
220
+
221
+ def add_generated_page(generated_page)
222
+ generated_pages << generated_page
223
+ end
182
224
  end
183
225
  end
@@ -11,6 +11,7 @@ class Bridgetown::Site
11
11
  # @see #cleanup
12
12
  # @see #write
13
13
  def process
14
+ Bridgetown::Current.site = self
14
15
  reset
15
16
  read
16
17
  generate # Extensible
@@ -29,6 +29,26 @@ class Bridgetown::Site
29
29
  end
30
30
  end
31
31
 
32
+ def matched_converters_for_convertible(convertible)
33
+ @layout_converters ||= {}
34
+
35
+ if convertible.is_a?(Bridgetown::Layout) && @layout_converters[convertible]
36
+ return @layout_converters[convertible]
37
+ end
38
+
39
+ matches = converters.select do |converter|
40
+ if converter.method(:matches).arity == 1
41
+ converter.matches(convertible.extname)
42
+ else
43
+ converter.matches(convertible.extname, convertible)
44
+ end
45
+ end
46
+
47
+ @layout_converters[convertible] = matches if convertible.is_a?(Bridgetown::Layout)
48
+
49
+ matches
50
+ end
51
+
32
52
  # Renders all documents
33
53
  # @return [void]
34
54
  def render_docs
@@ -38,6 +58,12 @@ class Bridgetown::Site
38
58
  render_regenerated document
39
59
  end
40
60
  end
61
+
62
+ collection.resources.each do |resource|
63
+ render_with_locale(resource) do
64
+ resource.transform!
65
+ end
66
+ end
41
67
  end
42
68
  end
43
69
 
@@ -27,11 +27,21 @@ class Bridgetown::Site
27
27
  #
28
28
  # @return [void]
29
29
  def each_site_file
30
- %w(pages static_files_to_write docs_to_write).each do |type|
30
+ %w(pages static_files_to_write docs_to_write resources_to_write).each do |type|
31
31
  send(type).each do |item|
32
32
  yield item
33
33
  end
34
34
  end
35
35
  end
36
+
37
+ def resources_cache_manifest
38
+ resources.each_with_object({}) do |resource, hsh|
39
+ next if resource.relative_url == ""
40
+
41
+ hsh[resource.relative_url] = {
42
+ id: resource.model.id,
43
+ }
44
+ end
45
+ end
36
46
  end
37
47
  end
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Bridgetown
4
+ # TODO: to be retired once the Resource engine is made official
4
5
  module Validatable
5
6
  # FIXME: there should be ONE TRUE METHOD to read the YAML frontmatter
6
7
  # in the entire project. Both this and the equivalent Document method
@@ -23,6 +23,9 @@ module Bridgetown
23
23
  "includes_dir" => "_includes",
24
24
  "partials_dir" => "_partials",
25
25
  "collections" => {},
26
+ "taxonomies" => {
27
+ category: { key: "categories", title: "Category" }, tag: { key: "tags", title: "Tag" },
28
+ },
26
29
 
27
30
  # Handling Reading
28
31
  "include" => [".htaccess", "_redirects", ".well-known"],
@@ -32,6 +35,7 @@ module Bridgetown
32
35
  "markdown_ext" => "markdown,mkdown,mkdn,mkd,md",
33
36
  "strict_front_matter" => false,
34
37
  "slugify_categories" => true,
38
+ "slugify_mode" => "pretty",
35
39
 
36
40
  # Filtering Content
37
41
  "limit_posts" => 0,
@@ -56,7 +60,7 @@ module Bridgetown
56
60
  # Output Configuration
57
61
  "available_locales" => ["en"],
58
62
  "default_locale" => "en",
59
- "permalink" => "date",
63
+ "permalink" => nil, # default is set according to content engine
60
64
  "timezone" => nil, # use the local timezone
61
65
 
62
66
  "quiet" => false,
@@ -95,8 +99,8 @@ module Bridgetown
95
99
  # user_config - a Hash or Configuration of overrides.
96
100
  #
97
101
  # Returns a Configuration filled with defaults.
98
- def from(user_config)
99
- Utils.deep_merge_hashes(DEFAULTS, Configuration[user_config])
102
+ def from(user_config, starting_defaults = DEFAULTS)
103
+ Utils.deep_merge_hashes(starting_defaults.deep_dup, Configuration[user_config])
100
104
  .merge_environment_specific_options!
101
105
  .add_default_collections
102
106
  .add_default_excludes
@@ -242,23 +246,38 @@ module Bridgetown
242
246
  self
243
247
  end
244
248
 
245
- def add_default_collections
249
+ def add_default_collections # rubocop:todo all
246
250
  # It defaults to `{}`, so this is only if someone sets it to null manually.
247
- return self if self["collections"].nil?
251
+ return self if self[:collections].nil?
248
252
 
249
253
  # Ensure we have a hash.
250
- if self["collections"].is_a?(Array)
251
- self["collections"] = self["collections"].each_with_object({}) do |collection, hash|
254
+ if self[:collections].is_a?(Array)
255
+ self[:collections] = self[:collections].each_with_object({}) do |collection, hash|
252
256
  hash[collection] = {}
253
257
  end
254
258
  end
255
259
 
256
- self["collections"] = Utils.deep_merge_hashes(
257
- { "posts" => {} }, self["collections"]
258
- ).tap do |collections|
259
- collections["posts"]["output"] = true
260
- if self["permalink"]
261
- collections["posts"]["permalink"] ||= style_to_permalink(self["permalink"])
260
+ # Setup default collections
261
+ self[:collections][:posts] = {} unless self[:collections][:posts]
262
+ self[:collections][:posts][:output] = true
263
+ self[:collections][:posts][:sort_direction] ||= "descending"
264
+
265
+ if self[:content_engine] == "resource"
266
+ self[:permalink] = "pretty" if self[:permalink].blank?
267
+ self[:collections][:pages] = {} unless self[:collections][:pages]
268
+ self[:collections][:pages][:output] = true
269
+ self[:collections][:pages][:permalink] ||= "/:path/"
270
+
271
+ self[:collections][:data] = {} unless self[:collections][:data]
272
+ self[:collections][:data][:output] = false
273
+
274
+ unless self[:collections][:posts][:permalink]
275
+ self[:collections][:posts][:permalink] = self[:permalink]
276
+ end
277
+ else
278
+ self[:permalink] = "date" if self[:permalink].blank?
279
+ unless self[:collections][:posts][:permalink]
280
+ self[:collections][:posts][:permalink] = style_to_permalink(self[:permalink])
262
281
  end
263
282
  end
264
283
 
@@ -284,9 +303,9 @@ module Bridgetown
284
303
  self["ruby_in_front_matter"]
285
304
  end
286
305
 
287
- # rubocop:disable Metrics/CyclomaticComplexity #
288
- def style_to_permalink(permalink_style)
289
- case permalink_style.to_sym
306
+ # Deprecated, to be removed when Bridgetown goes Resource-only
307
+ def style_to_permalink(permalink_style) # rubocop:todo Metrics/CyclomaticComplexity
308
+ case permalink_style.to_s.to_sym
290
309
  when :pretty
291
310
  "/:categories/:year/:month/:day/:title/"
292
311
  when :simple
@@ -303,7 +322,6 @@ module Bridgetown
303
322
  permalink_style.to_s
304
323
  end
305
324
  end
306
- # rubocop:enable Metrics/CyclomaticComplexity #
307
325
 
308
326
  def check_include_exclude
309
327
  %w(include exclude).each do |option|
@@ -314,8 +332,10 @@ module Bridgetown
314
332
  "'#{option}' should be set as an array, but was: #{self[option].inspect}."
315
333
  end
316
334
 
317
- # add _pages to includes set
318
- self[:include] << "_pages"
335
+ unless self[:include].include?("_pages") || self[:content_engine] == "resource"
336
+ # add _pages to includes set
337
+ self[:include] << "_pages"
338
+ end
319
339
 
320
340
  self
321
341
  end
@@ -23,6 +23,16 @@ module Bridgetown
23
23
  @config = config
24
24
  end
25
25
 
26
+ # Logic to do the content conversion.
27
+ #
28
+ # @param content [String] content of file (without front matter).
29
+ # @param convertible [Bridgetown::Document, Bridgetown::Layout, Bridgetown::Resource::Base]
30
+ #
31
+ # @return [String] the converted content.
32
+ def convert(content, convertible = nil) # rubocop:disable Lint/UnusedMethodArgument
33
+ content
34
+ end
35
+
26
36
  # Does the given extension match this converter's list of acceptable extensions?
27
37
  #
28
38
  # @param [String] ext
@@ -42,5 +52,9 @@ module Bridgetown
42
52
  def output_ext(_ext)
43
53
  ".html"
44
54
  end
55
+
56
+ def inspect
57
+ "#<#{self.class}#{self.class.extname_list ? " #{self.class.extname_list.join(", ")}" : nil}>"
58
+ end
45
59
  end
46
60
  end
@@ -25,15 +25,6 @@ module Bridgetown
25
25
  def output_ext(ext)
26
26
  ext
27
27
  end
28
-
29
- # Logic to do the content conversion.
30
- #
31
- # content - String content of file (without front matter).
32
- #
33
- # Returns a String of the converted content.
34
- def convert(content)
35
- content
36
- end
37
28
  end
38
29
  end
39
30
  end