Skip to content

Instantly share code, notes, and snippets.

@sidmani
Created May 9, 2018 21:11

Revisions

  1. Sid Mani created this gist May 9, 2018.
    79 changes: 79 additions & 0 deletions parse_posts.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,79 @@
    'use strict';
    // parse markdown files to html
    const fs = require('fs');
    const postTemplate = fs.readFileSync('templates/post.t', 'utf8');
    const postIndexTemplate = fs.readFileSync('templates/post_index.t', 'utf8');

    function parsePost(text) {
    let post = {};
    let match = /([\w\W]+?) <([\W\w]*?)>\n\/\/ ([\W\w]*?)\n([\W\w]*)/g.exec(text);
    post.title = match[1];
    post.date = match[2];
    post.subtitle = match[3];
    post.body = match[4];
    return post;
    }

    function markdownToHTML(text) {
    // replace double \n with paragraph break
    text = text.replace(/\n\n/g, '</p>\n<p>');
    // replace double whitespace + \n with line break
    text = text.replace(/ \n/g, '<br>');
    // replace image ![title](src) with image card
    text = text.replace(/(?<!\^)!\[([^\]\[]+?)\]\(([\W\w]+?)\)/g, (match, title, src) => '<div class="card">' +
    '<header class="card-header">' + title + '</header>' +
    '<div class="card-content">' +
    '<img alt="' + title + '"src="' + src + '" style="width:100%"></img>' +
    '</div>\n</div>');
    // replace image ^![title](src) with inline image
    text = text.replace(/\^!\[([^\]\[]+?)\]\(([\W\w]+?)\)/g, (match, title, src) => '<img alt="' + title + '" src="' + src + '"></img>');
    // replace ```text``` with <pre>text</pre>
    text = text.replace(/```([\W\w]*?)```/g, (match, content) => '<pre>' + content + '</pre>');
    // replace --- with <hr>
    text = text.replace(/---/g, '<hr>');
    // replace link [name](url) with <a href="url">name</a>
    text = text.replace(/(?<!!)\[([^\]\[]+?)\]\(([\W\w]+?)\)/g, (match, name, url) => '<a target="_top" href="' + url + '">' + name + '</a>');
    // replace **text** with <strong>text</strong>
    text = text.replace(/\*\*([\W\w]*?)\*\*/g, (match, strong) => '<strong>' + strong + '</strong>');
    // replace email with mailto
    text = text.replace(/<([\w.]+@[\w.]+)>/g, (match, email) => '<a class="rlink" href="mailto:' + email + '">' + email + '</a>');
    return '<p>' + text + '</p>';
    }

    function generateHTML(post) {
    let result = postTemplate.replace(/{{ title }}/g, post.title);
    result = result.replace(/{{ date }}/g, post.date);
    result = result.replace(/{{ body }}/g, markdownToHTML(post.body));
    return result;
    }

    function generateMediaCard(post) {
    let result = '<div class="media">\n<div class="media-body">\n';
    result += '<a class="media-heading" target="_top" href="/?posts&id=' + post.id + '">' + post.title + '</a>';
    result += '<span class="help-block"> ' + post.date + '</span>\n';
    result += '<div class="media-content">' + post.subtitle + '</div>\n';
    result += '</div>\n</div>\n';
    return result;
    }

    function generatePostIndex(posts) {
    let postHTML = '';
    posts.sort((a, b) => parseInt(b.id, 10) - parseInt(a.id, 10)).map(generateMediaCard).forEach(post => postHTML += post);
    return postIndexTemplate.replace(/{{ posts }}/g, postHTML);
    }

    fs.readdir("posts/", function(e, filenames) {
    let posts = [];
    filenames
    .filter(name => name.substr(name.length - 3) === ".md")
    .forEach(name => {
    const file = fs.readFileSync('posts/' + name, 'utf8');
    const post = parsePost(file);
    post.id = name.substr(0, name.length - 3);
    posts.push(post);
    const html = generateHTML(post);
    fs.writeFile('posts/' + name.substr(0, name.length - 3) + '.gen.html', html, () => {});
    });

    fs.writeFile('pages/posts.html', generatePostIndex(posts), () => {});
    });