all repos — archive/homestead @ fb7e421b9efea0a96adcf30d30cc2d318980d928

My future indieweb platform

Switch templating to hyperfast

This also means that highland is not (currently) required
Alan Pearce alan@alanpearce.eu
Sat, 01 Jul 2017 11:49:18 +0200
commit

fb7e421b9efea0a96adcf30d30cc2d318980d928

parent

248c74916e22f397ff95944ac2596b9e40b302e5

M package.jsonpackage.json
@@ -46,14 +46,13 @@ },   "dependencies": {
     "configly": "^4.1.0",
     "gray-matter": "^2.1.1",
-    "highland": "^2.11.0",
+    "hyperfast": "^2.1.0",
     "indent-string": "^3.1.0",
     "koa": "^2.2.0",
     "koa-helmet": "^3.2.0",
     "koa-router": "^7.2.1",
     "koa-send": "^4.1.0",
     "markdown-it": "^8.3.1",
-    "rheo": "^2.2.0",
     "toml": "^2.3.2"
   }
 }
M src/actions.jssrc/actions.js
@@ -1,46 +1,41 @@-'use strict'
+"use strict";
 
-const send = require('koa-send')
-const h = require('highland')
-const responders = require('./responders')
+const send = require("koa-send");
+const responders = require("./responders");
 
