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.
- checksums.yaml +4 -4
- data/bridgetown-core.gemspec +1 -1
- data/lib/bridgetown-core.rb +30 -11
- data/lib/bridgetown-core/cleaner.rb +7 -1
- data/lib/bridgetown-core/collection.rb +173 -77
- data/lib/bridgetown-core/commands/base.rb +9 -0
- data/lib/bridgetown-core/commands/configure.rb +4 -0
- data/lib/bridgetown-core/commands/console.rb +4 -0
- data/lib/bridgetown-core/concerns/data_accessible.rb +1 -0
- data/lib/bridgetown-core/concerns/site/configurable.rb +7 -3
- data/lib/bridgetown-core/concerns/site/content.rb +57 -15
- data/lib/bridgetown-core/concerns/site/processable.rb +1 -0
- data/lib/bridgetown-core/concerns/site/renderable.rb +26 -0
- data/lib/bridgetown-core/concerns/site/writable.rb +11 -1
- data/lib/bridgetown-core/concerns/validatable.rb +1 -0
- data/lib/bridgetown-core/configuration.rb +39 -19
- data/lib/bridgetown-core/converter.rb +14 -0
- data/lib/bridgetown-core/converters/identity.rb +0 -9
- data/lib/bridgetown-core/converters/markdown.rb +14 -4
- data/lib/bridgetown-core/converters/markdown/kramdown_parser.rb +3 -0
- data/lib/bridgetown-core/current.rb +10 -0
- data/lib/bridgetown-core/document.rb +6 -14
- data/lib/bridgetown-core/drops/collection_drop.rb +1 -1
- data/lib/bridgetown-core/drops/page_drop.rb +4 -0
- data/lib/bridgetown-core/drops/resource_drop.rb +81 -0
- data/lib/bridgetown-core/drops/site_drop.rb +33 -8
- data/lib/bridgetown-core/drops/unified_payload_drop.rb +4 -0
- data/lib/bridgetown-core/entry_filter.rb +10 -23
- data/lib/bridgetown-core/errors.rb +0 -2
- data/lib/bridgetown-core/filters.rb +2 -1
- data/lib/bridgetown-core/generators/prototype_generator.rb +37 -19
- data/lib/bridgetown-core/layout.rb +2 -2
- data/lib/bridgetown-core/liquid_renderer/file.rb +1 -0
- data/lib/bridgetown-core/liquid_renderer/table.rb +1 -0
- data/lib/bridgetown-core/model/base.rb +138 -0
- data/lib/bridgetown-core/model/builder_origin.rb +40 -0
- data/lib/bridgetown-core/model/file_origin.rb +119 -0
- data/lib/bridgetown-core/model/origin.rb +38 -0
- data/lib/bridgetown-core/page.rb +9 -1
- data/lib/bridgetown-core/plugin_manager.rb +0 -2
- data/lib/bridgetown-core/publisher.rb +7 -1
- data/lib/bridgetown-core/reader.rb +25 -12
- data/lib/bridgetown-core/readers/data_reader.rb +3 -4
- data/lib/bridgetown-core/readers/post_reader.rb +1 -1
- data/lib/bridgetown-core/regenerator.rb +8 -1
- data/lib/bridgetown-core/related_posts.rb +1 -1
- data/lib/bridgetown-core/renderer.rb +5 -12
- data/lib/bridgetown-core/resource/base.rb +275 -0
- data/lib/bridgetown-core/resource/destination.rb +49 -0
- data/lib/bridgetown-core/resource/permalink_processor.rb +179 -0
- data/lib/bridgetown-core/resource/taxonomy_term.rb +25 -0
- data/lib/bridgetown-core/resource/taxonomy_type.rb +47 -0
- data/lib/bridgetown-core/resource/transformer.rb +173 -0
- data/lib/bridgetown-core/ruby_template_view.rb +4 -0
- data/lib/bridgetown-core/site.rb +9 -1
- data/lib/bridgetown-core/static_file.rb +33 -10
- data/lib/bridgetown-core/url.rb +1 -0
- data/lib/bridgetown-core/utils.rb +40 -40
- data/lib/bridgetown-core/utils/platforms.rb +1 -0
- data/lib/bridgetown-core/version.rb +2 -2
- data/lib/site_template/webpack.config.js.erb +8 -6
- metadata +28 -21
- data/lib/bridgetown-core/page_without_a_file.rb +0 -17
- data/lib/bridgetown-core/readers/collection_reader.rb +0 -23
- data/lib/bridgetown-core/utils/exec.rb +0 -26
- data/lib/bridgetown-core/utils/internet.rb +0 -37
- data/lib/bridgetown-core/utils/win_tz.rb +0 -75
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c58653595832ef2fb9e6bbea3f147a0b3be9edae554d169e974570b84565a507
|
4
|
+
data.tar.gz: 7af409e9a01570321171cf1afc562c00cacdcc6e0dce98f2b8eac4988a60e8d6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b21d9c304dd99dd306b70e97e172d1ec172f0d1fa48034610cc3d9e6bc9c40b98e7fe10479226103cb2ff501c22c7c2841f20630235262cc7214661be62bcf3e
|
7
|
+
data.tar.gz: cab7afb0f441e412850ce648d6e7ca9a3996f106b0800c31ef24a0cf63af9db770498f307da275860c0572d6d6f2a5f1e56570d10349bb11cd4f17f96b3266ee
|
data/bridgetown-core.gemspec
CHANGED
@@ -31,6 +31,7 @@ Gem::Specification.new do |s|
|
|
31
31
|
s.required_ruby_version = ">= 2.5.0"
|
32
32
|
s.required_rubygems_version = ">= 2.7.0"
|
33
33
|
|
34
|
+
s.add_runtime_dependency("activemodel", "~> 6.0")
|
34
35
|
s.add_runtime_dependency("activesupport", "~> 6.0")
|
35
36
|
s.add_runtime_dependency("addressable", "~> 2.4")
|
36
37
|
s.add_runtime_dependency("amazing_print", "~> 1.2")
|
@@ -45,7 +46,6 @@ Gem::Specification.new do |s|
|
|
45
46
|
s.add_runtime_dependency("liquid", "~> 5.0")
|
46
47
|
s.add_runtime_dependency("liquid-component", ">= 0.1")
|
47
48
|
s.add_runtime_dependency("listen", "~> 3.0")
|
48
|
-
s.add_runtime_dependency("pathutil", "~> 0.9")
|
49
49
|
s.add_runtime_dependency("rouge", "~> 3.0")
|
50
50
|
s.add_runtime_dependency("safe_yaml", "~> 1.0")
|
51
51
|
s.add_runtime_dependency("terminal-table", "~> 1.8")
|
data/lib/bridgetown-core.rb
CHANGED
@@ -18,6 +18,7 @@ end
|
|
18
18
|
require "rubygems"
|
19
19
|
|
20
20
|
# stdlib
|
21
|
+
require "find"
|
21
22
|
require "forwardable"
|
22
23
|
require "fileutils"
|
23
24
|
require "time"
|
@@ -31,13 +32,16 @@ require "json"
|
|
31
32
|
# 3rd party
|
32
33
|
require "active_support"
|
33
34
|
require "active_support/core_ext/hash/keys"
|
35
|
+
require "active_support/core_ext/module/delegation"
|
34
36
|
require "active_support/core_ext/object/blank"
|
37
|
+
require "active_support/core_ext/object/deep_dup"
|
38
|
+
require "active_support/core_ext/object/inclusion"
|
35
39
|
require "active_support/core_ext/string/inflections"
|
36
40
|
require "active_support/core_ext/string/inquiry"
|
37
41
|
require "active_support/core_ext/string/starts_ends_with"
|
42
|
+
require "active_support/current_attributes"
|
38
43
|
require "active_support/descendants_tracker"
|
39
44
|
require "hash_with_dot_access"
|
40
|
-
require "pathutil"
|
41
45
|
require "addressable/uri"
|
42
46
|
require "safe_yaml/load"
|
43
47
|
require "liquid"
|
@@ -47,6 +51,7 @@ require "colorator"
|
|
47
51
|
require "i18n"
|
48
52
|
require "faraday"
|
49
53
|
require "thor"
|
54
|
+
require "zeitwerk"
|
50
55
|
|
51
56
|
module HashWithDotAccess
|
52
57
|
class Hash # :nodoc:
|
@@ -73,7 +78,6 @@ if RUBY_VERSION.start_with?("3.0")
|
|
73
78
|
end
|
74
79
|
|
75
80
|
module Bridgetown
|
76
|
-
# internal requires
|
77
81
|
autoload :Cleaner, "bridgetown-core/cleaner"
|
78
82
|
autoload :Collection, "bridgetown-core/collection"
|
79
83
|
autoload :Configuration, "bridgetown-core/configuration"
|
@@ -81,30 +85,38 @@ module Bridgetown
|
|
81
85
|
autoload :Deprecator, "bridgetown-core/deprecator"
|
82
86
|
autoload :Document, "bridgetown-core/document"
|
83
87
|
autoload :EntryFilter, "bridgetown-core/entry_filter"
|
88
|
+
# TODO: we have too many errors! This is silly
|
84
89
|
autoload :Errors, "bridgetown-core/errors"
|
85
90
|
autoload :Excerpt, "bridgetown-core/excerpt"
|
91
|
+
# TODO: this is a poorly named, unclear class. Relocate to Utils:
|
86
92
|
autoload :External, "bridgetown-core/external"
|
87
93
|
autoload :FrontmatterDefaults, "bridgetown-core/frontmatter_defaults"
|
88
94
|
autoload :Hooks, "bridgetown-core/hooks"
|
89
95
|
autoload :Layout, "bridgetown-core/layout"
|
90
96
|
autoload :LayoutPlaceable, "bridgetown-core/concerns/layout_placeable"
|
91
97
|
autoload :Cache, "bridgetown-core/cache"
|
92
|
-
autoload :
|
98
|
+
autoload :Current, "bridgetown-core/current"
|
99
|
+
# TODO: remove this when legacy content engine is gone:
|
93
100
|
autoload :DataReader, "bridgetown-core/readers/data_reader"
|
94
101
|
autoload :DefaultsReader, "bridgetown-core/readers/defaults_reader"
|
95
102
|
autoload :LayoutReader, "bridgetown-core/readers/layout_reader"
|
103
|
+
# TODO: remove this when legacy content engine is gone:
|
96
104
|
autoload :PostReader, "bridgetown-core/readers/post_reader"
|
105
|
+
# TODO: we can merge this back into Reader class:
|
97
106
|
autoload :PageReader, "bridgetown-core/readers/page_reader"
|
98
107
|
autoload :PluginContentReader, "bridgetown-core/readers/plugin_content_reader"
|
108
|
+
# TODO: also merge this:
|
99
109
|
autoload :StaticFileReader, "bridgetown-core/readers/static_file_reader"
|
100
110
|
autoload :LogAdapter, "bridgetown-core/log_adapter"
|
101
111
|
autoload :Page, "bridgetown-core/page"
|
102
|
-
autoload :
|
112
|
+
autoload :GeneratedPage, "bridgetown-core/page"
|
113
|
+
# TODO: figure out how to get rid of this seemingly banal class:
|
103
114
|
autoload :PathManager, "bridgetown-core/path_manager"
|
104
115
|
autoload :PluginManager, "bridgetown-core/plugin_manager"
|
105
116
|
autoload :Publishable, "bridgetown-core/concerns/publishable"
|
106
117
|
autoload :Publisher, "bridgetown-core/publisher"
|
107
118
|
autoload :Reader, "bridgetown-core/reader"
|
119
|
+
# TODO: remove this when the incremental regenerator is gone:
|
108
120
|
autoload :Regenerator, "bridgetown-core/regenerator"
|
109
121
|
autoload :RelatedPosts, "bridgetown-core/related_posts"
|
110
122
|
autoload :Renderer, "bridgetown-core/renderer"
|
@@ -130,6 +142,7 @@ module Bridgetown
|
|
130
142
|
|
131
143
|
require "bridgetown-core/drops/drop"
|
132
144
|
require "bridgetown-core/drops/document_drop"
|
145
|
+
require "bridgetown-core/drops/resource_drop"
|
133
146
|
require_all "bridgetown-core/converters"
|
134
147
|
require_all "bridgetown-core/converters/markdown"
|
135
148
|
require_all "bridgetown-core/drops"
|
@@ -193,11 +206,7 @@ module Bridgetown
|
|
193
206
|
# @return [void]
|
194
207
|
# rubocop:disable Naming/AccessorMethodName
|
195
208
|
def set_timezone(timezone)
|
196
|
-
ENV["TZ"] =
|
197
|
-
Utils::WinTZ.calculate(timezone)
|
198
|
-
else
|
199
|
-
timezone
|
200
|
-
end
|
209
|
+
ENV["TZ"] = timezone
|
201
210
|
end
|
202
211
|
# rubocop:enable Naming/AccessorMethodName
|
203
212
|
|
@@ -218,11 +227,11 @@ module Bridgetown
|
|
218
227
|
@logger = LogAdapter.new(writer, (ENV["BRIDGETOWN_LOG_LEVEL"] || :info).to_sym)
|
219
228
|
end
|
220
229
|
|
221
|
-
#
|
230
|
+
# Deprecated. Now using the Current site.
|
222
231
|
#
|
223
232
|
# @return [Array<Bridgetown::Site>] the Bridgetown sites created.
|
224
233
|
def sites
|
225
|
-
|
234
|
+
[Bridgetown::Current.site].compact
|
226
235
|
end
|
227
236
|
|
228
237
|
# Ensures the questionable path is prefixed with the base directory
|
@@ -259,3 +268,13 @@ module Bridgetown
|
|
259
268
|
Bridgetown::External.require_if_present("liquid/c")
|
260
269
|
end
|
261
270
|
end
|
271
|
+
|
272
|
+
module Bridgetown
|
273
|
+
module Model; end
|
274
|
+
module Resource; end
|
275
|
+
end
|
276
|
+
|
277
|
+
loader = Zeitwerk::Loader.new
|
278
|
+
loader.push_dir File.join(__dir__, "bridgetown-core/model"), namespace: Bridgetown::Model
|
279
|
+
loader.push_dir File.join(__dir__, "bridgetown-core/resource"), namespace: Bridgetown::Resource
|
280
|
+
loader.setup # ready!
|
@@ -58,7 +58,13 @@ module Bridgetown
|
|
58
58
|
# Returns a Set with the file paths
|
59
59
|
def new_files
|
60
60
|
@new_files ||= Set.new.tap do |files|
|
61
|
-
site.each_site_file
|
61
|
+
site.each_site_file do |item|
|
62
|
+
files << if item.method(:destination).arity == 1
|
63
|
+
item.destination(site.dest)
|
64
|
+
else
|
65
|
+
item.destination.output_path
|
66
|
+
end
|
67
|
+
end
|
62
68
|
end
|
63
69
|
end
|
64
70
|
|
@@ -8,82 +8,104 @@ module Bridgetown
|
|
8
8
|
attr_reader :label, :metadata
|
9
9
|
attr_writer :docs
|
10
10
|
|
11
|
+
attr_writer :resources
|
12
|
+
|
11
13
|
# Create a new Collection.
|
12
14
|
#
|
13
|
-
# site
|
14
|
-
# label
|
15
|
-
#
|
16
|
-
# Returns nothing.
|
15
|
+
# @param site [Bridgetown::Site] the site to which this collection belongs
|
16
|
+
# @param label [String] the name of the collection
|
17
17
|
def initialize(site, label)
|
18
18
|
@site = site
|
19
19
|
@label = sanitize_label(label)
|
20
20
|
@metadata = extract_metadata
|
21
21
|
end
|
22
22
|
|
23
|
+
def builtin?
|
24
|
+
label.in? %w(posts pages data).freeze
|
25
|
+
end
|
26
|
+
|
27
|
+
def legacy_reader?
|
28
|
+
label.in? %w(posts data).freeze
|
29
|
+
end
|
30
|
+
|
31
|
+
def data?
|
32
|
+
label == "data"
|
33
|
+
end
|
34
|
+
|
23
35
|
# Fetch the Documents in this collection.
|
24
36
|
# Defaults to an empty array if no documents have been read in.
|
25
37
|
#
|
26
|
-
#
|
38
|
+
# @return [Array<Bridgetown::Document>]
|
27
39
|
def docs
|
28
40
|
@docs ||= []
|
29
41
|
end
|
30
42
|
|
31
|
-
#
|
32
|
-
#
|
33
|
-
|
34
|
-
|
43
|
+
# Fetch the Resources in this collection.
|
44
|
+
# Defaults to an empty array if no resources have been read in.
|
45
|
+
#
|
46
|
+
# @return [Array<Bridgetown::Resource::Base>]
|
47
|
+
def resources
|
48
|
+
@resources ||= []
|
35
49
|
end
|
36
50
|
|
37
|
-
#
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
"#{label}.#{method} should be changed to #{label}.docs.#{method}."
|
42
|
-
Bridgetown.logger.warn "", "Called by #{caller(0..0)}."
|
43
|
-
docs.public_send(method.to_sym, *args, &blck)
|
44
|
-
else
|
45
|
-
super
|
46
|
-
end
|
51
|
+
# Iterate over either Resources or Documents depending on how the site is
|
52
|
+
# configured
|
53
|
+
def each(&block)
|
54
|
+
site.uses_resource? ? resources.each(&block) : docs.each(&block)
|
47
55
|
end
|
48
56
|
|
49
57
|
# Fetch the static files in this collection.
|
50
58
|
# Defaults to an empty array if no static files have been read in.
|
51
59
|
#
|
52
|
-
#
|
60
|
+
# @return [Array<Bridgetown::StaticFile>]
|
61
|
+
def static_files
|
62
|
+
@static_files ||= []
|
63
|
+
end
|
64
|
+
|
53
65
|
def files
|
54
|
-
|
66
|
+
Bridgetown::Deprecator.deprecation_message "Collection#files is now Collection#static_files"
|
67
|
+
static_files
|
55
68
|
end
|
56
69
|
|
57
70
|
# Read the allowed documents into the collection's array of docs.
|
58
71
|
#
|
59
|
-
#
|
60
|
-
def read
|
72
|
+
# @return [Bridgetown::Collection] self
|
73
|
+
def read # rubocop:todo Metrics/PerceivedComplexity, Metrics/CyclomaticComplexity
|
61
74
|
filtered_entries.each do |file_path|
|
62
75
|
full_path = collection_dir(file_path)
|
63
76
|
next if File.directory?(full_path)
|
64
77
|
|
65
|
-
if
|
78
|
+
if site.uses_resource?
|
79
|
+
next if File.basename(file_path).starts_with?("_")
|
80
|
+
|
81
|
+
if label == "data" || Utils.has_yaml_header?(full_path)
|
82
|
+
read_resource(full_path)
|
83
|
+
else
|
84
|
+
read_static_file(file_path, full_path)
|
85
|
+
end
|
86
|
+
elsif Utils.has_yaml_header? full_path
|
66
87
|
read_document(full_path)
|
67
88
|
else
|
68
89
|
read_static_file(file_path, full_path)
|
69
90
|
end
|
70
91
|
end
|
71
|
-
site.static_files.concat(
|
92
|
+
site.static_files.concat(static_files)
|
72
93
|
sort_docs!
|
94
|
+
|
95
|
+
self
|
73
96
|
end
|
74
97
|
|
75
98
|
# All the entries in this collection.
|
76
99
|
#
|
77
|
-
#
|
78
|
-
# relative to the collection's
|
100
|
+
# @return [Array<String>] file paths to the documents in this collection
|
101
|
+
# relative to the collection's folder
|
79
102
|
def entries
|
80
103
|
return [] unless exists?
|
81
104
|
|
82
105
|
@entries ||= begin
|
83
106
|
collection_dir_slash = "#{collection_dir}/"
|
84
107
|
Utils.safe_glob(collection_dir, ["**", "*"], File::FNM_DOTMATCH).map do |entry|
|
85
|
-
entry
|
86
|
-
entry
|
108
|
+
entry.sub(collection_dir_slash, "")
|
87
109
|
end
|
88
110
|
end
|
89
111
|
end
|
@@ -91,85 +113,87 @@ module Bridgetown
|
|
91
113
|
# Filtered version of the entries in this collection.
|
92
114
|
# See `Bridgetown::EntryFilter#filter` for more information.
|
93
115
|
#
|
94
|
-
#
|
116
|
+
# @return [Array<String>] list of filtered entry paths
|
95
117
|
def filtered_entries
|
96
118
|
return [] unless exists?
|
97
119
|
|
98
120
|
@filtered_entries ||=
|
99
|
-
Dir.chdir(
|
121
|
+
Dir.chdir(absolute_path) do
|
100
122
|
entry_filter.filter(entries).reject do |f|
|
101
123
|
path = collection_dir(f)
|
102
|
-
File.directory?(path)
|
124
|
+
File.directory?(path)
|
103
125
|
end
|
104
126
|
end
|
105
127
|
end
|
106
128
|
|
107
|
-
# The
|
108
|
-
# containing the collection.
|
129
|
+
# The folder name of this Collection, e.g. `_posts` or `_events`
|
109
130
|
#
|
110
|
-
#
|
111
|
-
|
112
|
-
|
113
|
-
@relative_directory ||= "_#{label}"
|
131
|
+
# @return [String]
|
132
|
+
def folder_name
|
133
|
+
@folder_name ||= "_#{label}"
|
114
134
|
end
|
135
|
+
alias_method :relative_directory, :folder_name
|
115
136
|
|
116
|
-
# The relative path to the
|
137
|
+
# The relative path to the folder containing the collection.
|
117
138
|
#
|
118
|
-
#
|
119
|
-
#
|
139
|
+
# @return [String] folder where the collection is stored relative to the
|
140
|
+
# configured collections folder (usually the site source)
|
120
141
|
def relative_path
|
121
|
-
Pathname.new(container).join(
|
142
|
+
Pathname.new(container).join(folder_name).to_s
|
122
143
|
end
|
123
144
|
|
124
|
-
# The full path to the
|
145
|
+
# The full path to the folder containing the collection.
|
125
146
|
#
|
126
|
-
#
|
127
|
-
|
128
|
-
|
129
|
-
@directory ||= site.in_source_dir(relative_path)
|
147
|
+
# @return [String] full path where the collection is stored on the filesystem
|
148
|
+
def absolute_path
|
149
|
+
@absolute_path ||= site.in_source_dir(relative_path)
|
130
150
|
end
|
151
|
+
alias_method :directory, :absolute_path
|
131
152
|
|
132
|
-
# The full path to the
|
153
|
+
# The full path to the folder containing the collection, with
|
133
154
|
# optional subpaths.
|
134
155
|
#
|
135
|
-
# *files
|
136
|
-
#
|
137
|
-
#
|
138
|
-
# Returns a String containing th directory name where the collection
|
139
|
-
# is stored on the filesystem.
|
156
|
+
# @param *files [Array<String>] any other path pieces relative to the
|
157
|
+
# folder to append to the path
|
158
|
+
# @return [String]
|
140
159
|
def collection_dir(*files)
|
141
|
-
return
|
160
|
+
return absolute_path if files.empty?
|
142
161
|
|
143
|
-
site.in_source_dir(
|
162
|
+
site.in_source_dir(relative_path, *files)
|
144
163
|
end
|
145
164
|
|
146
|
-
# Checks whether the
|
165
|
+
# Checks whether the folder "exists" for this collection.
|
166
|
+
#
|
167
|
+
# @return [Boolean]
|
147
168
|
def exists?
|
148
|
-
File.directory?(
|
169
|
+
File.directory?(absolute_path)
|
149
170
|
end
|
150
171
|
|
151
172
|
# The entry filter for this collection.
|
152
|
-
# Creates an instance of Bridgetown::EntryFilter.
|
173
|
+
# Creates an instance of Bridgetown::EntryFilter if needed.
|
153
174
|
#
|
154
|
-
#
|
175
|
+
# @return [Bridgetown::EntryFilter]
|
155
176
|
def entry_filter
|
156
|
-
@entry_filter ||= Bridgetown::EntryFilter.new(
|
177
|
+
@entry_filter ||= Bridgetown::EntryFilter.new(
|
178
|
+
site,
|
179
|
+
base_directory: folder_name,
|
180
|
+
include_underscores: site.uses_resource?
|
181
|
+
)
|
157
182
|
end
|
158
183
|
|
159
184
|
# An inspect string.
|
160
185
|
#
|
161
|
-
#
|
186
|
+
# @return [String]
|
162
187
|
def inspect
|
163
|
-
"#<#{self.class} @label=#{label} docs=#{docs}>"
|
188
|
+
"#<#{self.class} @label=#{label} docs=#{docs} resources=#{resources}>"
|
164
189
|
end
|
165
190
|
|
166
191
|
# Produce a sanitized label name
|
167
192
|
# Label names may not contain anything but alphanumeric characters,
|
168
193
|
# underscores, and hyphens.
|
169
194
|
#
|
170
|
-
# label
|
171
|
-
#
|
172
|
-
# Returns a sanitized version of the label.
|
195
|
+
# @param label [String] the possibly-unsafe label
|
196
|
+
# @return [String] sanitized version of the label.
|
173
197
|
def sanitize_label(label)
|
174
198
|
label.gsub(%r![^a-z0-9_\-\.]!i, "")
|
175
199
|
end
|
@@ -179,7 +203,8 @@ module Bridgetown
|
|
179
203
|
# - label
|
180
204
|
# - docs
|
181
205
|
#
|
182
|
-
#
|
206
|
+
# @return [Bridgetown::Drops::CollectionDrop] representation of this
|
207
|
+
# collection for use in Liquid
|
183
208
|
def to_liquid
|
184
209
|
Drops::CollectionDrop.new self
|
185
210
|
end
|
@@ -187,14 +212,22 @@ module Bridgetown
|
|
187
212
|
# Whether the collection's documents ought to be written as individual
|
188
213
|
# files in the output.
|
189
214
|
#
|
190
|
-
#
|
215
|
+
# @return [Boolean] true if the 'write' metadata is true, false otherwise.
|
191
216
|
def write?
|
192
217
|
!!metadata.fetch("output", false)
|
193
218
|
end
|
194
219
|
|
195
|
-
#
|
220
|
+
# Used by Resource's permalink processor
|
221
|
+
# @return [String]
|
222
|
+
def default_permalink
|
223
|
+
metadata.fetch("permalink") do
|
224
|
+
"/:collection/:path/"
|
225
|
+
end
|
226
|
+
end
|
227
|
+
|
228
|
+
# LEGACY: The URL template to render collection's documents at.
|
196
229
|
#
|
197
|
-
#
|
230
|
+
# @return [String]
|
198
231
|
def url_template
|
199
232
|
@url_template ||= metadata.fetch("permalink") do
|
200
233
|
Utils.add_permalink_suffix("/:collection/:path", site.permalink_style)
|
@@ -203,13 +236,47 @@ module Bridgetown
|
|
203
236
|
|
204
237
|
# Extract options for this collection from the site configuration.
|
205
238
|
#
|
206
|
-
#
|
239
|
+
# @return [HashWithDotAccess::Hash]
|
207
240
|
def extract_metadata
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
241
|
+
site.config.collections[label] || HashWithDotAccess::Hash.new
|
242
|
+
end
|
243
|
+
|
244
|
+
def merge_data_resources
|
245
|
+
data_contents = {}
|
246
|
+
|
247
|
+
sanitize_filename = ->(name) do
|
248
|
+
name.gsub(%r![^\w\s-]+|(?<=^|\b\s)\s+(?=$|\s?\b)!, "")
|
249
|
+
.gsub(%r!\s+!, "_")
|
212
250
|
end
|
251
|
+
|
252
|
+
resources.each do |data_resource|
|
253
|
+
segments = data_resource.relative_path.each_filename.to_a[1..-1]
|
254
|
+
nested = []
|
255
|
+
segments.each_with_index do |segment, index|
|
256
|
+
sanitized_segment = sanitize_filename.(File.basename(segment, ".*"))
|
257
|
+
hsh = nested.empty? ? data_contents : data_contents.dig(*nested)
|
258
|
+
hsh[sanitized_segment] = if index == segments.length - 1
|
259
|
+
data_resource.data.array || data_resource.data
|
260
|
+
else
|
261
|
+
{}
|
262
|
+
end
|
263
|
+
nested << sanitized_segment
|
264
|
+
end
|
265
|
+
end
|
266
|
+
|
267
|
+
merge_environment_specific_metadata(data_contents).with_dot_access
|
268
|
+
end
|
269
|
+
|
270
|
+
def merge_environment_specific_metadata(data_contents)
|
271
|
+
if data_contents["site_metadata"]
|
272
|
+
data_contents["site_metadata"][Bridgetown.environment]&.each_key do |k|
|
273
|
+
data_contents["site_metadata"][k] =
|
274
|
+
data_contents["site_metadata"][Bridgetown.environment][k]
|
275
|
+
end
|
276
|
+
data_contents["site_metadata"].delete(Bridgetown.environment)
|
277
|
+
end
|
278
|
+
|
279
|
+
data_contents
|
213
280
|
end
|
214
281
|
|
215
282
|
private
|
@@ -219,17 +286,28 @@ module Bridgetown
|
|
219
286
|
end
|
220
287
|
|
221
288
|
def read_document(full_path)
|
222
|
-
doc = Document.new(full_path, site: site, collection: self)
|
223
|
-
doc.read
|
289
|
+
doc = Document.new(full_path, site: site, collection: self).tap(&:read)
|
224
290
|
docs << doc if site.unpublished || doc.published?
|
225
291
|
end
|
226
292
|
|
293
|
+
def read_resource(full_path)
|
294
|
+
id = "file://#{label}.collection/" + Addressable::URI.escape(
|
295
|
+
Pathname(full_path).relative_path_from(Pathname(site.source)).to_s
|
296
|
+
)
|
297
|
+
resource = Bridgetown::Model::Base.find(id).to_resource.read!
|
298
|
+
resources << resource if site.unpublished || resource.published?
|
299
|
+
end
|
300
|
+
|
227
301
|
def sort_docs!
|
228
302
|
if metadata["sort_by"].is_a?(String)
|
229
303
|
sort_docs_by_key!
|
304
|
+
sort_resources_by_key!
|
230
305
|
else
|
231
306
|
docs.sort!
|
307
|
+
resources.sort!
|
232
308
|
end
|
309
|
+
docs.reverse! if metadata.sort_direction == "descending"
|
310
|
+
resources.reverse! if metadata.sort_direction == "descending"
|
233
311
|
end
|
234
312
|
|
235
313
|
# A custom sort function based on Schwartzian transform
|
@@ -252,6 +330,24 @@ module Bridgetown
|
|
252
330
|
end.map!(&:last)
|
253
331
|
end
|
254
332
|
|
333
|
+
def sort_resources_by_key!
|
334
|
+
meta_key = metadata["sort_by"]
|
335
|
+
# Modify `docs` array to cache document's property along with the Document instance
|
336
|
+
resources.map! { |doc| [doc.data[meta_key], doc] }.sort! do |apples, olives|
|
337
|
+
order = determine_sort_order(meta_key, apples, olives)
|
338
|
+
|
339
|
+
# Fall back to `Document#<=>` if the properties were equal or were non-sortable
|
340
|
+
# Otherwise continue with current sort-order
|
341
|
+
if order.nil? || order.zero?
|
342
|
+
apples[-1] <=> olives[-1]
|
343
|
+
else
|
344
|
+
order
|
345
|
+
end
|
346
|
+
|
347
|
+
# Finally restore the `docs` array with just the Document objects themselves
|
348
|
+
end.map!(&:last)
|
349
|
+
end
|
350
|
+
|
255
351
|
def determine_sort_order(sort_key, apples, olives)
|
256
352
|
apple_property, apple_document = apples
|
257
353
|
olive_property, olive_document = olives
|
@@ -277,7 +373,7 @@ module Bridgetown
|
|
277
373
|
File.dirname(file_path)
|
278
374
|
).chomp("/.")
|
279
375
|
|
280
|
-
|
376
|
+
static_files << StaticFile.new(
|
281
377
|
site,
|
282
378
|
site.source,
|
283
379
|
relative_dir,
|