Last active
November 14, 2017 17:36
-
-
Save savelichalex/4801025665743b87f26e867608994464 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React from "react"; | |
const linkBlock = "\\[[^\\]]*]\\([^\\)]*\\)"; | |
const linkGrouped = "\\[([^\\]]*)]\\(([^\\)]*)\\)"; | |
const linkRegex = new RegExp(`^${linkGrouped}$`); | |
const variableBlock = "\\{[^\\}]*\\}"; | |
const variableGrouped = "\\{([^\\}]*)\\}"; | |
const variableRegex = new RegExp(`${variableGrouped}`, "g"); | |
const ifElseBlock = "#if(?:-not)?\\s\\{[^\\}]+\\}\\s*[^#]+(?:#else\\s*[^#]+)?#fi"; | |
const ifElseGrouped = "#if(-not)?\\s\\{([^\\}]+)\\}\\s*([^#]+)(?:#else\\s*([^#]+))?#fi"; | |
const ifElseRegex = new RegExp(`^${ifElseGrouped}$`); | |
const createStringWithVariable = stringTemplate => { | |
const matchedVariables = stringTemplate.match(variableRegex); | |
if (matchedVariables == null) { | |
return () => stringTemplate; | |
} | |
return props => | |
stringTemplate.replace(variableRegex, variable => props[variable.slice(1, -1)] || ""); | |
}; | |
export const templateCompiler = template => { | |
let match; | |
const result = []; | |
const justTexts = []; | |
let lastTextIndex = 0; | |
const blocks = new RegExp(`(${[ifElseBlock, linkBlock].join(")|(")})`, "g"); | |
while ((match = blocks.exec(template)) !== null) { | |
if (match == null) continue; | |
const [, ifElse, link] = match; | |
if (link != null) { | |
const [, linkHref, linkText] = link.match(linkRegex); | |
const linkHrefWithVariable = createStringWithVariable(linkHref); | |
const linkTextWithVariable = createStringWithVariable(linkText); | |
if (match.index !== lastTextIndex) { | |
const justTextWithVariable = createStringWithVariable( | |
template.slice(lastTextIndex, match.index) | |
); | |
result.push(props => <span>{justTextWithVariable(props)}</span>); | |
lastTextIndex = match.index + link.length; | |
} | |
result.push(props => ( | |
<a href={linkHrefWithVariable(props)} rel="noopener noreferrer" target="_blank"> | |
{linkTextWithVariable(props)} | |
</a> | |
)); | |
continue; | |
} | |
if (ifElse != null) { | |
const [, isNot, variable, ifThread, elseThread] = ifElse.match(ifElseRegex); | |
const ifThreadExpression = templateCompiler(ifThread); | |
const elseThreadExpression = elseThread == null ? () => null : templateCompiler(elseThread); | |
if (match.index !== lastTextIndex) { | |
const justTextWithVariable = createStringWithVariable( | |
template.slice(lastTextIndex, match.index) | |
); | |
result.push(props => <span>{justTextWithVariable(props)}</span>); | |
lastTextIndex = match.index + ifElse.length; | |
} | |
const matcher = isNot == null; | |
result.push( | |
props => | |
props[variable] == matcher ? ifThreadExpression(props) : elseThreadExpression(props) | |
); | |
continue; | |
} | |
} | |
justTexts.forEach(text => { | |
const justTextWithVariable = createStringWithVariable(text); | |
result.push(props => <span>{justTextWithVariable(props)}</span>); | |
}); | |
return function Template(props) { | |
return <span>{result.map((Comp, index) => <Comp key={index} {...props} />)}</span>; | |
}; | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment