]> git.r.bdr.sh - rbdr/blog/blobdiff - lib/blog.js
Add title to html/rss generators
[rbdr/blog] / lib / blog.js
index 9024a00b95ce825ed5e0244bc322a9fe1762ec36..50ebbf20e31804a254f96c24c348d73b38621432 100644 (file)
@@ -1,28 +1,28 @@
 'use strict';
 
-const { exec } = require('child_process');
 const { access, mkdir, readdir, readFile, rmdir, writeFile } = require('fs/promises');
-const { template } = require('dot');
 const { ncp } = require('ncp');
 const { join } = require('path');
 const Marked = require('marked');
 const { debuglog, promisify } = require('util');
 
+const StaticGenerator = require('./generators/static');
+const HTMLGenerator = require('./generators/html');
+const RSSGenerator = require('./generators/rss');
+const TXTGenerator = require('./generators/txt');
+
 const internals = {
 
   // Promisified functions
   ncp: promisify(ncp),
 
-  exec: promisify(exec),
   debuglog: debuglog('blog'),
 
   // constants
 
-  kAssetsDirectoryName: 'assets',
-  kIndexName: 'index.html',
   kFileNotFoundError: 'ENOENT',
   kMarkdownRe: /\.md$/i,
-  kRemoveCommand: 'rm -rf',
+  kMetadataFilename: 'metadata.json',
 
   // Strings
 
@@ -36,7 +36,7 @@ const internals = {
  * updating posts, and handling the publishing.
  *
  * @class Blog
- * @param {Potluck.tConfiguration} config the initialization options to
+ * @param {Blog.tConfiguration} config the initialization options to
  * extend the instance
  */
 module.exports = class Blog {
@@ -59,6 +59,7 @@ module.exports = class Blog {
    */
   async add(postLocation) {
 
+    await this._ensurePostsDirectoryExists();
     await this._shift();
     await this.update(postLocation);
   }
@@ -75,7 +76,11 @@ module.exports = class Blog {
    */
   async update(postLocation) {
 
+    const metadata = await this._getMetadata();
+    await this._ensurePostsDirectoryExists();
     await this._copyPost(postLocation);
+    await this._writeMetadata(metadata);
+
     await this._generate();
   }
 
@@ -97,33 +102,43 @@ module.exports = class Blog {
 
   async _generate() {
 
-    const assetsTarget = join(this.staticDirectory, internals.kAssetsDirectoryName);
-    const indexTarget = join(this.staticDirectory, internals.kIndexName);
-    const indexLocation = join(this.templatesDirectory, internals.kIndexName);
-    const posts = [];
+    internals.debuglog('Generating output');
+
+    const posts = await this._readPosts(this.postsDirectory);
+
+    await StaticGenerator(this.postsDirectory, this.staticDirectory, posts);
+    await HTMLGenerator(this.templatesDirectory, this.staticDirectory, posts);
+    await RSSGenerator(this.templatesDirectory, this.staticDirectory, posts);
+    await TXTGenerator(this.templatesDirectory, this.staticDirectory, posts);
+  }
 
-    internals.debuglog(`Removing ${assetsTarget}`);
-    await rmdir(assetsTarget, { recursive: true });
+  // Reads the posts into an array
+
+  async _readPosts(source) {
+
+    internals.debuglog('Reading posts');
+    const posts = [];
 
     for (let i = 0; i < this.maxPosts; ++i) {
-      const sourcePath = join(this.postsDirectory, `${i}`);
+      const postSourcePath = join(source, `${i}`);
 
-      try {
-        await access(this.postsDirectory);
+      internals.debuglog(`Reading ${postSourcePath} into posts array`);
 
-        const assetsSource = join(sourcePath, internals.kAssetsDirectoryName);
-        const postContentPath = await this._findBlogContent(sourcePath);
+      try {
+        await access(postSourcePath);
 
-        internals.debuglog(`Copying ${assetsSource} to ${assetsTarget}`);
-        await internals.ncp(assetsSource, assetsTarget);
+        const metadata = await this._getMetadata(i);
 
+        const postContentPath = await this._findBlogContent(postSourcePath);
         internals.debuglog(`Reading ${postContentPath}`);
         const postContent = await readFile(postContentPath, { encoding: 'utf8' });
 
         internals.debuglog('Parsing markdown');
         posts.push({
+          ...metadata,
+          index: i,
           html: Marked(postContent),
-          id: i + 1
+          raw: postContent
         });
       }
       catch (error) {
@@ -136,30 +151,24 @@ module.exports = class Blog {
       }
     }
 
-    internals.debuglog(`Reading ${indexLocation}`);
-    const indexTemplate = await readFile(indexLocation, { encoding: 'utf8' });
-
-    internals.debuglog('Generating HTML');
-    const indexHtml = template(indexTemplate)({ posts });
-    await writeFile(indexTarget, indexHtml);
+    return posts;
   }
 
   // Shift the posts, delete any remainder.
 
   async _shift() {
 
-    await this._ensurePostsDirectoryExists();
 
-    for (let i = this.maxPosts - 1; i > 0; --i) {
+    for (let i = this.maxPosts - 1; i >= 0; --i) {
       const targetPath = join(this.postsDirectory, `${i}`);
       const sourcePath = join(this.postsDirectory, `${i - 1}`);
 
       try {
-        await access(sourcePath);
-
         internals.debuglog(`Removing ${targetPath}`);
         await rmdir(targetPath, { recursive: true });
 
+        await access(sourcePath); // check the source path
+
         internals.debuglog(`Shifting blog post ${sourcePath} to ${targetPath}`);
         await internals.ncp(sourcePath, targetPath);
       }
@@ -174,12 +183,42 @@ module.exports = class Blog {
     }
   }
 
+  // Attempts to read existing metadata. Otherwise generates new set.
+
+  async _getMetadata(index = 0) {
+
+    const metadataTarget = join(this.postsDirectory, String(index), internals.kMetadataFilename);
+
+    try {
+      internals.debuglog(`Looking for metadata at ${metadataTarget}`);
+      return JSON.parse(await readFile(metadataTarget, { encoding: 'utf8' }));
+    }
+    catch (e) {
+      internals.debuglog(`Metadata not found or unreadable. Generating new set.`);
+      const createdOn = Date.now();
+      const metadata = {
+        id: String(createdOn),
+        createdOn
+      };
+
+      return metadata;
+    }
+  }
+
+  // Writes metadata. Assumes post 0 since it only gets written
+  // on create
+
+  async _writeMetadata(metadata) {
+
+    const metadataTarget = join(this.postsDirectory, '0', internals.kMetadataFilename);
+    internals.debuglog(`Writing ${metadataTarget}`);
+    await writeFile(metadataTarget, JSON.stringify(metadata, null, 2));
+  }
+
   // Copies a post directory to the latest slot.
 
   async _copyPost(postLocation) {
 
-    await this._ensurePostsDirectoryExists();
-
     const targetPath = join(this.postsDirectory, '0');
 
     internals.debuglog(`Removing ${targetPath}`);