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