@kodeko/akita-core
Version:
A powerfull string interpreter
253 lines (252 loc) • 10.7 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Lexer = exports.LexerAkitaFunction = exports.LexerError = void 0;
var tslib_1 = require("tslib");
var lodash_1 = require("lodash");
var util_1 = require("util");
var LexerError = (function (_super) {
tslib_1.__extends(LexerError, _super);
function LexerError(property, header, explain) {
var _this = _super.call(this, "\u001B[34m[Lexer.".concat(property, "]\u001B[0m-> \u001B[31m").concat(header, "\n\t\u001B[90m").concat(explain, "\u001B[0m")) || this;
_this.name = "LexerError";
return _this;
}
return LexerError;
}(Error));
exports.LexerError = LexerError;
var LexerAkitaFunction = (function () {
function LexerAkitaFunction(options, matched, uid) {
this.options = options;
this.matched = matched;
this.uid = uid;
this.fields = [];
}
Object.defineProperty(LexerAkitaFunction.prototype, "identifier", {
get: function () {
return "SAF(".concat(this.uid, ")");
},
enumerable: false,
configurable: true
});
Object.defineProperty(LexerAkitaFunction.prototype, "position", {
get: function () {
return this.matched.position;
},
enumerable: false,
configurable: true
});
Object.defineProperty(LexerAkitaFunction.prototype, "name", {
get: function () {
return this.matched.name;
},
enumerable: false,
configurable: true
});
Object.defineProperty(LexerAkitaFunction.prototype, "prototype", {
get: function () {
return this.matched.prototype;
},
enumerable: false,
configurable: true
});
Object.defineProperty(LexerAkitaFunction.prototype, "inside", {
get: function () {
return this.fields.map(function (n) { return n.value; }).join(this.options.argument);
},
enumerable: false,
configurable: true
});
Object.defineProperty(LexerAkitaFunction.prototype, "total", {
get: function () {
var _a;
return this.matched.name.concat((_a = this.matched.prototype) !== null && _a !== void 0 ? _a : "", this.inside
? this.options.opener.concat(this.inside, this.options.closer)
: "");
},
enumerable: false,
configurable: true
});
LexerAkitaFunction.prototype.toJSON = function () {
return {
identifier: this.identifier,
position: this.position,
fields: this.fields.map(function (saf) {
saf.overloads = saf.overloads.map(function (_) { return _.toJSON(); });
return saf;
}),
name: this.name,
};
};
return LexerAkitaFunction;
}());
exports.LexerAkitaFunction = LexerAkitaFunction;
var Lexer = (function () {
function Lexer(default_options) {
if (default_options === void 0) { default_options = {
insensitive: false,
argument: ";",
opener: "(",
closer: ")",
}; }
this.default_options = default_options;
this.regular_expression = "";
this.functions = [];
}
Lexer.generateToken = function () {
var timestamp = Date.now().toString(36), random = Math.random().toString(36).substring(2, 9), token = timestamp + random;
return token;
};
Lexer.prototype.set_functions = function (functions) {
this.functions = functions.sort(function (a, b) { return b.length - a.length; });
this.regular_expression = "(".concat(this.functions
.map(lodash_1.escapeRegExp)
.join("|"), ")(\\.[a-zA-Z]+)?");
return this;
};
Lexer.prototype.find_function = function (x) {
return this.functions.find(function (f) { return (0, lodash_1.toLower)(f) === (0, lodash_1.toLower)(x); });
};
Lexer.prototype.match_functions = function (input, options) {
var _this = this;
var _a;
if ((0, lodash_1.isNil)(this.regular_expression) || (0, lodash_1.isEmpty)(this.regular_expression))
throw new LexerError("match_functions", "Expected regular expression value!", "The Lexer expected a value for the regular expression (Lexer.regular_expression) but instead an empty string or a falsy value was provided");
var insensitive = (_a = options.insensitive) !== null && _a !== void 0 ? _a : this.default_options;
return Array.from(input.matchAll(new RegExp(this.regular_expression, insensitive ? "gi" : "g")), function (k) { return ({
prototype: k[2],
position: Number(k.index),
length: k[0].length,
match: k[0],
name: insensitive ? _this.find_function(k[1]) : k[1],
}); });
};
Lexer.prototype.inside = function (options, after, block) {
var fields = [
{ overloads: [], value: "" },
];
var escape = false;
var closed = false;
var inside = "";
var depth = 0;
for (var i = 1; i < after.length; i++) {
var char = after[i];
if (escape) {
inside += char;
escape = false;
}
else if (char === "\\") {
escape = true;
}
else if (char === options.argument) {
fields.push({ overloads: [], value: "" });
inside += char;
}
else if (char === options.closer && depth <= 0) {
closed = true;
break;
}
else if (char === options.opener) {
fields[fields.length - 1].value += char;
inside += char;
depth++;
}
else if (char === options.closer && depth > 0) {
fields[fields.length - 1].value += char;
inside += char;
depth--;
}
else {
fields[fields.length - 1].value += char;
inside += char;
}
}
for (var index = 0; index < fields.length; index++) {
var overloads = fields[index].value.match(Lexer.SAF_EXPRESSION);
if (overloads && overloads.length > 0) {
var _loop_1 = function (overload) {
var maybe = block.findIndex(function (saf) { return saf.identifier === overload; });
if (maybe !== -1) {
fields[index].overloads.push(block[maybe]);
block.splice(maybe, 1);
}
};
for (var _i = 0, overloads_1 = overloads; _i < overloads_1.length; _i++) {
var overload = overloads_1[_i];
_loop_1(overload);
}
}
}
if (!closed) {
throw new LexerError("Lexer.inside", "Missing closer!", "The Lexer expected the same or greater number of closers than openers");
}
return { fields: fields, inside: inside, block: block };
};
Lexer.prototype.lex = function (input, options, debug) {
if (options === void 0) { options = {}; }
if (debug === void 0) { debug = false; }
input = this.resolve(input, options);
if (debug)
console.log("\n", input);
options = (0, lodash_1.merge)(options, this.default_options);
var matches = this.match_functions(input, options);
var block = [];
for (var index = matches.length - 1; index > -1; index--) {
var saf = new LexerAkitaFunction(options, matches[index], Lexer.generateToken());
var after = input.slice(saf.position + saf.total.length);
if (after.charAt(0) === options.opener) {
var _a = this.inside(options, after, block), iblock = _a.block, fields = _a.fields;
block = iblock;
saf.fields = fields;
}
block.unshift(saf);
input = input
.slice(0, saf.position)
.concat(saf.identifier, input.slice(saf.position + saf.total.length));
if (debug)
console.log("\n", input);
}
if (debug) {
console.log((0, util_1.inspect)(block.map(function (saf) { return saf.toJSON(); }), { depth: null, colors: true }));
}
return { block: block, input: input };
};
Lexer.prototype.resolve = function (input, _a) {
var opener = _a.opener, closer = _a.closer, argument = _a.argument;
argument !== null && argument !== void 0 ? argument : (argument = this.default_options.argument);
opener !== null && opener !== void 0 ? opener : (opener = this.default_options.opener);
closer !== null && closer !== void 0 ? closer : (closer = this.default_options.closer);
for (var _i = 0, _b = Array.from(input.matchAll(Lexer.CONDITION_EXPRESSION), function (match) { return [match[0], match[1], match[4], match[5]]; }); _i < _b.length; _i++) {
var _c = _b[_i], match = _c[0], left = _c[1], symbol = _c[2], right = _c[3];
var type = get_type(symbol);
input = input.replace(match, type === "setter"
? "akita-core:set".concat(opener + left + argument + right + closer)
: "akita-core:condition".concat(opener + type + argument + left + argument + right + closer));
}
function get_type(symbol) {
switch (symbol) {
case "==":
return "equal";
case "!=":
return "not equal";
case ">":
return "greater";
case "<":
return "lesser";
case ">=":
return "greater or equal";
case "<=":
return "lesser or equal";
case "=":
return "setter";
default:
return "unknown";
}
}
return input;
};
Lexer.CONDITION_EXPRESSION = /([^()\s;]+(\([^)]*\))?)(\s*([=!<>]+)\s*)([^()\s;]+(\([^)]*\))?)/g;
Lexer.SAF_EXPRESSION = /^SAF\([a-z0-9]{15}\)$/g;
Lexer.SAR_EXPRESSION = /^SAR\([a-z0-9]{15}\)$/g;
return Lexer;
}());
exports.Lexer = Lexer;