From 44fef3fb784515a7775339128cb8a3397e64b42e Mon Sep 17 00:00:00 2001 From: Sami Samhuri Date: Tue, 17 Dec 2019 10:29:28 -0800 Subject: [PATCH] Port site.json to Swift code in samhuri_net module --- Readme.md | 2 +- .../Sources/SiteGenerator/BuiltSite.swift | 20 ++++ .../Generator/Contexts/PageContext.swift | 4 - .../Generator/Contexts/SiteContext.swift | 4 +- .../SiteGenerator/Generator/HumanSite.swift | 50 --------- .../SiteGenerator/Generator/Site.swift | 38 ++++--- .../Generator/SiteTemplateRenderer.swift | 10 +- .../Generator/TemplateRenderer.swift | 4 +- .../Posts/Feeds/JSONFeedWriter.swift | 16 +-- .../Posts/Feeds/RSSFeedWriter.swift | 10 +- .../SiteGenerator/Posts/JSONFeed.swift | 15 +++ .../SiteGenerator/Posts/PostsPlugin.swift | 12 +- .../Posts/PostsPluginBuilder.swift | 80 +++++++++++++ .../Sources/SiteGenerator/Posts/RSSFeed.swift | 12 ++ .../Projects/ProjectsPlugin.swift | 4 +- .../Renderers/MarkdownRenderer.swift | 7 +- .../Sources/SiteGenerator/SiteBuilder.swift | 105 ++++++++++++++++++ .../Sources/SiteGenerator/SiteGenerator.swift | 31 ++---- .../Sources/samhuri_net/samhuri_net.swift | 25 ++++- site.json | 22 ---- 20 files changed, 319 insertions(+), 152 deletions(-) create mode 100644 SiteGenerator/Sources/SiteGenerator/BuiltSite.swift delete mode 100644 SiteGenerator/Sources/SiteGenerator/Generator/HumanSite.swift create mode 100644 SiteGenerator/Sources/SiteGenerator/Posts/JSONFeed.swift create mode 100644 SiteGenerator/Sources/SiteGenerator/Posts/PostsPluginBuilder.swift create mode 100644 SiteGenerator/Sources/SiteGenerator/Posts/RSSFeed.swift create mode 100644 SiteGenerator/Sources/SiteGenerator/SiteBuilder.swift delete mode 100644 site.json diff --git a/Readme.md b/Readme.md index 32d5853..7b82c98 100644 --- a/Readme.md +++ b/Readme.md @@ -115,7 +115,7 @@ Execution, trying TDD for the first time: - [x] Create new packages and distribute the code accordingly - - [ ] Replace site.json with Swift code + - [x] Replace site.json with Swift code - [ ] Replace page template with Swift code diff --git a/SiteGenerator/Sources/SiteGenerator/BuiltSite.swift b/SiteGenerator/Sources/SiteGenerator/BuiltSite.swift new file mode 100644 index 0000000..ef9733d --- /dev/null +++ b/SiteGenerator/Sources/SiteGenerator/BuiltSite.swift @@ -0,0 +1,20 @@ +// +// BuiltSite.swift +// SiteGenerator +// +// Created by Sami Samhuri on 2019-12-15. +// + +import Foundation + +public struct BuiltSite { + public let site: Site + public let plugins: [Plugin] + public let renderers: [Renderer] + + init(site: Site, plugins: [Plugin], renderers: [Renderer]) { + self.site = site + self.plugins = plugins + self.renderers = renderers + } +} diff --git a/SiteGenerator/Sources/SiteGenerator/Generator/Contexts/PageContext.swift b/SiteGenerator/Sources/SiteGenerator/Generator/Contexts/PageContext.swift index d69e790..061ba48 100644 --- a/SiteGenerator/Sources/SiteGenerator/Generator/Contexts/PageContext.swift +++ b/SiteGenerator/Sources/SiteGenerator/Generator/Contexts/PageContext.swift @@ -15,10 +15,6 @@ struct PageContext { } extension PageContext { - var template: String { - page.template ?? site.template - } - var dictionary: [String: Any] { [ "site": site, diff --git a/SiteGenerator/Sources/SiteGenerator/Generator/Contexts/SiteContext.swift b/SiteGenerator/Sources/SiteGenerator/Generator/Contexts/SiteContext.swift index 5aa77f9..dfb7b7d 100644 --- a/SiteGenerator/Sources/SiteGenerator/Generator/Contexts/SiteContext.swift +++ b/SiteGenerator/Sources/SiteGenerator/Generator/Contexts/SiteContext.swift @@ -9,11 +9,9 @@ import Foundation struct SiteContext { let site: Site - let template: String - init(site: Site, template: String? = nil) { + init(site: Site) { self.site = site - self.template = template ?? site.template } } diff --git a/SiteGenerator/Sources/SiteGenerator/Generator/HumanSite.swift b/SiteGenerator/Sources/SiteGenerator/Generator/HumanSite.swift deleted file mode 100644 index 6ac09d0..0000000 --- a/SiteGenerator/Sources/SiteGenerator/Generator/HumanSite.swift +++ /dev/null @@ -1,50 +0,0 @@ -// -// HumanSite.swift -// SiteGenerator -// -// Created by Sami Samhuri on 2019-12-01. -// - -import Foundation - -/// This is used to make the JSON simpler to write with optionals. -struct HumanSite: Codable { - let author: String - let email: String? - let title: String - let description: String? - let url: URL - let template: String? - let styles: [String]? - let scripts: [String]? - let avatar: String? - let icon: String? - let favicon: String? - let plugins: [String: [String: String]]? -} - -extension Site { - init(humanSite: HumanSite) { - self.init( - author: humanSite.author, - email: humanSite.email, - title: humanSite.title, - description: humanSite.description, - url: humanSite.url, - template: humanSite.template ?? "page", - styles: humanSite.styles ?? [], - scripts: humanSite.scripts ?? [], - avatarPath: humanSite.avatar, - iconPath: humanSite.icon, - faviconPath: humanSite.favicon, - plugins: (humanSite.plugins ?? [:]).reduce(into: [:], { dict, pair in - let (name, options) = pair - guard let sitePlugin = SitePlugin(rawValue: name) else { - print("warning: unknown site plugin \"\(name)\"") - return - } - dict[sitePlugin] = options - }) - ) - } -} diff --git a/SiteGenerator/Sources/SiteGenerator/Generator/Site.swift b/SiteGenerator/Sources/SiteGenerator/Generator/Site.swift index f610b09..9e1472d 100644 --- a/SiteGenerator/Sources/SiteGenerator/Generator/Site.swift +++ b/SiteGenerator/Sources/SiteGenerator/Generator/Site.swift @@ -12,23 +12,31 @@ public struct Site { public let email: String? public let title: String public let description: String? - public var url: URL - public let template: String + public let url: URL public let styles: [String] public let scripts: [String] + public let renderers: [Renderer] + public let plugins: [Plugin] - // Used for JSON feed - public let avatarPath: String? - public let iconPath: String? - public let faviconPath: String? - - public let plugins: [SitePlugin: [String: Any]] -} - -extension Site { - static func decode(from url: URL) throws -> Site { - let json = try Data(contentsOf: url) - let humanSite = try JSONDecoder().decode(HumanSite.self, from: json) - return Site(humanSite: humanSite) + public init( + author: String, + email: String?, + title: String, + description: String?, + url: URL, + styles: [String], + scripts: [String], + renderers: [Renderer], + plugins: [Plugin] + ) { + self.author = author + self.email = email + self.title = title + self.description = description + self.url = url + self.styles = styles + self.scripts = scripts + self.renderers = renderers + self.plugins = plugins } } diff --git a/SiteGenerator/Sources/SiteGenerator/Generator/SiteTemplateRenderer.swift b/SiteGenerator/Sources/SiteGenerator/Generator/SiteTemplateRenderer.swift index 8ea24bb..7bac757 100644 --- a/SiteGenerator/Sources/SiteGenerator/Generator/SiteTemplateRenderer.swift +++ b/SiteGenerator/Sources/SiteGenerator/Generator/SiteTemplateRenderer.swift @@ -20,16 +20,16 @@ final class SiteTemplateRenderer: TemplateRenderer { self.stencil = Environment(loader: loader) } - func renderPage(bodyHTML: String, metadata: [String: String]) throws -> String { + func renderPage(template: String, bodyHTML: String, metadata: [String: String]) throws -> String { let page = Page(metadata: metadata) let context = PageContext(site: site, body: bodyHTML, page: page, metadata: metadata) - let pageHTML = try stencil.renderTemplate(name: "\(context.template).html", context: context.dictionary) + let pageHTML = try stencil.renderTemplate(name: template, context: context.dictionary) return pageHTML } - func renderTemplate(name: String?, context: [String: Any]) throws -> String { - let siteContext = SiteContext(site: site, template: name) + func renderTemplate(name: String, context: [String: Any]) throws -> String { + let siteContext = SiteContext(site: site) let contextDict = siteContext.dictionary.merging(context, uniquingKeysWith: { _, new in new }) - return try stencil.renderTemplate(name: siteContext.template, context: contextDict) + return try stencil.renderTemplate(name: name, context: contextDict) } } diff --git a/SiteGenerator/Sources/SiteGenerator/Generator/TemplateRenderer.swift b/SiteGenerator/Sources/SiteGenerator/Generator/TemplateRenderer.swift index 649b54a..14a069c 100644 --- a/SiteGenerator/Sources/SiteGenerator/Generator/TemplateRenderer.swift +++ b/SiteGenerator/Sources/SiteGenerator/Generator/TemplateRenderer.swift @@ -8,6 +8,6 @@ import Foundation public protocol TemplateRenderer: AnyObject { - func renderPage(bodyHTML: String, metadata: [String: String]) throws -> String - func renderTemplate(name: String?, context: [String: Any]) throws -> String + func renderPage(template: String, bodyHTML: String, metadata: [String: String]) throws -> String + func renderTemplate(name: String, context: [String: Any]) throws -> String } diff --git a/SiteGenerator/Sources/SiteGenerator/Posts/Feeds/JSONFeedWriter.swift b/SiteGenerator/Sources/SiteGenerator/Posts/Feeds/JSONFeedWriter.swift index 0ace428..a669f74 100644 --- a/SiteGenerator/Sources/SiteGenerator/Posts/Feeds/JSONFeedWriter.swift +++ b/SiteGenerator/Sources/SiteGenerator/Posts/Feeds/JSONFeedWriter.swift @@ -37,11 +37,11 @@ private struct FeedItem: Codable { final class JSONFeedWriter { let fileManager: FileManager - let feedPath: String + let jsonFeed: JSONFeed - init(fileManager: FileManager = .default, feedPath: String = "feed.json") { + init(fileManager: FileManager = .default, feed: JSONFeed) { self.fileManager = fileManager - self.feedPath = feedPath + self.jsonFeed = feed } func writeFeed(_ posts: [Post], site: Site, to targetURL: URL, with templateRenderer: TemplateRenderer) throws { @@ -60,21 +60,21 @@ final class JSONFeedWriter { tags: post.tags ) } - let avatar = site.avatarPath.map(site.url.appendingPathComponent) + let avatar = jsonFeed.avatarPath.map(site.url.appendingPathComponent) let feed: Feed = Feed( title: site.title, home_page_url: site.url.absoluteString, - feed_url: site.url.appendingPathComponent(feedPath).absoluteString, + feed_url: site.url.appendingPathComponent(jsonFeed.path).absoluteString, author: FeedAuthor(name: site.author, avatar: avatar?.absoluteString, url: site.url.absoluteString), - icon: site.iconPath.map(site.url.appendingPathComponent)?.absoluteString, - favicon: site.faviconPath.map(site.url.appendingPathComponent)?.absoluteString, + icon: jsonFeed.iconPath.map(site.url.appendingPathComponent)?.absoluteString, + favicon: jsonFeed.faviconPath.map(site.url.appendingPathComponent)?.absoluteString, items: items ) let encoder = JSONEncoder() encoder.dateEncodingStrategy = .iso8601 encoder.outputFormatting = [.prettyPrinted, .withoutEscapingSlashes] let feedJSON = try encoder.encode(feed) - let feedURL = targetURL.appendingPathComponent(feedPath) + let feedURL = targetURL.appendingPathComponent(jsonFeed.path) try feedJSON.write(to: feedURL, options: [.atomic]) } } diff --git a/SiteGenerator/Sources/SiteGenerator/Posts/Feeds/RSSFeedWriter.swift b/SiteGenerator/Sources/SiteGenerator/Posts/Feeds/RSSFeedWriter.swift index fde11c8..5f4e131 100644 --- a/SiteGenerator/Sources/SiteGenerator/Posts/Feeds/RSSFeedWriter.swift +++ b/SiteGenerator/Sources/SiteGenerator/Posts/Feeds/RSSFeedWriter.swift @@ -37,11 +37,11 @@ private extension Date { final class RSSFeedWriter { let fileManager: FileManager - let feedPath: String + let feed: RSSFeed - init(fileManager: FileManager = .default, feedPath: String = "feed.xml") { + init(fileManager: FileManager = .default, feed: RSSFeed) { self.fileManager = fileManager - self.feedPath = feedPath + self.feed = feed } func writeFeed(_ posts: [Post], site: Site, to targetURL: URL, with templateRenderer: TemplateRenderer) throws { @@ -74,10 +74,10 @@ final class RSSFeedWriter { } let feedXML = try templateRenderer.renderTemplate(name: "feed.xml", context: [ "site": feedSite, - "feedURL": site.url.appendingPathComponent(feedPath).absoluteString.escapedForXML(), + "feedURL": site.url.appendingPathComponent(feed.path).absoluteString.escapedForXML(), "posts": renderedPosts, ]) - let feedURL = targetURL.appendingPathComponent(feedPath) + let feedURL = targetURL.appendingPathComponent(feed.path) try feedXML.write(to: feedURL, atomically: true, encoding: .utf8) } } diff --git a/SiteGenerator/Sources/SiteGenerator/Posts/JSONFeed.swift b/SiteGenerator/Sources/SiteGenerator/Posts/JSONFeed.swift new file mode 100644 index 0000000..adeb06f --- /dev/null +++ b/SiteGenerator/Sources/SiteGenerator/Posts/JSONFeed.swift @@ -0,0 +1,15 @@ +// +// JSONFeed.swift +// SiteGenerator +// +// Created by Sami Samhuri on 2019-12-15. +// + +import Foundation + +struct JSONFeed { + let path: String + let avatarPath: String? + let iconPath: String? + let faviconPath: String? +} diff --git a/SiteGenerator/Sources/SiteGenerator/Posts/PostsPlugin.swift b/SiteGenerator/Sources/SiteGenerator/Posts/PostsPlugin.swift index 30002d8..e0d36d8 100644 --- a/SiteGenerator/Sources/SiteGenerator/Posts/PostsPlugin.swift +++ b/SiteGenerator/Sources/SiteGenerator/Posts/PostsPlugin.swift @@ -7,7 +7,7 @@ import Foundation -final class PostsPlugin: Plugin { +public final class PostsPlugin: Plugin { let postRepo: PostRepo let postWriter: PostWriter let jsonFeedWriter: JSONFeedWriter? @@ -41,7 +41,8 @@ final class PostsPlugin: Plugin { let jsonFeedWriter: JSONFeedWriter? if let jsonFeedPath = options["json_feed"] as? String { - jsonFeedWriter = JSONFeedWriter(feedPath: jsonFeedPath) + let jsonFeed = JSONFeed(path: jsonFeedPath, avatarPath: nil, iconPath: nil, faviconPath: nil) + jsonFeedWriter = JSONFeedWriter(feed: jsonFeed) } else { jsonFeedWriter = nil @@ -49,7 +50,8 @@ final class PostsPlugin: Plugin { let rssFeedWriter: RSSFeedWriter? if let rssFeedPath = options["rss_feed"] as? String { - rssFeedWriter = RSSFeedWriter(feedPath: rssFeedPath) + let rssFeed = RSSFeed(path: rssFeedPath) + rssFeedWriter = RSSFeedWriter(feed: rssFeed) } else { rssFeedWriter = nil @@ -58,7 +60,7 @@ final class PostsPlugin: Plugin { self.init(postRepo: postRepo, postWriter: postWriter, jsonFeedWriter: jsonFeedWriter, rssFeedWriter: rssFeedWriter) } - func setUp(site: Site, sourceURL: URL) throws { + public func setUp(site: Site, sourceURL: URL) throws { guard postRepo.postDataExists(at: sourceURL) else { return } @@ -66,7 +68,7 @@ final class PostsPlugin: Plugin { try postRepo.readPosts(sourceURL: sourceURL) } - func render(site: Site, targetURL: URL, templateRenderer: TemplateRenderer) throws { + public func render(site: Site, targetURL: URL, templateRenderer: TemplateRenderer) throws { guard !postRepo.isEmpty else { return } diff --git a/SiteGenerator/Sources/SiteGenerator/Posts/PostsPluginBuilder.swift b/SiteGenerator/Sources/SiteGenerator/Posts/PostsPluginBuilder.swift new file mode 100644 index 0000000..af3a848 --- /dev/null +++ b/SiteGenerator/Sources/SiteGenerator/Posts/PostsPluginBuilder.swift @@ -0,0 +1,80 @@ +// +// PostsPluginBuilder.swift +// SiteGenerator +// +// Created by Sami Samhuri on 2019-12-15. +// + +import Foundation + +public final class PostsPluginBuilder { + private var path: String? + private var jsonFeed: JSONFeed? + private var rssFeed: RSSFeed? + + public init() {} + + public func path(_ path: String) -> PostsPluginBuilder { + precondition(self.path == nil, "path is already defined") + self.path = path + return self + } + + public func jsonFeed( + path: String? = nil, + avatarPath: String? = nil, + iconPath: String? = nil, + faviconPath: String? = nil + ) -> PostsPluginBuilder { + precondition(jsonFeed == nil, "JSON feed is already defined") + jsonFeed = JSONFeed( + path: path ?? "feed.json", + avatarPath: avatarPath, + iconPath: iconPath, + faviconPath: faviconPath + ) + return self + } + + public func rssFeed(path: String? = nil) -> PostsPluginBuilder { + precondition(rssFeed == nil, "RSS feed is already defined") + rssFeed = RSSFeed(path: path ?? "feed.xml") + return self + } + + public func build() -> PostsPlugin { + let postRepo: PostRepo + let postWriter: PostWriter + if let outputPath = path { + postRepo = PostRepo(outputPath: outputPath) + postWriter = PostWriter(outputPath: outputPath) + } + else { + postRepo = PostRepo() + postWriter = PostWriter() + } + + let jsonFeedWriter: JSONFeedWriter? + if let jsonFeed = jsonFeed { + jsonFeedWriter = JSONFeedWriter(feed: jsonFeed) + } + else { + jsonFeedWriter = nil + } + + let rssFeedWriter: RSSFeedWriter? + if let rssFeed = rssFeed { + rssFeedWriter = RSSFeedWriter(feed: rssFeed) + } + else { + rssFeedWriter = nil + } + + return PostsPlugin( + postRepo: postRepo, + postWriter: postWriter, + jsonFeedWriter: jsonFeedWriter, + rssFeedWriter: rssFeedWriter + ) + } +} diff --git a/SiteGenerator/Sources/SiteGenerator/Posts/RSSFeed.swift b/SiteGenerator/Sources/SiteGenerator/Posts/RSSFeed.swift new file mode 100644 index 0000000..38013fd --- /dev/null +++ b/SiteGenerator/Sources/SiteGenerator/Posts/RSSFeed.swift @@ -0,0 +1,12 @@ +// +// RSSFeed.swift +// SiteGenerator +// +// Created by Sami Samhuri on 2019-12-15. +// + +import Foundation + +struct RSSFeed { + let path: String +} diff --git a/SiteGenerator/Sources/SiteGenerator/Projects/ProjectsPlugin.swift b/SiteGenerator/Sources/SiteGenerator/Projects/ProjectsPlugin.swift index 0fe76b9..86ae3be 100644 --- a/SiteGenerator/Sources/SiteGenerator/Projects/ProjectsPlugin.swift +++ b/SiteGenerator/Sources/SiteGenerator/Projects/ProjectsPlugin.swift @@ -24,8 +24,8 @@ final class ProjectsPlugin: Plugin { var projects: [Project] = [] var sourceURL: URL! - init(outputPath: String = "projects") { - self.outputPath = outputPath + init(outputPath: String? = nil) { + self.outputPath = outputPath ?? "projects" } convenience init(options: [String: Any]) { diff --git a/SiteGenerator/Sources/SiteGenerator/Renderers/MarkdownRenderer.swift b/SiteGenerator/Sources/SiteGenerator/Renderers/MarkdownRenderer.swift index 8cfd376..00c891a 100644 --- a/SiteGenerator/Sources/SiteGenerator/Renderers/MarkdownRenderer.swift +++ b/SiteGenerator/Sources/SiteGenerator/Renderers/MarkdownRenderer.swift @@ -11,8 +11,11 @@ import Ink public final class MarkdownRenderer: Renderer { let fileManager: FileManager = .default let markdownParser = MarkdownParser() + let defaultTemplate: String - public init() {} + public init(defaultTemplate: String) { + self.defaultTemplate = defaultTemplate + } public func canRenderFile(named filename: String, withExtension ext: String) -> Bool { ext == "md" @@ -23,7 +26,7 @@ public final class MarkdownRenderer: Renderer { let bodyMarkdown = try String(contentsOf: fileURL, encoding: .utf8) let bodyHTML = markdownParser.html(from: bodyMarkdown).trimmingCharacters(in: .whitespacesAndNewlines) let metadata = try markdownMetadata(from: fileURL) - let pageHTML = try templateRenderer.renderPage(bodyHTML: bodyHTML, metadata: metadata) + let pageHTML = try templateRenderer.renderPage(template: defaultTemplate, bodyHTML: bodyHTML, metadata: metadata) let mdFilename = fileURL.lastPathComponent let htmlPath: String diff --git a/SiteGenerator/Sources/SiteGenerator/SiteBuilder.swift b/SiteGenerator/Sources/SiteGenerator/SiteBuilder.swift new file mode 100644 index 0000000..ba7e6b4 --- /dev/null +++ b/SiteGenerator/Sources/SiteGenerator/SiteBuilder.swift @@ -0,0 +1,105 @@ +// +// SiteBuilder.swift +// SiteGenerator +// +// Created by Sami Samhuri on 2019-12-15. +// + +import Foundation + +public final class SiteBuilder { + private let author: String + private let title: String + private let url: URL + + private var email: String? + private var description: String? + + private var styles: [String] = [] + private var scripts: [String] = [] + + private var plugins: [Plugin] = [] + private var renderers: [Renderer] = [] + + public init( + author: String, + email: String? = nil, + title: String, + description: String? = nil, + url: URL + ) { + self.author = author + self.email = email + self.title = title + self.description = description + self.url = url + } + + public func email(_ email: String) -> SiteBuilder { + precondition(self.email == nil, "email is already defined") + self.email = email + return self + } + + public func description(_ description: String) -> SiteBuilder { + precondition(self.description == nil, "description is already defined") + self.description = description + return self + } + + public func styles(_ styles: String...) -> SiteBuilder { + self.styles.append(contentsOf: styles) + return self + } + + public func scripts(_ scripts: String...) -> SiteBuilder { + self.scripts.append(contentsOf: scripts) + return self + } + + public func plugin(_ plugin: Plugin) -> SiteBuilder { + plugins.append(plugin) + return self + } + + public func renderer(_ renderer: Renderer) -> SiteBuilder { + renderers.append(renderer) + return self + } + + public func build() -> Site { + Site( + author: author, + email: email, + title: title, + description: description, + url: url, + styles: styles, + scripts: scripts, + renderers: renderers, + plugins: plugins + ) + } +} + +// MARK: - Markdown + +public extension SiteBuilder { + func renderMarkdown(defaultTemplate: String) -> SiteBuilder { + renderer(MarkdownRenderer(defaultTemplate: defaultTemplate)) + } +} + +// MARK: - Projects + +public extension SiteBuilder { + func projects(path: String? = nil) -> SiteBuilder { + plugin(ProjectsPlugin(outputPath: path)) + } +} + +// MARK: - Posts + +public extension SiteBuilder { + // anything nice we can do there? +} diff --git a/SiteGenerator/Sources/SiteGenerator/SiteGenerator.swift b/SiteGenerator/Sources/SiteGenerator/SiteGenerator.swift index 7d32917..c01a5bf 100644 --- a/SiteGenerator/Sources/SiteGenerator/SiteGenerator.swift +++ b/SiteGenerator/Sources/SiteGenerator/SiteGenerator.swift @@ -15,44 +15,27 @@ public final class SiteGenerator { // Site properties public let site: Site public let sourceURL: URL - public private(set) var plugins: [Plugin] = [] - public let renderers: [Renderer] let ignoredFilenames = [".DS_Store", ".gitkeep"] - public init(sourceURL: URL, siteURLOverride: URL? = nil, renderers: [Renderer]) throws { - let siteURL = sourceURL.appendingPathComponent("site.json") - var site = try Site.decode(from: siteURL) - if let url = siteURLOverride { - print("Overriding site URL \(site.url) with \(url)") - site.url = url - } + public init(sourceURL: URL, site: Site) throws { + self.site = site + self.sourceURL = sourceURL let templatesURL = sourceURL.appendingPathComponent("templates") self.templateRenderer = SiteTemplateRenderer(site: site, templatesURL: templatesURL) - self.site = site - self.sourceURL = sourceURL - self.renderers = renderers - try initializePlugins() } private func initializePlugins() throws { - plugins = site.plugins.map { pair in - let (sitePlugin, options) = pair - return sitePlugin.construct(options: options) + for plugin in site.plugins { + try plugin.setUp(site: site, sourceURL: sourceURL) } - try plugins.forEach(addPlugin) - } - - public func addPlugin(_ plugin: Plugin) throws { - try plugin.setUp(site: site, sourceURL: sourceURL) - plugins.append(plugin) } public func generate(targetURL: URL) throws { - for plugin in plugins { + for plugin in site.plugins { try plugin.render(site: site, targetURL: targetURL, templateRenderer: templateRenderer) } @@ -87,7 +70,7 @@ public final class SiteGenerator { func renderOrCopyFile(url fileURL: URL, targetDir: URL) throws { let filename = fileURL.lastPathComponent let ext = String(filename.split(separator: ".").last!) - for renderer in renderers { + for renderer in site.renderers { if renderer.canRenderFile(named: filename, withExtension: ext) { try renderer.render(fileURL: fileURL, targetDir: targetDir, templateRenderer: templateRenderer) return diff --git a/samhuri_net/Sources/samhuri_net/samhuri_net.swift b/samhuri_net/Sources/samhuri_net/samhuri_net.swift index e8d594b..1887844 100644 --- a/samhuri_net/Sources/samhuri_net/samhuri_net.swift +++ b/samhuri_net/Sources/samhuri_net/samhuri_net.swift @@ -5,11 +5,28 @@ public struct samhuri_net { public init() {} public func generate(sourceURL: URL, targetURL: URL, siteURLOverride: URL? = nil) throws { - let generator = try SiteGenerator( - sourceURL: sourceURL, - siteURLOverride: siteURLOverride, - renderers: [MarkdownRenderer()] + let postsPlugin = PostsPluginBuilder() + .path("posts") + .jsonFeed( + avatarPath: "images/me.jpg", + iconPath: "images/apple-touch-icon-300.png", + faviconPath: "images/apple-touch-icon-80.png" + ) + .rssFeed() + .build() + let site = SiteBuilder( + author: "Sami Samhuri", + email: "sami@samhuri.net", + title: "samhuri.net", + description: "just some blog", + url: siteURLOverride ?? URL(string: "https://samhuri.net")! ) + .styles("css/normalize.css", "css/style.css") + .renderMarkdown(defaultTemplate: "page.html") + .projects() + .plugin(postsPlugin) + .build() + let generator = try SiteGenerator(sourceURL: sourceURL, site: site) try generator.generate(targetURL: targetURL) } } diff --git a/site.json b/site.json deleted file mode 100644 index cc58a7d..0000000 --- a/site.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "title": "samhuri.net", - "description": "just some blog", - "author": "Sami Samhuri", - "email": "sami@samhuri.net", - "url": "https://samhuri.net", - "styles": [ - "/css/normalize.css", - "/css/style.css" - ], - "scripts": [], - "icon": "images/apple-touch-icon-300.png", - "favicon": "images/apple-touch-icon-80.png", - "avatar": "images/me.jpg", - "plugins": { - "projects": {}, - "posts": { - "json_feed": "feed.json", - "rss_feed": "feed.xml" - } - } -}