bridgetown-core 0.15.0 → 0.16.0.beta1
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/Rakefile +14 -0
- data/bridgetown-core.gemspec +1 -0
- data/lib/bridgetown-core.rb +6 -1
- data/lib/bridgetown-core/concerns/data_accessible.rb +19 -0
- data/lib/bridgetown-core/concerns/layout_placeable.rb +17 -0
- data/lib/bridgetown-core/concerns/liquid_renderable.rb +20 -0
- data/lib/bridgetown-core/concerns/publishable.rb +10 -0
- data/lib/bridgetown-core/concerns/site/configurable.rb +62 -31
- data/lib/bridgetown-core/concerns/site/content.rb +88 -29
- data/lib/bridgetown-core/concerns/site/extensible.rb +15 -12
- data/lib/bridgetown-core/concerns/site/processable.rb +12 -10
- data/lib/bridgetown-core/concerns/site/renderable.rb +22 -2
- data/lib/bridgetown-core/concerns/site/writable.rb +16 -2
- data/lib/bridgetown-core/concerns/validatable.rb +59 -0
- data/lib/bridgetown-core/configuration.rb +1 -0
- data/lib/bridgetown-core/converter.rb +34 -0
- data/lib/bridgetown-core/converters/erb_templates.rb +61 -0
- data/lib/bridgetown-core/converters/markdown.rb +6 -23
- data/lib/bridgetown-core/converters/smartypants.rb +0 -10
- data/lib/bridgetown-core/document.rb +8 -52
- data/lib/bridgetown-core/errors.rb +2 -0
- data/lib/bridgetown-core/excerpt.rb +1 -6
- data/lib/bridgetown-core/filters.rb +2 -0
- data/lib/bridgetown-core/layout.rb +24 -1
- data/lib/bridgetown-core/liquid_renderer/file_system.rb +1 -1
- data/lib/bridgetown-core/page.rb +33 -24
- data/lib/bridgetown-core/regenerator.rb +1 -1
- data/lib/bridgetown-core/renderer.rb +38 -12
- data/lib/bridgetown-core/ruby_template_view.rb +84 -0
- data/lib/bridgetown-core/tags/class_map.rb +90 -0
- data/lib/bridgetown-core/tags/webpack_path.rb +48 -16
- data/lib/bridgetown-core/version.rb +2 -2
- metadata +24 -3
- data/lib/bridgetown-core/concerns/convertible.rb +0 -235
@@ -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
|
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
|
data/lib/bridgetown-core/page.rb
CHANGED
@@ -2,7 +2,11 @@
|
|
2
2
|
|
3
3
|
module Bridgetown
|
4
4
|
class Page
|
5
|
-
include
|
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
|
@@ -168,6 +150,16 @@ module Bridgetown
|
|
168
150
|
@relative_path ||= File.join(*[@dir, @name].map(&:to_s).reject(&:empty?)).delete_prefix("/")
|
169
151
|
end
|
170
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
|
161
|
+
end
|
162
|
+
|
171
163
|
# Obtain destination path.
|
172
164
|
#
|
173
165
|
# dest - The String path to the destination dir.
|
@@ -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}
|
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
|
@@ -163,7 +163,7 @@ module Bridgetown
|
|
163
163
|
end
|
164
164
|
|
165
165
|
def regenerate_page?(document)
|
166
|
-
document.
|
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
|
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
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
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?
|
@@ -0,0 +1,84 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "digest"
|
4
|
+
|
5
|
+
module Bridgetown
|
6
|
+
class RubyTemplateView
|
7
|
+
class Helpers
|
8
|
+
include Bridgetown::Filters
|
9
|
+
end
|
10
|
+
|
11
|
+
attr_reader :layout, :page, :site, :content
|
12
|
+
|
13
|
+
def initialize(convertible)
|
14
|
+
if convertible.is_a?(Layout)
|
15
|
+
@layout = convertible
|
16
|
+
@page = layout.current_document
|
17
|
+
@content = layout.current_document_output
|
18
|
+
else
|
19
|
+
@page = convertible
|
20
|
+
end
|
21
|
+
@site = page.site
|
22
|
+
end
|
23
|
+
|
24
|
+
def partial(_partial_name, _options = {})
|
25
|
+
raise "Must be implemented in a subclass"
|
26
|
+
end
|
27
|
+
|
28
|
+
def site_drop
|
29
|
+
site.site_payload.site
|
30
|
+
end
|
31
|
+
|
32
|
+
def liquid_render(component, options = {})
|
33
|
+
render_statement = _render_statement(component, options)
|
34
|
+
|
35
|
+
template = site.liquid_renderer.file(
|
36
|
+
"#{page.path}.#{Digest::SHA2.hexdigest(render_statement)}"
|
37
|
+
).parse(render_statement)
|
38
|
+
template.warnings.each do |e|
|
39
|
+
Bridgetown.logger.warn "Liquid Warning:",
|
40
|
+
LiquidRenderer.format_error(e, path || document.relative_path)
|
41
|
+
end
|
42
|
+
template.render!(options.deep_stringify_keys, _liquid_context)
|
43
|
+
end
|
44
|
+
|
45
|
+
def helpers
|
46
|
+
@helpers ||= Helpers.new
|
47
|
+
end
|
48
|
+
|
49
|
+
def method_missing(method, *args, &block)
|
50
|
+
if helpers.respond_to?(method.to_sym)
|
51
|
+
helpers.send method.to_sym, *args, &block
|
52
|
+
else
|
53
|
+
super
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def respond_to_missing?(method, include_private = false)
|
58
|
+
helpers.respond_to?(method.to_sym, include_private) || super
|
59
|
+
end
|
60
|
+
|
61
|
+
private
|
62
|
+
|
63
|
+
def _render_statement(component, options)
|
64
|
+
render_statement = ["{% render \"#{component}\""]
|
65
|
+
unless options.empty?
|
66
|
+
render_statement << ", " + options.keys.map { |k| "#{k}: #{k}" }.join(", ")
|
67
|
+
end
|
68
|
+
render_statement << " %}"
|
69
|
+
render_statement.join
|
70
|
+
end
|
71
|
+
|
72
|
+
def _liquid_context
|
73
|
+
{
|
74
|
+
registers: {
|
75
|
+
site: site,
|
76
|
+
page: page,
|
77
|
+
cached_partials: Bridgetown::Renderer.cached_partials,
|
78
|
+
},
|
79
|
+
strict_filters: site.config["liquid"]["strict_filters"],
|
80
|
+
strict_variables: site.config["liquid"]["strict_variables"],
|
81
|
+
}
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "set"
|
4
|
+
|
5
|
+
module Bridgetown
|
6
|
+
module Tags
|
7
|
+
# A ClassMap class is meant to take a hash and append styles based on if the
|
8
|
+
# value is truthy or falsy
|
9
|
+
#
|
10
|
+
# @example
|
11
|
+
# center-var = true
|
12
|
+
# small-var = nil
|
13
|
+
#
|
14
|
+
# # input
|
15
|
+
# <div class="{% class_map has-centered-text: center-var, is-small: small-var %}">
|
16
|
+
# Text
|
17
|
+
# </div>
|
18
|
+
#
|
19
|
+
# # output
|
20
|
+
# <div class="has-centered-text">
|
21
|
+
# Text
|
22
|
+
# </div>
|
23
|
+
class ClassMap < Liquid::Tag
|
24
|
+
# @see https://api.rubyonrails.org/classes/ActiveModel/Type/Boolean.html
|
25
|
+
FALSE_VALUES = [
|
26
|
+
nil, "nil", "NIL", false, 0, "0", :"0", "f", :f, "F", :F, "false",
|
27
|
+
false, "FALSE", :FALSE,
|
28
|
+
].to_set.freeze
|
29
|
+
|
30
|
+
# @param tag_name [String] The name to use for the tag
|
31
|
+
# @param input [String] The input to the tag
|
32
|
+
# @param tokens [Hash] A hash of config tokens for Liquid.
|
33
|
+
#
|
34
|
+
#
|
35
|
+
# @return [ClassMap] Returns a ClassMap object
|
36
|
+
def initialize(tag_name, input, tokens)
|
37
|
+
super
|
38
|
+
@input = input
|
39
|
+
end
|
40
|
+
|
41
|
+
def render(context)
|
42
|
+
class_map(@input, context)
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
def class_map(string, context)
|
48
|
+
ary = []
|
49
|
+
|
50
|
+
string.split(%r!,\s+!).each do |item|
|
51
|
+
kv_pair = item.split(%r!:\s+!)
|
52
|
+
klass = kv_pair[0]
|
53
|
+
variable = kv_pair[1]
|
54
|
+
|
55
|
+
# Check if a user wants the opposite of the variable
|
56
|
+
if variable[0] == "!"
|
57
|
+
check_opposite = true
|
58
|
+
variable.slice!(1..-1)
|
59
|
+
end
|
60
|
+
|
61
|
+
variable = find_variable(context, variable)
|
62
|
+
|
63
|
+
if check_opposite
|
64
|
+
ary.push(klass) if FALSE_VALUES.include?(variable)
|
65
|
+
else
|
66
|
+
ary.push(klass) unless FALSE_VALUES.include?(variable)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
ary.join(" ")
|
71
|
+
|
72
|
+
# Gracefully handle if syntax is improper
|
73
|
+
rescue NoMethodError
|
74
|
+
"invalid-class-map"
|
75
|
+
end
|
76
|
+
|
77
|
+
def find_variable(context, variable)
|
78
|
+
lookup = context
|
79
|
+
|
80
|
+
variable.split(".").each do |value|
|
81
|
+
lookup = lookup[value.strip]
|
82
|
+
end
|
83
|
+
|
84
|
+
lookup || nil
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
Liquid::Template.register_tag("class_map", Bridgetown::Tags::ClassMap)
|