All files / src templateCompiler.ts

93.33% Statements 28/30
80% Branches 8/10
100% Functions 5/5
92.86% Lines 26/28
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 688x   8x 8x 8x 8x 8x                   34x 34x 85x 6x 6x     34x                   154x                 48x 7x 7x 7x 21x 7x 7x 7x 7x     7x       14x     7x 7x            
import {ERROR_CODES, PuzzleError} from "./errors";
 
export class TemplateCompiler {
    static TEMPLATE_REGEX: RegExp = /(\${.*?}?})/;
    static EXPRESSION_REGEX: RegExp = /^\${(.*?)}$/;
    static TEMPLATE_CONTENT_REGEX: RegExp = /<template>(.*?)<\/template>/mis;
    static PAGE_CLASS_CONTENT_REGEX: RegExp = /<script>(.*?)<\/script>(.*)<template>/mis;
 
 
    /**
     * Process object values and convert it using binding object.
     * @param expression
     * @param binding
     * @param req
     * */
    static processExpression(expression: { [key: string]: any }, binding: any, req?: any) {
        const processedExpression: { [key: string]: any } = Object.assign({}, expression);
        Object.keys(processedExpression).forEach((key) => {
            if (this.isExpression(processedExpression[key])) {
                const expressionVariable = processedExpression[key].split('${')[1].split('}')[0];
                processedExpression[key] = (new Function("req", `return ${expressionVariable}`)).apply(binding, [req]);
            }
        });
        return processedExpression;
    }
 
 
    /**
     * Checks if there is any string interpolation.
     * @param {string} template
     * @returns {boolean}
     */
    static isExpression(template: string) {
        return template.indexOf('${') > -1;
    }
 
    /**
     * Compiles given html string into function that acceps req as an argument.
     * @param {string} template
     * @returns {Function}
     */
    static compile(template: string): Function {
        if (!this.isExpression(template)) return () => template;
        let generatedFn = `let out = '';`;
        const partials = template.split(this.TEMPLATE_REGEX);
        for (let x = 0, len = partials.length; x < len; x++) {
            if (this.isExpression(partials[x])) {
                const expressionMathes = partials[x].match(this.EXPRESSION_REGEX);
                Eif (expressionMathes) {
                    const expression = expressionMathes[1];
                    Iif (expression.match(/if|for|else|switch|case|break|{|}/)) {
                        generatedFn += expression;
                    } else {
                        generatedFn += 'out+=\`${' + expression + '}\`;';
                    }
                }
            } else {
                generatedFn += `out+=\`${partials[x]}\`;`;
            }
        }
        try {
            return new Function('req', `${generatedFn}return out;`);
        } catch (e) {
            throw new PuzzleError(ERROR_CODES.FAILED_TO_COMPILE_TEMPLATE, `${generatedFn}return out;`);
        }
    }
}