bridgetown-core 2.1.2 → 2.2.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/bin/bridgetown +1 -1
- data/bridgetown-core.gemspec +1 -1
- data/lib/bridgetown-core/commands/build.rb +3 -0
- data/lib/bridgetown-core/commands/esbuild/esbuild.defaults.js.erb +5 -6
- data/lib/bridgetown-core/commands/esbuild/update.rb +2 -1
- data/lib/bridgetown-core/commands/help.rb +2 -2
- data/lib/bridgetown-core/commands/new.rb +16 -0
- data/lib/bridgetown-core/commands/start.rb +20 -13
- data/lib/bridgetown-core/concerns/localizable.rb +32 -16
- data/lib/bridgetown-core/concerns/site/renderable.rb +21 -0
- data/lib/bridgetown-core/concerns/site/ssr.rb +0 -1
- data/lib/bridgetown-core/configuration/configuration_dsl.rb +31 -13
- data/lib/bridgetown-core/configuration.rb +1 -1
- data/lib/bridgetown-core/converters/liquid_templates.rb +1 -0
- data/lib/bridgetown-core/generated_page.rb +7 -0
- data/lib/bridgetown-core/helpers.rb +1 -1
- data/lib/bridgetown-core/rack/routes.rb +28 -17
- data/lib/bridgetown-core/readers/plugin_content_reader.rb +16 -1
- data/lib/bridgetown-core/resource/base.rb +1 -1
- data/lib/bridgetown-core/tags/ruby_render.rb +45 -0
- data/lib/bridgetown-core/utils/initializers.rb +12 -1
- data/lib/bridgetown-core/utils/wikilinks.rb +60 -0
- data/lib/bridgetown-core/utils.rb +9 -8
- data/lib/site_template/Gemfile.erb +5 -1
- data/lib/site_template/config/falcon.erb +23 -0
- data/lib/site_template/package.json.erb +1 -2
- metadata +14 -8
- /data/lib/site_template/config/{puma.rb → puma.erb} +0 -0
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: e9715f653a27d94059baa731a1857efa33b69db2206ba2d18b8f4222765f093b
|
|
4
|
+
data.tar.gz: 0214baa25fa3ed326df7e62f24a3996f018c6586cc5e75b5882d91594bc26eb0
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 7e74294c2a04ab34b80ea4ebe0e917dfc0d23b6b53003c355f25739a3d01ddc33eae1eb722b0cc3489c84d33dd3adfcc49dc2d497785932f4e6c0ee14b5ead75
|
|
7
|
+
data.tar.gz: 614ef83083050fcff1e2a8585dc06591917448273bcf95f29c9aaeba5650dc263d10a49652c9d1e29594543fc7465ebb7cbb8035c57e96ea60d8512a79f0e489
|
data/bin/bridgetown
CHANGED
|
@@ -31,7 +31,7 @@ custom_commands_file = File.expand_path("config/custom_commands.rb", Dir.pwd)
|
|
|
31
31
|
require custom_commands_file if File.exist?(custom_commands_file)
|
|
32
32
|
|
|
33
33
|
begin
|
|
34
|
-
Bridgetown::Commands::Application.parse(ARGV).call
|
|
34
|
+
Bridgetown::Commands::Application.parse(ARGV.dup).call
|
|
35
35
|
rescue Samovar::MissingValueError => e
|
|
36
36
|
puts "#{"Command error:".bold.red} #{e.message.to_s.yellow}\n\n"
|
|
37
37
|
e.command.print_usage
|
data/bridgetown-core.gemspec
CHANGED
|
@@ -39,7 +39,7 @@ Gem::Specification.new do |spec|
|
|
|
39
39
|
spec.add_dependency("csv", "~> 3.2")
|
|
40
40
|
spec.add_dependency("erubi", "~> 1.9")
|
|
41
41
|
spec.add_dependency("faraday", "~> 2.0")
|
|
42
|
-
spec.add_dependency("faraday-follow_redirects", "~> 0.
|
|
42
|
+
spec.add_dependency("faraday-follow_redirects", "~> 0.5")
|
|
43
43
|
spec.add_dependency("freyia", ">= 0.5")
|
|
44
44
|
spec.add_dependency("i18n", "~> 1.0")
|
|
45
45
|
spec.add_dependency("irb", ">= 1.14")
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require "bridgetown-core/commands/start"
|
|
4
|
+
|
|
3
5
|
module Bridgetown
|
|
4
6
|
module Commands
|
|
5
7
|
class Build < Bridgetown::Command
|
|
@@ -9,6 +11,7 @@ module Bridgetown
|
|
|
9
11
|
|
|
10
12
|
options do
|
|
11
13
|
BuildOptions.include_options(self)
|
|
14
|
+
Start::StartOptions.include_options(self) if ARGV[0] == "start"
|
|
12
15
|
option "-w/--watch", "Watch for changes and rebuild"
|
|
13
16
|
end
|
|
14
17
|
|
|
@@ -16,11 +16,10 @@ const autogeneratedBridgetownConfig = {
|
|
|
16
16
|
"islandsDir": "_islands"
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
-
import path from "path"
|
|
20
|
-
import fsLib from "fs"
|
|
19
|
+
import path from "node:path"
|
|
20
|
+
import fsLib from "node:fs"
|
|
21
21
|
const fs = fsLib.promises
|
|
22
|
-
import { pathToFileURL, fileURLToPath } from "url"
|
|
23
|
-
import { glob } from "glob"
|
|
22
|
+
import { pathToFileURL, fileURLToPath } from "node:url"
|
|
24
23
|
import postcss from "postcss"
|
|
25
24
|
import postCssImport from "postcss-import"
|
|
26
25
|
import readCache from "read-cache"
|
|
@@ -72,7 +71,7 @@ const importGlobPlugin = (options, bridgetownConfig) => ({
|
|
|
72
71
|
})
|
|
73
72
|
|
|
74
73
|
build.onLoad({ filter: /.*/, namespace: "import-glob" }, async (args) => {
|
|
75
|
-
const files =
|
|
74
|
+
const files = fsLib.globSync(args.pluginData.path, {
|
|
76
75
|
cwd: args.pluginData.resolveDir,
|
|
77
76
|
})
|
|
78
77
|
.filter(module => options.excludeFilter ? !options.excludeFilter.test(module) : true)
|
|
@@ -317,7 +316,7 @@ export default async (esbuildOptions, ...args) => {
|
|
|
317
316
|
const entryPoints = esbuildOptions.entryPoints || ["./frontend/javascript/index.js"]
|
|
318
317
|
if (esbuildOptions.entryPoints) delete esbuildOptions.entryPoints
|
|
319
318
|
|
|
320
|
-
const islands =
|
|
319
|
+
const islands = fsLib.globSync(`./${bridgetownConfig.source}/${bridgetownConfig.islandsDir}/*.{js,js.rb}`).map(item => `./${item}`)
|
|
321
320
|
const islandsAsObject = islands.reduce((obj, str) => obj[str] = str, {})
|
|
322
321
|
|
|
323
322
|
esbuild.context({
|
|
@@ -16,7 +16,8 @@ end
|
|
|
16
16
|
gsub_file "postcss.config.js", "module.exports =", "export default"
|
|
17
17
|
gsub_file "esbuild.config.js", 'const build = require("./config/esbuild.defaults.js")',
|
|
18
18
|
'import build from "./config/esbuild.defaults.js"'
|
|
19
|
-
add_npm_package "esbuild@latest
|
|
19
|
+
add_npm_package "esbuild@latest" unless Bridgetown.env.test?
|
|
20
|
+
remove_npm_package "glob"
|
|
20
21
|
|
|
21
22
|
say "\n🎉 esbuild configuration updated successfully!"
|
|
22
23
|
say "You may need to add `$styles/` to the front of your main CSS imports."
|
|
@@ -5,7 +5,7 @@ module Bridgetown
|
|
|
5
5
|
class Help < Bridgetown::Command
|
|
6
6
|
self.description = "Show detailed command usage information and exit"
|
|
7
7
|
|
|
8
|
-
one :command, "The name of a Bridgetown command", required:
|
|
8
|
+
one :command, "The name of a Bridgetown command", required: false
|
|
9
9
|
|
|
10
10
|
def call
|
|
11
11
|
found_command = parent.class.table[:command].commands[command]
|
|
@@ -14,7 +14,7 @@ module Bridgetown
|
|
|
14
14
|
|
|
15
15
|
return if found_command
|
|
16
16
|
|
|
17
|
-
puts "Unknown command: #{command}\n\n"
|
|
17
|
+
puts "Unknown command: #{command}\n\n" if command
|
|
18
18
|
parent.print_usage
|
|
19
19
|
end
|
|
20
20
|
end
|
|
@@ -18,6 +18,7 @@ module Bridgetown
|
|
|
18
18
|
"Comma separated list of bundled configurations to perform"
|
|
19
19
|
option "-h/--help", "Print help for the new command"
|
|
20
20
|
option "-t/--templates <erb|serbea|liquid>", "Preferred template engine (defaults to ERB)"
|
|
21
|
+
option "-s/--server <falcon|puma>", "The Rack-compliant web server to install"
|
|
21
22
|
option "--force", "Force creation even if PATH already exists"
|
|
22
23
|
option "--skip-bundle", "Skip 'bundle install'"
|
|
23
24
|
option "--skip-npm", "Skip 'npm install'"
|
|
@@ -25,6 +26,7 @@ module Bridgetown
|
|
|
25
26
|
end
|
|
26
27
|
|
|
27
28
|
DOCSURL = "https://bridgetownrb.com/docs"
|
|
29
|
+
SUPPORTED_RACK_SERVERS = %w[falcon puma].freeze
|
|
28
30
|
|
|
29
31
|
def self.exit_on_failure?
|
|
30
32
|
false
|
|
@@ -83,6 +85,10 @@ module Bridgetown
|
|
|
83
85
|
!options[:use_sass]
|
|
84
86
|
end
|
|
85
87
|
|
|
88
|
+
def rack_server_option
|
|
89
|
+
SUPPORTED_RACK_SERVERS.find { _1 == options[:server] } || "falcon"
|
|
90
|
+
end
|
|
91
|
+
|
|
86
92
|
def disable_postcss?
|
|
87
93
|
# TODO: add option not to use postcss/sass at all
|
|
88
94
|
false
|
|
@@ -105,6 +111,8 @@ module Bridgetown
|
|
|
105
111
|
template("src/posts.md.erb", "src/posts.md")
|
|
106
112
|
copy_file("frontend/styles/syntax-highlighting.css")
|
|
107
113
|
|
|
114
|
+
setup_rack_server
|
|
115
|
+
|
|
108
116
|
case options[:templates]
|
|
109
117
|
when "serbea"
|
|
110
118
|
setup_serbea_templates
|
|
@@ -144,6 +152,14 @@ module Bridgetown
|
|
|
144
152
|
RUBY
|
|
145
153
|
end
|
|
146
154
|
|
|
155
|
+
def setup_rack_server
|
|
156
|
+
if rack_server_option == "puma"
|
|
157
|
+
template "config/puma.erb", "config/puma.rb"
|
|
158
|
+
else
|
|
159
|
+
template "config/falcon.erb", "config/falcon.rb"
|
|
160
|
+
end
|
|
161
|
+
end
|
|
162
|
+
|
|
147
163
|
def configure_sass
|
|
148
164
|
template("postcss.config.js.erb", "postcss.config.js") unless disable_postcss?
|
|
149
165
|
copy_file("frontend/styles/index.css", "frontend/styles/index.scss")
|
|
@@ -15,10 +15,6 @@ module Bridgetown
|
|
|
15
15
|
server.to_s.split("::").last
|
|
16
16
|
end
|
|
17
17
|
|
|
18
|
-
def using_puma?
|
|
19
|
-
name == "Puma"
|
|
20
|
-
end
|
|
21
|
-
|
|
22
18
|
def serveable?
|
|
23
19
|
server
|
|
24
20
|
true
|
|
@@ -29,6 +25,19 @@ module Bridgetown
|
|
|
29
25
|
|
|
30
26
|
module Commands
|
|
31
27
|
class Start < Bridgetown::Command
|
|
28
|
+
module StartOptions
|
|
29
|
+
def self.include_options(klass)
|
|
30
|
+
klass.option "-P/--port <NUM>",
|
|
31
|
+
"Serve your site on the specified port. Defaults to 4000",
|
|
32
|
+
type: Integer
|
|
33
|
+
klass.option "-B/--bind <IP>", "IP address for the server to bind to", default: "0.0.0.0"
|
|
34
|
+
klass.option "--skip-frontend",
|
|
35
|
+
"Don't load the frontend bundler (always true for production)"
|
|
36
|
+
klass.option "--skip-live-reload",
|
|
37
|
+
"Don't use the live reload functionality (always true for production)"
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
32
41
|
include ConfigurationOverridable
|
|
33
42
|
include Freyia::Setup
|
|
34
43
|
include Inclusive
|
|
@@ -37,13 +46,7 @@ module Bridgetown
|
|
|
37
46
|
|
|
38
47
|
options do
|
|
39
48
|
BuildOptions.include_options(self)
|
|
40
|
-
|
|
41
|
-
"Serve your site on the specified port. Defaults to 4000",
|
|
42
|
-
type: Integer
|
|
43
|
-
option "-B/--bind <IP>", "IP address for the server to bind to", default: "0.0.0.0"
|
|
44
|
-
option "--skip-frontend", "Don't load the frontend bundler (always true for production)"
|
|
45
|
-
option "--skip-live-reload",
|
|
46
|
-
"Don't use the live reload functionality (always true for production)"
|
|
49
|
+
StartOptions.include_options(self)
|
|
47
50
|
end
|
|
48
51
|
|
|
49
52
|
def call # rubocop:disable Metrics
|
|
@@ -58,7 +61,7 @@ module Bridgetown
|
|
|
58
61
|
# Load Bridgetown configuration into thread memory
|
|
59
62
|
bt_options = configuration_with_overrides(options)
|
|
60
63
|
bt_options.port = port = load_env_and_determine_port(bt_options, options)
|
|
61
|
-
# TODO: support
|
|
64
|
+
# TODO: support Falcon serving HTTPS directly
|
|
62
65
|
bt_bound_url = "http://#{bt_options.bind}:#{port}"
|
|
63
66
|
|
|
64
67
|
# Set a local site URL in the config if one is not available
|
|
@@ -66,6 +69,10 @@ module Bridgetown
|
|
|
66
69
|
bt_options.url = bt_bound_url.sub("0.0.0.0", "localhost")
|
|
67
70
|
end
|
|
68
71
|
|
|
72
|
+
# Temporary hack to silence `Errno::EPIPE: Broken pipe` errors in dev.
|
|
73
|
+
# Only happens when using Falcon with HTTP/1.1.
|
|
74
|
+
# When we can use Falcon with HTTP/2 in dev, we can remove this line.
|
|
75
|
+
ENV["CONSOLE_ERROR"] = "Async::Task"
|
|
69
76
|
Bridgetown::Server.new({
|
|
70
77
|
Host: bt_options.bind,
|
|
71
78
|
Port: port,
|
|
@@ -74,7 +81,7 @@ module Bridgetown
|
|
|
74
81
|
if server.serveable?
|
|
75
82
|
pid_tracker.create_pid_dir
|
|
76
83
|
|
|
77
|
-
bt_options.skip_live_reload ||=
|
|
84
|
+
bt_options.skip_live_reload ||= false
|
|
78
85
|
|
|
79
86
|
build_args = ["-w"] + Array(ARGV[1..])
|
|
80
87
|
build_pid = Process.fork { Bridgetown::Commands::Build[*build_args].() }
|
|
@@ -2,23 +2,16 @@
|
|
|
2
2
|
|
|
3
3
|
module Bridgetown
|
|
4
4
|
module Localizable
|
|
5
|
+
# Sort items by their locale's position in the configured available_locales list.
|
|
6
|
+
# Items with unknown locales sort last.
|
|
7
|
+
def self.sort_by_locale(items, available_locales)
|
|
8
|
+
items.sort_by { |item| available_locales.index(item.data.locale) || Float::INFINITY }
|
|
9
|
+
end
|
|
10
|
+
|
|
5
11
|
def all_locales
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
when Bridgetown::GeneratedPage
|
|
10
|
-
site.generated_pages
|
|
11
|
-
else
|
|
12
|
-
[]
|
|
13
|
-
end
|
|
14
|
-
|
|
15
|
-
matching_resources = result_set.select do |item|
|
|
16
|
-
matches_resource?(item)
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
matching_resources.sort_by do |item|
|
|
20
|
-
site.config.available_locales.index item.data.locale
|
|
21
|
-
end
|
|
12
|
+
return @all_locales if @all_locales
|
|
13
|
+
|
|
14
|
+
@all_locales = site.tmp_cache.dig(:locale_index, locale_index_key) || find_matching_locales
|
|
22
15
|
end
|
|
23
16
|
|
|
24
17
|
def matches_resource?(item)
|
|
@@ -32,5 +25,28 @@ module Bridgetown
|
|
|
32
25
|
def localeless_path
|
|
33
26
|
relative_path.gsub(%r{\A#{data.locale}/}, "")
|
|
34
27
|
end
|
|
28
|
+
|
|
29
|
+
# Key used to group locale variants of the same content in the locale index.
|
|
30
|
+
# Uses the same matching criteria as matches_resource? (slug + path identity).
|
|
31
|
+
def locale_index_key
|
|
32
|
+
slug = data.slug
|
|
33
|
+
return unless slug
|
|
34
|
+
|
|
35
|
+
path_key = relative_path.is_a?(String) ? localeless_path : relative_path.parent.to_s
|
|
36
|
+
prefix = respond_to?(:collection) ? collection.label : "generated"
|
|
37
|
+
|
|
38
|
+
"#{prefix}:#{slug}:#{path_key}"
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
private
|
|
42
|
+
|
|
43
|
+
def find_matching_locales
|
|
44
|
+
result_set = respond_to?(:collection) ? collection.resources : site.generated_pages
|
|
45
|
+
|
|
46
|
+
Bridgetown::Localizable.sort_by_locale(
|
|
47
|
+
result_set.select { |item| matches_resource?(item) },
|
|
48
|
+
site.config.available_locales
|
|
49
|
+
)
|
|
50
|
+
end
|
|
35
51
|
end
|
|
36
52
|
end
|
|
@@ -9,6 +9,7 @@ class Bridgetown::Site
|
|
|
9
9
|
# @see Document
|
|
10
10
|
def render
|
|
11
11
|
Bridgetown::Hooks.trigger :site, :pre_render, self
|
|
12
|
+
build_locale_index
|
|
12
13
|
execute_inline_ruby_for_layouts!
|
|
13
14
|
render_resources
|
|
14
15
|
generated_pages.each(&:transform!)
|
|
@@ -97,6 +98,26 @@ class Bridgetown::Site
|
|
|
97
98
|
)
|
|
98
99
|
end
|
|
99
100
|
|
|
101
|
+
# Builds a lookup index grouping resources by their locale-independent identity
|
|
102
|
+
# (collection + slug + localeless path). This turns `all_locales` from an O(n)
|
|
103
|
+
# linear scan into an O(1) hash lookup per resource, which is critical for sites
|
|
104
|
+
# with many localized pages.
|
|
105
|
+
#
|
|
106
|
+
# @return [void]
|
|
107
|
+
def build_locale_index
|
|
108
|
+
groups = Hash.new { |h, k| h[k] = [] }
|
|
109
|
+
|
|
110
|
+
collections.each_value.flat_map(&:resources).concat(generated_pages).each do |item|
|
|
111
|
+
key = item.locale_index_key
|
|
112
|
+
groups[key] << item if key
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
locale_order = config.available_locales
|
|
116
|
+
tmp_cache[:locale_index] = groups.transform_values do |items|
|
|
117
|
+
Bridgetown::Localizable.sort_by_locale(items, locale_order).freeze
|
|
118
|
+
end.freeze
|
|
119
|
+
end
|
|
120
|
+
|
|
100
121
|
# Renders all resources
|
|
101
122
|
#
|
|
102
123
|
# @return [void]
|
|
@@ -244,23 +244,41 @@ module Bridgetown
|
|
|
244
244
|
# Control the behavior of Bridgetown's live reload functionality in development
|
|
245
245
|
# @param bool [Boolean] - default: `true`
|
|
246
246
|
|
|
247
|
-
#
|
|
248
|
-
#
|
|
249
|
-
#
|
|
247
|
+
# Exclude source directories and/or files from the build conversion
|
|
248
|
+
# @param files_list [Array<String>] - you can pass multiple string arguments
|
|
249
|
+
# in lieu of an array
|
|
250
|
+
def exclude(*files_list)
|
|
251
|
+
files_list = Array(files_list[0]) if files_list.length == 1
|
|
252
|
+
get("exclude").tap do |value|
|
|
253
|
+
files_list.each { value << _1 }
|
|
254
|
+
end
|
|
255
|
+
end
|
|
250
256
|
|
|
251
|
-
#
|
|
252
|
-
#
|
|
253
|
-
#
|
|
254
|
-
#
|
|
257
|
+
# Force inclusion of directories and/or files in the conversion (e.g. starting with
|
|
258
|
+
# underscores or dots)
|
|
259
|
+
# @param files_list [Array<String>] - you can pass multiple string arguments
|
|
260
|
+
# in lieu of an array
|
|
261
|
+
def include(*files_list)
|
|
262
|
+
files_list = Array(files_list[0]) if files_list.length == 1
|
|
263
|
+
get("include").tap do |value|
|
|
264
|
+
files_list.each { value << _1 }
|
|
265
|
+
end
|
|
266
|
+
end
|
|
255
267
|
|
|
256
|
-
#
|
|
257
|
-
#
|
|
258
|
-
#
|
|
259
|
-
#
|
|
268
|
+
# Files to keep when clobbering the site destination (aka not generated in typical
|
|
269
|
+
# Bridgetown builds)
|
|
270
|
+
# @param files_list [Array<String>] - you can pass multiple string arguments
|
|
271
|
+
# in lieu of an array
|
|
272
|
+
def keep_files(*files_list)
|
|
273
|
+
files_list = Array(files_list[0]) if files_list.length == 1
|
|
274
|
+
get("keep_files").tap do |value|
|
|
275
|
+
files_list.each { value << _1 }
|
|
276
|
+
end
|
|
277
|
+
end
|
|
260
278
|
|
|
261
279
|
# @!method autoload_paths
|
|
262
|
-
# Add paths to the Zeitwerk autoloader. Use a `config.
|
|
263
|
-
# advanced hash config
|
|
280
|
+
# Add paths to the Zeitwerk autoloader. Use a `config.autoload_paths << "..."` syntax or
|
|
281
|
+
# a more advanced hash config
|
|
264
282
|
# @example Add a new path for autoloading and eager load on boot
|
|
265
283
|
# config.autoload_paths << {
|
|
266
284
|
# path: "loadme",
|
|
@@ -6,7 +6,7 @@ module Bridgetown
|
|
|
6
6
|
using Bridgetown::Refinements
|
|
7
7
|
|
|
8
8
|
# Built-in initializer list which isn't Gem-backed:
|
|
9
|
-
REQUIRE_DENYLIST = %i(external_sources parse_routes ssr) # rubocop:disable Style/MutableConstant
|
|
9
|
+
REQUIRE_DENYLIST = %i(external_sources parse_routes ssr wikilinks) # rubocop:disable Style/MutableConstant
|
|
10
10
|
|
|
11
11
|
Initializer = Struct.new(:name, :block, :completed) do
|
|
12
12
|
def to_s
|
|
@@ -25,6 +25,13 @@ module Bridgetown
|
|
|
25
25
|
.htm
|
|
26
26
|
).freeze
|
|
27
27
|
|
|
28
|
+
# NOTE: these are no-op methods, only here to provide "compatibility" with
|
|
29
|
+
# `Bridgetown::Resource::Base` in edge case rendering contexts. There's
|
|
30
|
+
# actually no case when a GeneratedPage will have a linkage with the Roda
|
|
31
|
+
# app because GeneratedPage instances are only used in static builds.
|
|
32
|
+
def roda_app=(*); end
|
|
33
|
+
def roda_app = nil
|
|
34
|
+
|
|
28
35
|
# Initialize a new GeneratedPage
|
|
29
36
|
#
|
|
30
37
|
# @param site [Bridgetown::Site]
|
|
@@ -114,29 +114,39 @@ module Bridgetown
|
|
|
114
114
|
file_to_check = Bridgetown.live_reload_path
|
|
115
115
|
errors_file = Bridgetown.build_errors_path
|
|
116
116
|
|
|
117
|
+
# rubocop:disable Metrics/BlockLength
|
|
117
118
|
app.request.get "_bridgetown/live_reload" do
|
|
118
119
|
@_mod = File.exist?(file_to_check) ? File.stat(file_to_check).mtime.to_i : 0
|
|
119
120
|
event_stream = proc do |stream|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
121
|
+
# We don't need to do this when using Falcon.
|
|
122
|
+
# Puma hangs with Ctrl+C without this manual interruption.
|
|
123
|
+
# Very very hacky, but it's only in dev.
|
|
124
|
+
# https://github.com/puma/puma/issues/3569
|
|
125
|
+
unless defined? Falcon
|
|
126
|
+
trap(:INT) do
|
|
127
|
+
stream.close
|
|
128
|
+
raise Interrupt
|
|
129
|
+
end
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
loop do
|
|
133
|
+
new_mod = File.exist?(file_to_check) ? File.stat(file_to_check).mtime.to_i : 0
|
|
134
|
+
|
|
135
|
+
if @_mod < new_mod
|
|
136
|
+
stream.write "data: reloaded!\n\n"
|
|
135
137
|
break
|
|
138
|
+
elsif File.exist?(errors_file)
|
|
139
|
+
stream.write "event: builderror\ndata: #{File.read(errors_file).to_json}\n\n"
|
|
140
|
+
else
|
|
141
|
+
stream.write "data: #{new_mod}\n\n"
|
|
136
142
|
end
|
|
137
|
-
|
|
138
|
-
|
|
143
|
+
|
|
144
|
+
sleep sleep_interval
|
|
145
|
+
rescue Errno::EPIPE # User refreshed the page
|
|
146
|
+
break
|
|
139
147
|
end
|
|
148
|
+
ensure
|
|
149
|
+
stream.close
|
|
140
150
|
end
|
|
141
151
|
|
|
142
152
|
app.request.halt [200, {
|
|
@@ -144,6 +154,7 @@ module Bridgetown
|
|
|
144
154
|
"cache-control" => "no-cache",
|
|
145
155
|
}, event_stream,]
|
|
146
156
|
end
|
|
157
|
+
# rubocop:enable Metrics/BlockLength
|
|
147
158
|
end
|
|
148
159
|
end
|
|
149
160
|
|
|
@@ -23,6 +23,7 @@ module Bridgetown
|
|
|
23
23
|
end
|
|
24
24
|
end
|
|
25
25
|
|
|
26
|
+
# rubocop:disable Metrics/MethodLength, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
|
26
27
|
def read_content_root(collection_name, content_dir)
|
|
27
28
|
collection = site.collections[collection_name]
|
|
28
29
|
unless collection
|
|
@@ -35,10 +36,16 @@ module Bridgetown
|
|
|
35
36
|
|
|
36
37
|
Find.find(content_dir) do |path|
|
|
37
38
|
if File.directory?(path)
|
|
38
|
-
|
|
39
|
+
if rejected_by_external_sources_filter?(path, collection_name) ||
|
|
40
|
+
EntryFilter::SPECIAL_LEADING_CHAR_REGEX.match?(File.basename(path))
|
|
41
|
+
Find.prune
|
|
42
|
+
end
|
|
43
|
+
|
|
39
44
|
next
|
|
40
45
|
end
|
|
41
46
|
|
|
47
|
+
next if rejected_by_external_sources_filter?(path, collection_name)
|
|
48
|
+
|
|
42
49
|
if File.symlink?(path)
|
|
43
50
|
Bridgetown.logger.warn "Plugin content reader:", "Ignored symlinked asset: #{path}"
|
|
44
51
|
else
|
|
@@ -46,6 +53,14 @@ module Bridgetown
|
|
|
46
53
|
end
|
|
47
54
|
end
|
|
48
55
|
end
|
|
56
|
+
# rubocop:enable Metrics/MethodLength, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
|
57
|
+
|
|
58
|
+
def rejected_by_external_sources_filter?(path, collection_name)
|
|
59
|
+
filter = site.config.external_sources_filters&.dig(collection_name)
|
|
60
|
+
return false unless filter
|
|
61
|
+
|
|
62
|
+
!filter.call(File.basename(path), path)
|
|
63
|
+
end
|
|
49
64
|
|
|
50
65
|
# @param collection [Bridgetown::Collection]
|
|
51
66
|
def read_content_file(content_dir, path, collection)
|
|
@@ -368,7 +368,7 @@ module Bridgetown
|
|
|
368
368
|
correct_locale = origin_data["locale"] || origin_data[:locale] || data.locale
|
|
369
369
|
model.attributes = origin_data
|
|
370
370
|
model.attributes.locale = correct_locale.to_s == "multi" ? data.locale : correct_locale
|
|
371
|
-
@relative_url = @absolute_url = nil # wipe memoizations
|
|
371
|
+
@relative_url = @absolute_url = @all_locales = nil # wipe memoizations
|
|
372
372
|
read!
|
|
373
373
|
tax_diff = past_values.any? { |k, v| @data.peek[k] != v }
|
|
374
374
|
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Bridgetown
|
|
4
|
+
module Tags
|
|
5
|
+
class RubyRender < Liquid::Tag
|
|
6
|
+
using Bridgetown::Refinements
|
|
7
|
+
|
|
8
|
+
# @param tag_name [String] "ruby_render"
|
|
9
|
+
# @param input [String] The input to the tag: snake-case name of the
|
|
10
|
+
# Ruby component, plus initialize args. Example:
|
|
11
|
+
# '"card", title: "Hello", footer: "I am a card"'
|
|
12
|
+
# @param tokens [Hash] A hash of config tokens for Liquid
|
|
13
|
+
def initialize(tag_name, input, tokens)
|
|
14
|
+
super
|
|
15
|
+
@input = input
|
|
16
|
+
|
|
17
|
+
@attributes = {}
|
|
18
|
+
input.scan(Liquid::TagAttributes) do |key, value|
|
|
19
|
+
@attributes[key.to_sym] = parse_expression(value)
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# @param context [Liquid::Context]
|
|
24
|
+
# @return [String]
|
|
25
|
+
def render(context)
|
|
26
|
+
view_context = Bridgetown::RubyTemplateView.new(context.registers[:resource])
|
|
27
|
+
component_class_name_snakecase = @input.split(",").first
|
|
28
|
+
component_class_name = component_class_name_snakecase.tr("\"'", "").camelize.strip
|
|
29
|
+
component_class = self.class.const_get(component_class_name)
|
|
30
|
+
@attributes.each do |key, value|
|
|
31
|
+
@attributes[key] = value.evaluate(context) if value.is_a?(Liquid::VariableLookup)
|
|
32
|
+
end
|
|
33
|
+
component_instance = component_class.new(**@attributes)
|
|
34
|
+
|
|
35
|
+
if component_instance.respond_to?(:render_in)
|
|
36
|
+
component_instance.render_in(view_context)
|
|
37
|
+
else
|
|
38
|
+
component_instance.to_s
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
Liquid::Template.register_tag("ruby_render", Bridgetown::Tags::RubyRender)
|
|
@@ -13,7 +13,7 @@ Bridgetown.initializer :ssr do |config, setup: nil, **options|
|
|
|
13
13
|
end
|
|
14
14
|
end
|
|
15
15
|
|
|
16
|
-
Bridgetown.initializer :external_sources do |config, contents
|
|
16
|
+
Bridgetown.initializer :external_sources do |config, contents:, filters: nil|
|
|
17
17
|
Bridgetown::ExternalSources = Module.new
|
|
18
18
|
|
|
19
19
|
contents.each do |coll, path|
|
|
@@ -35,6 +35,13 @@ Bridgetown.initializer :external_sources do |config, contents:|
|
|
|
35
35
|
contents.each_value do |path|
|
|
36
36
|
config.additional_watch_paths << path
|
|
37
37
|
end
|
|
38
|
+
|
|
39
|
+
if filters
|
|
40
|
+
config.external_sources_filters = {}
|
|
41
|
+
filters.each do |coll, filter|
|
|
42
|
+
config.external_sources_filters[coll] = filter
|
|
43
|
+
end
|
|
44
|
+
end
|
|
38
45
|
end
|
|
39
46
|
|
|
40
47
|
Bridgetown.initializer :parse_routes do |config|
|
|
@@ -73,3 +80,7 @@ Bridgetown.initializer :parse_routes do |config|
|
|
|
73
80
|
|
|
74
81
|
File.write(File.join(config.root_dir, ".routes.json"), routing_tree.to_json(json_gen_opts))
|
|
75
82
|
end
|
|
83
|
+
|
|
84
|
+
Bridgetown.initializer :wikilinks do |config|
|
|
85
|
+
Bridgetown::Utils::Wikilinks.setup_parsing_hook config
|
|
86
|
+
end
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Bridgetown
|
|
4
|
+
module Utils
|
|
5
|
+
class Wikilinks
|
|
6
|
+
# @param config [Bridgetown::Configuration::ConfigurationDSL]
|
|
7
|
+
def self.setup_parsing_hook(config)
|
|
8
|
+
markdown_exts = config.markdown_ext.split(",").map { ".#{_1}" }
|
|
9
|
+
|
|
10
|
+
config.hook :resources, :pre_render, priority: :low do |resource|
|
|
11
|
+
next unless markdown_exts.include?(resource.relative_path.extname)
|
|
12
|
+
next if resource.data.bypass_wikilinks
|
|
13
|
+
|
|
14
|
+
Wikilinks.new(resource:).convert
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# @param resource [Bridgetown::Resource::Base]
|
|
19
|
+
def initialize(resource:)
|
|
20
|
+
@resource = resource
|
|
21
|
+
@site = resource.site
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# Sets the resource's new content to the parsed string where `[[Wiki-style Links]]` are
|
|
25
|
+
# turned into `[Wiki-style Links](...)`
|
|
26
|
+
def convert
|
|
27
|
+
@resource.content = parse_content(@resource.content)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# Parse all `[[wiki links]]` unless they're escaped, e.g. `\[[don't parse me bro]]`.
|
|
31
|
+
# You can use a pipe character to control the displayed text of the link:
|
|
32
|
+
# `[[Actual page title|Link text here]]`, and you can also add an anchor for the link:
|
|
33
|
+
# `[[Page Title#page_section_anchor]]`
|
|
34
|
+
# @param input [String]
|
|
35
|
+
# @return String
|
|
36
|
+
def parse_content(input)
|
|
37
|
+
input.gsub %r!(\\?)\[\[(.+?)\]\]! do
|
|
38
|
+
next "[[#{Regexp.last_match[2]}]]" if Regexp.last_match[1] == "\\"
|
|
39
|
+
|
|
40
|
+
search_title, printed_title =
|
|
41
|
+
Regexp.last_match[2].split("|").map(&:strip)
|
|
42
|
+
search_title, anchor = search_title.split("#")
|
|
43
|
+
anchor = "##{anchor}" if anchor
|
|
44
|
+
title = printed_title || search_title
|
|
45
|
+
found = @site.resources.find { _1.data.title == search_title }
|
|
46
|
+
if found
|
|
47
|
+
"[#{title}](#{found.relative_url}#{anchor}){:.wikilink}"
|
|
48
|
+
else
|
|
49
|
+
missing_title_strategy(title)
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def missing_title_strategy(title)
|
|
55
|
+
# TODO: this should be configurable
|
|
56
|
+
"<u>#{title} (missing)</u>"
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
@@ -9,6 +9,7 @@ module Bridgetown
|
|
|
9
9
|
autoload :RequireGems, "bridgetown-core/utils/require_gems"
|
|
10
10
|
autoload :RubyExec, "bridgetown-core/utils/ruby_exec"
|
|
11
11
|
autoload :SmartyPantsConverter, "bridgetown-core/utils/smarty_pants_converter"
|
|
12
|
+
autoload :Wikilinks, "bridgetown-core/utils/wikilinks"
|
|
12
13
|
|
|
13
14
|
# Constants for use in #slugify
|
|
14
15
|
SLUGIFY_MODES = %w(raw default pretty simple ascii latin).freeze
|
|
@@ -149,30 +150,30 @@ module Bridgetown
|
|
|
149
150
|
# When mode is `pretty`, some non-alphabetic characters (`._~!$&'()+,;=@`)
|
|
150
151
|
# are not replaced with hyphen.
|
|
151
152
|
#
|
|
152
|
-
# When mode is `ascii`,
|
|
153
|
-
# `a-z` (lowercase), `A-Z` (uppercase) and `0-9` (numbers) are
|
|
153
|
+
# When mode is `ascii`, everything else except ASCII characters
|
|
154
|
+
# `a-z` (lowercase), `A-Z` (uppercase) and `0-9` (numbers) are replaced with hyphen.
|
|
154
155
|
#
|
|
155
156
|
# When mode is `latin`, the input string is first preprocessed so that
|
|
156
157
|
# any letters with accents are replaced with the plain letter. Afterwards,
|
|
157
158
|
# it follows the `default` mode of operation.
|
|
158
159
|
#
|
|
159
|
-
# If `cased` is `
|
|
160
|
+
# If `cased` is `false`, all uppercase letters in the result string are
|
|
160
161
|
# replaced with their lowercase counterparts.
|
|
161
162
|
#
|
|
162
163
|
# @example
|
|
163
164
|
# slugify("The _config.yml file")
|
|
164
165
|
# # => "the-config-yml-file"
|
|
165
166
|
#
|
|
166
|
-
# slugify("The _config.yml file", "pretty")
|
|
167
|
+
# slugify("The _config.yml file", mode: "pretty")
|
|
167
168
|
# # => "the-_config.yml-file"
|
|
168
169
|
#
|
|
169
|
-
# slugify("The _config.yml file", "pretty", true)
|
|
170
|
-
# # => "The-_config.yml
|
|
170
|
+
# slugify("The _config.yml file", mode: "pretty", cased: true)
|
|
171
|
+
# # => "The-_config.yml-file"
|
|
171
172
|
#
|
|
172
|
-
# slugify("The _config.yml file", "ascii")
|
|
173
|
+
# slugify("The _config.yml file", mode: "ascii")
|
|
173
174
|
# # => "the-config-yml-file"
|
|
174
175
|
#
|
|
175
|
-
# slugify("The _config.yml file", "latin")
|
|
176
|
+
# slugify("The _config.yml file", mode: "latin")
|
|
176
177
|
# # => "the-config-yml-file"
|
|
177
178
|
#
|
|
178
179
|
# @param string [String] filename or title to slugify
|
|
@@ -30,9 +30,13 @@ gem "bridgetown", "~> <%= Bridgetown::VERSION %>"
|
|
|
30
30
|
# Uncomment to add file-based dynamic routing to your project:
|
|
31
31
|
# gem "bridgetown-routes", "~> <%= Bridgetown::VERSION %>"
|
|
32
32
|
|
|
33
|
-
#
|
|
33
|
+
# The Rack-compliant web server
|
|
34
34
|
# (you can optionally limit this to the "development" group)
|
|
35
|
+
<% if rack_server_option == "puma" %>
|
|
35
36
|
gem "puma", "< 8"
|
|
37
|
+
<% else %>
|
|
38
|
+
gem "falcon"
|
|
39
|
+
<% end %>
|
|
36
40
|
|
|
37
41
|
# Uncomment to use the Inspectors API to manipulate the output
|
|
38
42
|
# of your HTML or XML resources:
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
#!/usr/bin/env falcon-host
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
# This file configures Falcon for production.
|
|
5
|
+
# It is ignored in development when using `bin/bt start`.
|
|
6
|
+
#
|
|
7
|
+
# Use `falcon host` to start Falcon in production.
|
|
8
|
+
# `bundle exec falcon host config/falcon.rb`
|
|
9
|
+
|
|
10
|
+
require "falcon/environment/rack"
|
|
11
|
+
|
|
12
|
+
service "<%= @site_name %>" do
|
|
13
|
+
include Falcon::Environment::Rack
|
|
14
|
+
|
|
15
|
+
rackup_path \
|
|
16
|
+
File.expand_path("config.ru", Pathname.new(root).join(".."))
|
|
17
|
+
port ENV.fetch("BRIDGETOWN_PORT") { 4000 }
|
|
18
|
+
|
|
19
|
+
endpoint do
|
|
20
|
+
Async::HTTP::Endpoint
|
|
21
|
+
.parse("http://localhost", port: port)
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -8,8 +8,7 @@
|
|
|
8
8
|
"esbuild-dev": "node esbuild.config.js --watch"
|
|
9
9
|
},
|
|
10
10
|
"devDependencies": {
|
|
11
|
-
"esbuild": "^0.25.11",
|
|
12
|
-
"glob": "^11.0.3",
|
|
11
|
+
"esbuild": "^0.25.11"<%= "," unless disable_postcss? %>
|
|
13
12
|
<%- unless disable_postcss? -%>
|
|
14
13
|
"postcss": "^8.5.6",
|
|
15
14
|
"postcss-flexbugs-fixes": "^5.0.2",
|
metadata
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: bridgetown-core
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 2.
|
|
4
|
+
version: 2.2.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Bridgetown Team
|
|
8
|
+
autorequire:
|
|
8
9
|
bindir: bin
|
|
9
10
|
cert_chain: []
|
|
10
|
-
date:
|
|
11
|
+
date: 2026-05-20 00:00:00.000000000 Z
|
|
11
12
|
dependencies:
|
|
12
13
|
- !ruby/object:Gem::Dependency
|
|
13
14
|
name: addressable
|
|
@@ -71,14 +72,14 @@ dependencies:
|
|
|
71
72
|
requirements:
|
|
72
73
|
- - '='
|
|
73
74
|
- !ruby/object:Gem::Version
|
|
74
|
-
version: 2.
|
|
75
|
+
version: 2.2.0
|
|
75
76
|
type: :runtime
|
|
76
77
|
prerelease: false
|
|
77
78
|
version_requirements: !ruby/object:Gem::Requirement
|
|
78
79
|
requirements:
|
|
79
80
|
- - '='
|
|
80
81
|
- !ruby/object:Gem::Version
|
|
81
|
-
version: 2.
|
|
82
|
+
version: 2.2.0
|
|
82
83
|
- !ruby/object:Gem::Dependency
|
|
83
84
|
name: csv
|
|
84
85
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -127,14 +128,14 @@ dependencies:
|
|
|
127
128
|
requirements:
|
|
128
129
|
- - "~>"
|
|
129
130
|
- !ruby/object:Gem::Version
|
|
130
|
-
version: '0.
|
|
131
|
+
version: '0.5'
|
|
131
132
|
type: :runtime
|
|
132
133
|
prerelease: false
|
|
133
134
|
version_requirements: !ruby/object:Gem::Requirement
|
|
134
135
|
requirements:
|
|
135
136
|
- - "~>"
|
|
136
137
|
- !ruby/object:Gem::Version
|
|
137
|
-
version: '0.
|
|
138
|
+
version: '0.5'
|
|
138
139
|
- !ruby/object:Gem::Dependency
|
|
139
140
|
name: freyia
|
|
140
141
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -595,6 +596,7 @@ files:
|
|
|
595
596
|
- lib/bridgetown-core/tags/live_reload_dev_js.rb
|
|
596
597
|
- lib/bridgetown-core/tags/post_url.rb
|
|
597
598
|
- lib/bridgetown-core/tags/render_content.rb
|
|
599
|
+
- lib/bridgetown-core/tags/ruby_render.rb
|
|
598
600
|
- lib/bridgetown-core/tags/t.rb
|
|
599
601
|
- lib/bridgetown-core/tags/with.rb
|
|
600
602
|
- lib/bridgetown-core/tasks/bridgetown_tasks.rake
|
|
@@ -606,6 +608,7 @@ files:
|
|
|
606
608
|
- lib/bridgetown-core/utils/require_gems.rb
|
|
607
609
|
- lib/bridgetown-core/utils/ruby_exec.rb
|
|
608
610
|
- lib/bridgetown-core/utils/smarty_pants_converter.rb
|
|
611
|
+
- lib/bridgetown-core/utils/wikilinks.rb
|
|
609
612
|
- lib/bridgetown-core/watcher.rb
|
|
610
613
|
- lib/bridgetown-core/yaml_parser.rb
|
|
611
614
|
- lib/roda/plugins/bridgetown_server.rb
|
|
@@ -640,8 +643,9 @@ files:
|
|
|
640
643
|
- lib/site_template/TEMPLATES/serbea/_partials/_footer.serb
|
|
641
644
|
- lib/site_template/TEMPLATES/serbea/_partials/_head.serb
|
|
642
645
|
- lib/site_template/config.ru
|
|
646
|
+
- lib/site_template/config/falcon.erb
|
|
643
647
|
- lib/site_template/config/initializers.rb
|
|
644
|
-
- lib/site_template/config/puma.
|
|
648
|
+
- lib/site_template/config/puma.erb
|
|
645
649
|
- lib/site_template/frontend/javascript/index.js.erb
|
|
646
650
|
- lib/site_template/frontend/styles/index.css
|
|
647
651
|
- lib/site_template/frontend/styles/syntax-highlighting.css
|
|
@@ -671,6 +675,7 @@ metadata:
|
|
|
671
675
|
changelog_uri: https://github.com/bridgetownrb/bridgetown/releases
|
|
672
676
|
homepage_uri: https://www.bridgetownrb.com
|
|
673
677
|
rubygems_mfa_required: 'true'
|
|
678
|
+
post_install_message:
|
|
674
679
|
rdoc_options:
|
|
675
680
|
- "--charset=UTF-8"
|
|
676
681
|
require_paths:
|
|
@@ -686,7 +691,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
686
691
|
- !ruby/object:Gem::Version
|
|
687
692
|
version: '0'
|
|
688
693
|
requirements: []
|
|
689
|
-
rubygems_version: 3.
|
|
694
|
+
rubygems_version: 3.5.22
|
|
695
|
+
signing_key:
|
|
690
696
|
specification_version: 4
|
|
691
697
|
summary: A next-generation, progressive site generator & fullstack framework, powered
|
|
692
698
|
by Ruby
|
|
File without changes
|