UNPKG

incr-regex-package

Version:

An incremental regular expression parser in JavaScript; useful for input validation, RegExp

452 lines (406 loc) 13.6 kB
"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; }();