2019-07-23 01:18:51 +03:00
|
|
|
/* eslint-disable no-console */
|
2019-07-23 00:57:11 +03:00
|
|
|
const visit = require('unist-util-visit')
|
|
|
|
const cache = new Map()
|
2019-07-23 20:42:23 +03:00
|
|
|
const ERB_BLOCK_PATTERN = /<%=[^%]+%>/g
|
2019-07-23 00:57:11 +03:00
|
|
|
|
|
|
|
module.exports = options => {
|
|
|
|
const convert = converter(options)
|
|
|
|
return tree => {
|
2019-07-23 01:18:51 +03:00
|
|
|
visit(tree, 'code', node => {
|
2019-07-23 00:57:11 +03:00
|
|
|
const match = node.lang ? node.lang.match(/^[a-z]+/) : null
|
|
|
|
const lang = match ? match[0] : null
|
|
|
|
if (lang === 'erb' || lang === 'html') {
|
|
|
|
const erb = node.value
|
2019-07-23 01:18:51 +03:00
|
|
|
const html = convert(erb)
|
2019-07-23 20:42:23 +03:00
|
|
|
const remaining = html ? html.match(ERB_BLOCK_PATTERN) : null
|
|
|
|
if (html && !remaining) {
|
2019-07-23 00:57:11 +03:00
|
|
|
node.value = html
|
|
|
|
node.lang = node.lang.replace(/^erb/, 'html')
|
2019-07-23 20:42:23 +03:00
|
|
|
} else if (remaining) {
|
2019-08-08 00:30:00 +03:00
|
|
|
// console.warn(`Unable to convert ${remaining.length} ERB blocks:\n ${remaining.join(' \n')}`)
|
2019-07-23 20:42:23 +03:00
|
|
|
} else {
|
|
|
|
// console.warn(`No conversions made in: ${erb}`)
|
2019-07-23 00:57:11 +03:00
|
|
|
}
|
|
|
|
} else {
|
2019-08-08 00:30:00 +03:00
|
|
|
// console.warn(`Unknown code block lang: ${node.lang}`)
|
2019-07-23 00:57:11 +03:00
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-07-23 20:42:23 +03:00
|
|
|
function converter({methods = {}}) {
|
2019-07-23 00:57:11 +03:00
|
|
|
return erb => {
|
2019-07-23 20:42:23 +03:00
|
|
|
const blocks = erb.match(ERB_BLOCK_PATTERN)
|
2019-07-23 00:57:11 +03:00
|
|
|
if (blocks && blocks.length) {
|
|
|
|
let html = erb
|
2019-08-08 00:30:00 +03:00
|
|
|
// console.warn(`Replacing ${blocks.length} ERB block(s)...`)
|
2019-07-23 20:42:23 +03:00
|
|
|
for (const block of blocks) {
|
|
|
|
const output = convert(block)
|
|
|
|
if (output !== block) {
|
2019-08-08 00:39:09 +03:00
|
|
|
// const count = html.split(block).length - 1
|
2019-08-08 00:30:00 +03:00
|
|
|
// console.warn(` found ${count} instances of "${block}"`)
|
2019-07-23 20:42:23 +03:00
|
|
|
html = replaceAll(html, block, output)
|
2019-08-08 00:30:00 +03:00
|
|
|
// console.warn(html)
|
2019-07-23 00:57:11 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return html
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function convert(block) {
|
|
|
|
if (cache.has(block)) {
|
|
|
|
return cache.get(block)
|
|
|
|
}
|
|
|
|
|
2019-07-23 01:18:51 +03:00
|
|
|
// eslint-disable-next-line no-unused-vars
|
|
|
|
const [_, method, argString] = block.match(/<%= *(\w+)[ (]([^)]+)\)? *%>/)
|
2019-07-23 00:57:11 +03:00
|
|
|
const parts = argString.split(/, */)
|
|
|
|
const args = []
|
|
|
|
const kwargs = {}
|
2019-07-23 02:43:45 +03:00
|
|
|
let match
|
2019-07-23 00:57:11 +03:00
|
|
|
for (const part of parts) {
|
2019-07-23 01:18:51 +03:00
|
|
|
if ((match = part.match(/^:(.+) => (.+)$/))) {
|
2019-07-23 00:57:11 +03:00
|
|
|
kwargs[unquote(match[1])] = unquote(match[2])
|
2019-07-23 01:18:51 +03:00
|
|
|
} else if ((match = part.match(/^(.+): (.+)$/))) {
|
2019-07-23 00:57:11 +03:00
|
|
|
kwargs[unquote(match[1])] = unquote(match[2])
|
|
|
|
} else {
|
|
|
|
args.push(unquote(part))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-07-23 20:42:23 +03:00
|
|
|
if (typeof methods[method] === 'function') {
|
|
|
|
let output = methods[method](args, kwargs)
|
|
|
|
console.warn(`converted: ${block} -> ${output}`)
|
|
|
|
const escaped = block.replace('<', '').replace('>', '')
|
|
|
|
output = `<!--${escaped}-->\n${output}`
|
2019-07-23 00:57:11 +03:00
|
|
|
cache.set(block, output)
|
|
|
|
return output
|
|
|
|
} else {
|
2019-07-23 20:42:23 +03:00
|
|
|
console.warn(`No such ERB method implemented: "${method}"`)
|
2019-07-23 00:57:11 +03:00
|
|
|
return block
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function replaceAll(str, input, output) {
|
2019-07-23 02:43:45 +03:00
|
|
|
return str.split(input).join(output)
|
2019-07-23 00:57:11 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
function unquote(str) {
|
|
|
|
return str.replace(/^\s*"([^"]+)"\s*$/, (_, value) => value)
|
|
|
|
}
|