-function toArrayStream (iterator) {
-  return h(iterator.entries())
+function home(config, posts) {
+  const postsArray = Array.from(posts.values());
+  return async function(ctx, next) {
+    responders.home(ctx, config, postsArray);
+  };
 }
 
-function home (config, posts) {
-  const postsStream = toArrayStream(posts)
-  return async function (ctx, next) {
-    responders.home(ctx, config, postsStream)
-  }
-}
+function post(config, posts) {
+  return async function(ctx, next) {
+    ctx.assert(posts.has(ctx.params.filename), 404, "Post not found");
+    const post = posts.get(ctx.params.filename);
 
-function post (config, posts) {
-  return async function (ctx, next) {
-    ctx.assert(posts.has(ctx.params.filename), 404, 'Post not found')
-    const post = posts.get(ctx.params.filename)
-
-    responders.post(ctx, config, post)
-  }
+    responders.post(ctx, config, post);
+  };
 }
 
-function taxonGenerator (config, term, items) {
-  return async function (ctx, next) {
-    const value = ctx.params.value
-    ctx.assert(items.has(ctx.params.value), 404, `${term} ${value} not found`)
+function taxonGenerator(config, term, items) {
+  return async function(ctx, next) {
+    const value = ctx.params.value;
+    ctx.assert(items.has(ctx.params.value), 404, `${term} ${value} not found`);
 
-    const taxonItems = toArrayStream(items.get(value))
+    const taxonItems = items.get(value);
 
-    responders.taxon(ctx, config, taxonItems)
-  }
+    responders.taxon(ctx, config, taxonItems);
+  };
 }
 
-const prefix = /^\/static\//
-async function serveFiles (ctx) {
+const prefix = /^\/static\//;
+async function serveFiles(ctx) {
   if (prefix.test(ctx.path)) {
-    await send(ctx, ctx.path.replace(prefix, ''), {
-      root: './static'
-    })
+    await send(ctx, ctx.path.replace(prefix, ""), {
+      root: "./static"
+    });
   }
 }
 
@@ -49,4 +44,4 @@ home,   post,
   taxonGenerator,
   serveFiles
-}
+};
M src/responders.jssrc/responders.js
@@ -1,13 +1,8 @@ "use strict";
 
-const h = require("highland");
 const fs = require("fs");
-const rheo = require("rheo");
+const hyperfast = require("hyperfast");
 const indent = require("indent-string");
-const PassThrough = require("stream").PassThrough;
-
-const toLines = string =>
-  string.split("\n").map((s, i, arr) => (i === arr.length - 1 ? s : s + "\n"));
 
 const getTemplate = name =>
   fs.readFileSync(`${__dirname}/templates/${name}.html`, "utf8");
@@ -15,21 +10,15 @@ const findMain = /^(\s+)<main/m;
 const baseIndentLevel = findMain.exec(getTemplate("layout"))[1].length;
 const postIndentLevel =
-  baseIndentLevel + findMain.exec(getTemplate("post"))[1].length;
+  baseIndentLevel +
+  /^(\s+)<div class="post-content/m.exec(getTemplate("post"))[1].length;
 
 function indentForTemplate(text, indentLevel) {
   return indent(text, indentLevel).slice(indentLevel).replace(/\n+$/, "");
 }
 
 function templateReader(template, indentLevel) {
-  const content = toLines(
-    indentForTemplate(getTemplate(template), indentLevel)
-  );
-  return () => h(content);
-}
-
-function prependDoctype(stream) {
-  return h(["<!DOCTYPE html>"]).concat(stream).pipe(new PassThrough());
+  return indentForTemplate(getTemplate(template), indentLevel);
 }
 
 const templates = {
@@ -39,29 +28,27 @@ post: templateReader("post", baseIndentLevel),   taxon: templateReader("taxon", baseIndentLevel)
 };
 
-function setTitle(siteTitle, pageTitle) {
-  return rheo.template(function(s) {
-    return s
-      .inner(
-        "title",
-        rheo(pageTitle ? `${pageTitle} · ${siteTitle}` : siteTitle)
-      )
-      .inner("body header h1", rheo(siteTitle));
-  });
+function title(siteTitle, pageTitle) {
+  return pageTitle ? `${pageTitle} · ${siteTitle}` : siteTitle;
 }
 
-function renderPostListItem(ctx) {
-  return function(template, [, post]) {
-    return template
-      .attribute("a", "href", () => ctx.getURL("post", post.basename))
-      .inner("a", () => rheo(post.data.get("title")));
-  };
-}
+const renderPostListItem = ctx => post => ({
+  a: {
+    href: ctx.getURL(post, post.basename),
+    _text: post.data.get("title")
+  }
+});
 
-function showPage(name) {
-  return function(els) {
-    return rheo(templates[name]());
-  };
+function layout(config, pageTitle, pageElement) {
+  return hyperfast(templates.layout, {
+    title: title(config.site.author.name, pageTitle),
+    "body > header .p-name": config.site.author.name,
+    "body > header .u-photo": {
+      alt: config.site.author.name,
+      src: config.site.author.photo
+    },
+    "body > main": pageElement
+  }).outerHTML.trim();
 }
 
 module.exports = {
@@ -69,51 +56,42 @@ baseIndentLevel,   postIndentLevel,
   indentForTemplate,
 
-  home(ctx, config, postsStream) {
+  home(ctx, config, posts) {
     ctx.type = "html";
 
-    ctx.body = prependDoctype(
-      templates
-        .layout()
-        .pipe(rheo())
-        .attribute(".u-photo", "alt", config.site.author.name)
-        .attribute(".u-photo", "src", config.site.author.photo)
-        .outer("main", showPage("home"))
-        .inner(".posts", function(postsTemplate) {
-          return postsStream.pipe(postsTemplate.map(renderPostListItem(ctx)));
-        })
-        .pipe(setTitle(config.site.author.name))
-        .render()
+    ctx.body = layout(
+      config,
+      null,
+      hyperfast(templates.home, {
+        ".post": posts.map(renderPostListItem(ctx))
+      })
     );
   },
 
   post(ctx, config, post) {
     ctx.type = "html";
-    ctx.body = prependDoctype(
-      templates
-        .layout()
-        .pipe(rheo())
-        .outer("main", showPage("post"))
-        .inner("article h1", rheo(post.data.get("title")))
-        .outer("article main", rheo(post.body))
-        .pipe(setTitle(config.site.author.name, post.data.get("title")))
-        .render()
+
+    ctx.body = layout(
+      config,
+      post.data.get("title"),
+      hyperfast(templates.post, {
+        "article h1": post.data.get("title"),
+        "article .post-content": {
+          _html: post.body
+        }
+      })
     );
   },
 
   taxon(ctx, config, taxonItems) {
     ctx.type = "html";
-    ctx.body = prependDoctype(
-      templates
-        .layout()
-        .pipe(rheo())
-        .outer("main", showPage("taxon"))
-        .inner("h1", rheo(config.site.author.name))
-        .inner(".posts", function(postsTemplate) {
-          return taxonItems.pipe(postsTemplate.map(renderPostListItem(ctx)));
-        })
-        .pipe(setTitle(config.site.author.name))
-        .render()
+
+    ctx.body = layout(
+      config,
+      null,
+      hyperfast(templates.taxon, {
+        ".post": taxonItems.map(renderPostListItem(ctx))
+      })
     );
   }
 };
M src/templates/home.htmlsrc/templates/home.html
@@ -1,7 +1,5 @@-<main class="home">
-  <ul class="posts">
-    <li class="post">
-      <a href="/">Test post please ignore</a>
-    </li>
-  </ul>
-</main>
+<ul class="posts">
+  <li class="post">
+    <a href="/">Test post please ignore</a>
+  </li>
+</ul>
M src/templates/post.htmlsrc/templates/post.html
@@ -1,11 +1,9 @@-<main class="post">
-  <article>
-    <h1>post title</h1>
-    <main>
-      Fringilla ut morbi tincidunt augue interdum velit euismod!
-      Interdum velit laoreet id donec ultrices tincidunt arcu, non
-      sodales neque sodales ut etiam sit amet nisl purus, in
-      mollis nunc sed.
-    </main>
-  </article>
-</main>
+<article>
+  <h1>post title</h1>
+  <div class="post-content">
+    Fringilla ut morbi tincidunt augue interdum velit euismod!
+    Interdum velit laoreet id donec ultrices tincidunt arcu, non
+    sodales neque sodales ut etiam sit amet nisl purus, in
+    mollis nunc sed.
+  </div>
+</article>
M test/app.test.jstest/app.test.js
@@ -32,6 +32,7 @@ .then($ => {       t.is($("head > title").text(), "John Doe");
       t.is($("h1").text(), "John Doe");
       t.is($("main").length, 1);
+      t.is($("main .posts").length, 1);
       return $;
     })
     .then(toMicroformatsOptions)
M yarn.lockyarn.lock
@@ -1153,7 +1153,7 @@ crypto-random-string@^1.0.0:   version "1.0.0"
   resolved "https://registry.yarnpkg.com/crypto-random-string/-/crypto-random-string-1.0.0.tgz#a230f64f568310e1498009940790ec99545bca7e"
 
-css-select@~1.2.0:
+css-select@^1.1.0, css-select@~1.2.0:
   version "1.2.0"
   resolved "https://registry.yarnpkg.com/css-select/-/css-select-1.2.0.tgz#2b3a110539c5355f1cd8d314623e870b121ec858"
   dependencies:
@@ -1165,12 +1165,6 @@ css-what@2.1:
   version "2.1.0"
   resolved "https://registry.yarnpkg.com/css-what/-/css-what-2.1.0.tgz#9467d032c38cfaefb9f2d79501253062f87fa1bd"
-
-cssauron@^1.2.0:
-  version "1.4.0"
-  resolved "https://registry.yarnpkg.com/cssauron/-/cssauron-1.4.0.tgz#a6602dff7e04a8306dc0db9a551e92e8b5662ad8"
-  dependencies:
-    through X.X.X
 
 currently-unhandled@^0.4.1:
   version "0.4.1"
@@ -1399,7 +1393,7 @@ dependencies:     dom-serializer "0"
     domelementtype "1"
 
-domutils@^1.5.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:
@@ -1415,10 +1409,6 @@ version "4.1.1"   resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-4.1.1.tgz#a8493f0b7b5eeec82525b5c7587fa7de7ca859c1"
   dependencies:
     is-obj "^1.0.0"
-
-double-ended-queue@^0.9.7:
-  version "0.9.7"
-  resolved "https://registry.yarnpkg.com/double-ended-queue/-/double-ended-queue-0.9.7.tgz#8ae0a7265df66cdc3f07dce558e9716adb586ab8"
 
 duplexer2@^0.1.4:
   version "0.1.4"
@@ -1466,6 +1456,10 @@ version "1.0.0"   resolved "https://registry.yarnpkg.com/enhance-visitors/-/enhance-visitors-1.0.0.tgz#aa945d05da465672a1ebd38fee2ed3da8518e95a"
   dependencies:
     lodash "^4.13.1"
+
+ent@^2.2.0:
+  version "2.2.0"
+  resolved "https://registry.yarnpkg.com/ent/-/ent-2.2.0.tgz#e964219325a21d05f44466a2f686ed6ce5f5dd1d"
 
 entities@^1.1.1, entities@~1.1.1:
   version "1.1.1"
@@ -2359,12 +2353,6 @@ hide-powered-by@1.0.0:   version "1.0.0"
   resolved "https://registry.yarnpkg.com/hide-powered-by/-/hide-powered-by-1.0.0.tgz#4a85ad65881f62857fc70af7174a1184dccce32b"
 
-highland@^2.11.0:
-  version "2.11.0"
-  resolved "https://registry.yarnpkg.com/highland/-/highland-2.11.0.tgz#4d156709c5f10bc31cab6a97c7feb6c373e2466d"
-  dependencies:
-    util-deprecate "^1.0.2"
-
 hoek@2.x.x:
   version "2.16.3"
   resolved "https://registry.yarnpkg.com/hoek/-/hoek-2.16.3.tgz#20bb7403d3cea398e91dc4710a8ff1b8274a25ed"
@@ -2390,7 +2378,7 @@ resolved "https://registry.yarnpkg.com/hsts/-/hsts-2.0.0.tgz#a52234c6070decf214b2b6b70bb144d07e4776c7"   dependencies:
     core-util-is "1.0.2"
 
-htmlparser2@^3.8.3, htmlparser2@^3.9.1:
+htmlparser2@^3.8.2, htmlparser2@^3.9.1:
   version "3.9.2"
   resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-3.9.2.tgz#1bdf87acca0f3f9e53fa4fcceb0f4b4cbb00b338"
   dependencies:
@@ -2460,6 +2448,15 @@ chalk "^1.1.3"     find-parent-dir "^0.3.0"
     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"
+  dependencies:
+    css-select "^1.1.0"
+    domutils "^1.5.0"
+    ent "^2.2.0"
+    htmlparser2 "^3.8.2"
 
 iconv-lite@^0.4.17:
   version "0.4.18"
@@ -4445,15 +4442,6 @@ dependencies:     onetime "^2.0.0"
     signal-exit "^3.0.2"
 
-rheo@^2.2.0:
-  version "2.2.0"
-  resolved "https://registry.yarnpkg.com/rheo/-/rheo-2.2.0.tgz#614187095b12847f49f284e2f804ad59623ca243"
-  dependencies:
-    cssauron "^1.2.0"
-    double-ended-queue "^0.9.7"
-    htmlparser2 "^3.8.3"
-    void-elements "^2.0.1"
-
 rimraf@2, rimraf@^2.2.8, rimraf@^2.5.1, rimraf@^2.6.1:
   version "2.6.1"
   resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.1.tgz#c2338ec643df7a1b7fe5c54fa86f57428a55f33d"
@@ -4854,7 +4842,7 @@ dependencies:     readable-stream "^2.1.5"
     xtend "~4.0.1"
 
-through@X.X.X, through@^2.3.6:
+through@^2.3.6:
   version "2.3.8"
   resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5"
 
@@ -5005,7 +4993,7 @@ resolved "https://registry.yarnpkg.com/user-home/-/user-home-2.0.0.tgz#9c70bfd8169bc1dcbf48604e0f04b8b49cde9e9f"   dependencies:
     os-homedir "^1.0.0"
 
-util-deprecate@^1.0.2, util-deprecate@~1.0.1:
+util-deprecate@~1.0.1:
   version "1.0.2"
   resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
 
@@ -5033,10 +5021,6 @@ version "1.3.6"   resolved "https://registry.yarnpkg.com/verror/-/verror-1.3.6.tgz#cff5df12946d297d2baaefaa2689e25be01c005c"
   dependencies:
     extsprintf "1.0.2"
-
-void-elements@^2.0.1:
-  version "2.0.1"
-  resolved "https://registry.yarnpkg.com/void-elements/-/void-elements-2.0.1.tgz#c066afb582bb1cb4128d60ea92392e94d5e9dbec"
 
 which-module@^1.0.0:
   version "1.0.0"