bridgetown-core 1.2.0.beta5 → 1.3.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.
@@ -0,0 +1,140 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Roda
4
+ module RodaPlugins
5
+ module BridgetownServer
6
+ SiteContext = Struct.new(:registers) # for use by Liquid-esque URL helpers
7
+
8
+ def self.load_dependencies(app) # rubocop:disable Metrics
9
+ unless Bridgetown::Current.preloaded_configuration
10
+ raise "You must supply a preloaded configuration before loading the Bridgetown Roda " \
11
+ "plugin"
12
+ end
13
+
14
+ app.plugin :initializers
15
+ app.plugin :method_override
16
+ app.plugin :all_verbs
17
+ app.plugin :hooks
18
+ app.plugin :common_logger, Bridgetown::Rack::Logger.new($stdout), method: :info
19
+ app.plugin :json
20
+ app.plugin :json_parser
21
+ app.plugin :indifferent_params
22
+ app.plugin :cookies
23
+ app.plugin :streaming
24
+ app.plugin :public, root: Bridgetown::Current.preloaded_configuration.destination
25
+ app.plugin :not_found do
26
+ output_folder = Bridgetown::Current.preloaded_configuration.destination
27
+ File.read(File.join(output_folder, "404.html"))
28
+ rescue Errno::ENOENT
29
+ "404 Not Found"
30
+ end
31
+ app.plugin :exception_page
32
+ app.plugin :error_handler do |e|
33
+ Bridgetown::Errors.print_build_error(
34
+ e, logger: Bridgetown::LogAdapter.new(self.class.opts[:common_logger]), server: true
35
+ )
36
+ next exception_page(e) if ENV.fetch("RACK_ENV", nil) == "development"
37
+
38
+ output_folder = Bridgetown::Current.preloaded_configuration.destination
39
+ File.read(File.join(output_folder, "500.html"))
40
+ rescue Errno::ENOENT
41
+ "500 Internal Server Error"
42
+ end
43
+
44
+ ExceptionPage.class_eval do # rubocop:disable Metrics/BlockLength
45
+ def self.css
46
+ <<~CSS
47
+ html * { padding:0; margin:0; }
48
+ body * { padding:10px 20px; }
49
+ body * * { padding:0; }
50
+ body { font-family: -apple-system, sans-serif; font-size: 90%; }
51
+ body>div { border-bottom:1px solid #ddd; }
52
+ code { font-family: ui-monospace, monospace; }
53
+ h1 { font-weight: bold; margin-block-end: .8em; }
54
+ h2 { margin-block-end:.8em; }
55
+ h2 span { font-size:80%; color:#f7f7db; font-weight:normal; }
56
+ h3 { margin:1em 0 .5em 0; }
57
+ h4 { margin:0 0 .5em 0; font-weight: normal; }
58
+ table {
59
+ border:1px solid #ccc; border-collapse: collapse; background:white; }
60
+ tbody td, tbody th { vertical-align:top; padding:2px 3px; }
61
+ thead th {
62
+ padding:1px 6px 1px 3px; background:#fefefe; text-align:left;
63
+ font-weight:normal; font-size:11px; border:1px solid #ddd; }
64
+ tbody th { text-align:right; opacity: 0.7; padding-right:.5em; }
65
+ table.vars { margin:5px 0 2px 40px; }
66
+ table.vars td, table.req td { font-family: ui-monospace, monospace; }
67
+ table td.code { width:100%;}
68
+ table td.code div { overflow:hidden; }
69
+ table.source th { color:#666; }
70
+ table.source td {
71
+ font-family: ui-monospace, monospace; white-space:pre; border-bottom:1px solid #eee; }
72
+ ul.traceback { list-style-type:none; }
73
+ ul.traceback li.frame { margin-bottom:1em; }
74
+ div.context { margin: 10px 0; }
75
+ div.context ol {
76
+ padding-left:30px; margin:0 10px; list-style-position: inside; }
77
+ div.context ol li {
78
+ font-family: ui-monospace, monospace; white-space:pre; color:#666; cursor:pointer; }
79
+ div.context ol.context-line li { color:black; background-color:#f7f7db; }
80
+ div.context ol.context-line li span { float: right; }
81
+ div.commands { margin-left: 40px; }
82
+ div.commands a { color:black; text-decoration:none; }
83
+ #summary { background: #1D453C; color: white; }
84
+ #summary h2 { font-weight: normal; color: white; }
85
+ #summary ul#quicklinks { list-style-type: none; margin-bottom: 2em; }
86
+ #summary ul#quicklinks li { float: left; padding: 0 1em; }
87
+ #summary ul#quicklinks>li+li { border-left: 1px #666 solid; }
88
+ #summary a { color: #f47c3c; }
89
+ #explanation { background:#eee; }
90
+ #traceback { background: white; }
91
+ #requestinfo { background:#f6f6f6; padding-left:120px; }
92
+ #summary table { border:none; background:transparent; }
93
+ #requestinfo h2, #requestinfo h3 { position:relative; margin-left:-100px; }
94
+ #requestinfo h3 { margin-bottom:-1em; }
95
+ .error { background: #ffc; }
96
+ .specific { color:#cc3300; font-weight:bold; }
97
+ CSS
98
+ end
99
+ end
100
+
101
+ app.before do
102
+ if self.class.opts[:bridgetown_site]
103
+ # The site had previously been initialized via the bridgetown_ssr plugin
104
+ Bridgetown::Current.sites[self.class.opts[:bridgetown_site].label] =
105
+ self.class.opts[:bridgetown_site]
106
+ @context ||= SiteContext.new({ site: self.class.opts[:bridgetown_site] })
107
+ end
108
+ Bridgetown::Current.preloaded_configuration ||=
109
+ self.class.opts[:bridgetown_preloaded_config]
110
+
111
+ request.root do
112
+ output_folder = Bridgetown::Current.preloaded_configuration.destination
113
+ File.read(File.join(output_folder, "index.html"))
114
+ rescue StandardError
115
+ response.status = 500
116
+ "<p>ERROR: cannot find <code>index.html</code> in the output folder.</p>"
117
+ end
118
+ end
119
+ end
120
+
121
+ Roda::RodaRequest.alias_method :_previous_roda_cookies, :cookies
122
+
123
+ module RequestMethods
124
+ # Monkeypatch Roda/Rack's Request object so it returns a hash which allows for
125
+ # indifferent access
126
+ def cookies
127
+ # TODO: maybe replace with a simpler hash that offers an overloaded `[]` method
128
+ _previous_roda_cookies.with_indifferent_access
129
+ end
130
+
131
+ # Starts up the Bridgetown routing system
132
+ def bridgetown
133
+ Bridgetown::Rack::Routes.start!(scope)
134
+ end
135
+ end
136
+ end
137
+
138
+ register_plugin :bridgetown_server, BridgetownServer
139
+ end
140
+ end
@@ -24,10 +24,13 @@ gem "bridgetown", "~> <%= Bridgetown::VERSION %>"
24
24
  # Uncomment to add file-based dynamic routing to your project:
25
25
  # gem "bridgetown-routes", "~> <%= Bridgetown::VERSION %>"
26
26
 
27
+ # Puma is the Rack-compatible web server used by Bridgetown
28
+ # (you can optionally limit this to the "development" group)
29
+ gem "puma", "< 7"
30
+
27
31
  # Uncomment to use the Inspectors API to manipulate the output
28
32
  # of your HTML or XML resources:
29
33
  # gem "nokogiri", "~> 1.13"
30
34
 
31
- # Puma is a Rack-compatible server used by Bridgetown
32
- # (you can optionally limit this to the "development" group)
33
- gem "puma", "~> 5.6"
35
+ # Or for faster parsing of HTML-only resources via Inspectors, use Nokolexbor:
36
+ # gem "nokolexbor", "~> 0.4"
@@ -2,9 +2,11 @@
2
2
  # on the concept of a routing tree. Bridgetown uses it for its development
3
3
  # server, but you can also run it in production for fast, dynamic applications.
4
4
  #
5
- # Learn more at: http://roda.jeremyevans.net
5
+ # Learn more at: https://www.bridgetownrb.com/docs/routes
6
+
7
+ class RodaApp < Roda
8
+ plugin :bridgetown_server
6
9
 
7
- class RodaApp < Bridgetown::Rack::Roda
8
10
  # Some Roda configuration is handled in the `config/initializers.rb` file.
9
11
  # But you can also add additional Roda configuration here if needed.
10
12
 
@@ -5,7 +5,7 @@ date: <%= Time.now.strftime('%Y-%m-%d %H:%M:%S %z') %>
5
5
  categories: updates
6
6
  ---
7
7
 
8
- You’ll find this post in your `_posts` directory. Go ahead and edit it and re-build the site to see your changes. You can rebuild the site in many different ways, but the most common way is to run `bridgetown serve`, which launches a web server and auto-regenerates your site when a file is updated.
8
+ You’ll find this post in your `_posts` directory. Go ahead and edit it and re-build the site to see your changes. You can rebuild the site in many different ways, but the most common way is to run `bin/bridgetown start`, which launches a web server and auto-regenerates your site when a file is updated.
9
9
 
10
10
  Bridgetown requires blog post files to be named according to the following format:
11
11
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bridgetown-core
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.0.beta5
4
+ version: 1.3.0.beta1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Bridgetown Team
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-01-02 00:00:00.000000000 Z
11
+ date: 2023-05-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activemodel
@@ -112,28 +112,28 @@ dependencies:
112
112
  requirements:
113
113
  - - "~>"
114
114
  - !ruby/object:Gem::Version
115
- version: '1.0'
115
+ version: '2.0'
116
116
  type: :runtime
117
117
  prerelease: false
118
118
  version_requirements: !ruby/object:Gem::Requirement
119
119
  requirements:
120
120
  - - "~>"
121
121
  - !ruby/object:Gem::Version
122
- version: '1.0'
122
+ version: '2.0'
123
123
  - !ruby/object:Gem::Dependency
124
- name: faraday_middleware
124
+ name: faraday-follow_redirects
125
125
  requirement: !ruby/object:Gem::Requirement
126
126
  requirements:
127
127
  - - "~>"
128
128
  - !ruby/object:Gem::Version
129
- version: '1.0'
129
+ version: '0.3'
130
130
  type: :runtime
131
131
  prerelease: false
132
132
  version_requirements: !ruby/object:Gem::Requirement
133
133
  requirements:
134
134
  - - "~>"
135
135
  - !ruby/object:Gem::Version
136
- version: '1.0'
136
+ version: '0.3'
137
137
  - !ruby/object:Gem::Dependency
138
138
  name: hash_with_dot_access
139
139
  requirement: !ruby/object:Gem::Requirement
@@ -274,20 +274,6 @@ dependencies:
274
274
  - - "~>"
275
275
  - !ruby/object:Gem::Version
276
276
  version: '1.0'
277
- - !ruby/object:Gem::Dependency
278
- name: terminal-table
279
- requirement: !ruby/object:Gem::Requirement
280
- requirements:
281
- - - "~>"
282
- - !ruby/object:Gem::Version
283
- version: '1.8'
284
- type: :runtime
285
- prerelease: false
286
- version_requirements: !ruby/object:Gem::Requirement
287
- requirements:
288
- - - "~>"
289
- - !ruby/object:Gem::Version
290
- version: '1.8'
291
277
  - !ruby/object:Gem::Dependency
292
278
  name: thor
293
279
  requirement: !ruby/object:Gem::Requirement
@@ -316,20 +302,6 @@ dependencies:
316
302
  - - "~>"
317
303
  - !ruby/object:Gem::Version
318
304
  version: '2.0'
319
- - !ruby/object:Gem::Dependency
320
- name: webrick
321
- requirement: !ruby/object:Gem::Requirement
322
- requirements:
323
- - - "~>"
324
- - !ruby/object:Gem::Version
325
- version: '1.7'
326
- type: :runtime
327
- prerelease: false
328
- version_requirements: !ruby/object:Gem::Requirement
329
- requirements:
330
- - - "~>"
331
- - !ruby/object:Gem::Version
332
- version: '1.7'
333
305
  - !ruby/object:Gem::Dependency
334
306
  name: zeitwerk
335
307
  requirement: !ruby/object:Gem::Requirement
@@ -382,8 +354,6 @@ files:
382
354
  - lib/bridgetown-core/commands/new.rb
383
355
  - lib/bridgetown-core/commands/plugins.rb
384
356
  - lib/bridgetown-core/commands/registrations.rb
385
- - lib/bridgetown-core/commands/serve.rb
386
- - lib/bridgetown-core/commands/serve/servlet.rb
387
357
  - lib/bridgetown-core/commands/start.rb
388
358
  - lib/bridgetown-core/commands/webpack.rb
389
359
  - lib/bridgetown-core/commands/webpack/enable-postcss.rb
@@ -501,7 +471,6 @@ files:
501
471
  - lib/bridgetown-core/plugin_manager.rb
502
472
  - lib/bridgetown-core/rack/boot.rb
503
473
  - lib/bridgetown-core/rack/logger.rb
504
- - lib/bridgetown-core/rack/roda.rb
505
474
  - lib/bridgetown-core/rack/routes.rb
506
475
  - lib/bridgetown-core/rack/static_indexes.rb
507
476
  - lib/bridgetown-core/reader.rb
@@ -543,7 +512,7 @@ files:
543
512
  - lib/bridgetown-core/version.rb
544
513
  - lib/bridgetown-core/watcher.rb
545
514
  - lib/bridgetown-core/yaml_parser.rb
546
- - lib/roda/plugins/bridgetown_boot.rb
515
+ - lib/roda/plugins/bridgetown_server.rb
547
516
  - lib/roda/plugins/bridgetown_ssr.rb
548
517
  - lib/roda/plugins/initializers.rb
549
518
  - lib/roda/plugins/method_override.rb
@@ -1,68 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "webrick"
4
-
5
- module Bridgetown
6
- module Commands
7
- class Serve
8
- class Servlet < WEBrick::HTTPServlet::FileHandler
9
- DEFAULTS = {
10
- "Cache-Control" => "private, max-age=0, proxy-revalidate, " \
11
- "no-store, no-cache, must-revalidate",
12
- }.freeze
13
-
14
- def initialize(server, root, callbacks)
15
- # So we can access them easily.
16
- @bridgetown_opts = server.config[:BridgetownOptions]
17
- set_defaults
18
- super
19
- end
20
-
21
- def search_index_file(req, res)
22
- super ||
23
- search_file(req, res, ".html") ||
24
- search_file(req, res, ".xhtml")
25
- end
26
-
27
- # Add the ability to tap file.html the same way that Nginx does on our
28
- # Docker images (or on GitHub Pages.) The difference is that we might end
29
- # up with a different preference on which comes first.
30
-
31
- def search_file(req, res, basename)
32
- # /file.* > /file/index.html > /file.html
33
- super ||
34
- super(req, res, "#{basename}.html") ||
35
- super(req, res, "#{basename}.xhtml")
36
- end
37
-
38
- # rubocop:disable Naming/MethodName
39
- def do_GET(req, res)
40
- rtn = super
41
-
42
- validate_and_ensure_charset(req, res)
43
- res.header.merge!(@headers)
44
- rtn
45
- end
46
- # rubocop:enable Naming/MethodName
47
-
48
- private
49
-
50
- def validate_and_ensure_charset(_req, res)
51
- key = res.header.keys.grep(%r!content-type!i).first
52
- typ = res.header[key]
53
-
54
- return if %r!;\s*charset=!.match?(typ)
55
-
56
- res.header[key] = "#{typ}; charset=#{@bridgetown_opts["encoding"]}"
57
- end
58
-
59
- def set_defaults
60
- hash_ = @bridgetown_opts.fetch("webrick", {}).fetch("headers", {})
61
- DEFAULTS.each_with_object(@headers = hash_) do |(key, val), hash|
62
- hash[key] = val unless hash.key?(key)
63
- end
64
- end
65
- end
66
- end
67
- end
68
- end
@@ -1,253 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Bridgetown
4
- module Commands
5
- class Serve < Thor::Group
6
- extend BuildOptions
7
- extend Summarizable
8
- include ConfigurationOverridable
9
-
10
- Registrations.register do
11
- register(Serve, "serve", "serve", Serve.summary)
12
- end
13
-
14
- class_option :host, aliases: "-H", desc: "Host to bind to"
15
- class_option :port, aliases: "-P", desc: "Port to listen on"
16
- class_option :detach,
17
- aliases: "-B",
18
- type: :boolean,
19
- desc: "Run the server in the background"
20
- class_option :ssl_cert, desc: "X.509 (SSL) certificate."
21
- class_option :ssl_key, desc: "X.509 (SSL) Private Key."
22
- class_option :show_dir_listing,
23
- type: :boolean,
24
- desc: "Show a directory listing instead of loading your index file."
25
- class_option :skip_initial_build,
26
- type: :boolean,
27
- desc: "Skips the initial site build which occurs before the server is started."
28
- class_option :watch,
29
- type: :boolean,
30
- aliases: "-w",
31
- default: true,
32
- desc: "Watch for changes and rebuild"
33
-
34
- def self.banner
35
- "bridgetown serve [options]"
36
- end
37
- summary "DEPRECATED (Serve your site locally using WEBrick)"
38
-
39
- DIRECTORY_INDEX = %w(
40
- index.htm
41
- index.html
42
- index.rhtml
43
- index.xht
44
- index.xhtml
45
- index.cgi
46
- index.xml
47
- index.json
48
- ).freeze
49
-
50
- def serve
51
- Bridgetown::Deprecator.deprecation_message(
52
- "WEBrick (serve) will be removed in favor of Puma (start) in the next Bridgetown release"
53
- )
54
-
55
- @mutex = Mutex.new
56
- @run_cond = ConditionVariable.new
57
- @running = false
58
-
59
- no_watch = options["watch"] == false
60
-
61
- options = Thor::CoreExt::HashWithIndifferentAccess.new(self.options)
62
- options["serving"] = true
63
- options["watch"] = true unless no_watch
64
-
65
- config = configuration_with_overrides(options, Bridgetown::Current.preloaded_configuration)
66
- if Bridgetown.environment == "development"
67
- default_url(config).tap do |url|
68
- options["url"] = url
69
- config.url = url
70
- end
71
- end
72
-
73
- invoke(Build, [], options)
74
- start_server
75
- end
76
-
77
- protected
78
-
79
- def start_server
80
- destination = Bridgetown::Current.preloaded_configuration.destination
81
- setup(destination)
82
-
83
- start_up_webrick(destination)
84
- end
85
-
86
- def setup(destination)
87
- require_relative "serve/servlet"
88
-
89
- FileUtils.mkdir_p(destination)
90
- return unless File.exist?(File.join(destination, "404.html"))
91
-
92
- WEBrick::HTTPResponse.class_eval do
93
- def create_error_page
94
- @header["Content-Type"] = "text/html; charset=UTF-8"
95
- @body = File.read(File.join(@config[:DocumentRoot], "404.html"))
96
- end
97
- end
98
- end
99
-
100
- def webrick_opts(opts)
101
- opts = {
102
- BridgetownOptions: opts,
103
- DoNotReverseLookup: true,
104
- MimeTypes: mime_types,
105
- DocumentRoot: opts["destination"],
106
- StartCallback: start_callback(opts["detach"]),
107
- StopCallback: stop_callback(opts["detach"]),
108
- BindAddress: opts["host"],
109
- Port: opts["port"],
110
- DirectoryIndex: DIRECTORY_INDEX,
111
- }
112
-
113
- opts[:DirectoryIndex] = [] if opts[:BridgetownOptions]["show_dir_listing"]
114
-
115
- enable_ssl(opts)
116
- enable_logging(opts)
117
- opts
118
- end
119
-
120
- def start_up_webrick(destination)
121
- opts = Bridgetown::Current.preloaded_configuration
122
- @server = WEBrick::HTTPServer.new(webrick_opts(opts)).tap { |o| o.unmount("") }
123
- @server.mount(opts["base_path"].to_s, Servlet, destination, file_handler_opts)
124
-
125
- Bridgetown.logger.info "Server address:", server_address(@server, opts)
126
- launch_browser @server, opts if opts["open_url"]
127
- boot_or_detach @server, opts
128
- end
129
-
130
- def shutdown
131
- @server.shutdown if running?
132
- end
133
-
134
- def default_url(config)
135
- format_url(
136
- config["ssl_cert"] && config["ssl_key"],
137
- config["host"] == "127.0.0.1" ? "localhost" : config["host"],
138
- config["port"]
139
- )
140
- end
141
-
142
- def format_url(ssl_enabled, address, port, baseurl = nil)
143
- format("%<prefix>s://%<address>s:%<port>i%<baseurl>s",
144
- prefix: ssl_enabled ? "https" : "http",
145
- address: address,
146
- port: port,
147
- baseurl: baseurl ? "#{baseurl}/" : "")
148
- end
149
-
150
- # Recreate NondisclosureName under utf-8 circumstance
151
- def file_handler_opts
152
- WEBrick::Config::FileHandler.merge(
153
- FancyIndexing: true,
154
- NondisclosureName: [
155
- ".ht*", "~*",
156
- ]
157
- )
158
- end
159
-
160
- def server_address(server, options = {})
161
- format_url(
162
- server.config[:SSLEnable],
163
- server.config[:BindAddress],
164
- server.config[:Port],
165
- options["baseurl"]
166
- )
167
- end
168
-
169
- # Keep in our area with a thread or detach the server as requested
170
- # by the user. This method determines what we do based on what you
171
- # ask us to do.
172
- def boot_or_detach(server, opts)
173
- if opts["detach"]
174
- pid = Process.fork do
175
- server.start
176
- end
177
-
178
- Process.detach(pid)
179
- Bridgetown.logger.info "Server detached with pid '#{pid}'.", \
180
- "Run `pkill -f bridgetown' or `kill -9 #{pid}' " \
181
- "to stop the server."
182
- else
183
- t = Thread.new { server.start }
184
- trap("INT") { server.shutdown }
185
- t.join
186
- end
187
- end
188
-
189
- # Make the stack verbose if the user requests it.
190
- def enable_logging(opts)
191
- opts[:AccessLog] = []
192
- level = WEBrick::Log.const_get(opts[:BridgetownOptions]["verbose"] ? :DEBUG : :WARN)
193
- opts[:Logger] = WEBrick::Log.new($stdout, level)
194
- end
195
-
196
- # Add SSL to the stack if the user triggers --enable-ssl and they
197
- # provide both types of certificates commonly needed. Raise if they
198
- # forget to add one of the certificates.
199
- def enable_ssl(opts)
200
- cert, key, src =
201
- opts[:BridgetownOptions].values_at("ssl_cert", "ssl_key", "source")
202
-
203
- return if cert.nil? && key.nil?
204
- raise "Missing --ssl_cert or --ssl_key. Both are required." unless cert && key
205
-
206
- require "openssl"
207
- require "webrick/https"
208
-
209
- opts[:SSLCertificate] = OpenSSL::X509::Certificate.new(read_file(src, cert))
210
- begin
211
- opts[:SSLPrivateKey] = OpenSSL::PKey::RSA.new(read_file(src, key))
212
- rescue StandardError
213
- raise unless defined?(OpenSSL::PKey::EC)
214
-
215
- opts[:SSLPrivateKey] = OpenSSL::PKey::EC.new(read_file(src, key))
216
- end
217
- opts[:SSLEnable] = true
218
- end
219
-
220
- def start_callback(detached)
221
- return if detached
222
-
223
- proc do
224
- @mutex.synchronize do
225
- @running = true
226
- Bridgetown.logger.info("Server running…", "press ctrl-c to stop.")
227
- @run_cond.broadcast
228
- end
229
- end
230
- end
231
-
232
- def stop_callback(detached)
233
- return if detached
234
-
235
- proc do
236
- @mutex.synchronize do
237
- @running = false
238
- @run_cond.broadcast
239
- end
240
- end
241
- end
242
-
243
- def mime_types
244
- file = File.expand_path("../mime.types", __dir__)
245
- WEBrick::HTTPUtils.load_mime_types(file)
246
- end
247
-
248
- def read_file(source_dir, file_path)
249
- File.read(Bridgetown.sanitized_path(source_dir, file_path))
250
- end
251
- end
252
- end
253
- end