Roll the feed plugins into PostsPlugin

You can't have feeds without posts that they link to. Doesn't make sense to have feeds without posts.
This commit is contained in:
Sami Samhuri 2019-12-11 00:18:19 -08:00
parent 23b3d2d625
commit 0748053a82
10 changed files with 57 additions and 139 deletions

View file

@ -1,48 +0,0 @@
//
// JSONFeedPlugin.swift
// SiteGenerator
//
// Created by Sami Samhuri on 2019-12-10.
//
import Foundation
final class JSONFeedPlugin: Plugin {
let postRepo: PostRepo
let jsonFeedWriter: JSONFeedWriter
init(
postRepo: PostRepo = PostRepo(),
jsonFeedWriter: JSONFeedWriter = JSONFeedWriter()
) {
self.postRepo = postRepo
self.jsonFeedWriter = jsonFeedWriter
}
// MARK: - Plugin methods
convenience init(options: [String: Any]) {
if let feedPath = options["feed_path"] as? String {
self.init(jsonFeedWriter: JSONFeedWriter(feedPath: feedPath))
}
else {
self.init()
}
}
func setUp(site: Site, sourceURL: URL) throws {
guard postRepo.postDataExists(at: sourceURL) else {
return
}
try postRepo.readPosts(sourceURL: sourceURL)
}
func render(site: Site, targetURL: URL, templateRenderer: TemplateRenderer) throws {
guard !postRepo.isEmpty else {
return
}
try jsonFeedWriter.writeFeed(postRepo.postsForFeed, site: site, to: targetURL, with: templateRenderer)
}
}

View file

@ -1,16 +0,0 @@
//
// PostRepo+Feeds.swift
// SiteGenerator
//
// Created by Sami Samhuri on 2019-12-10.
//
import Foundation
extension PostRepo {
var feedPostsCount: Int { 30 }
var postsForFeed: [Post] {
Array(sortedPosts.prefix(feedPostsCount))
}
}

View file

@ -1,48 +0,0 @@
//
// RSSFeedPlugin.swift
// SiteGenerator
//
// Created by Sami Samhuri on 2019-12-10.
//
import Foundation
final class RSSFeedPlugin: Plugin {
let postRepo: PostRepo
let rssFeedWriter: RSSFeedWriter
init(
postRepo: PostRepo = PostRepo(),
rssFeedWriter: RSSFeedWriter = RSSFeedWriter()
) {
self.postRepo = postRepo
self.rssFeedWriter = rssFeedWriter
}
// MARK: - Plugin methods
convenience init(options: [String: Any]) {
if let feedPath = options["feed_path"] as? String {
self.init(rssFeedWriter: RSSFeedWriter(feedPath: feedPath))
}
else {
self.init()
}
}
func setUp(site: Site, sourceURL: URL) throws {
guard postRepo.postDataExists(at: sourceURL) else {
return
}
try postRepo.readPosts(sourceURL: sourceURL)
}
func render(site: Site, targetURL: URL, templateRenderer: TemplateRenderer) throws {
guard !postRepo.isEmpty else {
return
}
try rssFeedWriter.writeFeed(postRepo.postsForFeed, site: site, to: targetURL, with: templateRenderer)
}
}

View file

