frontman-ssg 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.circleci/config.yml +42 -0
- data/.github/CODE_OF_CONDUCT.md +9 -0
- data/.github/ISSUE_TEMPLATE/bug_report.md +25 -0
- data/.github/ISSUE_TEMPLATE/feature_request.md +22 -0
- data/.github/PULL_REQUEST_TEMPLATE.md +22 -0
- data/.gitignore +5 -0
- data/.rubocop.yml +88 -0
- data/CHANGELOG.md +11 -0
- data/CONTRIBUTING.md +42 -0
- data/Gemfile +5 -0
- data/LICENSE.md +21 -0
- data/Rakefile +94 -0
- data/SECURITY.md +6 -0
- data/bin/frontman +6 -0
- data/frontman-ssg.gemspec +48 -0
- data/frontman.svg +2 -0
- data/lib/frontman.rb +15 -0
- data/lib/frontman/app.rb +175 -0
- data/lib/frontman/bootstrapper.rb +70 -0
- data/lib/frontman/builder/asset_pipeline.rb +55 -0
- data/lib/frontman/builder/builder.rb +193 -0
- data/lib/frontman/builder/file.rb +55 -0
- data/lib/frontman/builder/mapping.rb +54 -0
- data/lib/frontman/builder/statistics_collector.rb +37 -0
- data/lib/frontman/cli.rb +6 -0
- data/lib/frontman/commands/build.rb +76 -0
- data/lib/frontman/commands/init.rb +58 -0
- data/lib/frontman/commands/serve.rb +110 -0
- data/lib/frontman/concerns/dispatch_events.rb +56 -0
- data/lib/frontman/concerns/forward_calls_to_app.rb +28 -0
- data/lib/frontman/config.rb +52 -0
- data/lib/frontman/context.rb +125 -0
- data/lib/frontman/custom_struct.rb +44 -0
- data/lib/frontman/data_store.rb +106 -0
- data/lib/frontman/data_store_file.rb +60 -0
- data/lib/frontman/helpers/app_helper.rb +18 -0
- data/lib/frontman/helpers/link_helper.rb +35 -0
- data/lib/frontman/helpers/render_helper.rb +76 -0
- data/lib/frontman/helpers/url_helper.rb +11 -0
- data/lib/frontman/iterator.rb +48 -0
- data/lib/frontman/process/chain.rb +43 -0
- data/lib/frontman/process/processor.rb +11 -0
- data/lib/frontman/renderers/erb_renderer.rb +21 -0
- data/lib/frontman/renderers/haml_renderer.rb +22 -0
- data/lib/frontman/renderers/markdown_renderer.rb +26 -0
- data/lib/frontman/renderers/renderer.rb +26 -0
- data/lib/frontman/renderers/renderer_resolver.rb +26 -0
- data/lib/frontman/resource.rb +279 -0
- data/lib/frontman/sitemap_tree.rb +211 -0
- data/lib/frontman/toolbox/timer.rb +49 -0
- data/lib/frontman/version.rb +6 -0
- data/project-templates/default/.gitignore +2 -0
- data/project-templates/default/Gemfile +3 -0
- data/project-templates/default/config.rb +17 -0
- data/project-templates/default/data/site.yml +4 -0
- data/project-templates/default/helpers/site_helper.rb +7 -0
- data/project-templates/default/public/code.css +77 -0
- data/project-templates/default/public/frontman-logo.svg +2 -0
- data/project-templates/default/public/main.css +27 -0
- data/project-templates/default/public/main.js +1 -0
- data/project-templates/default/source/index.html.md.erb +7 -0
- data/project-templates/default/source/sitemap.xml.erb +11 -0
- data/project-templates/default/views/layouts/main.erb +19 -0
- data/project-templates/default/views/layouts/main.haml +15 -0
- data/project-templates/default/views/partials/menu.erb +7 -0
- data/project-templates/webpack/.gitignore +4 -0
- data/project-templates/webpack/Gemfile +3 -0
- data/project-templates/webpack/README.md +54 -0
- data/project-templates/webpack/assets/css/code.css +77 -0
- data/project-templates/webpack/assets/css/style.css +27 -0
- data/project-templates/webpack/assets/images/.gitkeep +0 -0
- data/project-templates/webpack/assets/images/frontman_logo.svg +2 -0
- data/project-templates/webpack/assets/js/index.js +1 -0
- data/project-templates/webpack/config.rb +24 -0
- data/project-templates/webpack/data/site.yml +4 -0
- data/project-templates/webpack/helpers/assets_helper.rb +24 -0
- data/project-templates/webpack/helpers/site_helper.rb +7 -0
- data/project-templates/webpack/package-lock.json +7603 -0
- data/project-templates/webpack/package.json +34 -0
- data/project-templates/webpack/source/index.html.md.erb +7 -0
- data/project-templates/webpack/source/sitemap.xml.erb +11 -0
- data/project-templates/webpack/views/layouts/main.erb +20 -0
- data/project-templates/webpack/views/layouts/main.haml +14 -0
- data/project-templates/webpack/views/partials/menu.erb +7 -0
- data/project-templates/webpack/views/partials/script_with_vendors.haml +5 -0
- data/project-templates/webpack/webpack/base.config.js +51 -0
- data/project-templates/webpack/webpack/dev.config.js +6 -0
- data/project-templates/webpack/webpack/prod.config.js +30 -0
- data/readme.md +80 -0
- data/sorbet/config +2 -0
- data/sorbet/rbi/hidden-definitions/errors.txt +27259 -0
- data/sorbet/rbi/hidden-definitions/hidden.rbi +45122 -0
- data/sorbet/rbi/sorbet-typed/lib/rainbow/all/rainbow.rbi +276 -0
- data/sorbet/rbi/todo.rbi +6 -0
- data/spec/frontman/app_spec.rb +48 -0
- data/spec/frontman/bootstrapper_spec.rb +26 -0
- data/spec/frontman/builder/builder_spec.rb +79 -0
- data/spec/frontman/builder/file_spec.rb +45 -0
- data/spec/frontman/builder/mapping_spec.rb +8 -0
- data/spec/frontman/concerns/dispatch_events_spec.rb +70 -0
- data/spec/frontman/concerns/forward_calls_to_app_spec.rb +21 -0
- data/spec/frontman/config_spec.rb +54 -0
- data/spec/frontman/context_spec.rb +48 -0
- data/spec/frontman/custom_struct_spec.rb +51 -0
- data/spec/frontman/data_store_file_spec.rb +9 -0
- data/spec/frontman/data_store_spec.rb +36 -0
- data/spec/frontman/frontman_ssg_spec.rb +7 -0
- data/spec/frontman/helpers/app_helper_spec.rb +24 -0
- data/spec/frontman/helpers/link_helper_spec.rb +37 -0
- data/spec/frontman/helpers/render_helper_spec.rb +55 -0
- data/spec/frontman/helpers/url_helper_spec.rb +21 -0
- data/spec/frontman/iterator_spec.rb +47 -0
- data/spec/frontman/mocks/asset.css +3 -0
- data/spec/frontman/mocks/config.rb +0 -0
- data/spec/frontman/mocks/helpers/formatting_helper.rb +5 -0
- data/spec/frontman/mocks/helpers/language_helper.rb +5 -0
- data/spec/frontman/mocks/helpers/link_helper.rb +5 -0
- data/spec/frontman/mocks/helpers/test_command.rb +5 -0
- data/spec/frontman/mocks/html_file.html +8 -0
- data/spec/frontman/mocks/html_file.html.md.erb +9 -0
- data/spec/frontman/mocks/html_file.md.html +8 -0
- data/spec/frontman/mocks/info.yml +4 -0
- data/spec/frontman/mocks/layouts/raw_without_body.haml +1 -0
- data/spec/frontman/mocks/nested/data.yml +4 -0
- data/spec/frontman/mocks/nested/more_data.yml +4 -0
- data/spec/frontman/mocks/partials/paragraph.haml +2 -0
- data/spec/frontman/mocks/snippet/html_file.html +8 -0
- data/spec/frontman/mocks/snippet/html_file.yml +670 -0
- data/spec/frontman/mocks/test.html +8 -0
- data/spec/frontman/mocks/wrap.haml +3 -0
- data/spec/frontman/process/chain_spec.rb +56 -0
- data/spec/frontman/renderers/erb_renderer_spec.rb +22 -0
- data/spec/frontman/renderers/haml_renderer_spec.rb +12 -0
- data/spec/frontman/renderers/markdown_renderer_spec.rb +12 -0
- data/spec/frontman/renderers/renderer_spec.rb +16 -0
- data/spec/frontman/resource_spec.rb +151 -0
- data/spec/frontman/sitemap_tree_spec.rb +128 -0
- data/spec/frontman/toolbox/timer_spec.rb +34 -0
- data/spec/spec_setup.rb +19 -0
- metadata +507 -0
@@ -0,0 +1,55 @@
|
|
1
|
+
# typed: true
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require 'sorbet-runtime'
|
5
|
+
|
6
|
+
module Frontman
|
7
|
+
module Builder
|
8
|
+
class File
|
9
|
+
extend T::Sig
|
10
|
+
|
11
|
+
attr_accessor :path, :status
|
12
|
+
|
13
|
+
sig { params(path: String, status: T.any(String, Symbol)).void }
|
14
|
+
def initialize(path, status)
|
15
|
+
unless valid_status?(status)
|
16
|
+
raise "#{status} is not a valid file status!"
|
17
|
+
end
|
18
|
+
|
19
|
+
@path = path
|
20
|
+
@status = status.to_sym
|
21
|
+
end
|
22
|
+
|
23
|
+
class << self
|
24
|
+
extend T::Sig
|
25
|
+
|
26
|
+
sig { params(path: String).returns(Frontman::Builder::File) }
|
27
|
+
def unchanged(path)
|
28
|
+
new(path, :unchanged)
|
29
|
+
end
|
30
|
+
|
31
|
+
sig { params(path: String).returns(Frontman::Builder::File) }
|
32
|
+
def deleted(path)
|
33
|
+
new(path, :deleted)
|
34
|
+
end
|
35
|
+
|
36
|
+
sig { params(path: String).returns(Frontman::Builder::File) }
|
37
|
+
def created(path)
|
38
|
+
new(path, :created)
|
39
|
+
end
|
40
|
+
|
41
|
+
sig { params(path: String).returns(Frontman::Builder::File) }
|
42
|
+
def updated(path)
|
43
|
+
new(path, :updated)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
private
|
48
|
+
|
49
|
+
sig { params(status: T.any(String, Symbol)).returns(T::Boolean) }
|
50
|
+
def valid_status?(status)
|
51
|
+
%i[updated deleted created unchanged].include?(status.to_sym)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
# typed: true
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require 'fileutils'
|
5
|
+
require 'json'
|
6
|
+
require 'sorbet-runtime'
|
7
|
+
|
8
|
+
module Frontman
|
9
|
+
module Builder
|
10
|
+
class Mapping
|
11
|
+
extend T::Sig
|
12
|
+
|
13
|
+
attr_reader :output_path
|
14
|
+
|
15
|
+
sig { params(output_path: String).void }
|
16
|
+
def initialize(output_path)
|
17
|
+
@output_path = output_path
|
18
|
+
@mapping = {
|
19
|
+
updated: [],
|
20
|
+
created: [],
|
21
|
+
unchanged: [],
|
22
|
+
deleted: []
|
23
|
+
}
|
24
|
+
end
|
25
|
+
|
26
|
+
sig { returns(T::Hash[T.any(String, Symbol), T::Array[String]]) }
|
27
|
+
def all
|
28
|
+
@mapping
|
29
|
+
end
|
30
|
+
|
31
|
+
sig { params(build_file: Frontman::Builder::File).void }
|
32
|
+
def add_from_build_file(build_file)
|
33
|
+
add(build_file.status, build_file.path)
|
34
|
+
end
|
35
|
+
|
36
|
+
sig { params(status: T.any(String, Symbol), path: String).void }
|
37
|
+
def add(status, path)
|
38
|
+
@mapping[status.to_sym].push(path)
|
39
|
+
end
|
40
|
+
|
41
|
+
sig { void }
|
42
|
+
def save_file
|
43
|
+
::File.open(output_path, 'w') do |f|
|
44
|
+
f.write(JSON.pretty_generate(@mapping))
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
sig { void }
|
49
|
+
def delete_file
|
50
|
+
FileUtils.rm_f(output_path)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# typed: true
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require 'frontman/builder/builder'
|
5
|
+
require 'frontman/builder/mapping'
|
6
|
+
require 'frontman/toolbox/timer'
|
7
|
+
require 'sorbet-runtime'
|
8
|
+
|
9
|
+
module Frontman
|
10
|
+
module Builder
|
11
|
+
class StatisticsCollector
|
12
|
+
extend T::Sig
|
13
|
+
|
14
|
+
sig do
|
15
|
+
params(
|
16
|
+
builder: Frontman::Builder::Builder,
|
17
|
+
mapping: Frontman::Builder::Mapping,
|
18
|
+
timer: Frontman::Toolbox::Timer,
|
19
|
+
new_files: T::Array[String]
|
20
|
+
).void
|
21
|
+
end
|
22
|
+
def self.output(builder, mapping, timer, new_files = [])
|
23
|
+
puts JSON.pretty_generate(mapping.all)
|
24
|
+
puts '================================================================='
|
25
|
+
puts "Previous build size : #{builder.current_build_files.size} files"
|
26
|
+
puts "Current build size : #{new_files.size} files"
|
27
|
+
|
28
|
+
%i[updated created deleted unchanged].each do |status|
|
29
|
+
puts "#{status} : #{Array(mapping.all[status]).length} files"
|
30
|
+
end
|
31
|
+
|
32
|
+
timer.stop
|
33
|
+
puts timer.output
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
data/lib/frontman/cli.rb
ADDED
@@ -0,0 +1,76 @@
|
|
1
|
+
# frozen_string_literal: false
|
2
|
+
|
3
|
+
require 'thor'
|
4
|
+
require 'frontman/app'
|
5
|
+
require 'frontman/bootstrapper'
|
6
|
+
require 'frontman/builder/asset_pipeline'
|
7
|
+
require 'frontman/builder/builder'
|
8
|
+
require 'frontman/builder/mapping'
|
9
|
+
require 'frontman/builder/statistics_collector'
|
10
|
+
require 'frontman/config'
|
11
|
+
require 'frontman/toolbox/timer'
|
12
|
+
require 'frontman/sitemap_tree'
|
13
|
+
|
14
|
+
module Frontman
|
15
|
+
class CLI < Thor
|
16
|
+
option :parallel, type: :boolean
|
17
|
+
option :verbose, type: :boolean
|
18
|
+
desc 'build', 'Generate the HTML for your website'
|
19
|
+
def build
|
20
|
+
Frontman::Config.set(:mode, 'build')
|
21
|
+
Frontman::Bootstrapper.bootstrap_app(Frontman::App.instance)
|
22
|
+
|
23
|
+
assets_pipeline = Frontman::Builder::AssetPipeline.new(
|
24
|
+
Frontman::App.instance
|
25
|
+
.asset_pipelines
|
26
|
+
.filter { |p| %i[all build].include?(p[:mode]) }
|
27
|
+
)
|
28
|
+
|
29
|
+
assets_pipeline.run!(:before)
|
30
|
+
|
31
|
+
enable_parallel = options[:parallel]
|
32
|
+
|
33
|
+
Frontman::Config.set(:parallel, enable_parallel)
|
34
|
+
|
35
|
+
timer = Frontman::Toolbox::Timer.start
|
36
|
+
|
37
|
+
current_build_files = Dir.glob(Dir.pwd + '/build/**/*').reject do |f|
|
38
|
+
File.directory? f
|
39
|
+
end
|
40
|
+
|
41
|
+
public_dir = Frontman::Config.get(:public_dir, fallback: 'public/')
|
42
|
+
assets_to_build = Dir.glob(File.join(public_dir, '**/*')).reject do |f|
|
43
|
+
File.directory? f
|
44
|
+
end
|
45
|
+
|
46
|
+
mapping_path = Dir.pwd + '/_build.json'
|
47
|
+
mapping = Frontman::Builder::Mapping.new(mapping_path)
|
48
|
+
mapping.delete_file
|
49
|
+
|
50
|
+
build_directory = Dir.pwd + '/build/'
|
51
|
+
builder = Frontman::Builder::Builder.new
|
52
|
+
builder.build_directory = build_directory
|
53
|
+
builder.current_build_files = current_build_files
|
54
|
+
|
55
|
+
builder.on('created, updated, deleted, unchanged', lambda { |build_file|
|
56
|
+
mapping.add_from_build_file(build_file)
|
57
|
+
})
|
58
|
+
|
59
|
+
assets = builder.build_assets(assets_to_build)
|
60
|
+
redirects = builder.build_redirects
|
61
|
+
|
62
|
+
resources_paths = builder.build_from_resources(
|
63
|
+
Frontman::SitemapTree.resources
|
64
|
+
)
|
65
|
+
|
66
|
+
new_files = assets + redirects + resources_paths
|
67
|
+
|
68
|
+
builder.delete_files(current_build_files - new_files)
|
69
|
+
mapping.save_file
|
70
|
+
|
71
|
+
assets_pipeline.run!(:after)
|
72
|
+
|
73
|
+
Builder::StatisticsCollector.output(builder, mapping, timer, new_files)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
# frozen_string_literal: false
|
2
|
+
|
3
|
+
require 'fileutils'
|
4
|
+
require 'thor'
|
5
|
+
|
6
|
+
module Frontman
|
7
|
+
class CLI < Thor
|
8
|
+
option :template
|
9
|
+
desc 'init', 'Bootstrap a new Frontman project'
|
10
|
+
def init(path)
|
11
|
+
template = options[:template] || 'default'
|
12
|
+
unless template_exists?(template)
|
13
|
+
raise "Template #{template} does not exist!"
|
14
|
+
end
|
15
|
+
|
16
|
+
target_dir = File.join(Dir.pwd, path == '.' ? '' : path)
|
17
|
+
|
18
|
+
unless allowed_to_modify_dir?(target_dir)
|
19
|
+
say 'Not bootstrapping new Frontman project'
|
20
|
+
return
|
21
|
+
end
|
22
|
+
|
23
|
+
copy_template(template, target_dir)
|
24
|
+
|
25
|
+
command = path == '.' ? '' : "cd #{path} && "
|
26
|
+
command += 'bundle exec frontman serve'
|
27
|
+
|
28
|
+
say "Your project is ready. Run `#{command}` and start developing!"
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def copy_template(template, dest)
|
34
|
+
FileUtils.cp_r(
|
35
|
+
"#{path_to_template(template)}/.",
|
36
|
+
dest
|
37
|
+
)
|
38
|
+
end
|
39
|
+
|
40
|
+
def allowed_to_modify_dir?(dir)
|
41
|
+
return true if !Dir.exist?(dir) || Dir.empty?(dir)
|
42
|
+
|
43
|
+
say 'This folder already contains files. '
|
44
|
+
say 'Initializing a new Frontman project here may override these files.'
|
45
|
+
answer = ask('Are you sure you want to continue? [y/N]')
|
46
|
+
|
47
|
+
answer.to_s.downcase == 'y'
|
48
|
+
end
|
49
|
+
|
50
|
+
def template_exists?(template)
|
51
|
+
Dir.exist?(path_to_template(template))
|
52
|
+
end
|
53
|
+
|
54
|
+
def path_to_template(template)
|
55
|
+
File.join(__dir__, '../../../project-templates', template)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,110 @@
|
|
1
|
+
# frozen_string_literal: false
|
2
|
+
|
3
|
+
require 'thor'
|
4
|
+
require 'sinatra/base'
|
5
|
+
require 'better_errors'
|
6
|
+
require 'listen'
|
7
|
+
require 'frontman/app'
|
8
|
+
require 'frontman/bootstrapper'
|
9
|
+
require 'frontman/builder/asset_pipeline'
|
10
|
+
require 'frontman/config'
|
11
|
+
require 'frontman/resource'
|
12
|
+
|
13
|
+
module Frontman
|
14
|
+
class CLI < Thor
|
15
|
+
desc 'serve', 'Serve your application'
|
16
|
+
def serve
|
17
|
+
Frontman::Config.set(:mode, 'serve')
|
18
|
+
app = Frontman::App.instance
|
19
|
+
Frontman::Bootstrapper.bootstrap_app(app)
|
20
|
+
|
21
|
+
assets_pipeline = Frontman::Builder::AssetPipeline.new(
|
22
|
+
app
|
23
|
+
.asset_pipelines
|
24
|
+
.filter { |p| %i[all serve].include?(p[:mode]) }
|
25
|
+
)
|
26
|
+
processes = assets_pipeline.run_in_background!(:before)
|
27
|
+
|
28
|
+
helpers_dir = Frontman::Config.get(:helpers_dir, fallback: 'helpers')
|
29
|
+
content_dir = Frontman::Config.get(:content_dir, fallback: 'source/')
|
30
|
+
listen_to_dirs = Frontman::Config.get(:observe_dirs, fallback:
|
31
|
+
[
|
32
|
+
Frontman::Config.get(:layout_dir, fallback: 'views/layouts'),
|
33
|
+
Frontman::Config.get(:partial_dir, fallback: 'views/partials'),
|
34
|
+
content_dir,
|
35
|
+
helpers_dir
|
36
|
+
]).filter { |dir| Dir.exist?(dir) }
|
37
|
+
app.refresh_data_files = true
|
38
|
+
|
39
|
+
listener = Listen.to(*listen_to_dirs) do |modified, added|
|
40
|
+
(added + modified).each do |m|
|
41
|
+
resource_path = m.sub("#{Dir.pwd}/", '')
|
42
|
+
begin
|
43
|
+
if resource_path.start_with?(helpers_dir)
|
44
|
+
helper_name = File.basename(resource_path).gsub('.rb', '')
|
45
|
+
load("./#{resource_path}")
|
46
|
+
app.register_helpers(
|
47
|
+
[{
|
48
|
+
path: File.join(Dir.pwd, resource_path),
|
49
|
+
name: helper_name.split('_').collect(&:capitalize).join
|
50
|
+
}]
|
51
|
+
)
|
52
|
+
elsif resource_path.start_with?(*listen_to_dirs)
|
53
|
+
r = Frontman::Resource.from_path(resource_path)
|
54
|
+
|
55
|
+
if resource_path.start_with?(content_dir)
|
56
|
+
exists = app.sitemap_tree.from_resource(r)
|
57
|
+
app.sitemap_tree.add(r) unless exists
|
58
|
+
end
|
59
|
+
|
60
|
+
r&.parse_resource(true)
|
61
|
+
elsif resource_path.end_with?('.rb')
|
62
|
+
load("./#{resource_path}")
|
63
|
+
end
|
64
|
+
rescue Error
|
65
|
+
# We ignore all errors to prevent the listener from crashing.
|
66
|
+
# Errors will be surfaced by the server instead.
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
listener.start
|
72
|
+
|
73
|
+
FrontManServer.set :public_folder, Frontman::Config.get(
|
74
|
+
:public_dir, fallback: 'public'
|
75
|
+
)
|
76
|
+
FrontManServer.run! do
|
77
|
+
host = "http://localhost:#{FrontManServer.settings.port}"
|
78
|
+
print "== View your site at \"#{host}/\"\n"
|
79
|
+
processes += assets_pipeline.run_in_background!(:after)
|
80
|
+
at_exit { processes.each { |pid| Process.kill(0, pid) } }
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
class FrontManServer < Sinatra::Base
|
87
|
+
set :port, 4568
|
88
|
+
set :server_settings,
|
89
|
+
# Avoid having webrick displaying logs for every requests to the serve
|
90
|
+
AccessLog: [],
|
91
|
+
# Remove logger for WebRick, we have the one of sinatra already
|
92
|
+
Logger: Rack::NullLogger.new(self)
|
93
|
+
|
94
|
+
use BetterErrors::Middleware
|
95
|
+
BetterErrors.application_root = Dir.pwd
|
96
|
+
|
97
|
+
get '*' do |path|
|
98
|
+
app = Frontman::App.instance
|
99
|
+
return redirect to app.get_redirect(path), 302 if app.get_redirect(path)
|
100
|
+
|
101
|
+
tree = app.sitemap_tree.from_url(path)
|
102
|
+
if tree&.resource
|
103
|
+
extension = File.extname(tree.resource.destination_path)
|
104
|
+
headers['Content-Type'] = Rack::Mime.mime_type(extension)
|
105
|
+
tree.resource.render
|
106
|
+
else
|
107
|
+
halt 404
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
# typed: true
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require 'sorbet-runtime'
|
5
|
+
|
6
|
+
module Frontman
|
7
|
+
module DispatchEvents
|
8
|
+
extend T::Sig
|
9
|
+
|
10
|
+
sig { returns(T::Hash[Symbol, T::Array[T.untyped]]) }
|
11
|
+
def listeners
|
12
|
+
@listeners ||= {}
|
13
|
+
end
|
14
|
+
|
15
|
+
sig do
|
16
|
+
params(events: T.any(Symbol, String), callback: T.untyped)
|
17
|
+
.returns(T.self_type)
|
18
|
+
end
|
19
|
+
def on(events, callback)
|
20
|
+
list(events).each do |event_name|
|
21
|
+
listeners[event_name.to_sym] ||= []
|
22
|
+
T.must(listeners[event_name.to_sym]).push(callback)
|
23
|
+
end
|
24
|
+
|
25
|
+
self
|
26
|
+
end
|
27
|
+
|
28
|
+
# We don't annotate with sig because of bad support for splat arguments
|
29
|
+
def emit(events, *arguments)
|
30
|
+
list(events).each do |event_name|
|
31
|
+
event_listeners = listeners[event_name.to_sym] || []
|
32
|
+
event_listeners.each do |listener|
|
33
|
+
listener.call(*arguments)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
self
|
38
|
+
end
|
39
|
+
|
40
|
+
sig { params(events: T.any(Symbol, String)).returns(T.self_type) }
|
41
|
+
def off(events)
|
42
|
+
list(events).each do |event_name|
|
43
|
+
listeners[event_name.to_sym] = []
|
44
|
+
end
|
45
|
+
|
46
|
+
self
|
47
|
+
end
|
48
|
+
|
49
|
+
private
|
50
|
+
|
51
|
+
sig { params(events: T.any(Symbol, String)).returns(T::Array[String]) }
|
52
|
+
def list(events)
|
53
|
+
events.to_s.split(',').map(&:strip)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|