Make the site generator recursively render public files

- Now renders markdown

- Separates templates from content now
This commit is contained in:
Sami Samhuri 2019-12-01 15:43:05 -08:00
parent b11e0686ad
commit 2ce8d2f376
8 changed files with 80 additions and 24 deletions

View file

@ -1,6 +1,15 @@
{
"object": {
"pins": [
{
"package": "Ink",
"repositoryURL": "https://github.com/johnsundell/ink.git",
"state": {
"branch": null,
"revision": "af743ad6882bfe1adb0acf7453d36d2075ebb1d5",
"version": "0.1.3"
}
},
{
"package": "PathKit",
"repositoryURL": "https://github.com/kylef/PathKit.git",

View file

@ -6,16 +6,14 @@ import PackageDescription
let package = Package(
name: "SiteGenerator",
dependencies: [
.package(url: "https://github.com/stencilproject/Stencil.git", from: "0.13.0")
.package(url: "https://github.com/stencilproject/Stencil.git", from: "0.13.0"),
.package(url: "https://github.com/johnsundell/ink.git", from: "0.1.0"),
],
targets: [
// Targets are the basic building blocks of a package. A target can define a module or a test suite.
// Targets can depend on other targets in this package, and on products in packages which this package depends on.
.target(
name: "SiteGenerator",
dependencies: ["Stencil"]),
.testTarget(
name: "SiteGeneratorTests",
dependencies: ["SiteGenerator"]),
.target( name: "SiteGenerator", dependencies: [
"Ink",
"Stencil",
]),
.testTarget(name: "SiteGeneratorTests", dependencies: ["SiteGenerator"]),
]
)

View file

@ -6,6 +6,7 @@
//
import Foundation
import Ink
import PathKit
import Stencil
@ -16,19 +17,72 @@ public final class Generator {
public let sourceURL: URL
private let renderer: Environment
private let mdParser: MarkdownParser
public init(sourceURL: URL) throws {
let publicURL = sourceURL.appendingPathComponent("public")
self.renderer = Environment(loader: FileSystemLoader(paths: [Path(publicURL.path)]))
let siteURL = sourceURL.appendingPathComponent("site.json")
self.site = try Site.decode(from: siteURL)
self.sourceURL = sourceURL
let templatesURL = sourceURL.appendingPathComponent("templates")
self.renderer = Environment(loader: FileSystemLoader(paths: [Path(templatesURL.path)]))
self.mdParser = MarkdownParser(modifiers: [])
}
public func generate(targetURL: URL) throws {
try fileManager.createDirectory(at: targetURL, withIntermediateDirectories: true, attributes: nil)
let indexHTML = try renderer.renderTemplate(name: "index.html", context: ["site": site])
let indexURL = targetURL.appendingPathComponent("index.html")
try indexHTML.write(to: indexURL, atomically: true, encoding: .utf8)
// Iterate through all files in public recursively and render or copy each one
let publicURL = sourceURL.appendingPathComponent("public")
try renderPath(publicURL.path, to: targetURL)
}
func renderPath(_ path: String, to targetURL: URL) throws {
for filename in try fileManager.contentsOfDirectory(atPath: path) {
// Recurse into subdirectories, updating the target directory as well.
let fileURL = URL(fileURLWithPath: path).appendingPathComponent(filename)
var isDir: ObjCBool = false
fileManager.fileExists(atPath: fileURL.path, isDirectory: &isDir)
guard !isDir.boolValue else {
try renderPath(fileURL.path, to: targetURL.appendingPathComponent(filename))
return
}
// Make sure this path exists so we can write to it.
try fileManager.createDirectory(at: targetURL, withIntermediateDirectories: true, attributes: nil)
// Handle the file, transforming it if necessary.
let ext = filename.split(separator: ".").last!
switch ext {
case "md":
let htmlURL = targetURL.appendingPathComponent(filename.replacingOccurrences(of: ".md", with: ".html"))
try renderMarkdown(from: fileURL, to: htmlURL, template: "site", context: [:])
default:
// Who knows. Copy the file unchanged.
let src = URL(fileURLWithPath: path).appendingPathComponent(filename)
let dest = targetURL.appendingPathComponent(filename)
try fileManager.copyItem(at: src, to: dest)
}
}
}
func renderMarkdown(
from sourceURL: URL,
to targetURL: URL,
template: String,
context: [String: Any]
) throws {
let bodyMarkdown = try String(contentsOf: sourceURL, encoding: .utf8)
let bodyResult = mdParser.parse(bodyMarkdown)
let bodyHTML = bodyResult.html.trimmingCharacters(in: .whitespacesAndNewlines)
var context = context
context["site"] = site
context["body"] = bodyHTML
context.merge(bodyResult.metadata, uniquingKeysWith: { _, new in new })
let siteHTML = try renderer.renderTemplate(name: "\(template).html", context: context)
try siteHTML.write(to: targetURL, atomically: true, encoding: .utf8)
}
}

View file

@ -8,6 +8,7 @@ cp .build/x86_64-apple-macosx/debug/SiteGenerator ../bin/sitegen
popd >/dev/null
for site in Tests/test-*; do
rm -rf "$site/actual"
bin/compile "$site/in" "$site/actual" # >/dev/null
diff -ru "$site/expected" "$site/actual"
rm -r "$site/actual"

View file

@ -5,8 +5,6 @@
</head>
<body>
<h1><a href="http://example.net">Valar Morghulis</a></h1>
<p>hello world</p>
<p>hello world</p>
</body>
</html>

View file

@ -1,4 +0,0 @@
{% extends "layout.html" %}
{% block content %}
<p>hello world</p>
{% endblock %}

View file

@ -0,0 +1 @@
hello world

View file

@ -5,7 +5,6 @@
</head>
<body>
<h1><a href="{{ site.url }}">{{ site.title }}</a></h1>
{% block content %}
{% endblock %}
{{ body }}
</body>
</html>