mirror of
https://github.com/samsonjs/samhuri.net.git
synced 2026-03-30 09:45:57 +00:00
157 lines
5.1 KiB
Ruby
157 lines
5.1 KiB
Ruby
require_relative '../site'
|
|
require_relative '../posts/plugin'
|
|
require_relative '../projects/plugin'
|
|
require_relative '../utils/markdown_renderer'
|
|
require_relative 'simple_toml'
|
|
|
|
module Pressa
|
|
module Config
|
|
class ValidationError < StandardError; end
|
|
|
|
class Loader
|
|
REQUIRED_SITE_KEYS = %w[author email title description url].freeze
|
|
REQUIRED_PROJECT_KEYS = %w[name title description url].freeze
|
|
|
|
def initialize(source_path:)
|
|
@source_path = source_path
|
|
end
|
|
|
|
def build_site(url_override: nil)
|
|
site_config = load_toml('site.toml')
|
|
projects_config = load_toml('projects.toml')
|
|
|
|
validate_required!(site_config, REQUIRED_SITE_KEYS, context: 'site.toml')
|
|
|
|
site_url = url_override || site_config['url']
|
|
projects_plugin = hash_or_empty(site_config['projects_plugin'], 'site.toml projects_plugin')
|
|
|
|
projects = build_projects(projects_config)
|
|
|
|
Site.new(
|
|
author: site_config['author'],
|
|
email: site_config['email'],
|
|
title: site_config['title'],
|
|
description: site_config['description'],
|
|
url: site_url,
|
|
image_url: normalize_image_url(site_config['image_url'], site_url),
|
|
scripts: build_scripts(site_config['scripts'], context: 'site.toml scripts'),
|
|
styles: build_styles(site_config['styles'], context: 'site.toml styles'),
|
|
plugins: [
|
|
Posts::Plugin.new,
|
|
Projects::Plugin.new(
|
|
projects:,
|
|
scripts: build_scripts(projects_plugin['scripts'], context: 'site.toml projects_plugin.scripts'),
|
|
styles: build_styles(projects_plugin['styles'], context: 'site.toml projects_plugin.styles')
|
|
)
|
|
],
|
|
renderers: [
|
|
Utils::MarkdownRenderer.new
|
|
]
|
|
)
|
|
end
|
|
|
|
private
|
|
|
|
def load_toml(filename)
|
|
path = File.join(@source_path, filename)
|
|
SimpleToml.load_file(path)
|
|
rescue ParseError => e
|
|
raise ValidationError, e.message
|
|
end
|
|
|
|
def build_projects(projects_config)
|
|
projects = projects_config['projects']
|
|
raise ValidationError, "Missing required top-level array 'projects' in projects.toml" unless projects
|
|
raise ValidationError, "Expected 'projects' to be an array in projects.toml" unless projects.is_a?(Array)
|
|
|
|
projects.map.with_index do |project, index|
|
|
unless project.is_a?(Hash)
|
|
raise ValidationError, "Project entry #{index + 1} must be a table in projects.toml"
|
|
end
|
|
|
|
validate_required!(project, REQUIRED_PROJECT_KEYS, context: "projects.toml project ##{index + 1}")
|
|
|
|
Projects::Project.new(
|
|
name: project['name'],
|
|
title: project['title'],
|
|
description: project['description'],
|
|
url: project['url']
|
|
)
|
|
end
|
|
end
|
|
|
|
def validate_required!(hash, keys, context:)
|
|
missing = keys.reject do |key|
|
|
hash[key].is_a?(String) && !hash[key].strip.empty?
|
|
end
|
|
|
|
return if missing.empty?
|
|
|
|
raise ValidationError, "Missing required #{context} keys: #{missing.join(', ')}"
|
|
end
|
|
|
|
def hash_or_empty(value, context)
|
|
return {} if value.nil?
|
|
return value if value.is_a?(Hash)
|
|
|
|
raise ValidationError, "Expected #{context} to be a table"
|
|
end
|
|
|
|
def build_scripts(value, context:)
|
|
entries = array_or_empty(value, context)
|
|
|
|
entries.map.with_index do |item, index|
|
|
case item
|
|
when String
|
|
Script.new(src: item, defer: true)
|
|
when Hash
|
|
src = item['src']
|
|
raise ValidationError, "Expected #{context}[#{index}].src to be a String" unless src.is_a?(String) && !src.empty?
|
|
|
|
defer = item.key?('defer') ? item['defer'] : true
|
|
unless [true, false].include?(defer)
|
|
raise ValidationError, "Expected #{context}[#{index}].defer to be a Boolean"
|
|
end
|
|
|
|
Script.new(src:, defer:)
|
|
else
|
|
raise ValidationError, "Expected #{context}[#{index}] to be a String or table"
|
|
end
|
|
end
|
|
end
|
|
|
|
def build_styles(value, context:)
|
|
entries = array_or_empty(value, context)
|
|
|
|
entries.map.with_index do |item, index|
|
|
case item
|
|
when String
|
|
Stylesheet.new(href: item)
|
|
when Hash
|
|
href = item['href']
|
|
raise ValidationError, "Expected #{context}[#{index}].href to be a String" unless href.is_a?(String) && !href.empty?
|
|
|
|
Stylesheet.new(href:)
|
|
else
|
|
raise ValidationError, "Expected #{context}[#{index}] to be a String or table"
|
|
end
|
|
end
|
|
end
|
|
|
|
def array_or_empty(value, context)
|
|
return [] if value.nil?
|
|
return value if value.is_a?(Array)
|
|
|
|
raise ValidationError, "Expected #{context} to be an array"
|
|
end
|
|
|
|
def normalize_image_url(value, site_url)
|
|
return nil if value.nil?
|
|
return value if value.start_with?('http://', 'https://')
|
|
|
|
normalized = value.start_with?('/') ? value : "/#{value}"
|
|
"#{site_url}#{normalized}"
|
|
end
|
|
end
|
|
end
|
|
end
|