require('array-findindex-polyfill') require('string.prototype.endswith') var fs = require('fs') var markdown = require('md-jml') var input = fs.readFileSync('content.md', 'utf8') markdown.parse(input, {}, function (tree) { // Assign numbers to headers var counter = [0, 0, 0, 0] var anchorStack = [''] for (var i = 2; i < tree.length; i++) { var e = tree[i] if (typeof e === 'string' || !e[0].match(/h\d/)) { continue // Not a header } var match = / \[(.+)\]/.exec(e[2]) if (!match) { continue // Doesn't contain anchor tag } var tag = match[1] e[2] = /(.+) \[.+\]/.exec(e[2])[1] var level = +e[0].substring(1) counter[level - 1]++ for (var j = level; j < 4; j++) { counter[j] = 0 } e[1].index = counter.slice(0, level).join('.') if (e[1].index.indexOf('.') === -1) { // There always has to be at least one dot in the index e[1].index += '.' } // Prepend index to text e[2] = e[1].index + ' ' + e[2] anchorStack = anchorStack.slice(0, level) anchorStack.push(anchorStack[level - 1] + '-' + tag) e[1].anchor = anchorStack[level].substring(1) } function forEachElement (elements, matcher, callback) { var indices = elements.map(function (h, index) { // Find the indices of all matched children return matcher(h) ? index : null }).filter(function (i) { // Filter out elements that didn't match return i !== null }) for (var i = 0; i < indices.length; i++) { var element = elements[indices[i]] var subElements = elements.slice(indices[i] + 1, i + 1 < indices.length ? indices[i + 1] : elements.length) callback(element, subElements) } } function generateIndex (headers, level) { var out = '' // Header if (level == 0) { out += '

Contents

' } else { out += '
' } else { out += '' } return out } var index = generateIndex(tree.slice(2).filter(function (e) { return e[1] && e[1].index }), 0) function generateBody (elements) { function generateElements (elements) { return elements.slice(2).map(generateElement).join('') } function generateElement (element) { if (!element) { return '' } else if (typeof element === 'string') { return element } else if (element[0] === 'em') { return '' + generateElements(element) + '' } else if (element[0] === 'strong') { return '' + generateElements(element) + '' } else if (element[0] === 'code') { return '' + generateElements(element) + '' } else if (element[0] === 'p') { if (element.length === 3 && element[2][0] === 'a' && element[2][2] === 'YouTube') { var id = element[2][1].href return '' + '
' } return '

' + generateElements(element) + '

' } else if (element[0] === 'a') { return '' + generateElements(element) + '' } else if (element[0] === 'ul') { return '' } else if (element[0] === 'li') { return '
  • ' + generateElements(element) + '
  • ' } else if (element[0] === 'img') { return '' + element[1].alt + '' } else if (element[0] === 'blockquote') { return element.slice(2).map(function (e) { return '

    ' + generateElements(e) + '

    ' }).join('') } else if (element[0] === 'hr') { return '
    ' } else if (element[0] === 'br') { return '
    ' } else { return JSON.stringify(element) } } function generateSection (header, elements) { // Remove images and store them for later var images = [] for (var i = 0; i < elements.length; i++) { var element = elements[i] if (element[0] !== 'p' || element[2][0] !== 'img') break images.push(element) } elements.splice(0, images.length) var out = '' if (header[1].anchor) { out += '' } out += '<' + header[0] + ' class="text-ul">' + header[2] + '' out += '
    ' // Generate text out += elements.map(generateElement).join('') out += '
    ' // Generate images images.forEach(function (image) { var url = image[2][1].src if (url.endsWith('.jpg') || url.endsWith('.png')) { var fullQualityUrl = url if (url.endsWith('.jpg')) { fullQualityUrl = url.substring(0, url.length - 3) + 'png' } out += '

    ' + generateElements(image.slice(1)) + '

    ' } else if (url.endsWith('gif')) { var webmUrl = url.substring(0, url.length - 3) + 'webm' out += '
    ' + '' + '

    ' + generateElements(image.slice(1)) + '

    ' } else { console.log('[Warning] Unhandled image format: ' + url) } }) out += '
    ' return out } var out = '' forEachElement(elements, function (e) { return e[0] === 'h1' }, function (header, elements) { out += '
    ' var firstHeaderIndex = elements.findIndex(function (e) { return e[0].match(/h\d/) }) header[0] = 'h2' // h1 headers should be rendered the same way as h2 ones are out += generateSection(header, elements.slice(0, firstHeaderIndex === -1 ? elements.length + 1 : firstHeaderIndex)) forEachElement(elements, function (e) { return e[0].match(/h\d/) }, function (header, elements) { out += generateSection(header, elements) }) out += '
    ' }) return out } var out = fs.readFileSync('template.html', 'utf-8') .replace('{{index}}', index) .replace('{{content}}', generateBody(tree.slice(2))) //out = JSON.stringify(tree, null, 2) fs.writeFileSync('content.html', out, 'utf-8') })