UNPKG

templify-js

Version:

A simple template language engine for Typescript

132 lines (131 loc) 6.43 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.Templify = void 0; class Templify { constructor(template) { this.pipes = {}; this.template = template; } addPipe(name, callback) { this.pipes[name] = callback; } simplify(template = this.template) { return template .replace(/\s}}/g, '}}') .replace(/{{\s/g, '{{') .replace(/\s%}/g, '%}') .replace(/{%\s/g, '{%') .replace(/{%foreach:\s/g, '{%foreach:'); } render(data, template = this.template) { let output = this.simplify(template); // Replace foreach loops deeply while (output.indexOf('{%foreach:') !== -1) { // Lets start with first foreach const startForeach = output.indexOf('{%foreach:'); // Find the end of the foreach let pointerPosition = startForeach + 10; while (output.indexOf('{%foreach:', pointerPosition) < output.indexOf('{%endforeach%}', pointerPosition) && output.indexOf('{%foreach:', pointerPosition) !== -1) { pointerPosition = output.indexOf('{%endforeach%}', pointerPosition) + 14; } const endForeach = output.indexOf('{%endforeach%}', pointerPosition); // Get the foreach content const content = output.substring(startForeach, endForeach + 14); let subcontent = content.substring(content.indexOf('%}') + 2, content.lastIndexOf('{%')); const variable = content.substring(content.indexOf(':') + 1, content.indexOf('%}')).replace(/\s/g, ''); const subdata = this.getPropertyValue(data, variable); if (subcontent.indexOf('{%foreach:') === -1) { const foreachContent = content.replace(/{%\s*foreach:([\w.-]+)\s*%}(.*?)\{%\s*endforeach\s*%}/gs, (match, variable, matchcontent) => { const list = this.getPropertyValue(Object.assign(Object.assign({}, data), { item: subdata }), variable); if (Array.isArray(list)) { return list.map((item, index) => { return this.render(Object.assign(Object.assign(Object.assign(Object.assign({}, subdata), { index }), data), { item }), subcontent); }).join(''); } else { return this.render(Object.assign({}, subdata), matchcontent); } }); output = output.replace(content, this.render(Object.assign(Object.assign({}, data), { item: subdata }), foreachContent)); } else { if (Array.isArray(subdata)) { output = output.replace(content, subdata.map((item, index) => this.render(Object.assign(Object.assign({ index }, data), { item }), subcontent)).join('')); } else { output = output.replace(content, this.render(Object.assign(Object.assign({}, data), { item: subdata }), subcontent)); } } } // Replace simple variable print output = output.replace(/{{\s*([\w.-]+)\s*}}/g, (match, variable) => { const value = this.getPropertyValue(data, variable); return value !== undefined ? value : match; }); // Replace variable with pipe and arguments output = output.replace(/{{\s*([\w.-]+)\s*\|\s*([\w.-]+)\s*:\s*([\w.-]+)\s*}}/g, (match, variable, pipe, args) => { const value = this.getPropertyValue(data, variable); return value !== undefined ? this.applyPipe(value, pipe, args) : match; }); // Replace variable with pipe output = output.replace(/{{\s*([\w.-]+)\s*\|\s*([\w.-]+)\s*}}/g, (match, variable, pipe) => { const value = this.getPropertyValue(data, variable); return value !== undefined ? this.applyPipe(value, pipe) : match; }); // Replace if statements const ifElsePattern = /{%\s*if:([\w.\-=\s]+)\s*%}(?:(?!{%\s*(?:if:[\w.\-=\s]+|endif)\s*%}).)*(?:{%\s*else\s*%}(?:(?!{%\s*(?:if:[\w.\-=\s]+|endif)\s*%}).)*)?{%\s*endif\s*%}/gs; while (ifElsePattern.exec(output) !== null) { output = output.replace(ifElsePattern, (match) => { return match.replace(/{%\s*if:([\w.\-=\s]+)\s*%}(.*?)({%\s*else\s*%}(.*?))?{%\s*endif\s*%}/gs, (match, condition, ifContent, elseStatement, elseContent) => { const conditions = condition.split('==').map((item) => item.trim()); let value = null; if (conditions.length === 2) { value = String(this.getPropertyValue(data, conditions[0])) === String(conditions[1]); } else { value = this.getPropertyValue(data, condition); } if (value) { return this.render(data, ifContent); } else if (elseContent) { return this.render(data, elseContent); } return ''; }); }); } ; // Clear unused variables output = output.replace(/{{\s*([\w.-]+)\s*}}/g, ''); return output; } getPropertyValue(obj, path) { const properties = path.split('.'); let value = obj; for (const property of properties) { if (typeof value !== 'object' || value === null || !(property in value)) { return undefined; } value = value[property]; } return value; } applyPipe(value, pipe, arg) { // Custom pipes if (Object.keys(this.pipes).indexOf(pipe) !== -1 && typeof this.pipes[pipe] === 'function') { try { return this.pipes[pipe](value, arg); } catch (e) { console.log("Error in pipe: " + pipe); } } // Default pipes switch (pipe) { case 'upper': return String(value).toUpperCase(); default: return value; } } } exports.Templify = Templify;