1
1
mirror of https://github.com/primer/css.git synced 2024-12-14 06:44:38 +03:00
css/lib/erb-to-html.js

92 lines
2.7 KiB
JavaScript
Raw Normal View History

2019-07-23 01:18:51 +03:00
/* eslint-disable no-console */
const visit = require('unist-util-visit')
const cache = new Map()
2019-07-23 20:42:23 +03:00
const ERB_BLOCK_PATTERN = /<%=[^%]+%>/g
module.exports = options => {
const convert = converter(options)
return tree => {
2019-07-23 01:18:51 +03:00
visit(tree, 'code', node => {
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) {
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}`)
}
} else {
2019-08-08 00:30:00 +03:00
// console.warn(`Unknown code block lang: ${node.lang}`)
}
})
}
}
2019-07-23 20:42:23 +03:00
function converter({methods = {}}) {
return erb => {
2019-07-23 20:42:23 +03:00
const blocks = erb.match(ERB_BLOCK_PATTERN)
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)
}
}
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+)[ (]([^)]+)\)? *%>/)
const parts = argString.split(/, */)
const args = []
const kwargs = {}
2019-07-23 02:43:45 +03:00
let match
for (const part of parts) {
2019-07-23 01:18:51 +03:00
if ((match = part.match(/^:(.+) => (.+)$/))) {
kwargs[unquote(match[1])] = unquote(match[2])
2019-07-23 01:18:51 +03:00
} else if ((match = part.match(/^(.+): (.+)$/))) {
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}`
cache.set(block, output)
return output
} else {
2019-07-23 20:42:23 +03:00
console.warn(`No such ERB method implemented: "${method}"`)
return block
}
}
}
function replaceAll(str, input, output) {
2019-07-23 02:43:45 +03:00
return str.split(input).join(output)
}
function unquote(str) {
return str.replace(/^\s*"([^"]+)"\s*$/, (_, value) => value)
}