1
1
mirror of https://github.com/primer/css.git synced 2025-01-05 21:22:57 +03:00

use ERB converts for octicon() and avatar_for()

This commit is contained in:
Shawn Allen 2019-07-22 14:57:11 -07:00
parent 7aa05a9d04
commit b82a3fc69f
2 changed files with 102 additions and 1 deletions

84
lib/erb-to-html.js Normal file
View File

@ -0,0 +1,84 @@
const visit = require('unist-util-visit')
const cache = new Map()
module.exports = options => {
const convert = converter(options)
return tree => {
visit(tree, 'code', (node, parent, index) => {
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
const html = convert(node.value)
if (html && !html.includes('<%')) {
node.value = html
node.lang = node.lang.replace(/^erb/, 'html')
}
} else {
// console.warn(`Unknown code block lang: ${node.lang}`)
}
})
}
}
function converter({converters = {}}) {
return erb => {
const blocks = erb.match(/<%=[^%]+%>/g)
if (blocks && blocks.length) {
let html = erb
console.warn(`Replacing ${blocks.length} ERB block(s)...`)
for (const input of blocks) {
const output = convert(input)
if (output !== input) {
html = replaceAll(html, input, output)
}
}
return html
}
}
function convert(block) {
if (cache.has(block)) {
return cache.get(block)
}
const [_, method, argString] = block.match(/<%= *(\w+)[ \(]([^\)]+)\)? *%>/)
const parts = argString.split(/, */)
const args = []
const kwargs = {}
for (const part of parts) {
let match
if (match = part.match(/^:(.+) => (.+)$/)) {
kwargs[unquote(match[1])] = unquote(match[2])
} else if (match = part.match(/^(.+): (.+)$/)) {
kwargs[unquote(match[1])] = unquote(match[2])
} else {
args.push(unquote(part))
}
}
if (typeof converters[method] === 'function') {
let output = converters[method](args, kwargs)
output = `<!-- ${block} -->\n${output}`
cache.set(block, output)
return output
} else {
console.warn(`Unable to convert: ${block}`)
return block
}
}
}
function replaceAll(str, input, output) {
let result = str
while (result.includes(input)) {
result = result.replace(input, output)
}
return result
}
function unquote(str) {
return str.replace(/^\s*"([^"]+)"\s*$/, (_, value) => value)
}

View File

@ -1,11 +1,13 @@
const {getOptions} = require('loader-utils')
const mdx = require('@mdx-js/mdx')
const octicons = require('@primer/octicons')
const emoji = require('remark-emoji')
const images = require('remark-images')
const rehypePrism = require('./rehype-prism')
const textr = require('remark-textr')
const toc = require('remark-toc')
const erbToHTML = require('./erb-to-html')
const mdxExportJSONByDefault = require('mdx-constant')
const grayMatter = require('gray-matter')
@ -22,7 +24,22 @@ module.exports = async function(source) {
[toc, {heading: '(table of|section)? contents'}],
images,
emoji,
[textr, {plugins: [typographicBase]}]
[textr, {plugins: [typographicBase]}],
[erbToHTML, {
converters: {
octicon: ([icon], attrs) => {
if (octicons[icon]) {
return octicons[icon].toSVG(attrs)
} else {
throw new Error(`No such octicon: "${icon}"`)
}
},
avatar_for: ([username, size], kwargs) => {
const attrs = Object.entries(kwargs).map(([key, value]) => ` ${key}="${value}"`).join(' ')
return `<img src="https://github.com/github.png?s=${size * 2}" width="${size}" height="${size}"${attrs}>`
}
}
}]
],
hastPlugins: [rehypePrism],
compilers: [mdxExportJSONByDefault('frontMatter', data)]