bridgetown-routes 1.0.0.alpha2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.rubocop.yml +6 -0
- data/Rakefile +11 -0
- data/bridgetown-routes.gemspec +19 -0
- data/lib/bridgetown-routes/code_blocks.rb +27 -0
- data/lib/bridgetown-routes/helpers.rb +30 -0
- data/lib/bridgetown-routes/manifest.rb +53 -0
- data/lib/bridgetown-routes/roda_router.rb +54 -0
- data/lib/bridgetown-routes.rb +37 -0
- data/lib/roda/plugins/bridgetown_routes.rb +106 -0
- metadata +80 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 7d99af4d6cf66c15ad4ca1da7044ca24142f45dbf6035696573dbb8e5033f8c7
|
4
|
+
data.tar.gz: 8418e77c8b4bd9263468149ba6d231d5a51b6922ffe299291374b8abb8e2ba80
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 5f0528d922fbf73a90edf3f62fd584f8fba34853337228b2fa16dcb3e2f31a927d0c6e30ebe549a4762aa56f9649812c03d4c9be5b5f9e1597fac4e00d8c25ff
|
7
|
+
data.tar.gz: b17f234af39b21ec58721c842eb6f4bbd6294c579f0c4a9cf0884ad0a891aaf873e33b7a01d34efef9abd7d496281dd9ab42a5454ce6648320046ef555e2555d
|
data/.rubocop.yml
ADDED
data/Rakefile
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "../bridgetown-core/lib/bridgetown-core/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |spec|
|
6
|
+
spec.name = "bridgetown-routes"
|
7
|
+
spec.version = Bridgetown::VERSION
|
8
|
+
spec.author = "Bridgetown Team"
|
9
|
+
spec.email = "maintainers@bridgetownrb.com"
|
10
|
+
spec.summary = "A Bridgetown plugin to add support for file-based Roda backend routes within the source folder."
|
11
|
+
spec.homepage = "https://github.com/bridgetownrb/bridgetown/tree/main/bridgetown-routes"
|
12
|
+
spec.license = "MIT"
|
13
|
+
|
14
|
+
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r!^(test|script|spec|features)/!) }
|
15
|
+
spec.require_paths = ["lib"]
|
16
|
+
|
17
|
+
spec.add_dependency("bridgetown-core", Bridgetown::VERSION)
|
18
|
+
spec.add_dependency("roda-route_list", ">= 2.1")
|
19
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Bridgetown
|
4
|
+
module Routes
|
5
|
+
module CodeBlocks
|
6
|
+
class << self
|
7
|
+
attr_accessor :blocks
|
8
|
+
|
9
|
+
def add_route(name, file_code = nil, &block)
|
10
|
+
block.instance_variable_set(:@_route_file_code, file_code) if file_code
|
11
|
+
|
12
|
+
@blocks ||= {}
|
13
|
+
@blocks[name] = block
|
14
|
+
end
|
15
|
+
|
16
|
+
# @param name [String]
|
17
|
+
def route_defined?(name)
|
18
|
+
blocks&.key?(name)
|
19
|
+
end
|
20
|
+
|
21
|
+
def route_block(name)
|
22
|
+
blocks[name] if route_defined?(name)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Bridgetown
|
4
|
+
module Routes
|
5
|
+
module ViewHelpers
|
6
|
+
def request
|
7
|
+
view.resource&.roda_data&.request
|
8
|
+
end
|
9
|
+
alias_method :r, :request
|
10
|
+
|
11
|
+
def response
|
12
|
+
view.resource&.roda_data&.response
|
13
|
+
end
|
14
|
+
|
15
|
+
def flash
|
16
|
+
view.resource&.roda_data&.flash
|
17
|
+
end
|
18
|
+
|
19
|
+
# def csrf_tag(...)
|
20
|
+
# request.scope.csrf_tag(...)
|
21
|
+
# end
|
22
|
+
|
23
|
+
# def csrf_token(...)
|
24
|
+
# request.scope.csrf_token(...)
|
25
|
+
# end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
Bridgetown::RubyTemplateView::Helpers.include Bridgetown::Routes::ViewHelpers
|
@@ -0,0 +1,53 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Bridgetown
|
4
|
+
module Routes
|
5
|
+
module Manifest
|
6
|
+
class << self
|
7
|
+
def routable_extensions
|
8
|
+
%w(rb md serb erb liquid)
|
9
|
+
end
|
10
|
+
|
11
|
+
def generate_manifest # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity
|
12
|
+
return @route_manifest if @route_manifest && Bridgetown.env.production?
|
13
|
+
|
14
|
+
routes_dir = File.expand_path("src/_routes", Dir.pwd)
|
15
|
+
# @type [Array]
|
16
|
+
routes = Dir.glob(routes_dir + "/**/*.{#{routable_extensions.join(",")}}").map do |file|
|
17
|
+
if File.basename(file).start_with?("_", ".") ||
|
18
|
+
File.basename(file, ".*").end_with?(".test")
|
19
|
+
next
|
20
|
+
end
|
21
|
+
|
22
|
+
# @type [String]
|
23
|
+
file_slug = file.delete_prefix("#{routes_dir}/").then do |f|
|
24
|
+
[File.dirname(f), File.basename(f, ".*")].join("/").delete_prefix("./")
|
25
|
+
end.delete_suffix("/index")
|
26
|
+
segment_keys = []
|
27
|
+
file_slug.gsub!(%r{\[([^/]+)\]}) do |_segment|
|
28
|
+
segment_keys << Regexp.last_match(1)
|
29
|
+
":#{Regexp.last_match(1)}"
|
30
|
+
end
|
31
|
+
|
32
|
+
[file, file_slug, segment_keys]
|
33
|
+
end.compact
|
34
|
+
|
35
|
+
routes.sort! do |route_a, route_b|
|
36
|
+
# @type [String]
|
37
|
+
_, slug_a = route_a
|
38
|
+
_, slug_b = route_b
|
39
|
+
|
40
|
+
weight1 = slug_a.count("/") <=> slug_b.count("/")
|
41
|
+
if weight1.zero?
|
42
|
+
slug_b.count("/:") <=> slug_a.count("/:")
|
43
|
+
else
|
44
|
+
weight1
|
45
|
+
end
|
46
|
+
end.reverse!
|
47
|
+
|
48
|
+
@route_manifest = routes
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Bridgetown
|
4
|
+
module Routes
|
5
|
+
module RodaRouter
|
6
|
+
def self.start!(app) # rubocop:disable Metrics/MethodLength
|
7
|
+
r = app.request
|
8
|
+
response = app.response
|
9
|
+
|
10
|
+
Bridgetown::Routes::Manifest.generate_manifest.each do |route|
|
11
|
+
file, file_slug, segment_keys = route
|
12
|
+
|
13
|
+
r.on file_slug do |*segment_values|
|
14
|
+
response["X-Bridgetown-SSR"] = "1"
|
15
|
+
unless Bridgetown.env.production? &&
|
16
|
+
Bridgetown::Routes::CodeBlocks.route_defined?(file_slug)
|
17
|
+
eval_route_file file, file_slug, app
|
18
|
+
end
|
19
|
+
|
20
|
+
segment_values.each_with_index do |value, index|
|
21
|
+
r.params[segment_keys[index]] ||= value
|
22
|
+
end
|
23
|
+
|
24
|
+
route_block = Bridgetown::Routes::CodeBlocks.route_block(file_slug)
|
25
|
+
app.instance_variable_set(
|
26
|
+
:@_route_file_code, route_block.instance_variable_get(:@_route_file_code)
|
27
|
+
) # could be nil
|
28
|
+
app.instance_exec(&route_block)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
nil
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.eval_route_file(file, file_slug, app) # rubocop:disable Lint/UnusedMethodArgument
|
36
|
+
code = File.read(file)
|
37
|
+
code_postmatch = nil
|
38
|
+
ruby_content = code.match(Bridgetown::FrontMatterImporter::RUBY_BLOCK)
|
39
|
+
if ruby_content
|
40
|
+
code = ruby_content[1]
|
41
|
+
code_postmatch = ruby_content.post_match
|
42
|
+
end
|
43
|
+
|
44
|
+
code = <<~RUBY
|
45
|
+
r = app.request
|
46
|
+
Bridgetown::Routes::CodeBlocks.add_route(#{file_slug.inspect}, #{code_postmatch.inspect}) do
|
47
|
+
#{code}
|
48
|
+
end
|
49
|
+
RUBY
|
50
|
+
instance_eval(code, file, -1)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "bridgetown-core"
|
4
|
+
require "bridgetown-core/version"
|
5
|
+
|
6
|
+
require_relative "roda/plugins/bridgetown_routes"
|
7
|
+
|
8
|
+
require_relative "bridgetown-routes/helpers"
|
9
|
+
|
10
|
+
module Bridgetown
|
11
|
+
module Routes
|
12
|
+
autoload :CodeBlocks, "bridgetown-routes/code_blocks"
|
13
|
+
autoload :Manifest, "bridgetown-routes/manifest"
|
14
|
+
autoload :RodaRouter, "bridgetown-routes/roda_router"
|
15
|
+
|
16
|
+
# rubocop:disable Bridgetown/NoPutsAllowed
|
17
|
+
def self.print_roda_routes
|
18
|
+
routes = begin
|
19
|
+
JSON.parse(File.read("#{Dir.pwd}/.routes.json"))
|
20
|
+
rescue StandardError
|
21
|
+
[]
|
22
|
+
end
|
23
|
+
puts
|
24
|
+
puts "Routes:"
|
25
|
+
puts "======="
|
26
|
+
if routes.blank?
|
27
|
+
puts "No routes found. Have you commented all of your routes?"
|
28
|
+
puts "Documentation: https://github.com/jeremyevans/roda-route_list#basic-usage-"
|
29
|
+
end
|
30
|
+
|
31
|
+
routes.each do |route|
|
32
|
+
puts [route["methods"]&.join("|") || "GET", route["path"]].compact.join(" ")
|
33
|
+
end
|
34
|
+
end
|
35
|
+
# rubocop:enable Bridgetown/NoPutsAllowed
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,106 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "roda/plugins/flash"
|
4
|
+
|
5
|
+
class Roda
|
6
|
+
module RodaPlugins
|
7
|
+
module BridgetownRoutes
|
8
|
+
def self.load_dependencies(app)
|
9
|
+
app.plugin :slash_path_empty # now /hello and /hello/ are both matched
|
10
|
+
app.plugin :placeholder_string_matchers
|
11
|
+
app.plugin :flash
|
12
|
+
app.plugin :route_csrf, check_header: true
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.configure(app, _opts = {})
|
16
|
+
return unless app.opts[:bridgetown_site].nil?
|
17
|
+
|
18
|
+
raise "Roda app failure: the bridgetown_ssr plugin must be registered before" \
|
19
|
+
" bridgetown_routes"
|
20
|
+
end
|
21
|
+
|
22
|
+
module InstanceMethods
|
23
|
+
def render_with(data: {}) # rubocop:todo Metrics/AbcSize
|
24
|
+
path = Kernel.caller_locations(1, 1).first.absolute_path
|
25
|
+
source_path = Pathname.new(path).relative_path_from(Bridgetown::Current.site.source)
|
26
|
+
code = @_route_file_code
|
27
|
+
|
28
|
+
unless code.present?
|
29
|
+
raise Bridgetown::Errors::FatalException,
|
30
|
+
"`render_with' method must be called from a template-based file in `src/_routes'"
|
31
|
+
end
|
32
|
+
|
33
|
+
data = Bridgetown::Model::BuilderOrigin.new("builder://#{source_path}").read do
|
34
|
+
data[:_collection_] = Bridgetown::Current.site.collections.pages
|
35
|
+
data[:_content_] = code
|
36
|
+
data
|
37
|
+
end
|
38
|
+
|
39
|
+
Bridgetown::Model::Base.new(data).to_resource.tap do |resource|
|
40
|
+
resource.roda_data[:request] = request
|
41
|
+
resource.roda_data[:response] = response
|
42
|
+
resource.roda_data[:flash] = nil
|
43
|
+
# resource.roda_data[:flash] = flash
|
44
|
+
end.read!.transform!.output
|
45
|
+
end
|
46
|
+
|
47
|
+
ruby2_keywords def render(*args, &block)
|
48
|
+
view.render(*args, &block)
|
49
|
+
end
|
50
|
+
|
51
|
+
def view(view_class: Bridgetown::ERBView)
|
52
|
+
response._fake_resource_view(
|
53
|
+
view_class: view_class, request: request, bridgetown_site: bridgetown_site
|
54
|
+
)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
module ResponseMethods
|
59
|
+
def _fake_resource_view(view_class:, request:, bridgetown_site:)
|
60
|
+
@_fake_resource_views ||= {}
|
61
|
+
@_fake_resource_views[view_class] ||= view_class.new(
|
62
|
+
# TODO: use a Stuct for better performance...?
|
63
|
+
HashWithDotAccess::Hash.new({
|
64
|
+
data: {},
|
65
|
+
roda_data: {
|
66
|
+
request: request,
|
67
|
+
response: self,
|
68
|
+
flash: nil, # flash,
|
69
|
+
},
|
70
|
+
site: bridgetown_site,
|
71
|
+
})
|
72
|
+
)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
register_plugin :bridgetown_routes, BridgetownRoutes
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
module RodaResourceExtension
|
82
|
+
module RubyResource
|
83
|
+
def roda_data
|
84
|
+
@roda_data ||= HashWithDotAccess::Hash.new
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
Bridgetown::Resource.register_extension RodaResourceExtension
|
89
|
+
|
90
|
+
Roda::RodaPlugins::Flash::FlashHash.class_eval do
|
91
|
+
def info
|
92
|
+
self["info"]
|
93
|
+
end
|
94
|
+
|
95
|
+
def info=(val)
|
96
|
+
self["info"] = val
|
97
|
+
end
|
98
|
+
|
99
|
+
def alert
|
100
|
+
self["alert"]
|
101
|
+
end
|
102
|
+
|
103
|
+
def alert=(val)
|
104
|
+
self["alert"] = val
|
105
|
+
end
|
106
|
+
end
|
metadata
ADDED
@@ -0,0 +1,80 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: bridgetown-routes
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0.alpha2
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Bridgetown Team
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2021-10-16 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bridgetown-core
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - '='
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 1.0.0.alpha2
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - '='
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 1.0.0.alpha2
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: roda-route_list
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '2.1'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '2.1'
|
41
|
+
description:
|
42
|
+
email: maintainers@bridgetownrb.com
|
43
|
+
executables: []
|
44
|
+
extensions: []
|
45
|
+
extra_rdoc_files: []
|
46
|
+
files:
|
47
|
+
- ".rubocop.yml"
|
48
|
+
- Rakefile
|
49
|
+
- bridgetown-routes.gemspec
|
50
|
+
- lib/bridgetown-routes.rb
|
51
|
+
- lib/bridgetown-routes/code_blocks.rb
|
52
|
+
- lib/bridgetown-routes/helpers.rb
|
53
|
+
- lib/bridgetown-routes/manifest.rb
|
54
|
+
- lib/bridgetown-routes/roda_router.rb
|
55
|
+
- lib/roda/plugins/bridgetown_routes.rb
|
56
|
+
homepage: https://github.com/bridgetownrb/bridgetown/tree/main/bridgetown-routes
|
57
|
+
licenses:
|
58
|
+
- MIT
|
59
|
+
metadata: {}
|
60
|
+
post_install_message:
|
61
|
+
rdoc_options: []
|
62
|
+
require_paths:
|
63
|
+
- lib
|
64
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
70
|
+
requirements:
|
71
|
+
- - ">"
|
72
|
+
- !ruby/object:Gem::Version
|
73
|
+
version: 1.3.1
|
74
|
+
requirements: []
|
75
|
+
rubygems_version: 3.1.4
|
76
|
+
signing_key:
|
77
|
+
specification_version: 4
|
78
|
+
summary: A Bridgetown plugin to add support for file-based Roda backend routes within
|
79
|
+
the source folder.
|
80
|
+
test_files: []
|