incr-regex-package
Version:
An incremental regular expression parser in JavaScript; useful for input validation, RegExp
452 lines (406 loc) • 13.6 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.BaseIncRegEx = exports.getArrayMask = undefined;
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
exports.convertMask = convertMask;
exports.isMeta = isMeta;
exports.isHolder = isHolder;
exports.isOptional = isOptional;
var _utils = require("../utils");
var _rxtree = require("../rxtree");
var _makeRxInfo = require("./makeRxInfo");
var _makeRxInfo2 = _interopRequireDefault(_makeRxInfo);
var _regexpParser = require("../regexp-parser");
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
function convertMask(s) {
return s.split('').map(function (c) {
return c === "*" ? _rxtree.HOLDER_ZERO_OR_MORE : c === "?" ? _rxtree.HOLDER_ZERO_OR_ONE : /*568*/
c === "_" ? _rxtree.HOLDER_ANY : c;
}).join('');
}
function isMeta(ch) {
return ch === _rxtree.HOLDER_ANY || isOptional(ch);
}
function isHolder(ch) {
return ch === _rxtree.HOLDER_ANY;
}
function isOptional(ch) {
return ch === _rxtree.HOLDER_ZERO_OR_ONE || ch === _rxtree.HOLDER_ZERO_OR_MORE;
}
function cleanMask(str) {
var last = void 0; // undefined
var list = [];
for (var i = 0; i < str.length; i++) {
var c = str.charAt(i);
if (isOptional(c) && last === c) continue;
last = c;
list.push(c);
}
return list.join('');
}
function strip(s, notAllowed) {
for (var i = 0; i < s.length; i++) {
if (!notAllowed(s.charAt(i))) return s.substring(i + 1, s.length);
}return s;
}
function rationalize(s1, s2) {
//let l = s1.length < s2.length? s1.length : s2.length;
var post = strip((0, _utils.rprefix)(s1, s2), isOptional);
var res = '';
//let hasNull = false;
var GET = 1;
var SKIP = 2;
var stream = function stream(str) {
var ix = 0;
return function (flag) {
switch (flag) {
case GET:
return ix < str.length ? str.charAt(ix) : undefined;
case SKIP:
ix++;break;
default:
return ix < str.length;
}
};
};
var eq = function eq(a, b) {
return a == b || isOptional(a) && isOptional(b);
};
var max = function max(a, b) {
return a === _rxtree.HOLDER_ZERO_OR_MORE ? a : b;
};
var ss1 = stream(s1);
var ss2 = stream(s2);
for (; ss1() && ss2();) {
var c1 = ss1(GET);
var c2 = ss2(GET);
var canbeNull = isOptional(c1) || isOptional(c2);
//if( c1 === c2 && !canbeNull) res += c1;
if (eq(c1, c2)) {
res += max(c1, c2);ss1(SKIP);ss2(SKIP);
} else if (!canbeNull) {
res += _rxtree.HOLDER_ANY;ss1(SKIP);ss2(SKIP);
} else if (isOptional(c1)) {
res += c1;ss1(SKIP);
} else {
res += c2;ss2(SKIP);
}
}
return (0, _utils.sRightMerge)(res, post);
}
function __isDoneN(res) {
return res !== undefined && res.filter(function (el) {
return el === _rxtree.DONE;
}).length === res.length;
}
//unit = [a]
//merge(a,b) = flatten([a,b]);
function makeArrayRxInfo(func, merge, base) {
return getArrayRxInfo;
function getArrayRxInfo(arr, prefix) {
return arr.reduce(function (a, b) {
return merge(a, func(b, prefix));
}, base());
}
}
function mapper(rxn, deflt) {
if (!rxn) return deflt;
switch (rxn.val) {
case "[0-9]":
case "\\d":
return "9\u0332";
case "[A-Za-z]":
case "[a-zA-Z]":
case "[a-z]":
return "a\u0332";
case "[A-Z]":
return "A\u0332";
case "[0-9A-Za-z]":
case "[A-Z0-9a-z]":
case "[A-Za-z0-9]":
case "[0-9a-zA-Z]":
case "[a-z0-9A-Z]":
case "[a-zA-Z0-9]":
return "z\u0332";
default:
return deflt;
}
}
var arrayMaskListBuilder = function arrayMaskListBuilder(mapper, useopt) {
var unit = function unit(a) {
return a === undefined ? [] : [a];
};
var addElem = function addElem(a, b) {
return a + b;
};
var merge = function merge(a, b) {
return (0, _utils.flatten)([a, b]);
};
var aMerge = function aMerge(a, b) {
return (0, _utils.flatten)((0, _utils.arr_push)(a, b));
};
var optfn = function optfn(rxn, prefix, getRxInfo, optStop) {
// interesting function, to deal with loops/optional
if (rxn.left) {
var ll = getRxInfo(rxn.nextNode, prefix, optStop);
var rr = getRxInfo(rxn.left, prefix, (0, _rxtree.zero_or_more)(rxn) ? (0, _utils.n_cons)(rxn, optStop) : // this is the optional part that could loop, push rxn (rx node) on the stack
// if we cone back to this node and find rxn of the stack, do not loop again
optStop); // Non-looping optional
return merge(ll, rr);
}
};
var optional = useopt ? optfn : undefined;
return makeArrayRxInfo((0, _makeRxInfo2.default)(unit, addElem, merge, optional, mapper), aMerge, unit);
};
var getArrayMask = exports.getArrayMask = function () {
var unit = function unit(a) {
return a;
};
var addElem = function addElem(a, b) {
return a + b;
};
var merge = function merge(a, b) {
return rationalize(a, b);
};
var aMerge = function aMerge(a, b) {
return rationalize(a || b, b);
};
var fn = makeArrayRxInfo((0, _makeRxInfo2.default)(unit, addElem, merge), aMerge, unit);
return function (rx) {
return cleanMask(fn(rx, ''));
};
}();
function combine(a, b) {
return a === -1 || b === -1 ? -1 : a + b;
}
function fixedSizePattern(rxNode) {
if (!rxNode) return 0;
if (rxNode === _rxtree.DONE) return 0;
if ((0, _rxtree.dot)(rxNode)) {
// this is a node that concat of two regexp /AB/ => dot(A,B) - where A and B are regexp themselves
return combine(fixedSizePattern(rxNode.left), fixedSizePattern(rxNode.right));
} else if ((0, _rxtree.or)(rxNode)) {
// /A|B/ => or(A,B)
var c = fixedSizePattern(rxNode.left);
return c >= 0 && c === fixedSizePattern(rxNode.right) ? c : -1;
} else if ((0, _rxtree.zero_or_one)(rxNode) || (0, _rxtree.zero_or_more)(rxNode)) return -1;else if ((0, _rxtree.matchable)(rxNode)) {
var res = (0, _rxtree.matchable)(rxNode)(undefined);
return res[1];
} else if ((0, _rxtree.boundary)(rxNode)) {
return fixedSizePattern(rxNode.left);
}
return 0;
}
var getArrayMaskListFull = arrayMaskListBuilder(mapper, true);
var getArrayMaskList = arrayMaskListBuilder(mapper, false);
var BaseIncRegEx = exports.BaseIncRegEx = function () {
function BaseIncRegEx(str, v) {
_classCallCheck(this, BaseIncRegEx);
var len = 30;
if (!str && !v) {
this.str = "";
this.base = undefined;
this.tracker = undefined;
this.current = undefined;
this.one = this.current;
this.two = undefined;
this.lastCh = undefined;
this.maxLen = 0;
this._mask = undefined;
// this._lastEditableIndex = undefined;
len = fixedSizePattern(this.base);
if (len <= 0) len = 30;
this._len = len;
} else {
if (!v && str) v = _regexpParser.RxParser.parse(str);
//if( v ) v = makeFSM(v);
this.str = str;
this.base = v;
this.tracker = [];
this.current = new _utils.StackDedup(v);
this.one = this.current;
this.two = new _utils.StackDedup();
this.lastCh = undefined;
this.maxLen = 0;
this.mask = undefined; // cached value (set this to undefined everytime we change the tracker)
// this._lastEditableIndex = undefined; // cached value
this._len = 30;
}
}
/**
* [reset description]
* @return {[type]} [description]
*/
_createClass(BaseIncRegEx, [{
key: "reset",
value: function reset() {
/* public */
this.tracker = [];
this.current.reset();
this.current.push(this.base);
this.lastCh = undefined;
this._state = undefined;
this._mask = undefined;
return this;
}
/**
* [clone description]
* @return {[type]} [description]
*/
}, {
key: "clone",
value: function clone() {
/* public */
var t = new this.constructor();
t.str = this.str;
t.base = this.base;
t.tracker = this.tracker.slice(0); // copy
t.one = this.one.map(_utils.ID);
t.two = this.two.map(_utils.ID);
t.current = this.current == this.one ? t.one : t.two;
t.lastCh = this.lastCh;
t._state = this._state;
t._mask = undefined;
t._len = this.length;
return t;
}
}, {
key: "test",
value: function test(ch, curr) {
var _this = this;
curr = curr || this.current;
var res = _rxtree.FAILED;
var next = this._getArr();
curr.forEach(function (e) {
res = _this._result(_this.action(e, ch, next), res);
});
if (res === _rxtree.FAILED || next.length === 0) {
return undefined;
}
//console.log("TEST: ",next);
return next;
}
/**
* [getInputTracker description]
* @return {[type]} [description]
*/
}, {
key: "getInputTracker",
value: function getInputTracker() {
return this.tracker.map(_utils.ID);
}
/**
* [minCharsList description]
* @param {[type]} flag [description]
* @return {[type]} [description]
*/
}, {
key: "minCharsList",
value: function minCharsList(flag) {
var fn = flag ? getArrayMaskListFull : getArrayMaskList;
return (0, _utils.arr_uniq)(fn(this.current, this.inputStr()));
}
// Private methods
}, {
key: "_after",
value: function _after(all, ix) {
/* public */ // get the input matched so far after ix.
if (!ix) {
var al = all ? this.tracker : this.tracker.filter(function (e) {
return e[1] === undefined;
});
return al.map(function (e) {
return e[0];
}).join('');
} else {
var _al = this.tracker.filter(function (e, i) {
return i >= ix && (all || e[1] === undefined);
});
return _al.map(function (e) {
return e[0];
}).join('');
}
}
}, {
key: "_getArr",
value: function _getArr() {
if (this.current === this.one) return this.two.reset();
return this.one.reset();
}
}, {
key: "action",
value: function action(e, ch, newStack, ignoreBoundary) {
if (e === _rxtree.DONE) {
if (ch === _rxtree.DONE) {
newStack.push(_rxtree.DONE);
//if(this.nurul) console.log("*** DONE: ",ch);
return _rxtree.DONE;
}
return _rxtree.FAILED;
} else if ((0, _rxtree.dot)(e)) {
return this.action(e.left, ch, newStack, ignoreBoundary);
} else if ((0, _rxtree.or)(e)) {
var rl = this.action(e.left, ch, newStack, ignoreBoundary);
var rr = this.action(e.right, ch, newStack, ignoreBoundary);
return this._result(rl, rr);
} else if ((0, _rxtree.zero_or_one)(e) || (0, _rxtree.zero_or_more)(e)) {
var _rl = (0, _rxtree.boundary)(e.left) ? _rxtree.DONE : this.action(e.left, ch, newStack, true);
var _rr = this.action(e.nextNode, ch, newStack, ignoreBoundary);
return this._result(_rl, _rr);
} else if ((0, _rxtree.matchable)(e)) {
var res = e.match(ch);
//if(this.nurul) console.log("match: ",ch);
if (res[0]) {
newStack.push(e.nextNode);
}
return res[0] ? e.nextNode === _rxtree.DONE ? _rxtree.DONE : _rxtree.MORE : _rxtree.FAILED;
} else if ((0, _rxtree.boundary)(e)) {
if (ignoreBoundary) return _rxtree.FAILED;
//if( ch === DONE && this.nurul) console.log("boundary",ch)
if (ch === _rxtree.DONE) return this.action(e.nextNode, ch, newStack); // ignore the boundary
var _res = e.match(this.lastCh, ch);
if (_res[0] || ch === undefined) {
return this.action(e.nextNode, ch, newStack);
}
return _rxtree.FAILED;
}
return _rxtree.FAILED;
}
}, {
key: "_result",
value: function _result(l, r) {
if (l === r) return l;
if (l === _rxtree.MORE || r === _rxtree.MORE) return _rxtree.MORE;
}
}, {
key: "_update",
value: function _update(res, ch, fixed) {
if (res !== undefined) {
this.tracker.push([ch === undefined ? _rxtree.HOLDER_ANY : ch, fixed]);
if (res.maxLen > this.maxLen) this.maxLen = res.maxLen;
this.current = res;
this.lastCh = ch;
this._state = undefined;
this._mask = undefined;
// this._lastEditableIndex = undefined;
}
return res !== undefined;
}
}, {
key: "_stateCompute",
value: function _stateCompute() {
//console.log("Compute State");
var res = this.test(undefined);
//if( this.nurul && res !== undefined) console.log("state:",res);
if (res === undefined) return _rxtree.DONE;
var isdone = this.test(_rxtree.DONE);
//if(isdone === undefined) return DONE;
if (__isDoneN(isdone)) return _rxtree.MAYBE;
return _rxtree.MORE;
}
}]);
return BaseIncRegEx;
}();