mirror of
https://github.com/samsonjs/samhuri.net.git
synced 2026-04-27 14:57:40 +00:00
Make the site generator recursively render public files
- Now renders markdown - Separates templates from content now
This commit is contained in:
parent
b11e0686ad
commit
2ce8d2f376
8 changed files with 80 additions and 24 deletions
|
|
@ -1,6 +1,15 @@
|
||||||
{
|
{
|
||||||
"object": {
|
"object": {
|
||||||
"pins": [
|
"pins": [
|
||||||
|
{
|
||||||
|
"package": "Ink",
|
||||||
|
"repositoryURL": "https://github.com/johnsundell/ink.git",
|
||||||
|
"state": {
|
||||||
|
"branch": null,
|
||||||
|
"revision": "af743ad6882bfe1adb0acf7453d36d2075ebb1d5",
|
||||||
|
"version": "0.1.3"
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"package": "PathKit",
|
"package": "PathKit",
|
||||||
"repositoryURL": "https://github.com/kylef/PathKit.git",
|
"repositoryURL": "https://github.com/kylef/PathKit.git",
|
||||||
|
|
|
||||||
|
|
@ -6,16 +6,14 @@ import PackageDescription
|
||||||
let package = Package(
|
let package = Package(
|
||||||
name: "SiteGenerator",
|
name: "SiteGenerator",
|
||||||
dependencies: [
|
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: [
|
||||||
// Targets are the basic building blocks of a package. A target can define a module or a test suite.
|
.target( name: "SiteGenerator", dependencies: [
|
||||||
// Targets can depend on other targets in this package, and on products in packages which this package depends on.
|
"Ink",
|
||||||
.target(
|
"Stencil",
|
||||||
name: "SiteGenerator",
|
]),
|
||||||
dependencies: ["Stencil"]),
|
.testTarget(name: "SiteGeneratorTests", dependencies: ["SiteGenerator"]),
|
||||||
.testTarget(
|
|
||||||
name: "SiteGeneratorTests",
|
|
||||||
dependencies: ["SiteGenerator"]),
|
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@
|
||||||
//
|
//
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
import Ink
|
||||||
import PathKit
|
import PathKit
|
||||||
import Stencil
|
import Stencil
|
||||||
|
|
||||||
|
|
@ -16,19 +17,72 @@ public final class Generator {
|
||||||
public let sourceURL: URL
|
public let sourceURL: URL
|
||||||
|
|
||||||
private let renderer: Environment
|
private let renderer: Environment
|
||||||
|
private let mdParser: MarkdownParser
|
||||||
|
|
||||||
public init(sourceURL: URL) throws {
|
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")
|
let siteURL = sourceURL.appendingPathComponent("site.json")
|
||||||
self.site = try Site.decode(from: siteURL)
|
self.site = try Site.decode(from: siteURL)
|
||||||
self.sourceURL = sourceURL
|
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 {
|
public func generate(targetURL: URL) throws {
|
||||||
try fileManager.createDirectory(at: targetURL, withIntermediateDirectories: true, attributes: nil)
|
// Iterate through all files in public recursively and render or copy each one
|
||||||
let indexHTML = try renderer.renderTemplate(name: "index.html", context: ["site": site])
|
let publicURL = sourceURL.appendingPathComponent("public")
|
||||||
let indexURL = targetURL.appendingPathComponent("index.html")
|
try renderPath(publicURL.path, to: targetURL)
|
||||||
try indexHTML.write(to: indexURL, atomically: true, encoding: .utf8)
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
1
bin/test
1
bin/test
|
|
@ -8,6 +8,7 @@ cp .build/x86_64-apple-macosx/debug/SiteGenerator ../bin/sitegen
|
||||||
popd >/dev/null
|
popd >/dev/null
|
||||||
|
|
||||||
for site in Tests/test-*; do
|
for site in Tests/test-*; do
|
||||||
|
rm -rf "$site/actual"
|
||||||
bin/compile "$site/in" "$site/actual" # >/dev/null
|
bin/compile "$site/in" "$site/actual" # >/dev/null
|
||||||
diff -ru "$site/expected" "$site/actual"
|
diff -ru "$site/expected" "$site/actual"
|
||||||
rm -r "$site/actual"
|
rm -r "$site/actual"
|
||||||
|
|
|
||||||
|
|
@ -5,8 +5,6 @@
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<h1><a href="http://example.net">Valar Morghulis</a></h1>
|
<h1><a href="http://example.net">Valar Morghulis</a></h1>
|
||||||
|
<p>hello world</p>
|
||||||
<p>hello world</p>
|
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
||||||
|
|
@ -1,4 +0,0 @@
|
||||||
{% extends "layout.html" %}
|
|
||||||
{% block content %}
|
|
||||||
<p>hello world</p>
|
|
||||||
{% endblock %}
|
|
||||||
1
tests/test-index/in/public/index.md
Normal file
1
tests/test-index/in/public/index.md
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
hello world
|
||||||
|
|
@ -5,7 +5,6 @@
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<h1><a href="{{ site.url }}">{{ site.title }}</a></h1>
|
<h1><a href="{{ site.url }}">{{ site.title }}</a></h1>
|
||||||
{% block content %}
|
{{ body }}
|
||||||
{% endblock %}
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
Loading…
Reference in a new issue