@ -45,10 +45,6 @@ public final class Generator {
return ProjectsPlugin(options: options)
case .posts:
return PostsPlugin(options: options)
case .jsonFeed:
return JSONFeedPlugin(options: options)
case .rssFeed:
return RSSFeedPlugin(options: options)
}
}
for plugin in plugins {

View file

@ -10,6 +10,4 @@ import Foundation
public enum SitePlugin: String, Codable {
case posts
case projects
case jsonFeed = "json_feed"
case rssFeed = "rss_feed"
}

View file

@ -15,16 +15,15 @@ struct RawPost {
final class PostRepo {
let postsPath = "posts"
let recentPostsCount = 10
let feedPostsCount = 30
let fileManager: FileManager
let postTransformer: PostTransformer
let outputPath: String
private(set) var posts: PostsByYear!
init(fileManager: FileManager = .default, postTransformer: PostTransformer = PostTransformer(), outputPath: String = "posts") {
init(fileManager: FileManager = .default, outputPath: String = "posts") {
self.fileManager = fileManager
self.postTransformer = postTransformer
self.outputPath = outputPath
}
@ -40,28 +39,22 @@ final class PostRepo {
Array(sortedPosts.prefix(recentPostsCount))
}
var postsForFeed: [Post] {
Array(sortedPosts.prefix(feedPostsCount))
}
func postDataExists(at sourceURL: URL) -> Bool {
let postsURL = sourceURL.appendingPathComponent(postsPath)
return fileManager.fileExists(atPath: postsURL.path)
}
func readPosts(sourceURL: URL) throws {
let postTransformer = PostTransformer(outputPath: outputPath)
let posts = try readRawPosts(sourceURL: sourceURL)
.map { try postTransformer.makePost(from: $0, makePath: urlPathForPost) }
.map(postTransformer.makePost)
self.posts = PostsByYear(posts: posts, path: "/\(outputPath)")
}
func urlPathForPost(date: Date, slug: String) -> String {
// format: /posts/2019/12/first-post
[
"",
outputPath,
"\(date.year)",
Month(date.month).padded,
slug,
].joined(separator: "/")
}
private func readRawPosts(sourceURL: URL) throws -> [RawPost] {
let postsURL = sourceURL.appendingPathComponent(postsPath)
return try enumerateMarkdownFiles(directory: postsURL)

View file

@ -10,15 +10,17 @@ import Ink
final class PostTransformer {
let markdownParser: MarkdownParser
let outputPath: String
init(markdownParser: MarkdownParser = MarkdownParser()) {
init(markdownParser: MarkdownParser = MarkdownParser(), outputPath: String = "posts") {
self.markdownParser = markdownParser
self.outputPath = outputPath
}
func makePost(from rawPost: RawPost, makePath: (Date, _ slug: String) -> String) throws -> Post {
func makePost(from rawPost: RawPost) throws -> Post {
let result = markdownParser.parse(rawPost.markdown)
let metadata = try parseMetadata(result.metadata)
let path = makePath(metadata.date, rawPost.slug)
let path = pathForPost(date: metadata.date, slug: rawPost.slug)
return Post(
slug: rawPost.slug,
title: metadata.title,
@ -31,6 +33,17 @@ final class PostTransformer {
path: path
)
}
func pathForPost(date: Date, slug: String) -> String {
// format: /posts/2019/12/first-post
[
"",
outputPath,
"\(date.year)",
Month(date.month).padded,
slug,
].joined(separator: "/")
}
}
struct ParsedMetadata {

View file

@ -10,24 +10,52 @@ import Foundation
final class PostsPlugin: Plugin {
let postRepo: PostRepo
let postWriter: PostWriter
let jsonFeedWriter: JSONFeedWriter?
let rssFeedWriter: RSSFeedWriter?
init(
postRepo: PostRepo = PostRepo(),
postWriter: PostWriter = PostWriter()
postWriter: PostWriter = PostWriter(),
jsonFeedWriter: JSONFeedWriter?,
rssFeedWriter: RSSFeedWriter?
) {
self.postRepo = postRepo
self.postWriter = postWriter
self.jsonFeedWriter = jsonFeedWriter
self.rssFeedWriter = rssFeedWriter
}
// MARK: - Plugin methods
convenience init(options: [String: Any]) {
let postRepo: PostRepo
let postWriter: PostWriter
if let outputPath = options["path"] as? String {
self.init(postWriter: PostWriter(outputPath: outputPath))
postRepo = PostRepo(outputPath: outputPath)
postWriter = PostWriter(outputPath: outputPath)
}
else {
self.init()
postRepo = PostRepo()
postWriter = PostWriter()
}
let jsonFeedWriter: JSONFeedWriter?
if let jsonFeedPath = options["json_feed"] as? String {
jsonFeedWriter = JSONFeedWriter(feedPath: jsonFeedPath)
}
else {
jsonFeedWriter = nil
}
let rssFeedWriter: RSSFeedWriter?
if let rssFeedPath = options["rss_feed"] as? String {
rssFeedWriter = RSSFeedWriter(feedPath: rssFeedPath)
}
else {
rssFeedWriter = nil
}
self.init(postRepo: postRepo, postWriter: postWriter, jsonFeedWriter: jsonFeedWriter, rssFeedWriter: rssFeedWriter)
}
func setUp(site: Site, sourceURL: URL) throws {
@ -48,5 +76,7 @@ final class PostsPlugin: Plugin {
try postWriter.writeArchive(posts: postRepo.posts, to: targetURL, with: templateRenderer)
try postWriter.writeYearIndexes(posts: postRepo.posts, to: targetURL, with: templateRenderer)
try postWriter.writeMonthRollups(posts: postRepo.posts, to: targetURL, with: templateRenderer)
try jsonFeedWriter?.writeFeed(postRepo.postsForFeed, site: site, to: targetURL, with: templateRenderer)
try rssFeedWriter?.writeFeed(postRepo.postsForFeed, site: site, to: targetURL, with: templateRenderer)
}
}