Created
May 9, 2018 21:11
-
-
Save sidmani/cbfc74773514b222742a50d932ebfc9d to your computer and use it in GitHub Desktop.
automatic post index generation for blogs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
'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