Browse Source

fix test resolving when using quantifiers within an optional group

Robin Herbots 3 years ago
parent
commit
3063fd3e71
10 changed files with 300 additions and 277 deletions
  1. 1 0
      CHANGELOG.md
  2. 1 1
      bower.json
  3. 1 1
      composer.json
  4. 56 51
      dist/inputmask.js
  5. 2 2
      dist/inputmask.min.js
  6. 56 51
      dist/jquery.inputmask.js
  7. 2 2
      dist/jquery.inputmask.min.js
  8. 2 7
      lib/mask-lexer.js
  9. 178 161
      lib/validation-tests.js
  10. 1 1
      package.json

+ 1 - 0
CHANGELOG.md

@@ -7,6 +7,7 @@
 - Comma input turns to decimal #2577 => add substituteRadixPoint option to numeric alias
 
 ### Updates
+- fix test resolving when using quantifiers within an optional group
 - drop IE Mobile support
 - datetime alias
   - change default for insertModeVisual to false. - #2664

+ 1 - 1
bower.json

@@ -1,6 +1,6 @@
 {
   "name": "inputmask",
-  "version": "5.0.8-beta.66",
+  "version": "5.0.8-beta.69",
   "main": [
 	  "./index.js",
     "./css/inputmask.css"

+ 1 - 1
composer.json

@@ -1,7 +1,7 @@
 {
   "name": "robinherbots/inputmask",
   "description": "Inputmask is a javascript library which creates an input mask.  Inputmask can run against vanilla javascript, jQuery and jqlite.",
-  "version": "5.0.8-beta.66",
+  "version": "5.0.8-beta.69",
   "type": "library",
   "keywords": ["jquery", "plugins", "input", "form", "inputmask", "mask"],
   "homepage": "http://robinherbots.github.io/Inputmask",

+ 56 - 51
dist/inputmask.js

@@ -3,7 +3,7 @@
  * https://github.com/RobinHerbots/Inputmask
  * Copyright (c) 2010 - 2022 Robin Herbots
  * Licensed under the MIT license
- * Version: 5.0.8-beta.66
+ * Version: 5.0.8-beta.69
  */
 !function(e, t) {
     if ("object" == typeof exports && "object" == typeof module) module.exports = t(); else if ("function" == typeof define && define.amd) define([], t); else {
@@ -2722,78 +2722,83 @@
                                 }), !r.optionality || void 0 !== c || !(u.definitions && u.definitions[r.nativeDef] && u.definitions[r.nativeDef].optional || n.default.prototype.definitions[r.nativeDef] && n.default.prototype.definitions[r.nativeDef].optional)) return !0;
                                 g = !0, h = e;
                             } else if (void 0 !== r.matches) {
-                                if (r.isGroup && c !== r) {
+                                if (r.isGroup && c !== r) return function() {
                                     if (r = s(t.matches[t.matches.indexOf(r) + 1], o, c)) return !0;
-                                } else if (r.isOptional) {
-                                    var w = r, S = m.length;
-                                    if (r = y(r, i, o, c)) {
+                                }();
+                                if (r.isOptional) return function() {
+                                    var t = r, n = m.length;
+                                    if (r = y(r, i, o, c), m.length > 0) {
                                         if (m.forEach((function(e, t) {
-                                            t >= S && (e.match.optionality = e.match.optionality ? e.match.optionality + 1 : 1);
-                                        })), a = m[m.length - 1].match, void 0 !== c || !p(a, w)) return !0;
+                                            t >= n && (e.match.optionality = e.match.optionality ? e.match.optionality + 1 : 1);
+                                        })), a = m[m.length - 1].match, void 0 !== c || !p(a, t)) return r;
                                         g = !0, h = e;
                                     }
-                                } else if (r.isAlternator) {
-                                    var _, M = r, O = [], E = m.slice(), T = o.length, j = !1, D = i.length > 0 ? i.shift() : -1;
-                                    if (-1 === D || "string" == typeof D) {
-                                        var A, B = h, C = i.slice(), R = [];
-                                        if ("string" == typeof D) R = D.split(","); else for (A = 0; A < M.matches.length; A++) R.push(A.toString());
+                                }();
+                                if (r.isAlternator) return function() {
+                                    var a, n, p, k = r, y = [], b = m.slice(), w = o.length, S = !1, _ = i.length > 0 ? i.shift() : -1;
+                                    if (-1 === _ || "string" == typeof _) {
+                                        var M, O = h, E = i.slice(), T = [];
+                                        if ("string" == typeof _) T = _.split(","); else for (M = 0; M < k.matches.length; M++) T.push(M.toString());
                                         if (void 0 !== l.excludes[e]) {
-                                            for (var L = R.slice(), F = 0, I = l.excludes[e].length; F < I; F++) {
-                                                var N = l.excludes[e][F].toString().split(":");
-                                                o.length == N[1] && R.splice(R.indexOf(N[0]), 1);
+                                            for (var j = T.slice(), D = 0, A = l.excludes[e].length; D < A; D++) {
+                                                var B = l.excludes[e][D].toString().split(":");
+                                                o.length == B[1] && T.splice(T.indexOf(B[0]), 1);
                                             }
-                                            0 === R.length && (delete l.excludes[e], R = L);
+                                            0 === T.length && (delete l.excludes[e], T = j);
                                         }
-                                        (!0 === u.keepStatic || isFinite(parseInt(u.keepStatic)) && B >= u.keepStatic) && (R = R.slice(0, 1));
-                                        for (var V = 0; V < R.length; V++) {
-                                            A = parseInt(R[V]), m = [], i = "string" == typeof D && v(h, A, T) || C.slice();
-                                            var G = M.matches[A];
-                                            if (G && s(G, [ A ].concat(o), c)) r = !0; else if (0 === V && (j = !0), G && G.matches && G.matches.length > M.matches[0].matches.length) break;
-                                            _ = m.slice(), h = B, m = [];
-                                            for (var H = 0; H < _.length; H++) {
-                                                var U = _[H], K = !1;
-                                                U.match.jit = U.match.jit || j, U.alternation = U.alternation || T, x(U);
-                                                for (var $ = 0; $ < O.length; $++) {
-                                                    var q = O[$];
-                                                    if ("string" != typeof D || void 0 !== U.alternation && R.includes(U.locator[U.alternation].toString())) {
-                                                        if (U.match.nativeDef === q.match.nativeDef) {
-                                                            K = !0, x(q, U);
+                                        (!0 === u.keepStatic || isFinite(parseInt(u.keepStatic)) && O >= u.keepStatic) && (T = T.slice(0, 1));
+                                        for (var C = 0; C < T.length; C++) {
+                                            M = parseInt(T[C]), m = [], i = "string" == typeof _ && v(h, M, w) || E.slice();
+                                            var R = k.matches[M];
+                                            if (R && s(R, [ M ].concat(o), c)) r = !0; else if (0 === C && (S = !0), R && R.matches && R.matches.length > k.matches[0].matches.length) break;
+                                            a = m.slice(), h = O, m = [];
+                                            for (var L = 0; L < a.length; L++) {
+                                                var F = a[L], I = !1;
+                                                F.match.jit = F.match.jit || S, F.alternation = F.alternation || w, x(F);
+                                                for (var N = 0; N < y.length; N++) {
+                                                    var V = y[N];
+                                                    if ("string" != typeof _ || void 0 !== F.alternation && T.includes(F.locator[F.alternation].toString())) {
+                                                        if (F.match.nativeDef === V.match.nativeDef) {
+                                                            I = !0, x(V, F);
                                                             break;
                                                         }
-                                                        if (f(U, q, u)) {
-                                                            x(U, q) && (K = !0, O.splice(O.indexOf(q), 0, U));
+                                                        if (f(F, V, u)) {
+                                                            x(F, V) && (I = !0, y.splice(y.indexOf(V), 0, F));
                                                             break;
                                                         }
-                                                        if (f(q, U, u)) {
-                                                            x(q, U);
+                                                        if (f(V, F, u)) {
+                                                            x(V, F);
                                                             break;
                                                         }
-                                                        if (J = q, !0 === (W = U).match.static && !0 !== J.match.static && J.match.fn.test(W.match.def, l, e, !1, u, !1)) {
-                                                            P(U, q) || void 0 !== d.inputmask.userOptions.keepStatic ? x(U, q) && (K = !0, O.splice(O.indexOf(q), 0, U)) : u.keepStatic = !0;
+                                                        if (p = V, !0 === (n = F).match.static && !0 !== p.match.static && p.match.fn.test(n.match.def, l, e, !1, u, !1)) {
+                                                            P(F, V) || void 0 !== d.inputmask.userOptions.keepStatic ? x(F, V) && (I = !0, y.splice(y.indexOf(V), 0, F)) : u.keepStatic = !0;
                                                             break;
                                                         }
                                                     }
                                                 }
-                                                K || O.push(U);
+                                                I || y.push(F);
                                             }
                                         }
-                                        m = E.concat(O), h = e, g = m.length > 0, r = O.length > 0, i = C.slice();
-                                    } else r = s(M.matches[D] || t.matches[D], [ D ].concat(o), c);
+                                        m = b.concat(y), h = e, g = m.length > 0, r = y.length > 0, i = E.slice();
+                                    } else r = s(k.matches[_] || t.matches[_], [ _ ].concat(o), c);
                                     if (r) return !0;
-                                } else if (r.isQuantifier && c !== t.matches[t.matches.indexOf(r) - 1]) for (var z = r, Q = !1, Z = i.length > 0 ? i.shift() : 0; Z < (isNaN(z.quantifier.max) ? Z + 1 : z.quantifier.max) && h <= e; Z++) {
-                                    var Y = t.matches[t.matches.indexOf(z) - 1];
-                                    if (r = s(Y, [ Z ].concat(o), Y)) {
-                                        if (m.forEach((function(t, i) {
-                                            (a = b(Y, t.match) ? t.match : m[m.length - 1].match).optionalQuantifier = Z >= z.quantifier.min, 
-                                            a.jit = (Z + 1) * (Y.matches.indexOf(a) + 1) > z.quantifier.jit, a.optionalQuantifier && p(a, Y) && (g = !0, 
-                                            h = e, u.greedy && null == l.validPositions[e - 1] && Z > z.quantifier.min && -1 != [ "*", "+" ].indexOf(z.quantifier.max) && (m.pop(), 
-                                            k = void 0), Q = !0), !Q && a.jit && (l.jitOffset[e] = Y.matches.length - Y.matches.indexOf(a));
-                                        })), Q) break;
-                                        return !0;
+                                }();
+                                if (r.isQuantifier && c !== t.matches[t.matches.indexOf(r) - 1]) return function() {
+                                    for (var n = r, c = !1, f = i.length > 0 ? i.shift() : 0; f < (isNaN(n.quantifier.max) ? f + 1 : n.quantifier.max) && h <= e; f++) {
+                                        var d = t.matches[t.matches.indexOf(n) - 1];
+                                        if (r = s(d, [ f ].concat(o), d)) {
+                                            if (m.forEach((function(t, i) {
+                                                (a = b(d, t.match) ? t.match : m[m.length - 1].match).optionalQuantifier = f >= n.quantifier.min, 
+                                                a.jit = (f + 1) * (d.matches.indexOf(a) + 1) > n.quantifier.jit, a.optionalQuantifier && p(a, d) && (g = !0, 
+                                                h = e, u.greedy && null == l.validPositions[e - 1] && f > n.quantifier.min && -1 != [ "*", "+" ].indexOf(n.quantifier.max) && (m.pop(), 
+                                                k = void 0), c = !0, r = !1), !c && a.jit && (l.jitOffset[e] = d.matches.length - d.matches.indexOf(a));
+                                            })), c) break;
+                                            return !0;
+                                        }
                                     }
-                                } else if (r = y(r, i, o, c)) return !0;
+                                }();
+                                if (r = y(r, i, o, c)) return !0;
                             } else h++;
-                            var W, J;
                         }
                         for (var c = i.length > 0 ? i.shift() : 0; c < t.matches.length; c++) if (!0 !== t.matches[c].isQuantifier) {
                             var p = s(t.matches[c], [ c ].concat(r), o);

File diff suppressed because it is too large
+ 2 - 2
dist/inputmask.min.js


+ 56 - 51
dist/jquery.inputmask.js

@@ -3,7 +3,7 @@
  * https://github.com/RobinHerbots/Inputmask
  * Copyright (c) 2010 - 2022 Robin Herbots
  * Licensed under the MIT license
- * Version: 5.0.8-beta.66
+ * Version: 5.0.8-beta.69
  */
 !function(e, t) {
     if ("object" == typeof exports && "object" == typeof module) module.exports = t(require("jquery")); else if ("function" == typeof define && define.amd) define([ "jquery" ], t); else {
@@ -2670,78 +2670,83 @@
                                 }), !r.optionality || void 0 !== c || !(u.definitions && u.definitions[r.nativeDef] && u.definitions[r.nativeDef].optional || n.default.prototype.definitions[r.nativeDef] && n.default.prototype.definitions[r.nativeDef].optional)) return !0;
                                 g = !0, h = e;
                             } else if (void 0 !== r.matches) {
-                                if (r.isGroup && c !== r) {
+                                if (r.isGroup && c !== r) return function() {
                                     if (r = s(t.matches[t.matches.indexOf(r) + 1], o, c)) return !0;
-                                } else if (r.isOptional) {
-                                    var w = r, S = v.length;
-                                    if (r = y(r, i, o, c)) {
+                                }();
+                                if (r.isOptional) return function() {
+                                    var t = r, n = v.length;
+                                    if (r = y(r, i, o, c), v.length > 0) {
                                         if (v.forEach((function(e, t) {
-                                            t >= S && (e.match.optionality = e.match.optionality ? e.match.optionality + 1 : 1);
-                                        })), a = v[v.length - 1].match, void 0 !== c || !d(a, w)) return !0;
+                                            t >= n && (e.match.optionality = e.match.optionality ? e.match.optionality + 1 : 1);
+                                        })), a = v[v.length - 1].match, void 0 !== c || !d(a, t)) return r;
                                         g = !0, h = e;
                                     }
-                                } else if (r.isAlternator) {
-                                    var M, _ = r, O = [], T = v.slice(), E = o.length, j = !1, D = i.length > 0 ? i.shift() : -1;
-                                    if (-1 === D || "string" == typeof D) {
-                                        var A, B = h, C = i.slice(), R = [];
-                                        if ("string" == typeof D) R = D.split(","); else for (A = 0; A < _.matches.length; A++) R.push(A.toString());
+                                }();
+                                if (r.isAlternator) return function() {
+                                    var a, n, d, k = r, y = [], b = v.slice(), w = o.length, S = !1, M = i.length > 0 ? i.shift() : -1;
+                                    if (-1 === M || "string" == typeof M) {
+                                        var _, O = h, T = i.slice(), E = [];
+                                        if ("string" == typeof M) E = M.split(","); else for (_ = 0; _ < k.matches.length; _++) E.push(_.toString());
                                         if (void 0 !== l.excludes[e]) {
-                                            for (var F = R.slice(), L = 0, I = l.excludes[e].length; L < I; L++) {
-                                                var V = l.excludes[e][L].toString().split(":");
-                                                o.length == V[1] && R.splice(R.indexOf(V[0]), 1);
+                                            for (var j = E.slice(), D = 0, A = l.excludes[e].length; D < A; D++) {
+                                                var B = l.excludes[e][D].toString().split(":");
+                                                o.length == B[1] && E.splice(E.indexOf(B[0]), 1);
                                             }
-                                            0 === R.length && (delete l.excludes[e], R = F);
+                                            0 === E.length && (delete l.excludes[e], E = j);
                                         }
-                                        (!0 === u.keepStatic || isFinite(parseInt(u.keepStatic)) && B >= u.keepStatic) && (R = R.slice(0, 1));
-                                        for (var N = 0; N < R.length; N++) {
-                                            A = parseInt(R[N]), v = [], i = "string" == typeof D && m(h, A, E) || C.slice();
-                                            var G = _.matches[A];
-                                            if (G && s(G, [ A ].concat(o), c)) r = !0; else if (0 === N && (j = !0), G && G.matches && G.matches.length > _.matches[0].matches.length) break;
-                                            M = v.slice(), h = B, v = [];
-                                            for (var H = 0; H < M.length; H++) {
-                                                var U = M[H], K = !1;
-                                                U.match.jit = U.match.jit || j, U.alternation = U.alternation || E, x(U);
-                                                for (var $ = 0; $ < O.length; $++) {
-                                                    var q = O[$];
-                                                    if ("string" != typeof D || void 0 !== U.alternation && R.includes(U.locator[U.alternation].toString())) {
-                                                        if (U.match.nativeDef === q.match.nativeDef) {
-                                                            K = !0, x(q, U);
+                                        (!0 === u.keepStatic || isFinite(parseInt(u.keepStatic)) && O >= u.keepStatic) && (E = E.slice(0, 1));
+                                        for (var C = 0; C < E.length; C++) {
+                                            _ = parseInt(E[C]), v = [], i = "string" == typeof M && m(h, _, w) || T.slice();
+                                            var R = k.matches[_];
+                                            if (R && s(R, [ _ ].concat(o), c)) r = !0; else if (0 === C && (S = !0), R && R.matches && R.matches.length > k.matches[0].matches.length) break;
+                                            a = v.slice(), h = O, v = [];
+                                            for (var F = 0; F < a.length; F++) {
+                                                var L = a[F], I = !1;
+                                                L.match.jit = L.match.jit || S, L.alternation = L.alternation || w, x(L);
+                                                for (var V = 0; V < y.length; V++) {
+                                                    var N = y[V];
+                                                    if ("string" != typeof M || void 0 !== L.alternation && E.includes(L.locator[L.alternation].toString())) {
+                                                        if (L.match.nativeDef === N.match.nativeDef) {
+                                                            I = !0, x(N, L);
                                                             break;
                                                         }
-                                                        if (f(U, q, u)) {
-                                                            x(U, q) && (K = !0, O.splice(O.indexOf(q), 0, U));
+                                                        if (f(L, N, u)) {
+                                                            x(L, N) && (I = !0, y.splice(y.indexOf(N), 0, L));
                                                             break;
                                                         }
-                                                        if (f(q, U, u)) {
-                                                            x(q, U);
+                                                        if (f(N, L, u)) {
+                                                            x(N, L);
                                                             break;
                                                         }
-                                                        if (J = q, !0 === (W = U).match.static && !0 !== J.match.static && J.match.fn.test(W.match.def, l, e, !1, u, !1)) {
-                                                            P(U, q) || void 0 !== p.inputmask.userOptions.keepStatic ? x(U, q) && (K = !0, O.splice(O.indexOf(q), 0, U)) : u.keepStatic = !0;
+                                                        if (d = N, !0 === (n = L).match.static && !0 !== d.match.static && d.match.fn.test(n.match.def, l, e, !1, u, !1)) {
+                                                            P(L, N) || void 0 !== p.inputmask.userOptions.keepStatic ? x(L, N) && (I = !0, y.splice(y.indexOf(N), 0, L)) : u.keepStatic = !0;
                                                             break;
                                                         }
                                                     }
                                                 }
-                                                K || O.push(U);
+                                                I || y.push(L);
                                             }
                                         }
-                                        v = T.concat(O), h = e, g = v.length > 0, r = O.length > 0, i = C.slice();
-                                    } else r = s(_.matches[D] || t.matches[D], [ D ].concat(o), c);
+                                        v = b.concat(y), h = e, g = v.length > 0, r = y.length > 0, i = T.slice();
+                                    } else r = s(k.matches[M] || t.matches[M], [ M ].concat(o), c);
                                     if (r) return !0;
-                                } else if (r.isQuantifier && c !== t.matches[t.matches.indexOf(r) - 1]) for (var z = r, Q = !1, Z = i.length > 0 ? i.shift() : 0; Z < (isNaN(z.quantifier.max) ? Z + 1 : z.quantifier.max) && h <= e; Z++) {
-                                    var Y = t.matches[t.matches.indexOf(z) - 1];
-                                    if (r = s(Y, [ Z ].concat(o), Y)) {
-                                        if (v.forEach((function(t, i) {
-                                            (a = b(Y, t.match) ? t.match : v[v.length - 1].match).optionalQuantifier = Z >= z.quantifier.min, 
-                                            a.jit = (Z + 1) * (Y.matches.indexOf(a) + 1) > z.quantifier.jit, a.optionalQuantifier && d(a, Y) && (g = !0, 
-                                            h = e, u.greedy && null == l.validPositions[e - 1] && Z > z.quantifier.min && -1 != [ "*", "+" ].indexOf(z.quantifier.max) && (v.pop(), 
-                                            k = void 0), Q = !0), !Q && a.jit && (l.jitOffset[e] = Y.matches.length - Y.matches.indexOf(a));
-                                        })), Q) break;
-                                        return !0;
+                                }();
+                                if (r.isQuantifier && c !== t.matches[t.matches.indexOf(r) - 1]) return function() {
+                                    for (var n = r, c = !1, f = i.length > 0 ? i.shift() : 0; f < (isNaN(n.quantifier.max) ? f + 1 : n.quantifier.max) && h <= e; f++) {
+                                        var p = t.matches[t.matches.indexOf(n) - 1];
+                                        if (r = s(p, [ f ].concat(o), p)) {
+                                            if (v.forEach((function(t, i) {
+                                                (a = b(p, t.match) ? t.match : v[v.length - 1].match).optionalQuantifier = f >= n.quantifier.min, 
+                                                a.jit = (f + 1) * (p.matches.indexOf(a) + 1) > n.quantifier.jit, a.optionalQuantifier && d(a, p) && (g = !0, 
+                                                h = e, u.greedy && null == l.validPositions[e - 1] && f > n.quantifier.min && -1 != [ "*", "+" ].indexOf(n.quantifier.max) && (v.pop(), 
+                                                k = void 0), c = !0, r = !1), !c && a.jit && (l.jitOffset[e] = p.matches.length - p.matches.indexOf(a));
+                                            })), c) break;
+                                            return !0;
+                                        }
                                     }
-                                } else if (r = y(r, i, o, c)) return !0;
+                                }();
+                                if (r = y(r, i, o, c)) return !0;
                             } else h++;
-                            var W, J;
                         }
                         for (var c = i.length > 0 ? i.shift() : 0; c < t.matches.length; c++) if (!0 !== t.matches[c].isQuantifier) {
                             var d = s(t.matches[c], [ c ].concat(r), o);

File diff suppressed because it is too large
+ 2 - 2
dist/jquery.inputmask.min.js


+ 2 - 7
lib/mask-lexer.js

@@ -354,17 +354,12 @@ function analyseMask(mask, regexMask, opts) {
                     m += regexTokenizer.exec(mask)[0]; // {
                     m += regexTokenizer.exec(mask)[0]; // ?}
                     break;
+                case "(?:": //non capturing group
                 case "(?=": //lookahead
-                    // openenings.push(new MaskToken(true));
-                    break;
                 case "(?!": //negative lookahead
-                    // openenings.push(new MaskToken(true));
-                    break;
                 case "(?<=": //lookbehind
-                    // openenings.push(new MaskToken(true));
-                    break;
                 case "(?<!": //negative lookbehind
-                    // openenings.push(new MaskToken(true));
+                    // treat as group
                     break;
             }
         }

+ 178 - 161
lib/validation-tests.js

@@ -319,6 +319,180 @@ function getTests(pos, ndxIntlzr, tstPs) {
                 return true;
             }
 
+            function handleGroup() {
+                match = handleMatch(maskToken.matches[maskToken.matches.indexOf(match) + 1], loopNdx, quantifierRecurse);
+                if (match) return true;
+            }
+
+            function handleOptional() {
+                var optionalToken = match, mtchsNdx = matches.length;
+                match = resolveTestFromToken(match, ndxInitializer, loopNdx, quantifierRecurse);
+                if (matches.length > 0) { //check on matches.length instead of match to handle quantifier in a recursive call
+                    //mark optionality in matches
+                    matches.forEach(function (mtch, ndx) {
+                        if (ndx >= mtchsNdx) {
+                            mtch.match.optionality = mtch.match.optionality ? mtch.match.optionality + 1 : 1;
+                        }
+                    });
+                    latestMatch = matches[matches.length - 1].match;
+
+                    if (quantifierRecurse === undefined && isFirstMatch(latestMatch, optionalToken)) { //prevent loop see #698
+                        insertStop = true; //insert a stop
+                        testPos = pos; //match the position after the group
+                    } else {
+                        return match; //make the loop continue when it is deliberately by a quantifier
+                    }
+                }
+            }
+
+            function handleAlternator() {
+                var alternateToken = match,
+                    malternateMatches = [],
+                    maltMatches,
+                    currentMatches = matches.slice(),
+                    loopNdxCnt = loopNdx.length,
+                    unMatchedAlternation = false;
+                var altIndex = ndxInitializer.length > 0 ? ndxInitializer.shift() : -1;
+                if (altIndex === -1 || typeof altIndex === "string") {
+                    var currentPos = testPos,
+                        ndxInitializerClone = ndxInitializer.slice(),
+                        altIndexArr = [],
+                        amndx;
+                    if (typeof altIndex == "string") {
+                        altIndexArr = altIndex.split(",");
+                    } else {
+                        for (amndx = 0; amndx < alternateToken.matches.length; amndx++) {
+                            altIndexArr.push(amndx.toString());
+                        }
+                    }
+
+                    if (maskset.excludes[pos] !== undefined) {
+                        var altIndexArrClone = altIndexArr.slice();
+                        for (var i = 0, exl = maskset.excludes[pos].length; i < exl; i++) {
+                            var excludeSet = maskset.excludes[pos][i].toString().split(":");
+                            if (loopNdx.length == excludeSet[1]) {
+                                altIndexArr.splice(altIndexArr.indexOf(excludeSet[0]), 1);
+                            }
+                        }
+                        if (altIndexArr.length === 0) { //fully alternated => reset
+                            delete maskset.excludes[pos];
+                            altIndexArr = altIndexArrClone;
+                        }
+                    }
+                    if (opts.keepStatic === true || (isFinite(parseInt(opts.keepStatic)) && currentPos >= opts.keepStatic)) altIndexArr = altIndexArr.slice(0, 1);
+                    for (var ndx = 0; ndx < altIndexArr.length; ndx++) {
+                        amndx = parseInt(altIndexArr[ndx]);
+                        matches = [];
+                        //set the correct ndxInitializer
+                        ndxInitializer = typeof altIndex === "string" ? resolveNdxInitializer(testPos, amndx, loopNdxCnt) || ndxInitializerClone.slice() : ndxInitializerClone.slice();
+                        var tokenMatch = alternateToken.matches[amndx];
+                        if (tokenMatch && handleMatch(tokenMatch, [amndx].concat(loopNdx), quantifierRecurse)) {
+                            match = true;
+                        } else {
+                            if (ndx === 0) {
+                                unMatchedAlternation = true;
+                            }
+                            if (tokenMatch && tokenMatch.matches && tokenMatch.matches.length > alternateToken.matches[0].matches.length) {
+                                break;
+                            }
+                        }
+
+                        maltMatches = matches.slice();
+                        testPos = currentPos;
+                        matches = [];
+
+                        //fuzzy merge matches
+                        for (var ndx1 = 0; ndx1 < maltMatches.length; ndx1++) {
+                            var altMatch = maltMatches[ndx1],
+                                dropMatch = false;
+                            altMatch.match.jit = altMatch.match.jit || unMatchedAlternation; //mark jit when there are unmatched alternations  ex: mask: "(a|aa)"
+                            altMatch.alternation = altMatch.alternation || loopNdxCnt;
+                            setMergeLocators(altMatch);
+                            for (var ndx2 = 0; ndx2 < malternateMatches.length; ndx2++) {
+                                var altMatch2 = malternateMatches[ndx2];
+                                if (typeof altIndex !== "string" || (altMatch.alternation !== undefined && altIndexArr.includes(altMatch.locator[altMatch.alternation].toString()))) {
+                                    if (altMatch.match.nativeDef === altMatch2.match.nativeDef) {
+                                        dropMatch = true;
+                                        setMergeLocators(altMatch2, altMatch);
+                                        break;
+                                    } else if (isSubsetOf(altMatch, altMatch2, opts)) {
+                                        if (setMergeLocators(altMatch, altMatch2)) {
+                                            dropMatch = true;
+                                            malternateMatches.splice(malternateMatches.indexOf(altMatch2), 0, altMatch);
+                                        }
+                                        break;
+                                    } else if (isSubsetOf(altMatch2, altMatch, opts)) {
+                                        setMergeLocators(altMatch2, altMatch);
+                                        break;
+                                    } else if (staticCanMatchDefinition(altMatch, altMatch2)) {
+                                        if (!isSameLevel(altMatch, altMatch2) && el.inputmask.userOptions.keepStatic === undefined) {
+                                            opts.keepStatic = true;
+                                        } else if (setMergeLocators(altMatch, altMatch2)) {
+                                            //insert match above general match
+                                            dropMatch = true;
+                                            malternateMatches.splice(malternateMatches.indexOf(altMatch2), 0, altMatch);
+                                        }
+                                        break;
+                                    }
+                                }
+                            }
+                            if (!dropMatch) {
+                                malternateMatches.push(altMatch);
+                            }
+                        }
+                    }
+
+                    matches = currentMatches.concat(malternateMatches);
+                    testPos = pos;
+                    insertStop = matches.length > 0; //insert a stopelemnt when there is an alternate - needed for non-greedy option
+                    match = malternateMatches.length > 0; //set correct match state
+
+                    //cloneback
+                    ndxInitializer = ndxInitializerClone.slice();
+                } else {
+                    match = handleMatch(alternateToken.matches[altIndex] || maskToken.matches[altIndex], [altIndex].concat(loopNdx), quantifierRecurse);
+                }
+                if (match) return true;
+            }
+
+            function handleQuantifier() {
+                var qt = match, breakloop = false;
+                for (var qndx = (ndxInitializer.length > 0) ? ndxInitializer.shift() : 0; (qndx < (isNaN(qt.quantifier.max) ? qndx + 1 : qt.quantifier.max)) && testPos <= pos; qndx++) {
+                    var tokenGroup = maskToken.matches[maskToken.matches.indexOf(qt) - 1];
+                    match = handleMatch(tokenGroup, [qndx].concat(loopNdx), tokenGroup); //set the tokenGroup as quantifierRecurse marker
+                    if (match) {
+                        matches.forEach(function (mtch, ndx) {
+                            if (IsMatchOf(tokenGroup, mtch.match))
+                                latestMatch = mtch.match;
+                            else latestMatch = matches[matches.length - 1].match;
+
+                            //mark optionality
+                            //TODO FIX RECURSIVE QUANTIFIERS
+                            latestMatch.optionalQuantifier = qndx >= qt.quantifier.min;
+                            // console.log(pos + " " + qt.quantifier.min + " " + latestMatch.optionalQuantifier);
+                            //qndx + 1 as the index starts from 0
+                            latestMatch.jit = (qndx + 1) * (tokenGroup.matches.indexOf(latestMatch) + 1) > qt.quantifier.jit;
+                            if (latestMatch.optionalQuantifier && isFirstMatch(latestMatch, tokenGroup)) {
+                                insertStop = true;
+                                testPos = pos; //match the position after the group
+                                if (opts.greedy && maskset.validPositions[pos - 1] == undefined && qndx > qt.quantifier.min && ["*", "+"].indexOf(qt.quantifier.max) != -1) {
+                                    matches.pop();
+                                    cacheDependency = undefined;
+                                }
+                                breakloop = true; //stop quantifierloop && search for next possible match
+                                match = false; //mark match to false to make sure the loop in optionals continues
+                            }
+                            if (!breakloop && latestMatch.jit /*&& !latestMatch.optionalQuantifier*/) {
+                                //always set jitOffset, isvalid checks when to apply
+                                maskset.jitOffset[pos] = tokenGroup.matches.length - tokenGroup.matches.indexOf(latestMatch);
+                            }
+                        });
+                        if (breakloop) break; // search for next possible match
+                        return true;
+                    }
+                }
+            }
+
             if (testPos > (pos + opts._maxTestPos)) {
                 throw "Inputmask: There is probably an error in your mask definition or in the code. Create an issue on github with an example of the mask you are using. " + maskset.mask;
             }
@@ -339,170 +513,13 @@ function getTests(pos, ndxIntlzr, tstPs) {
                 }
             } else if (match.matches !== undefined) {
                 if (match.isGroup && quantifierRecurse !== match) { //when a group pass along to the quantifier
-                    match = handleMatch(maskToken.matches[maskToken.matches.indexOf(match) + 1], loopNdx, quantifierRecurse);
-                    if (match) return true;
+                    return handleGroup();
                 } else if (match.isOptional) {
-                    var optionalToken = match, mtchsNdx = matches.length;
-                    match = resolveTestFromToken(match, ndxInitializer, loopNdx, quantifierRecurse);
-                    if (match) {
-                        //mark optionality in matches
-                        matches.forEach(function (mtch, ndx) {
-                            if (ndx >= mtchsNdx) {
-                                mtch.match.optionality = mtch.match.optionality ? mtch.match.optionality + 1 : 1;
-                            }
-                        });
-                        latestMatch = matches[matches.length - 1].match;
-
-                        if (quantifierRecurse === undefined && isFirstMatch(latestMatch, optionalToken)) { //prevent loop see #698
-                            insertStop = true; //insert a stop
-                            testPos = pos; //match the position after the group
-                        } else {
-                            return true;
-                        }
-                    }
+                    return handleOptional();
                 } else if (match.isAlternator) {
-                    var alternateToken = match,
-                        malternateMatches = [],
-                        maltMatches,
-                        currentMatches = matches.slice(),
-                        loopNdxCnt = loopNdx.length,
-                        unMatchedAlternation = false;
-                    var altIndex = ndxInitializer.length > 0 ? ndxInitializer.shift() : -1;
-                    if (altIndex === -1 || typeof altIndex === "string") {
-                        var currentPos = testPos,
-                            ndxInitializerClone = ndxInitializer.slice(),
-                            altIndexArr = [],
-                            amndx;
-                        if (typeof altIndex == "string") {
-                            altIndexArr = altIndex.split(",");
-                        } else {
-                            for (amndx = 0; amndx < alternateToken.matches.length; amndx++) {
-                                altIndexArr.push(amndx.toString());
-                            }
-                        }
-
-                        if (maskset.excludes[pos] !== undefined) {
-                            var altIndexArrClone = altIndexArr.slice();
-                            for (var i = 0, exl = maskset.excludes[pos].length; i < exl; i++) {
-                                var excludeSet = maskset.excludes[pos][i].toString().split(":");
-                                if (loopNdx.length == excludeSet[1]) {
-                                    altIndexArr.splice(altIndexArr.indexOf(excludeSet[0]), 1);
-                                }
-                            }
-                            if (altIndexArr.length === 0) { //fully alternated => reset
-                                delete maskset.excludes[pos];
-                                altIndexArr = altIndexArrClone;
-                            }
-                        }
-                        if (opts.keepStatic === true || (isFinite(parseInt(opts.keepStatic)) && currentPos >= opts.keepStatic)) altIndexArr = altIndexArr.slice(0, 1);
-                        for (var ndx = 0; ndx < altIndexArr.length; ndx++) {
-                            amndx = parseInt(altIndexArr[ndx]);
-                            matches = [];
-                            //set the correct ndxInitializer
-                            ndxInitializer = typeof altIndex === "string" ? resolveNdxInitializer(testPos, amndx, loopNdxCnt) || ndxInitializerClone.slice() : ndxInitializerClone.slice();
-                            var tokenMatch = alternateToken.matches[amndx];
-                            if (tokenMatch && handleMatch(tokenMatch, [amndx].concat(loopNdx), quantifierRecurse)) {
-                                match = true;
-                            } else {
-                                if (ndx === 0) {
-                                    unMatchedAlternation = true;
-                                }
-                                if (tokenMatch && tokenMatch.matches && tokenMatch.matches.length > alternateToken.matches[0].matches.length) {
-                                    break;
-                                }
-                            }
-
-                            maltMatches = matches.slice();
-                            testPos = currentPos;
-                            matches = [];
-
-                            //fuzzy merge matches
-                            for (var ndx1 = 0; ndx1 < maltMatches.length; ndx1++) {
-                                var altMatch = maltMatches[ndx1],
-                                    dropMatch = false;
-                                altMatch.match.jit = altMatch.match.jit || unMatchedAlternation; //mark jit when there are unmatched alternations  ex: mask: "(a|aa)"
-                                altMatch.alternation = altMatch.alternation || loopNdxCnt;
-                                setMergeLocators(altMatch);
-                                for (var ndx2 = 0; ndx2 < malternateMatches.length; ndx2++) {
-                                    var altMatch2 = malternateMatches[ndx2];
-                                    if (typeof altIndex !== "string" || (altMatch.alternation !== undefined && altIndexArr.includes(altMatch.locator[altMatch.alternation].toString()))) {
-                                        if (altMatch.match.nativeDef === altMatch2.match.nativeDef) {
-                                            dropMatch = true;
-                                            setMergeLocators(altMatch2, altMatch);
-                                            break;
-                                        } else if (isSubsetOf(altMatch, altMatch2, opts)) {
-                                            if (setMergeLocators(altMatch, altMatch2)) {
-                                                dropMatch = true;
-                                                malternateMatches.splice(malternateMatches.indexOf(altMatch2), 0, altMatch);
-                                            }
-                                            break;
-                                        } else if (isSubsetOf(altMatch2, altMatch, opts)) {
-                                            setMergeLocators(altMatch2, altMatch);
-                                            break;
-                                        } else if (staticCanMatchDefinition(altMatch, altMatch2)) {
-                                            if (!isSameLevel(altMatch, altMatch2) && el.inputmask.userOptions.keepStatic === undefined) {
-                                                opts.keepStatic = true;
-                                            } else if (setMergeLocators(altMatch, altMatch2)) {
-                                                //insert match above general match
-                                                dropMatch = true;
-                                                malternateMatches.splice(malternateMatches.indexOf(altMatch2), 0, altMatch);
-                                            }
-                                            break;
-                                        }
-                                    }
-                                }
-                                if (!dropMatch) {
-                                    malternateMatches.push(altMatch);
-                                }
-                            }
-                        }
-
-                        matches = currentMatches.concat(malternateMatches);
-                        testPos = pos;
-                        insertStop = matches.length > 0; //insert a stopelemnt when there is an alternate - needed for non-greedy option
-                        match = malternateMatches.length > 0; //set correct match state
-
-                        //cloneback
-                        ndxInitializer = ndxInitializerClone.slice();
-                    } else {
-                        match = handleMatch(alternateToken.matches[altIndex] || maskToken.matches[altIndex], [altIndex].concat(loopNdx), quantifierRecurse);
-                    }
-                    if (match) return true;
+                    return handleAlternator();
                 } else if (match.isQuantifier && quantifierRecurse !== maskToken.matches[maskToken.matches.indexOf(match) - 1]) {
-                    var qt = match, breakloop = false;
-                    for (var qndx = (ndxInitializer.length > 0) ? ndxInitializer.shift() : 0; (qndx < (isNaN(qt.quantifier.max) ? qndx + 1 : qt.quantifier.max)) && testPos <= pos; qndx++) {
-                        var tokenGroup = maskToken.matches[maskToken.matches.indexOf(qt) - 1];
-                        match = handleMatch(tokenGroup, [qndx].concat(loopNdx), tokenGroup); //set the tokenGroup as quantifierRecurse marker
-                        if (match) {
-                            matches.forEach(function (mtch, ndx) {
-                                if (IsMatchOf(tokenGroup, mtch.match))
-                                    latestMatch = mtch.match;
-                                else latestMatch = matches[matches.length - 1].match;
-
-                                //mark optionality
-                                //TODO FIX RECURSIVE QUANTIFIERS
-                                latestMatch.optionalQuantifier = qndx >= qt.quantifier.min;
-                                // console.log(pos + " " + qt.quantifier.min + " " + latestMatch.optionalQuantifier);
-                                //qndx + 1 as the index starts from 0
-                                latestMatch.jit = (qndx + 1) * (tokenGroup.matches.indexOf(latestMatch) + 1) > qt.quantifier.jit;
-                                if (latestMatch.optionalQuantifier && isFirstMatch(latestMatch, tokenGroup)) {
-                                    insertStop = true;
-                                    testPos = pos; //match the position after the group
-                                    if (opts.greedy && maskset.validPositions[pos - 1] == undefined && qndx > qt.quantifier.min && ["*", "+"].indexOf(qt.quantifier.max) != -1) {
-                                        matches.pop();
-                                        cacheDependency = undefined;
-                                    }
-                                    breakloop = true; //stop quantifierloop && search for next possible match
-                                }
-                                if (!breakloop && latestMatch.jit /*&& !latestMatch.optionalQuantifier*/) {
-                                    //always set jitOffset, isvalid checks when to apply
-                                    maskset.jitOffset[pos] = tokenGroup.matches.length - tokenGroup.matches.indexOf(latestMatch);
-                                }
-                            });
-                            if (breakloop) break;
-                            return true;
-                        }
-                    }
+                    return handleQuantifier();
                 } else {
                     match = resolveTestFromToken(match, ndxInitializer, loopNdx, quantifierRecurse);
                     if (match) return true;

+ 1 - 1
package.json

@@ -1,6 +1,6 @@
 {
   "name": "inputmask",
-  "version": "5.0.8-beta.66",
+  "version": "5.0.8-beta.69",
   "description": "Inputmask is a javascript library which creates an input mask.  Inputmask can run against vanilla javascript, jQuery and jqlite.",
   "main": "dist/inputmask.js",
   "files": [