From 7bf25f232569aa62edf1c88e7014a9f3c1b37014 Mon Sep 17 00:00:00 2001
From: Alan Pearce
Date: Thu, 20 Jul 2017 18:08:12 +0200
Subject: feat: Create feed handler for root
---
config/default.toml | 5 +++++
package.json | 2 +-
src/app.js | 13 +++++++++++++
src/domain/posts.js | 2 ++
src/responders.js | 42 ++++++++++++++++++++++++++++++++++++++++--
src/templates/feed.xml | 24 ++++++++++++++++++++++++
test/app.test.js | 13 +++++++++++++
yarn.lock | 33 +++++----------------------------
8 files changed, 103 insertions(+), 31 deletions(-)
create mode 100644 src/templates/feed.xml
diff --git a/config/default.toml b/config/default.toml
index b52674c..5dceae1 100644
--- a/config/default.toml
+++ b/config/default.toml
@@ -3,6 +3,7 @@ port = 3000
[site]
description = "Nobody in particular"
+baseURL = "http://localhost:3000/"
[[site.nav]]
text = "Home"
@@ -20,6 +21,10 @@ text = "johndoe@johndoe.org"
url = "https://twitter.com/johndoe"
text = "Twitter"
+[feed]
+originalDomainName = "johndoe.com"
+domainStartDate = "2016-01-01"
+
[posts]
folder = "./posts"
diff --git a/package.json b/package.json
index 20d7918..4d1ebe6 100644
--- a/package.json
+++ b/package.json
@@ -50,7 +50,7 @@
"gray-matter": "^2.1.1",
"highland": "^2.11.0",
"highlight.js": "^9.12.0",
- "hyperfast": "^2.1.0",
+ "hyperfast": "^2.2.0",
"indent-string": "^3.1.0",
"koa": "^2.2.0",
"koa-helmet": "^3.2.0",
diff --git a/src/app.js b/src/app.js
index 912dda2..a323b9c 100644
--- a/src/app.js
+++ b/src/app.js
@@ -13,6 +13,13 @@ const config = require("./modules/config.js");
const Router = require("koa-router");
const router = new Router();
+const makeTagURI = (authority, startDate) => specific =>
+ `tag:${authority},${startDate}:${specific}`;
+
+app.context.makeTagURI = makeTagURI(
+ config.feed.originalDomainName,
+ config.feed.domainStartDate
+);
app.context.getURL = router.url.bind(router);
module.exports = async function() {
@@ -34,6 +41,12 @@ module.exports = async function() {
actions.highlightTheme(config)
);
+ router.get(
+ "feed",
+ "/index.xml",
+ actions.posts(config, responders.feed, Posts.posts)
+ );
+
router.get(
"post",
"/post/:filename",
diff --git a/src/domain/posts.js b/src/domain/posts.js
index 98488ba..ab35518 100644
--- a/src/domain/posts.js
+++ b/src/domain/posts.js
@@ -86,7 +86,9 @@ function taxonomise(taxonomies, posts) {
module.exports = async function(config, getURL) {
const posts = await getFolder(config.folder, getURL);
const taxonomies = taxonomise(config.taxonomies, posts);
+ const lastPostDate = Math.max(Array.from(posts.values(), p => p.date));
return {
+ lastPostDate,
posts,
taxonomies,
get
diff --git a/src/responders.js b/src/responders.js
index 8f084a3..f4ea0a6 100644
--- a/src/responders.js
+++ b/src/responders.js
@@ -1,6 +1,7 @@
"use strict";
const fs = require("fs");
+const URL = require("url").URL;
const Case = require("case");
const hyperfast = require("hyperfast");
const indent = require("indent-string");
@@ -25,7 +26,7 @@ const findPostContent = /^(\s+)
post => {
};
};
+const renderPostAtom = (ctx, config) => post => {
+ return {
+ id: ctx.makeTagURI(`post:${post.basename}`),
+ title: post.data.get("title"),
+ updated: post.data.get("date"),
+ summary: post.data.get("summary"),
+ "link[rel=alternate]": {
+ href: new URL(ctx.getURL("post", post.basename), config.site.baseURL)
+ },
+ "content > div": {
+ _html: post.body
+ },
+ "author > name": config.author.name
+ };
+};
+
function layout(config, pageTitle, pageElement) {
return hyperfast(templates.layout, {
title: title(config.author.name, pageTitle),
@@ -125,5 +143,25 @@ module.exports = {
post.data.get("title"),
hyperfast(templates.post, renderPost(ctx)(post))
);
+ },
+
+ feed(ctx, config, { posts, lastPostDate }) {
+ ctx.type = "atom";
+
+ ctx.body = hyperfast(
+ templates.feed,
+ {
+ "feed > title": config.author.name,
+ "feed > link": {
+ href: config.site.baseURL
+ },
+ "feed > id": {
+ _text: ctx.makeTagURI("feed")
+ },
+ "feed > updated": lastPostDate,
+ "feed > entry": posts.map(renderPostAtom(ctx, config))
+ },
+ { xmlMode: true }
+ ).outerHTML;
}
};
diff --git a/src/templates/feed.xml b/src/templates/feed.xml
new file mode 100644
index 0000000..03d68d7
--- /dev/null
+++ b/src/templates/feed.xml
@@ -0,0 +1,24 @@
+
+
+ Example Feed
+
+ urn:uuid:60a76c80-d399-11d9-b91C-0003939e0af6
+ 2003-12-13T18:30:02Z
+
+
+ Atom-Powered Robots Run Amok
+
+ urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a
+ 2003-12-13T18:30:02Z
+ Some text.
+
+
+
This is the entry content.
+
+
+
+ John Doe
+
+
+
+
diff --git a/test/app.test.js b/test/app.test.js
index f0ab3da..33c8905 100644
--- a/test/app.test.js
+++ b/test/app.test.js
@@ -169,5 +169,18 @@ test("highlight css", async function(t) {
t.regex(res.text, /^\.hljs/m);
});
+test("feed", async function(t) {
+ const res = await request(app.listen()).get("/index.xml");
+
+ t.is(res.statusCode, 200);
+ t.is(res.type, "application/atom+xml");
+ t.regex(res.text, /^<\?xml/);
+
+ const $ = parseResponse(res);
+
+ t.is($("feed > title").text(), "John Doe");
+ t.is($("feed > link").attr("href"), "http://localhost:3000/");
+});
+
test(notFound, "/post/non-existent", /Post not found/);
test(notFound, "/tag/non-existent", /tag non-existent not found/);
diff --git a/yarn.lock b/yarn.lock
index 9d2e7de..fc6330a 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -743,10 +743,6 @@ buf-compare@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/buf-compare/-/buf-compare-1.0.1.tgz#fef28da8b8113a0a0db4430b0b6467b69730b34a"
-buffer-shims@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/buffer-shims/-/buffer-shims-1.0.0.tgz#9978ce317388c649ad8793028c3477ef044a8b51"
-
builtin-modules@^1.0.0, builtin-modules@^1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f"
@@ -1471,20 +1467,13 @@ domutils@1.4:
dependencies:
domelementtype "1"
-domutils@1.5, domutils@1.5.1:
+domutils@1.5, domutils@1.5.1, domutils@^1.5.0, domutils@^1.5.1:
version "1.5.1"
resolved "https://registry.yarnpkg.com/domutils/-/domutils-1.5.1.tgz#dcd8488a26f563d61079e48c9f7b7e32373682cf"
dependencies:
dom-serializer "0"
domelementtype "1"
-domutils@^1.5.0, domutils@^1.5.1:
- version "1.6.2"
- resolved "https://registry.yarnpkg.com/domutils/-/domutils-1.6.2.tgz#1958cc0b4c9426e9ed367fb1c8e854891b0fa3ff"
- dependencies:
- dom-serializer "0"
- domelementtype "1"
-
dont-sniff-mimetype@1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/dont-sniff-mimetype/-/dont-sniff-mimetype-1.0.0.tgz#5932890dc9f4e2f19e5eb02a20026e5e5efc8f58"
@@ -2581,9 +2570,9 @@ husky@^0.13.4:
is-ci "^1.0.9"
normalize-path "^1.0.0"
-hyperfast@^2.1.0:
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/hyperfast/-/hyperfast-2.1.0.tgz#72c91f87126c54e6fe0ad2264ece278b3a6c0a56"
+hyperfast@^2.2.0:
+ version "2.2.0"
+ resolved "https://registry.yarnpkg.com/hyperfast/-/hyperfast-2.2.0.tgz#27d9f1e8a81f02332b6af5dd96281e20d91a7f58"
dependencies:
css-select "^1.1.0"
domutils "^1.5.0"
@@ -4320,7 +4309,7 @@ readable-stream@1.1:
isarray "0.0.1"
string_decoder "~0.10.x"
-readable-stream@^2.0.0, readable-stream@^2.0.5, readable-stream@^2.0.6, readable-stream@^2.1.4, readable-stream@^2.1.5, readable-stream@^2.2.2:
+readable-stream@^2.0.0, readable-stream@^2.0.2, readable-stream@^2.0.5, readable-stream@^2.0.6, readable-stream@^2.1.4, readable-stream@^2.1.5, readable-stream@^2.2.2:
version "2.2.11"
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.2.11.tgz#0796b31f8d7688007ff0b93a8088d34aa17c0f72"
dependencies:
@@ -4332,18 +4321,6 @@ readable-stream@^2.0.0, readable-stream@^2.0.5, readable-stream@^2.0.6, readable
string_decoder "~1.0.0"
util-deprecate "~1.0.1"
-readable-stream@^2.0.2:
- version "2.1.5"
- resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.1.5.tgz#66fa8b720e1438b364681f2ad1a63c618448c9d0"
- dependencies:
- buffer-shims "^1.0.0"
- core-util-is "~1.0.0"
- inherits "~2.0.1"
- isarray "~1.0.0"
- process-nextick-args "~1.0.6"
- string_decoder "~0.10.x"
- util-deprecate "~1.0.1"
-
readable-stream@~2.0.5:
version "2.0.6"
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.0.6.tgz#8f90341e68a53ccc928788dacfcd11b36eb9b78e"
--
cgit 1.4.1