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 += ''
}
// Find the indices of all headers one level below this one
forEachElement(headers, function (h) {
return h[0] === 'h' + (level + 1) && h[1].anchor
}, function (header, subHeaders) {
// Output header
if (level == 0) {
out += '- ' + header[2] + '
'
} else {
out += '- ' + header[2] + '
'
}
// Output sub headers (if any)
if (subHeaders.length) {
out += generateIndex(subHeaders, level + 1)
}
})
// Footer
if (level == 0) {
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 '' + generateElements(element) + '
'
} else if (element[0] === 'li') {
return '' + generateElements(element) + ''
} else if (element[0] === 'img') {
return '
'
} 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] + '' + header[0] +'>'
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 += '
'
} 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')
})