bridgetown-core 1.3.3 → 2.0.0.beta1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/bin/bridgetown +0 -6
- data/bin/bt +6 -0
- data/bridgetown-core.gemspec +10 -7
- data/lib/bridgetown-core/cleaner.rb +1 -1
- data/lib/bridgetown-core/collection.rb +30 -18
- data/lib/bridgetown-core/commands/build.rb +9 -22
- data/lib/bridgetown-core/commands/concerns/actions.rb +15 -8
- data/lib/bridgetown-core/commands/concerns/configuration_overridable.rb +1 -1
- data/lib/bridgetown-core/commands/console.rb +3 -0
- data/lib/bridgetown-core/commands/doctor.rb +2 -4
- data/lib/bridgetown-core/commands/esbuild/esbuild.defaults.js.erb +5 -1
- data/lib/bridgetown-core/commands/esbuild/migrate-from-webpack.rb +1 -1
- data/lib/bridgetown-core/commands/esbuild/update.rb +2 -2
- data/lib/bridgetown-core/commands/esbuild.rb +3 -3
- data/lib/bridgetown-core/commands/new.rb +32 -39
- data/lib/bridgetown-core/commands/start.rb +76 -60
- data/lib/bridgetown-core/component.rb +19 -13
- data/lib/bridgetown-core/concerns/layout_placeable.rb +1 -1
- data/lib/bridgetown-core/concerns/prioritizable.rb +11 -1
- data/lib/bridgetown-core/concerns/site/configurable.rb +7 -18
- data/lib/bridgetown-core/concerns/site/content.rb +10 -9
- data/lib/bridgetown-core/concerns/site/extensible.rb +4 -6
- data/lib/bridgetown-core/concerns/site/fast_refreshable.rb +161 -0
- data/lib/bridgetown-core/concerns/site/processable.rb +1 -0
- data/lib/bridgetown-core/concerns/site/renderable.rb +31 -7
- data/lib/bridgetown-core/concerns/site/ssr.rb +23 -9
- data/lib/bridgetown-core/concerns/site/writable.rb +1 -1
- data/lib/bridgetown-core/concerns/transformable.rb +3 -5
- data/lib/bridgetown-core/configuration/configuration_dsl.rb +23 -14
- data/lib/bridgetown-core/configuration.rb +67 -114
- data/lib/bridgetown-core/configurations/bt-postcss.rb +1 -2
- data/lib/bridgetown-core/configurations/cypress/cypress_tasks +2 -2
- data/lib/bridgetown-core/configurations/cypress.rb +1 -1
- data/lib/bridgetown-core/configurations/gh-pages/gh-pages.yml +3 -3
- data/lib/bridgetown-core/configurations/is-land.rb +1 -1
- data/lib/bridgetown-core/configurations/lit.rb +1 -1
- data/lib/bridgetown-core/configurations/open-props.rb +1 -1
- data/lib/bridgetown-core/configurations/purgecss.rb +1 -1
- data/lib/bridgetown-core/configurations/ruby2js.rb +1 -1
- data/lib/bridgetown-core/configurations/shoelace.rb +8 -20
- data/lib/bridgetown-core/configurations/stimulus.rb +17 -36
- data/lib/bridgetown-core/configurations/turbo.rb +1 -2
- data/lib/bridgetown-core/converter.rb +38 -10
- data/lib/bridgetown-core/converters/erb_templates.rb +9 -26
- data/lib/bridgetown-core/converters/identity.rb +1 -1
- data/lib/bridgetown-core/converters/liquid_templates.rb +2 -20
- data/lib/bridgetown-core/converters/ruby_templates.rb +61 -3
- data/lib/bridgetown-core/converters/serbea_templates.rb +12 -24
- data/lib/bridgetown-core/current.rb +19 -17
- data/lib/bridgetown-core/drops/collection_drop.rb +1 -1
- data/lib/bridgetown-core/drops/drop.rb +3 -3
- data/lib/bridgetown-core/drops/relations_drop.rb +3 -2
- data/lib/bridgetown-core/drops/site_drop.rb +0 -5
- data/lib/bridgetown-core/entry_filter.rb +4 -6
- data/lib/bridgetown-core/errors.rb +2 -2
- data/lib/bridgetown-core/filters/from_liquid.rb +6 -10
- data/lib/bridgetown-core/filters/localization_filters.rb +1 -1
- data/lib/bridgetown-core/filters/translation_filters.rb +2 -2
- data/lib/bridgetown-core/filters.rb +3 -3
- data/lib/bridgetown-core/front_matter/defaults.rb +225 -0
- data/lib/bridgetown-core/front_matter/importer.rb +34 -0
- data/lib/bridgetown-core/front_matter/loaders/base.rb +29 -0
- data/lib/bridgetown-core/front_matter/loaders/ruby.rb +113 -0
- data/lib/bridgetown-core/front_matter/loaders/yaml.rb +42 -0
- data/lib/bridgetown-core/front_matter/loaders.rb +44 -0
- data/lib/bridgetown-core/{utils/ruby_front_matter.rb → front_matter/ruby.rb} +5 -5
- data/lib/bridgetown-core/front_matter.rb +11 -0
- data/lib/bridgetown-core/generated_page.rb +71 -31
- data/lib/bridgetown-core/generators/prototype_generator.rb +30 -18
- data/lib/bridgetown-core/helpers.rb +36 -47
- data/lib/bridgetown-core/hooks.rb +5 -5
- data/lib/bridgetown-core/inflector.rb +40 -0
- data/lib/bridgetown-core/kramdown/parser/gfm.rb +2 -2
- data/lib/bridgetown-core/layout.rb +3 -3
- data/lib/bridgetown-core/log_adapter.rb +12 -13
- data/lib/bridgetown-core/log_writer.rb +4 -4
- data/lib/bridgetown-core/model/base.rb +17 -17
- data/lib/bridgetown-core/model/builder_origin.rb +5 -3
- data/lib/bridgetown-core/model/origin.rb +1 -3
- data/lib/bridgetown-core/model/repo_origin.rb +12 -14
- data/lib/bridgetown-core/plugin.rb +0 -1
- data/lib/bridgetown-core/plugin_manager.rb +27 -84
- data/lib/bridgetown-core/rack/boot.rb +0 -15
- data/lib/bridgetown-core/rack/routes.rb +30 -90
- data/lib/bridgetown-core/reader.rb +6 -4
- data/lib/bridgetown-core/readers/layout_reader.rb +2 -2
- data/lib/bridgetown-core/readers/plugin_content_reader.rb +2 -2
- data/lib/bridgetown-core/resource/base.rb +112 -29
- data/lib/bridgetown-core/resource/destination.rb +1 -1
- data/lib/bridgetown-core/resource/relations.rb +11 -8
- data/lib/bridgetown-core/resource/taxonomy_type.rb +3 -1
- data/lib/bridgetown-core/resource/transformer.rb +4 -4
- data/lib/bridgetown-core/ruby_template_view.rb +44 -28
- data/lib/bridgetown-core/signals.rb +95 -0
- data/lib/bridgetown-core/site.rb +22 -4
- data/lib/bridgetown-core/slot.rb +5 -5
- data/lib/bridgetown-core/static_file.rb +5 -7
- data/lib/bridgetown-core/tags/asset_path.rb +11 -2
- data/lib/bridgetown-core/tags/find.rb +3 -5
- data/lib/bridgetown-core/tags/highlight.rb +3 -3
- data/lib/bridgetown-core/tags/post_url.rb +1 -1
- data/lib/bridgetown-core/tasks/bridgetown_tasks.rake +2 -2
- data/lib/bridgetown-core/utils/aux.rb +41 -41
- data/lib/bridgetown-core/utils/loaders_manager.rb +2 -21
- data/lib/bridgetown-core/utils/ruby_exec.rb +17 -0
- data/lib/bridgetown-core/utils.rb +46 -110
- data/lib/bridgetown-core/version.rb +2 -2
- data/lib/bridgetown-core/watcher.rb +21 -10
- data/lib/bridgetown-core.rb +35 -49
- data/lib/roda/plugins/bridgetown_server.rb +54 -12
- data/lib/roda/plugins/bridgetown_ssr.rb +13 -2
- data/lib/roda/plugins/ssg.rb +72 -0
- data/lib/site_template/.gitignore +9 -3
- data/lib/site_template/Gemfile.erb +3 -3
- data/lib/site_template/README.md +3 -4
- data/lib/site_template/Rakefile.erb +2 -15
- data/lib/site_template/TEMPLATES/erb/_partials/_head.erb +2 -2
- data/lib/site_template/TEMPLATES/serbea/_partials/_head.serb +2 -2
- data/lib/site_template/config/initializers.rb +60 -22
- data/lib/site_template/config/puma.rb +2 -0
- data/lib/site_template/package.json.erb +2 -27
- data/lib/site_template/src/index.md.erb +3 -3
- data/lib/site_template/tmp/pids/.keep +0 -0
- metadata +106 -65
- data/lib/bridgetown-core/commands/webpack/enable-postcss.rb +0 -12
- data/lib/bridgetown-core/commands/webpack/setup.rb +0 -4
- data/lib/bridgetown-core/commands/webpack/update.rb +0 -24
- data/lib/bridgetown-core/commands/webpack/webpack.config.js +0 -31
- data/lib/bridgetown-core/commands/webpack/webpack.defaults.js.erb +0 -135
- data/lib/bridgetown-core/commands/webpack.rb +0 -82
- data/lib/bridgetown-core/concerns/front_matter_importer.rb +0 -52
- data/lib/bridgetown-core/concerns/liquid_renderable.rb +0 -30
- data/lib/bridgetown-core/core_ext/psych.rb +0 -15
- data/lib/bridgetown-core/drops/url_drop.rb +0 -152
- data/lib/bridgetown-core/frontmatter_defaults.rb +0 -223
- data/lib/bridgetown-core/rack/static_indexes.rb +0 -31
- data/lib/bridgetown-core/url.rb +0 -166
- data/lib/bridgetown-core/utils/ansi.rb +0 -57
- data/lib/site_template/bridgetown.config.yml +0 -33
@@ -40,7 +40,7 @@ module Bridgetown
|
|
40
40
|
# See Utils.slugify for more detail.
|
41
41
|
def slugify(input, mode = nil)
|
42
42
|
mode = @context.registers[:site].config.slugify_mode if mode.nil?
|
43
|
-
Utils.slugify(input, mode:
|
43
|
+
Utils.slugify(input, mode:)
|
44
44
|
end
|
45
45
|
|
46
46
|
# Titleize a slug or identifier string.
|
@@ -395,8 +395,8 @@ module Bridgetown
|
|
395
395
|
end
|
396
396
|
end
|
397
397
|
|
398
|
-
FLOAT_LIKE = %r!\A\s*-?(?:\d+\.?\d*|\.\d+)\s*\Z
|
399
|
-
INTEGER_LIKE = %r!\A\s*-?\d+\s*\Z
|
398
|
+
FLOAT_LIKE = %r!\A\s*-?(?:\d+\.?\d*|\.\d+)\s*\Z!
|
399
|
+
INTEGER_LIKE = %r!\A\s*-?\d+\s*\Z!
|
400
400
|
private_constant :FLOAT_LIKE, :INTEGER_LIKE
|
401
401
|
|
402
402
|
# return numeric values as numbers for proper sorting
|
@@ -0,0 +1,225 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Bridgetown
|
4
|
+
module FrontMatter
|
5
|
+
# This class handles custom defaults for front matter settings.
|
6
|
+
# It is exposed via the frontmatter_defaults method on the site class.
|
7
|
+
class Defaults
|
8
|
+
# @return [Bridgetown::Site]
|
9
|
+
attr_reader :site
|
10
|
+
|
11
|
+
def initialize(site)
|
12
|
+
@site = site
|
13
|
+
@defaults_cache = {}
|
14
|
+
end
|
15
|
+
|
16
|
+
def reset
|
17
|
+
@glob_cache = {}
|
18
|
+
@defaults_cache = {}
|
19
|
+
end
|
20
|
+
|
21
|
+
def ensure_time!(set)
|
22
|
+
return set unless set.key?("values") && set["values"].key?("date")
|
23
|
+
return set if set["values"]["date"].is_a?(Time)
|
24
|
+
|
25
|
+
set["values"]["date"] = Utils.parse_date(
|
26
|
+
set["values"]["date"],
|
27
|
+
"An invalid date format was found in a front-matter default set: #{set}"
|
28
|
+
)
|
29
|
+
set
|
30
|
+
end
|
31
|
+
|
32
|
+
# Collects a hash with all default values for a resource
|
33
|
+
#
|
34
|
+
# @param path [String] the relative path of the resource
|
35
|
+
# @param collection_name [Symbol] :posts, :pages, etc.
|
36
|
+
#
|
37
|
+
# @return [Hash] all default values (an empty hash if there are none)
|
38
|
+
def all(path, collection_name)
|
39
|
+
if @defaults_cache.key?([path, collection_name])
|
40
|
+
return @defaults_cache[[path, collection_name]]
|
41
|
+
end
|
42
|
+
|
43
|
+
defaults = {}
|
44
|
+
merge_data_cascade_for_path(path, defaults)
|
45
|
+
|
46
|
+
old_scope = nil
|
47
|
+
matching_sets(path, collection_name).each do |set|
|
48
|
+
if has_precedence?(old_scope, set["scope"])
|
49
|
+
defaults = Utils.deep_merge_hashes(defaults, set["values"])
|
50
|
+
old_scope = set["scope"]
|
51
|
+
else
|
52
|
+
defaults = Utils.deep_merge_hashes(set["values"], defaults)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
@defaults_cache[[path, collection_name]] = defaults
|
57
|
+
end
|
58
|
+
|
59
|
+
private
|
60
|
+
|
61
|
+
def merge_data_cascade_for_path(path, merged_data)
|
62
|
+
absolute_path = site.in_source_dir(path)
|
63
|
+
site.defaults_reader.path_defaults
|
64
|
+
.select { |k, _v| absolute_path.include? k }
|
65
|
+
.sort_by { |k, _v| k.length }
|
66
|
+
.each do |defaults|
|
67
|
+
merged_data.merge!(defaults[1])
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
# Checks if a given default setting scope matches the given path and collection
|
72
|
+
#
|
73
|
+
# scope - the hash indicating the scope, as defined in bridgetown.config.yml
|
74
|
+
# path - the path to check for
|
75
|
+
# collection - the collection (:posts or :pages) to check for
|
76
|
+
#
|
77
|
+
# Returns true if the scope applies to the given collection and path
|
78
|
+
def applies?(scope, path, collection)
|
79
|
+
applies_collection?(scope, collection) && applies_path?(scope, path)
|
80
|
+
end
|
81
|
+
|
82
|
+
def applies_path?(scope, path)
|
83
|
+
rel_scope_path = scope["path"]
|
84
|
+
return true if !rel_scope_path.is_a?(String) || rel_scope_path.empty?
|
85
|
+
|
86
|
+
sanitized_path = strip_collections_dir(sanitize_path(path))
|
87
|
+
|
88
|
+
if rel_scope_path.include?("*")
|
89
|
+
glob_scope(sanitized_path, rel_scope_path)
|
90
|
+
else
|
91
|
+
path_is_subpath?(sanitized_path, strip_collections_dir(rel_scope_path))
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
def glob_scope(sanitized_path, rel_scope_path)
|
96
|
+
site_source = Pathname.new(site.source)
|
97
|
+
abs_scope_path = site_source.join(rel_scope_path).to_s
|
98
|
+
|
99
|
+
glob_cache(abs_scope_path).each do |scope_path|
|
100
|
+
scope_path = Pathname.new(scope_path).relative_path_from(site_source).to_s
|
101
|
+
scope_path = strip_collections_dir(scope_path)
|
102
|
+
Bridgetown.logger.debug "Globbed Scope Path:", scope_path
|
103
|
+
return true if path_is_subpath?(sanitized_path, scope_path)
|
104
|
+
end
|
105
|
+
false
|
106
|
+
end
|
107
|
+
|
108
|
+
def glob_cache(path)
|
109
|
+
@glob_cache ||= {}
|
110
|
+
@glob_cache[path] ||= Dir.glob(path)
|
111
|
+
end
|
112
|
+
|
113
|
+
def path_is_subpath?(path, parent_path)
|
114
|
+
path.start_with?(parent_path)
|
115
|
+
end
|
116
|
+
|
117
|
+
def strip_collections_dir(path)
|
118
|
+
collections_dir = site.config["collections_dir"]
|
119
|
+
slashed_coll_dir = collections_dir.empty? ? "/" : "#{collections_dir}/"
|
120
|
+
return path if collections_dir.empty? || !path.to_s.start_with?(slashed_coll_dir)
|
121
|
+
|
122
|
+
path.sub(slashed_coll_dir, "")
|
123
|
+
end
|
124
|
+
|
125
|
+
# Determines whether the scope applies to collection.
|
126
|
+
# The scope applies to the collection if:
|
127
|
+
# 1. no 'collection' is specified
|
128
|
+
# 2. the 'collection' in the scope is the same as the collection asked about
|
129
|
+
#
|
130
|
+
# @param scope [Hash] the defaults set being asked about
|
131
|
+
# @param collection [Symbol] the collection of the resource being processed
|
132
|
+
#
|
133
|
+
# @return [Boolean] whether either of the above conditions are satisfied
|
134
|
+
def applies_collection?(scope, collection)
|
135
|
+
!scope.key?("collection") || scope["collection"].eql?(collection.to_s)
|
136
|
+
end
|
137
|
+
|
138
|
+
# Checks if a given set of default values is valid
|
139
|
+
#
|
140
|
+
# @param set [Hash] the default value hash as defined in bridgetown.config.yml
|
141
|
+
#
|
142
|
+
# @return [Boolean] if the set is valid and can be used
|
143
|
+
def valid?(set)
|
144
|
+
set.is_a?(Hash) && set["values"].is_a?(Hash)
|
145
|
+
end
|
146
|
+
|
147
|
+
# Determines if a new scope has precedence over an old one
|
148
|
+
#
|
149
|
+
# old_scope - the old scope hash, or nil if there's none
|
150
|
+
# new_scope - the new scope hash
|
151
|
+
#
|
152
|
+
# Returns true if the new scope has precedence over the older
|
153
|
+
# rubocop: disable Naming/PredicateName
|
154
|
+
def has_precedence?(old_scope, new_scope)
|
155
|
+
return true if old_scope.nil?
|
156
|
+
|
157
|
+
new_path = sanitize_path(new_scope["path"])
|
158
|
+
old_path = sanitize_path(old_scope["path"])
|
159
|
+
|
160
|
+
if new_path.length != old_path.length
|
161
|
+
new_path.length >= old_path.length
|
162
|
+
elsif new_scope.key?("collection")
|
163
|
+
true
|
164
|
+
else
|
165
|
+
!old_scope.key? "collection"
|
166
|
+
end
|
167
|
+
end
|
168
|
+
# rubocop: enable Naming/PredicateName
|
169
|
+
|
170
|
+
# Collects a list of sets that match the given path and collection
|
171
|
+
#
|
172
|
+
# @return [Array<Hash>]
|
173
|
+
def matching_sets(path, collection)
|
174
|
+
@matched_set_cache ||= {}
|
175
|
+
@matched_set_cache[path] ||= {}
|
176
|
+
@matched_set_cache[path][collection] ||= valid_sets.select do |set|
|
177
|
+
!set.key?("scope") || applies?(set["scope"], path, collection)
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
# Returns a list of valid sets
|
182
|
+
#
|
183
|
+
# This is not cached to allow plugins to modify the configuration
|
184
|
+
# and have their changes take effect
|
185
|
+
#
|
186
|
+
# @return [Array<Hash>]
|
187
|
+
def valid_sets
|
188
|
+
sets = site.config["defaults"]
|
189
|
+
return [] unless sets.is_a?(Array)
|
190
|
+
|
191
|
+
sets.filter_map do |set|
|
192
|
+
if valid?(set)
|
193
|
+
massage_scope!(set)
|
194
|
+
# TODO: is this trip really necessary?
|
195
|
+
ensure_time!(set)
|
196
|
+
else
|
197
|
+
Bridgetown.logger.warn "Defaults:", "An invalid front-matter default set was found:"
|
198
|
+
Bridgetown.logger.warn set.to_s
|
199
|
+
nil
|
200
|
+
end
|
201
|
+
end
|
202
|
+
end
|
203
|
+
|
204
|
+
# Set path to blank if not specified and alias older type to collection
|
205
|
+
def massage_scope!(set)
|
206
|
+
set["scope"] ||= {}
|
207
|
+
set["scope"]["path"] ||= ""
|
208
|
+
return unless set["scope"]["type"] && !set["scope"]["collection"]
|
209
|
+
|
210
|
+
set["scope"]["collection"] = set["scope"]["type"]
|
211
|
+
end
|
212
|
+
|
213
|
+
SANITIZATION_REGEX = %r!\A/|(?<=[^/])\z!
|
214
|
+
|
215
|
+
# Sanitizes the given path by removing a leading and adding a trailing slash
|
216
|
+
def sanitize_path(path)
|
217
|
+
if path.nil? || path.empty?
|
218
|
+
""
|
219
|
+
else
|
220
|
+
path.gsub(SANITIZATION_REGEX, "")
|
221
|
+
end
|
222
|
+
end
|
223
|
+
end
|
224
|
+
end
|
225
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Bridgetown
|
4
|
+
module FrontMatter
|
5
|
+
module Importer
|
6
|
+
# Requires klass#content and klass#front_matter_line_count accessors
|
7
|
+
def self.included(klass)
|
8
|
+
klass.include Bridgetown::FrontMatter::RubyDSL
|
9
|
+
end
|
10
|
+
|
11
|
+
def read_front_matter(file_path)
|
12
|
+
file_contents = File.read(
|
13
|
+
file_path, **Bridgetown::Utils.merged_file_read_opts(Bridgetown::Current.site, {})
|
14
|
+
)
|
15
|
+
fm_result = nil
|
16
|
+
Loaders.for(self).each do |loader|
|
17
|
+
fm_result = loader.read(file_contents, file_path:) and break
|
18
|
+
end
|
19
|
+
|
20
|
+
if fm_result
|
21
|
+
self.content = fm_result.content
|
22
|
+
self.front_matter_line_count = fm_result.line_count
|
23
|
+
fm_result.front_matter
|
24
|
+
elsif is_a?(Layout)
|
25
|
+
self.content = file_contents
|
26
|
+
{}
|
27
|
+
else
|
28
|
+
yaml_data = YAMLParser.load_file(file_path)
|
29
|
+
(yaml_data.is_a?(Array) ? { rows: yaml_data } : yaml_data)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Bridgetown
|
4
|
+
module FrontMatter
|
5
|
+
module Loaders
|
6
|
+
# An abstract base class for processing front matter
|
7
|
+
class Base
|
8
|
+
# @param origin_or_layout [Bridgetown::Model::RepoOrigin, Bridgetown::Layout]
|
9
|
+
def initialize(origin_or_layout)
|
10
|
+
@origin_or_layout = origin_or_layout
|
11
|
+
end
|
12
|
+
|
13
|
+
# Reads the contents of a file, returning a possible {Result}
|
14
|
+
#
|
15
|
+
# @param file_contents [String] the contents of the file being processed
|
16
|
+
# @param file_path [String] the path to the file being processed
|
17
|
+
# @return [Result, nil]
|
18
|
+
def read(file_contents, file_path:) # rubocop:disable Lint/UnusedMethodArgument
|
19
|
+
raise "Implement #read in a subclass of Bridgetown::FrontMatter::Loaders::Base"
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
# @return [Bridgetown::Model::RepoOrigin, Bridgetown::Layout]
|
25
|
+
attr_reader :origin_or_layout
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,113 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Bridgetown
|
4
|
+
module FrontMatter
|
5
|
+
module Loaders
|
6
|
+
# Reads Ruby front matter delineated by fenced code blocks or ERB/Serbea indicators.
|
7
|
+
#
|
8
|
+
# For example, all of these resources load the hash `{published: false,
|
9
|
+
# title: "My post"}` as their front matter.
|
10
|
+
#
|
11
|
+
# ~~~
|
12
|
+
# ```ruby
|
13
|
+
# {
|
14
|
+
# published: false,
|
15
|
+
# title: My post
|
16
|
+
# }
|
17
|
+
# ```
|
18
|
+
# ~~~
|
19
|
+
#
|
20
|
+
# ~~~~
|
21
|
+
# ~~~ruby
|
22
|
+
# {
|
23
|
+
# published: false,
|
24
|
+
# title: My post
|
25
|
+
# }
|
26
|
+
# ~~~
|
27
|
+
# ~~~~
|
28
|
+
#
|
29
|
+
# ~~~
|
30
|
+
# ###ruby
|
31
|
+
# {
|
32
|
+
# published: false,
|
33
|
+
# title: My post
|
34
|
+
# }
|
35
|
+
# ###
|
36
|
+
# ~~~
|
37
|
+
#
|
38
|
+
# ~~~
|
39
|
+
# ---ruby
|
40
|
+
# {
|
41
|
+
# published: false,
|
42
|
+
# title: My post
|
43
|
+
# }
|
44
|
+
# ---
|
45
|
+
# ~~~
|
46
|
+
#
|
47
|
+
# ~~~~
|
48
|
+
# ~~~<%
|
49
|
+
# {
|
50
|
+
# published: false,
|
51
|
+
# title: My post
|
52
|
+
# }
|
53
|
+
# %>~~~
|
54
|
+
# ~~~~
|
55
|
+
#
|
56
|
+
# ~~~~
|
57
|
+
# ~~~{%
|
58
|
+
# {
|
59
|
+
# published: false,
|
60
|
+
# title: My post
|
61
|
+
# }
|
62
|
+
# %}~~~
|
63
|
+
# ~~~~
|
64
|
+
class Ruby < Base
|
65
|
+
HEADER = %r!\A[~`#-]{3,}(?:ruby|<%|{%)[ \t]*\n!
|
66
|
+
BLOCK = %r!#{HEADER.source}(.*?\n?)^((?:%>|%})?[~`#-]{3,}[ \t]*$\n?)!m
|
67
|
+
|
68
|
+
# Determines whether a given file has Ruby front matter
|
69
|
+
#
|
70
|
+
# @param file [Pathname, String] the path to the file
|
71
|
+
# @return [Boolean] true if the file has Ruby front matter, false otherwise
|
72
|
+
def self.header?(file)
|
73
|
+
File.open(file, "rb", &:gets)&.match?(HEADER) || false
|
74
|
+
end
|
75
|
+
|
76
|
+
# @see {Base#read}
|
77
|
+
def read(file_contents, file_path:)
|
78
|
+
if (ruby_content = file_contents.match(BLOCK)) && should_execute_inline_ruby?
|
79
|
+
Result.new(
|
80
|
+
content: ruby_content.post_match.lstrip,
|
81
|
+
front_matter: process_ruby_data(ruby_content[1], file_path, 2),
|
82
|
+
line_count: ruby_content[1].lines.size - 1
|
83
|
+
)
|
84
|
+
elsif self.class.header?(file_path)
|
85
|
+
Result.new(
|
86
|
+
front_matter: process_ruby_data(
|
87
|
+
File.read(file_path).lines[1..].join("\n"),
|
88
|
+
file_path,
|
89
|
+
2
|
90
|
+
),
|
91
|
+
line_count: 0
|
92
|
+
)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
private
|
97
|
+
|
98
|
+
def process_ruby_data(rubycode, file_path, starting_line)
|
99
|
+
Bridgetown::Utils::RubyExec.process_ruby_data(
|
100
|
+
@origin_or_layout,
|
101
|
+
rubycode,
|
102
|
+
file_path,
|
103
|
+
starting_line
|
104
|
+
)
|
105
|
+
end
|
106
|
+
|
107
|
+
def should_execute_inline_ruby?
|
108
|
+
Bridgetown::Current.site.config.should_execute_inline_ruby?
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Bridgetown
|
4
|
+
module FrontMatter
|
5
|
+
module Loaders
|
6
|
+
# Reads YAML-formatted front matter delineated by triple hyphens
|
7
|
+
#
|
8
|
+
# As an example, this resource loads to the hash `{"published": false,
|
9
|
+
# "title": "My post"}`.
|
10
|
+
#
|
11
|
+
# ~~~
|
12
|
+
# ---
|
13
|
+
# published: false
|
14
|
+
# title: My post
|
15
|
+
# ---
|
16
|
+
# ~~~
|
17
|
+
class YAML < Base
|
18
|
+
HEADER = %r!\A---[ \t]*\n!
|
19
|
+
BLOCK = %r!#{HEADER.source}(.*?\n?)^((---|\.\.\.)[ \t]*$\n?)!m
|
20
|
+
|
21
|
+
# Determines whether a given file has YAML front matter
|
22
|
+
#
|
23
|
+
# @param file [String] the path to the file
|
24
|
+
# @return [Boolean] true if the file has YAML front matter, false otherwise
|
25
|
+
def self.header?(file)
|
26
|
+
File.open(file, "rb", &:gets)&.match?(HEADER) || false
|
27
|
+
end
|
28
|
+
|
29
|
+
# @see {Base#read}
|
30
|
+
def read(file_contents, **)
|
31
|
+
yaml_content = file_contents.match(BLOCK) or return
|
32
|
+
|
33
|
+
Result.new(
|
34
|
+
content: yaml_content.post_match.lstrip,
|
35
|
+
front_matter: YAMLParser.load(yaml_content[1]),
|
36
|
+
line_count: yaml_content[1].lines.size - 1
|
37
|
+
)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Bridgetown
|
4
|
+
module FrontMatter
|
5
|
+
module Loaders
|
6
|
+
autoload :Base, "bridgetown-core/front_matter/loaders/base"
|
7
|
+
autoload :Ruby, "bridgetown-core/front_matter/loaders/ruby"
|
8
|
+
autoload :YAML, "bridgetown-core/front_matter/loaders/yaml"
|
9
|
+
|
10
|
+
Result = Struct.new(:content, :front_matter, :line_count, keyword_init: true)
|
11
|
+
|
12
|
+
# Constructs a list of possible loaders for a {Model::RepoOrigin} or {Layout}
|
13
|
+
#
|
14
|
+
# @param origin_or_layout [Bridgetown::Model::RepoOrigin, Bridgetown::Layout]
|
15
|
+
# @return [Array<Loaders::Base>]
|
16
|
+
def self.for(origin_or_layout)
|
17
|
+
registry.map { |loader_class| loader_class.new(origin_or_layout) }
|
18
|
+
end
|
19
|
+
|
20
|
+
# Determines whether a given file has front matter
|
21
|
+
#
|
22
|
+
# @param path [Pathname, String] the path to the file
|
23
|
+
# @return [Boolean] true if the file has front matter, false otherwise
|
24
|
+
def self.front_matter?(file)
|
25
|
+
registry.any? { |loader_class| loader_class.header?(file) }
|
26
|
+
end
|
27
|
+
|
28
|
+
# Registers a new type of front matter loader
|
29
|
+
#
|
30
|
+
# @param loader_class [Loader::Base]
|
31
|
+
# @return [void]
|
32
|
+
def self.register(loader_class)
|
33
|
+
registry.push(loader_class)
|
34
|
+
end
|
35
|
+
|
36
|
+
private_class_method def self.registry
|
37
|
+
@registry ||= []
|
38
|
+
end
|
39
|
+
|
40
|
+
register YAML
|
41
|
+
register Ruby
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -1,10 +1,10 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module Bridgetown
|
4
|
-
module
|
5
|
-
module
|
4
|
+
module FrontMatter
|
5
|
+
module RubyDSL
|
6
6
|
def front_matter(scope: nil, &block)
|
7
|
-
RubyFrontMatter.new(scope:
|
7
|
+
RubyFrontMatter.new(scope:).tap { |fm| fm.instance_exec(&block) }
|
8
8
|
end
|
9
9
|
end
|
10
10
|
|
@@ -21,8 +21,8 @@ module Bridgetown
|
|
21
21
|
set(key, value[0], &block)
|
22
22
|
end
|
23
23
|
|
24
|
-
def each(&
|
25
|
-
@data.each(&
|
24
|
+
def each(&)
|
25
|
+
@data.each(&)
|
26
26
|
end
|
27
27
|
|
28
28
|
def get(key)
|
@@ -0,0 +1,11 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Bridgetown
|
4
|
+
module FrontMatter
|
5
|
+
autoload :Defaults, "bridgetown-core/front_matter/defaults"
|
6
|
+
autoload :Importer, "bridgetown-core/front_matter/importer"
|
7
|
+
autoload :Loaders, "bridgetown-core/front_matter/loaders"
|
8
|
+
autoload :RubyDSL, "bridgetown-core/front_matter/ruby"
|
9
|
+
autoload :RubyFrontMatter, "bridgetown-core/front_matter/ruby"
|
10
|
+
end
|
11
|
+
end
|