bridgetown-core 0.15.0.beta1 → 0.16.0.beta1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Rakefile +14 -0
- data/bridgetown-core.gemspec +2 -0
- data/lib/bridgetown-core.rb +6 -1
- data/lib/bridgetown-core/commands/concerns/actions.rb +54 -21
- data/lib/bridgetown-core/commands/console.rb +12 -2
- data/lib/bridgetown-core/commands/serve.rb +5 -0
- 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 +23 -4
- 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/drops/document_drop.rb +9 -1
- data/lib/bridgetown-core/drops/page_drop.rb +1 -1
- data/lib/bridgetown-core/errors.rb +2 -0
- data/lib/bridgetown-core/excerpt.rb +5 -7
- data/lib/bridgetown-core/filters.rb +2 -0
- data/lib/bridgetown-core/layout.rb +24 -1
- data/lib/bridgetown-core/liquid_renderer/file.rb +1 -4
- data/lib/bridgetown-core/liquid_renderer/file_system.rb +1 -1
- data/lib/bridgetown-core/page.rb +36 -42
- data/lib/bridgetown-core/plugin_manager.rb +27 -13
- data/lib/bridgetown-core/regenerator.rb +1 -1
- data/lib/bridgetown-core/renderer.rb +41 -15
- 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/include.rb +2 -0
- data/lib/bridgetown-core/tags/render_content.rb +14 -2
- data/lib/bridgetown-core/tags/webpack_path.rb +48 -16
- data/lib/bridgetown-core/utils.rb +44 -0
- data/lib/bridgetown-core/version.rb +2 -2
- data/lib/site_template/bridgetown.config.yml +5 -3
- data/lib/site_template/package.json +1 -0
- data/lib/site_template/src/_components/{footer.html → footer.liquid} +0 -0
- data/lib/site_template/src/_components/{head.html → head.liquid} +0 -0
- data/lib/site_template/src/_components/{navbar.html → navbar.liquid} +0 -0
- data/lib/site_template/src/_layouts/default.html +1 -1
- data/lib/site_template/webpack.config.js +3 -3
- metadata +41 -6
- data/lib/bridgetown-core/concerns/convertible.rb +0 -238
@@ -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,30 +68,43 @@ module Bridgetown
|
|
67
68
|
# If that exact package hasn't been installed, execute yarn add
|
68
69
|
#
|
69
70
|
# Returns nothing.
|
70
|
-
# rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity
|
71
71
|
def self.install_yarn_dependencies(required_gems)
|
72
72
|
return unless File.exist?("package.json")
|
73
73
|
|
74
74
|
package_json = JSON.parse(File.read("package.json"))
|
75
75
|
|
76
76
|
required_gems.each do |loaded_gem|
|
77
|
-
|
78
|
-
|
79
|
-
yarn_add_dependency = loaded_gem.to_spec.metadata["yarn-add"].split("@")
|
80
|
-
next unless yarn_add_dependency.length == 2
|
81
|
-
|
82
|
-
# check matching version number is see if it's already installed
|
83
|
-
if package_json["dependencies"]
|
84
|
-
current_package = package_json["dependencies"].dig(yarn_add_dependency.first)
|
85
|
-
next unless current_package.nil? || current_package != yarn_add_dependency.last
|
86
|
-
end
|
77
|
+
yarn_dependency = find_yarn_dependency(loaded_gem)
|
78
|
+
next unless add_yarn_dependency?(yarn_dependency, package_json)
|
87
79
|
|
88
80
|
# all right, time to install the package
|
89
|
-
cmd = "yarn add #{
|
81
|
+
cmd = "yarn add #{yarn_dependency.join("@")}"
|
90
82
|
system cmd
|
91
83
|
end
|
92
84
|
end
|
93
|
-
|
85
|
+
|
86
|
+
def self.find_yarn_dependency(loaded_gem)
|
87
|
+
yarn_dependency = loaded_gem.to_spec&.metadata&.dig("yarn-add")&.match(YARN_DEPENDENCY_REGEXP)
|
88
|
+
return nil if yarn_dependency&.length != 3 || yarn_dependency[2] == ""
|
89
|
+
|
90
|
+
yarn_dependency[1..2]
|
91
|
+
end
|
92
|
+
|
93
|
+
def self.add_yarn_dependency?(yarn_dependency, package_json)
|
94
|
+
return false if yarn_dependency.nil?
|
95
|
+
|
96
|
+
# check matching version number is see if it's already installed
|
97
|
+
if package_json["dependencies"]
|
98
|
+
current_version = package_json["dependencies"].dig(yarn_dependency.first)
|
99
|
+
package_requires_updating?(current_version, yarn_dependency.last)
|
100
|
+
else
|
101
|
+
true
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
def self.package_requires_updating?(current_version, dep_version)
|
106
|
+
current_version.nil? || current_version != dep_version && !current_version.include?("/")
|
107
|
+
end
|
94
108
|
|
95
109
|
# Require all .rb files
|
96
110
|
#
|
@@ -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
|
)
|
@@ -53,18 +53,19 @@ module Bridgetown
|
|
53
53
|
|
54
54
|
# Prepare payload and render the document
|
55
55
|
#
|
56
|
-
# Returns
|
56
|
+
# Returns nothing
|
57
57
|
def run
|
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!
|
64
65
|
|
65
66
|
document.trigger_hooks(:pre_render, payload)
|
66
|
-
|
67
|
-
|
67
|
+
document.output = render_document
|
68
|
+
document.trigger_hooks(:post_render)
|
68
69
|
end
|
69
70
|
|
70
71
|
# Render the document.
|
@@ -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)
|
@@ -212,7 +212,9 @@ module Bridgetown
|
|
212
212
|
else
|
213
213
|
File.join(site.config["collections_dir"], page_payload["path"])
|
214
214
|
end
|
215
|
+
# rubocop:disable Performance/DeleteSuffix
|
215
216
|
resource_path.sub!(%r!/#excerpt\z!, "")
|
217
|
+
# rubocop:enable Performance/DeleteSuffix
|
216
218
|
site.in_source_dir File.dirname(resource_path)
|
217
219
|
end
|
218
220
|
end
|
@@ -3,9 +3,12 @@
|
|
3
3
|
module Bridgetown
|
4
4
|
module Tags
|
5
5
|
class BlockRenderTag < Liquid::Block
|
6
|
+
# rubocop:disable Metrics/AbcSize, Metrics/MethodLength
|
6
7
|
def render(context)
|
7
8
|
context.stack({}) do
|
8
|
-
|
9
|
+
# unindent the incoming text
|
10
|
+
content = Bridgetown::Utils.reindent_for_markdown(super)
|
11
|
+
|
9
12
|
regions = gather_content_regions(context)
|
10
13
|
|
11
14
|
site = context.registers[:site]
|
@@ -17,7 +20,15 @@ module Bridgetown
|
|
17
20
|
unless regions.empty?
|
18
21
|
regions.each do |region_name, region_content|
|
19
22
|
region_name = region_name.sub("content_with_region_", "")
|
20
|
-
|
23
|
+
|
24
|
+
if region_name.end_with? ":markdown"
|
25
|
+
region_name.sub!(%r!:markdown$!, "")
|
26
|
+
context[region_name] = converter.convert(
|
27
|
+
Bridgetown::Utils.reindent_for_markdown(region_content)
|
28
|
+
)
|
29
|
+
else
|
30
|
+
context[region_name] = region_content
|
31
|
+
end
|
21
32
|
render_params.push "#{region_name}: #{region_name}"
|
22
33
|
end
|
23
34
|
end
|
@@ -26,6 +37,7 @@ module Bridgetown
|
|
26
37
|
.render_tag(context, +"")
|
27
38
|
end
|
28
39
|
end
|
40
|
+
# rubocop:enable Metrics/AbcSize, Metrics/MethodLength
|
29
41
|
|
30
42
|
private
|
31
43
|
|
@@ -2,38 +2,70 @@
|
|
2
2
|
|
3
3
|
module Bridgetown
|
4
4
|
module Tags
|
5
|
+
# A helper class to help find the path to webpack asset inside of a webpack
|
6
|
+
# manifest file.
|
5
7
|
class WebpackPath < Liquid::Tag
|
6
8
|
include Bridgetown::Filters::URLFilters
|
7
9
|
|
8
|
-
|
10
|
+
# @param tag_name [String] Name of the tag
|
11
|
+
# @param asset_type [String] The type of asset to parse (js, css)
|
12
|
+
# @param options [Hash] An options hash
|
13
|
+
# @return WebpackPath
|
14
|
+
# @see {https://www.rdoc.info/github/Shopify/liquid/Liquid/Tag#initialize-instance_method}
|
15
|
+
def initialize(tag_name, asset_type, options)
|
9
16
|
super
|
10
17
|
|
11
18
|
# js or css
|
12
19
|
@asset_type = asset_type.strip
|
13
20
|
end
|
14
21
|
|
22
|
+
# Render the contents of a webpack manifest file
|
23
|
+
# @param context [String] Root directory that contains the manifest file
|
24
|
+
#
|
25
|
+
# @return [String] Returns "MISSING_WEBPACK_MANIFEST" if the manifest
|
26
|
+
# file isnt found
|
27
|
+
# @return [nil] Returns nil if the asset isnt found
|
28
|
+
# @return [String] Returns the path to the asset if no issues parsing
|
29
|
+
#
|
30
|
+
# @raise [WebpackAssetError] if unable to find css or js in the manifest
|
31
|
+
# file
|
15
32
|
def render(context)
|
16
33
|
@context = context
|
17
34
|
site = context.registers[:site]
|
18
35
|
|
36
|
+
manifest_file = site.in_root_dir(".bridgetown-webpack", "manifest.json")
|
37
|
+
|
38
|
+
parse_manifest_file(manifest_file)
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
def parse_manifest_file(manifest_file)
|
44
|
+
return "MISSING_WEBPACK_MANIFEST" unless File.exist?(manifest_file)
|
45
|
+
|
46
|
+
manifest = JSON.parse(File.read(manifest_file))
|
19
47
|
frontend_path = relative_url("_bridgetown/static")
|
20
48
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
else
|
31
|
-
Bridgetown.logger.error("Unknown Webpack asset type", @asset_type)
|
32
|
-
nil
|
33
|
-
end
|
34
|
-
else
|
35
|
-
"MISSING_WEBPACK_MANIFEST"
|
49
|
+
known_assets = %w(js css)
|
50
|
+
|
51
|
+
if known_assets.include?(@asset_type)
|
52
|
+
asset_path = manifest["main.#{@asset_type}"]
|
53
|
+
|
54
|
+
log_webpack_asset_error(@asset_type) if asset_path.nil?
|
55
|
+
|
56
|
+
asset_path = asset_path.split("/").last
|
57
|
+
return [frontend_path, @asset_type, asset_path].join("/")
|
36
58
|
end
|
59
|
+
|
60
|
+
Bridgetown.logger.error("Unknown Webpack asset type", @asset_type)
|
61
|
+
nil
|
62
|
+
end
|
63
|
+
|
64
|
+
def log_webpack_asset_error(asset_type)
|
65
|
+
error_message = "There was an error parsing your #{asset_type} files. \
|
66
|
+
Please check your #{asset_type} for any errors."
|
67
|
+
|
68
|
+
Bridgetown.logger.warn(Errors::WebpackAssetError, error_message)
|
37
69
|
end
|
38
70
|
end
|
39
71
|
end
|