Skip to content

Instantly share code, notes, and snippets.

@sidmani
Created May 9, 2018 21:11
Show Gist options
  • Save sidmani/cbfc74773514b222742a50d932ebfc9d to your computer and use it in GitHub Desktop.
Save sidmani/cbfc74773514b222742a50d932ebfc9d to your computer and use it in GitHub Desktop.
automatic post index generation for blogs
'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), () => {});
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment