Skip to content

Instantly share code, notes, and snippets.

@savelichalex
Last active November 14, 2017 17:36
Show Gist options
  • Save savelichalex/4801025665743b87f26e867608994464 to your computer and use it in GitHub Desktop.
Save savelichalex/4801025665743b87f26e867608994464 to your computer and use it in GitHub Desktop.
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