Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add HTML Mutator capability for Plugins. #120

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions Sources/Publish/API/Mutations.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,8 @@

/// Closure type used to implement content mutations.
public typealias Mutations<T> = (inout T) throws -> Void
public typealias HTMLIndexMutation<Site:Website> = (PublishingContext<Site>, String) throws -> String
public typealias HTMLSectionMutation<Site:Website> = (PublishingContext<Site>, Section<Site>, String) throws -> String
public typealias HTMLItemMutation<Site:Website> = (PublishingContext<Site>, Item<Site>, String) throws -> String
public typealias HTMLPageMutation<Site:Website> = (PublishingContext<Site>, Page, String) throws -> String
public typealias HTMLAllMutation<Site:Website> = (PublishingContext<Site>, Location, String) throws -> String
23 changes: 23 additions & 0 deletions Sources/Publish/API/PublishingContext.swift
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ public struct PublishingContext<Site: Website> {
/// Any date when the website was last generated.
public private(set) var lastGenerationDate: Date?

internal var htmlMutations = HTMLMutations<Site>()

private let folders: Folder.Group
private var tagCache = TagCache()
private var stepName: String
Expand Down Expand Up @@ -273,6 +275,27 @@ public extension PublishingContext {
)
}
}

mutating func mutateIndexHTML(using mutation: @escaping HTMLIndexMutation<Site>) {
self.htmlMutations.indexMutations.append(mutation)
}

mutating func mutateSectionHTML(using mutation: @escaping HTMLSectionMutation<Site>) {
self.htmlMutations.sectionMutations.append(mutation)
}

mutating func mutateItemHTML(using mutation: @escaping HTMLItemMutation<Site>) {
self.htmlMutations.itemMutations.append(mutation)
}

mutating func mutatePageHTML(using mutation: @escaping HTMLPageMutation<Site>) {
self.htmlMutations.pageMutations.append(mutation)
}

mutating func mutateAllHTML(using mutation: @escaping HTMLAllMutation<Site>) {
self.htmlMutations.allMutations.append(mutation)
}

}

internal extension PublishingContext {
Expand Down
33 changes: 33 additions & 0 deletions Sources/Publish/API/PublishingStep.swift
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,39 @@ public extension PublishingStep {
}
}

static func mutateIndexHTML(using mutation: @escaping HTMLIndexMutation<Site>) -> Self {
step(named: "Mutate Index HTML") { context in
context.mutateIndexHTML(using: mutation)
}
}

static func mutateSectionHTML(using mutation: @escaping HTMLSectionMutation<Site>) -> Self {
step(named: "Mutate Section HTML") { context in
context.mutateSectionHTML(using: mutation)
}
}

static func mutateItemHTML(using mutation: @escaping HTMLItemMutation<Site>) -> Self {
step(named: "Mutate Item HTML") { context in
context.mutateItemHTML(using: mutation)
}
}

static func mutatePageHTML(using mutation: @escaping HTMLPageMutation<Site>) -> Self {
step(named: "Mutate Page HTML") { context in
context.mutatePageHTML(using: mutation)
}
}

static func mutateAllHTML(using mutation: @escaping HTMLAllMutation<Site>) -> Self {
step(named: "Mutate All HTML") { context in
context.mutateAllHTML(using: mutation)
}
}




/// Sort all items, optionally within a specific section, using a key path.
/// - parameter section: Any specific section to sort all items within.
/// - parameter keyPath: The key path to use when sorting.
Expand Down
27 changes: 24 additions & 3 deletions Sources/Publish/Internal/HTMLGenerator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,9 @@ private extension HTMLGenerator {
func generateIndexHTML() throws {
let html = try theme.makeIndexHTML(context.index, context)
let indexFile = try context.createOutputFile(at: "index.html")
try indexFile.write(html.render(indentedBy: indentation))
var renderedHtml = html.render(indentedBy: indentation)
renderedHtml = try context.htmlMutations.mutateHtml(context: context, renderedHtml: renderedHtml)
try indexFile.write(renderedHtml)
}

func generateSectionHTML() throws {
Expand Down Expand Up @@ -122,16 +124,34 @@ private extension HTMLGenerator {
}
}

func renderHTML<T: Location>(
for location: T,
indentedBy indentation: Indentation.Kind?,
using generator: (T, PublishingContext<Site>) throws -> HTML
) throws -> String {
let html = try generator(location, context)
return html.render(indentedBy: indentation)
}

func outputHTML<T: Location>(
for location: T,
indentedBy indentation: Indentation.Kind?,
using generator: (T, PublishingContext<Site>) throws -> HTML,
fileMode: HTMLFileMode
) throws {
let html = try generator(location, context)
var renderedHtml = try renderHTML(for: location, indentedBy: indentation, using: generator)
if let section = location as? Section<Site> {
renderedHtml = try context.htmlMutations.mutateHtml(context: context, section: section, renderedHtml: renderedHtml)
} else if let item = location as? Item<Site> {
renderedHtml = try context.htmlMutations.mutateHtml(context: context, item: item, renderedHtml: renderedHtml)
} else if let page = location as? Page {
renderedHtml = try context.htmlMutations.mutateHtml(context: context, page: page, renderedHtml: renderedHtml)
} else {
renderedHtml = try context.htmlMutations.mutateHtml(context: context, location: location, renderedHtml: renderedHtml)
}
let path = filePath(for: location, fileMode: fileMode)
let file = try context.createOutputFile(at: path)
try file.write(html.render(indentedBy: indentation))
try file.write(renderedHtml)
}

func filePath(for location: Location, fileMode: HTMLFileMode) -> Path {
Expand All @@ -143,3 +163,4 @@ private extension HTMLGenerator {
}
}
}

58 changes: 58 additions & 0 deletions Sources/Publish/Internal/HTMLMutations.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import Plot

internal struct HTMLMutations<Site: Website> {
var indexMutations: [HTMLIndexMutation<Site>] = []
var sectionMutations: [HTMLSectionMutation<Site>] = []
var itemMutations: [HTMLItemMutation<Site>] = []
var pageMutations: [HTMLPageMutation<Site>] = []
var allMutations: [HTMLAllMutation<Site>] = []

public init() {
}

func mutateHtml(context: PublishingContext<Site>, renderedHtml: String) throws -> String {
var mutatedHtml = renderedHtml
for mutation in indexMutations {
mutatedHtml = try mutation(context, mutatedHtml)
}
mutatedHtml = try mutateHtml(context: context, location: context.index, renderedHtml: mutatedHtml)
return mutatedHtml
}

func mutateHtml(context: PublishingContext<Site>, section: Section<Site>, renderedHtml: String) throws -> String {
var mutatedHtml = renderedHtml
for mutation in sectionMutations {
mutatedHtml = try mutation(context, section, mutatedHtml)
}
mutatedHtml = try mutateHtml(context: context, location: section, renderedHtml: mutatedHtml)
return mutatedHtml
}

func mutateHtml(context: PublishingContext<Site>, item: Item<Site>, renderedHtml: String) throws -> String {
var mutatedHtml = renderedHtml
for mutation in itemMutations {
mutatedHtml = try mutation(context, item, mutatedHtml)
}
mutatedHtml = try mutateHtml(context: context, location: item, renderedHtml: mutatedHtml)
return mutatedHtml
}

func mutateHtml(context: PublishingContext<Site>, page: Page, renderedHtml: String) throws -> String {
var mutatedHtml = renderedHtml
for mutation in pageMutations {
mutatedHtml = try mutation(context, page, mutatedHtml)
}
mutatedHtml = try mutateHtml(context: context, location: page, renderedHtml: mutatedHtml)
return mutatedHtml
}

func mutateHtml(context: PublishingContext<Site>, location: Location, renderedHtml: String) throws -> String {
var mutatedHtml = renderedHtml
for mutation in allMutations {
mutatedHtml = try mutation(context, location, mutatedHtml)
}
return mutatedHtml
}

}