UNPKG

@akala/core

Version:
491 lines 19.9 kB
"use strict"; var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k]; result["default"] = mod; return result; }; Object.defineProperty(exports, "__esModule", { value: true }); const promiseHelpers_1 = require("./promiseHelpers"); const binder_1 = require("./binder"); const formatters = __importStar(require("./formatters")); const helpers_1 = require("./helpers"); var jsonKeyRegex = /^ *(?:(?:"([^"]+)")|(?:'([^']+)')|(?:([^\: ]+)) *): */; class ParsedBinary { constructor(operator, left, right) { this.operator = operator; this.left = left; this.right = right; this.$$length = this.left.$$length + this.operator.length + this.right.$$length; } evaluate(value, asBinding) { var operation = this; if (asBinding) { var left, right; if (operation.left instanceof Function) left = operation.left(value, asBinding); else if (operation.left instanceof ParsedBinary) left = operation.left.evaluate(value, asBinding); else if (operation.left instanceof ParsedString) left = operation.left.value; else if (operation.left instanceof ParsedNumber) left = operation.left.value; else if (operation.left instanceof Array) left = operation.left; else if (operation.left instanceof Object) left = operation.left; if (operation.right instanceof Function) right = operation.right(value, asBinding); else if (operation.right instanceof ParsedBinary) right = operation.right.evaluate(value, asBinding); else if (operation.right instanceof ParsedString) right = operation.right.value; else if (operation.right instanceof ParsedNumber) right = operation.right.value; else if (operation.right instanceof Array) right = operation.right; else if (operation.right instanceof Object) right = operation.right; var binding = new binder_1.Binding(null, null, false); if (left instanceof binder_1.Binding) left.pipe(binding); if (right instanceof binder_1.Binding) right.pipe(binding); binding['$$length'] = operation.$$length; binding.getValue = function () { var fleft, fright; if (left instanceof binder_1.Binding) fleft = left.getValue(); else fleft = left; if (right instanceof binder_1.Binding) fright = right.getValue(); else fright = right; return Parser.operate(operation.operator, fleft, fright); }; return binding; } else { var left, right; if (operation.left instanceof Function) left = operation.left(value, false); else if (operation.left instanceof ParsedBinary) left = operation.left.evaluate(value, asBinding); else if (operation.left instanceof ParsedString) left = operation.left.value; else if (operation.left instanceof ParsedNumber) left = operation.left.value; else if (operation.left instanceof Array) left = operation.left; else if (operation.left instanceof Object) left = operation.left; if (operation.right instanceof Function) right = operation.right(value, false); else if (operation.right instanceof ParsedBinary) right = operation.right.evaluate(value, asBinding); else if (operation.right instanceof ParsedString) right = operation.right.value; else if (operation.right instanceof ParsedNumber) right = operation.right.value; else if (operation.right instanceof Array) right = operation.right; else if (operation.right instanceof Object) right = operation.right; return Parser.operate(operation.operator, left, right); } } static applyPrecedence(operation) { if (operation.operator != '+' && operation.operator != '-') { if (operation.right instanceof Function && operation.right.$$ast) { var right = ParsedBinary.applyPrecedence(operation.right.$$ast); switch (right.operator) { case '+': case '-': break; case '*': // b*(c+d) ==> (b*c)+d case '/': case '&&': case '||': case '.': var left = operation.left; operation.right = right.right; operation.left = new ParsedBinary(operation.operator, left, right.left); operation.operator = right.operator; break; } } } return operation; } toString() { return '(' + this.left.toString() + this.operator + this.right.toString() + ')'; } } exports.ParsedBinary = ParsedBinary; class ParsedString { constructor(value) { this.value = value; this.$$length = value.length + 2; } toString() { return this.value; } } exports.ParsedString = ParsedString; class ParsedNumber { constructor(value) { this.value = Number(value); this.$$length = value.length; } } exports.ParsedNumber = ParsedNumber; class ParsedBoolean { constructor(value) { this.value = Boolean(value); if (typeof value != 'undefined') this.$$length = value.toString().length; } } exports.ParsedBoolean = ParsedBoolean; class Parser { static parse(expression, excludeFirstLevelFunction) { expression = expression.trim(); var result = Parser.parseAny(expression, excludeFirstLevelFunction); if (!excludeFirstLevelFunction && result instanceof ParsedBinary) return result.evaluate.bind(result); return result; } static parseAny(expression, excludeFirstLevelFunction) { switch (expression[0]) { case '{': return Parser.parseObject(expression, excludeFirstLevelFunction); case '[': return Parser.parseArray(expression, excludeFirstLevelFunction); case '"': case "'": return Parser.parseString(expression, expression[0]); case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case '.': return Parser.parseNumber(expression); default: return Parser.parseEval(expression); } } static parseNumber(expression) { var result = new ParsedNumber(/^[0-9.]/.exec(expression)[0]); return Parser.tryParseOperator(expression.substring(result.$$length), result); } static parseBoolean(expression) { var formatter = formatters.identity; if (expression[0] == '!') { formatter = formatters.negate; expression = expression.substring(1); } if (expression[0] == '!') { formatter = formatters.booleanize; expression = expression.substring(1); } if (/^true|false|undefined/.exec(expression)) { var result = new ParsedBoolean(/^true|false|undefined/.exec(expression)[0]); if (formatter !== formatters.identity) result.value = formatter(result.value); return result; } return null; } static parseEval(expression) { var b = Parser.parseBoolean(expression); if (b) return b; return Parser.parseFunction(expression); } static parseFunction(expression) { var length = 0; var formatter = formatters.identity; if (expression[0] == '!') { formatter = formatters.negate; expression = expression.substring(1); length++; } if (expression[0] == '!') { formatter = formatters.booleanize; expression = expression.substring(1); length++; } var item = /^[\w0-9\.\$]*/.exec(expression)[0]; length += item.length; var parts = Parser.parseBindable(item); var f = function (value, asBinding) { if (asBinding) { if (promiseHelpers_1.isPromiseLike(value)) { var binding = new binder_1.PromiseBinding(item, value); binding['$$length'] = item.length; binding.formatter = formatter; return binding; } var binding = new binder_1.Binding(item, value); binding['$$length'] = item.length; binding.formatter = formatter; return binding; } if (parts.length >= 1 && parts[0] != '') for (var i = 0; i < parts.length && value; i++) { value = value[parts[i]]; if (promiseHelpers_1.isPromiseLike(value)) { var promise; if (i == parts.length - 1) promise = value; else promise = value.then(Parser.parseFunction(parts.slice(i + 1).join('.'))).then(formatter); promise['$$length'] = item.length; return promise; } } return value; }; f.$$length = length; f = Parser.tryParseOperator(expression.substr(item.length), f); return f; } static parseFormatter(expression, lhs) { var item = /^ *# *([\w0-9\.\$]+) */.exec(expression); expression = expression.substring(item[0].length); var formatter = helpers_1.module('$formatters').resolve('#' + item[1]); if (!formatter) throw new Error(`filter not found: ${item[1]}`); var settings; if (expression[0] == ':') { settings = formatter.parse(expression.substring(1)); } var result = function (value, asBinding) { var left; if (lhs instanceof Function) left = lhs(value, asBinding); else if (lhs instanceof ParsedBinary) left = lhs.evaluate(value, asBinding); else if (lhs instanceof ParsedString) left = lhs.value; else if (lhs instanceof ParsedNumber) left = lhs.value; else if (lhs instanceof Array) left = lhs; else if (lhs instanceof Object) left = lhs; if (asBinding) { if (left instanceof binder_1.Binding) { left.formatter = formatter.build(left.formatter, settings); return left; } else { var b = new binder_1.Binding('', left); b.formatter = formatter.build(formatters.identity, settings); return b; } } else { if (left instanceof binder_1.Binding) { left.formatter = formatter.build(left.formatter, settings); return left.getValue(); } else { return formatter.build(formatters.identity, settings)(left); } } }; // console.log({ lhs: lhs.$$length, item0: item[0].length, settings: settings && settings.$$length }) result.$$length = lhs.$$length + item[0].length + ((settings && settings.$$length + 1) || 0); // console.log(result.$$length); return result; } static tryParseOperator(expression, lhs) { var operator = /^ *([<>=!\+\-\/\*&\|\.#]+) */.exec(expression); if (operator) { switch (operator[1]) { case '#': return Parser.parseFormatter(expression, lhs); case '.': default: expression = expression.substring(operator[0].length); var rhs = Parser.parseAny(expression, false); var binary = new ParsedBinary(operator[1], lhs, rhs); binary.$$length = lhs.$$length + operator[0].length + rhs.$$length; return ParsedBinary.applyPrecedence(binary); } } else return lhs; } static parseArray(expression, excludeFirstLevelFunction) { var results = []; Object.defineProperty(results, '$$length', { value: 0, enumerable: false, configurable: true, writable: true }); var isFunction = false; return Parser.parseCSV(expression, function (result) { var item = Parser.parseAny(result, false); item = Parser.tryParseOperator(result.substring(item.$$length), item); if (item instanceof ParsedBoolean || item instanceof ParsedString || item instanceof ParsedNumber) results.push(item); else if (item instanceof ParsedBinary) results.push(item.evaluate.bind(item)); else results.push(item); results.$$length += item.$$length; return item; }, ']', results, excludeFirstLevelFunction); } static parseString(expression, start) { var evaluatedRegex = new RegExp("^" + start + "((?:[^\\" + start + "]|\\.)+)" + start).exec(expression); // console.log(arguments); var result = evaluatedRegex[1]; var parsedString = new ParsedString(result); return Parser.tryParseOperator(expression.substring(evaluatedRegex[0].length), parsedString); } static operate(operator, left, right) { // if (arguments.length == 1) // return function (left: any, right: any) // { // return Parser.operate(operator, left, right); // } switch (operator) { case '==': return left == right; case '===': return left === right; case '<': return left < right; case '<=': return left <= right; case '>': return left > right; case '>=': return left >= right; case '!=': return left != right; case '!==': return left !== right; case '+': return left + right; case '-': return left - right; case '/': return left / right; case '*': return left * right; case '||': return left || right; case '&&': return left && right; case '.': if (right instanceof Function) return right(left); return left[right]; default: throw new Error('invalid operator' + operator); } } static parseCSV(expression, parseItem, end, output, excludeFirstLevelFunction) { expression = expression.substring(1); output.$$length++; var isFunction = false; do { var item = parseItem(expression); if (item instanceof Function || item instanceof ParsedBinary) isFunction = true; expression = expression.substring(item.$$length); var next = /^ *, */.exec(expression); // console.log(expression) if (!next) break; expression = expression.substring(next[0].length); // console.log(expression); output.$$length += next[0].length; } while (expression[0] != end); output.$$length += end.length; // console.log(output.$$length); var result; if (output instanceof Array) result = []; else result = {}; if (isFunction && !excludeFirstLevelFunction) { var f = function (value, asBinding) { for (var i in output) { if (output[i] instanceof Function) result[i] = output[i](value, asBinding); else result[i] = output[i]; } return result; }; f.$$length = output.$$length; return f; } else return output; } static parseObject(expression, excludeFirstLevelFunction) { var keyMatch; var parsedObject = {}; Object.defineProperty(parsedObject, '$$length', { value: 0, enumerable: false, writable: true, configurable: true }); var result = Parser.parseCSV(expression, function (expression) { // var length = 0; var keyMatch = jsonKeyRegex.exec(expression); var key = keyMatch[1] || keyMatch[2] || keyMatch[3]; //console.log(keyMatch); var length = keyMatch[0].length + keyMatch.index; expression = expression.substring(length); var item = Parser.parseAny(expression, false); length += item.$$length; if (item instanceof ParsedBoolean || item instanceof ParsedString || item instanceof ParsedNumber) parsedObject[key] = item.value; else if (item instanceof ParsedBinary) parsedObject[key] = item.evaluate.bind(item); else parsedObject[key] = item; // expression = expression.substring(result[key].$$length); item.$$length = length; parsedObject.$$length += length; // console.log(expression); //console.log(length); return item; }, '}', parsedObject, excludeFirstLevelFunction); return this.tryParseOperator(expression.substring(result.$$length), result); } static parseBindable(expression) { return expression.split('.'); } static getSetter(expression, root) { var target = root; var parts = Parser.parseBindable(expression); while (parts.length > 1 && typeof (target) != 'undefined') { target = Parser.eval(parts[0], target); parts.shift(); } if (typeof (target) == 'undefined') return null; return { expression: parts[0], target: target, set: function (value) { target[parts[0]] = value; } }; } static evalAsFunction(expression, excludeFirstLevelFunction) { if (!expression && typeof (expression) != 'string') return null; var parts = Parser.parse(expression, excludeFirstLevelFunction); if (parts instanceof Array) return Parser.parseFunction(expression); return parts; } static eval(expression, value) { return Parser.evalAsFunction(expression, false)(value, false); } } exports.Parser = Parser; //# sourceMappingURL=parser.js.map