import $ from "./dependencyLibs/inputmask.dependencyLib"; import MaskToken from "./masktoken"; import Inputmask from "./inputmask"; export {generateMaskSet, analyseMask}; function generateMaskSet(opts, nocache) { var ms; function generateMask(mask, metadata, opts) { var regexMask = false; if (mask === null || mask === "") { regexMask = opts.regex !== null; if (regexMask) { mask = opts.regex; mask = mask.replace(/^(\^)(.*)(\$)$/, "$2"); } else { regexMask = true; mask = ".*"; } } if (mask.length === 1 && opts.greedy === false && opts.repeat !== 0) { opts.placeholder = ""; } //hide placeholder with single non-greedy mask if (opts.repeat > 0 || opts.repeat === "*" || opts.repeat === "+") { var repeatStart = opts.repeat === "*" ? 0 : (opts.repeat === "+" ? 1 : opts.repeat); mask = opts.groupmarker[0] + mask + opts.groupmarker[1] + opts.quantifiermarker[0] + repeatStart + "," + opts.repeat + opts.quantifiermarker[1]; } // console.log(mask); var masksetDefinition, maskdefKey; maskdefKey = regexMask ? "regex_" + opts.regex : opts.numericInput ? mask.split("").reverse().join("") : mask; if (opts.keepStatic !== null) { //keepstatic modifies the output from the testdefinitions ~ so differentiate in the maskcache maskdefKey = "ks_" + opts.keepStatic + maskdefKey; } if (Inputmask.prototype.masksCache[maskdefKey] === undefined || nocache === true) { masksetDefinition = { "mask": mask, "maskToken": Inputmask.prototype.analyseMask(mask, regexMask, opts), "validPositions": {}, "_buffer": undefined, "buffer": undefined, "tests": {}, "excludes": {}, //excluded alternations "metadata": metadata, "maskLength": undefined, "jitOffset": {} }; if (nocache !== true) { Inputmask.prototype.masksCache[maskdefKey] = masksetDefinition; masksetDefinition = $.extend(true, {}, Inputmask.prototype.masksCache[maskdefKey]); } } else { masksetDefinition = $.extend(true, {}, Inputmask.prototype.masksCache[maskdefKey]); } return masksetDefinition; } if (typeof opts.mask === "function") { //allow mask to be a preprocessing fn - should return a valid mask opts.mask = opts.mask(opts); } if (Array.isArray(opts.mask)) { if (opts.mask.length > 1) { if (opts.keepStatic === null) { //enable by default when passing multiple masks when the option is not explicitly specified opts.keepStatic = true; } var altMask = opts.groupmarker[0]; (opts.isRTL ? opts.mask.reverse() : opts.mask).forEach(function (msk) { if (altMask.length > 1) { altMask += opts.alternatormarker; } if (msk.mask !== undefined && typeof msk.mask !== "function") { altMask += msk.mask; } else { altMask += msk; } }); altMask += opts.groupmarker[1]; // console.log(altMask); return generateMask(altMask, opts.mask, opts); } else { opts.mask = opts.mask.pop(); } } if (opts.mask && opts.mask.mask !== undefined && typeof opts.mask.mask !== "function") { ms = generateMask(opts.mask.mask, opts.mask, opts); } else { ms = generateMask(opts.mask, opts.mask, opts); } if (opts.keepStatic === null) opts.keepStatic = false; return ms; } function analyseMask(mask, regexMask, opts) { const tokenizer = /(?:[?*+]|\{[0-9+*]+(?:,[0-9+*]*)?(?:\|[0-9+*]*)?\})|[^.?*+^${[]()|\\]+|./g, //Thx to https://github.com/slevithan/regex-colorizer for the regexTokenizer regex regexTokenizer = /\[\^?]?(?:[^\\\]]+|\\[\S\s]?)*]?|\\(?:0(?:[0-3][0-7]{0,2}|[4-7][0-7]?)?|[1-9][0-9]*|x[0-9A-Fa-f]{2}|u[0-9A-Fa-f]{4}|c[A-Za-z]|[\S\s]?)|\((?:\?[:=!]?)?|(?:[?*+]|\{[0-9]+(?:,[0-9]*)?\})\??|[^.?*+^${[()|\\]+|./g; var escaped = false, currentToken = new MaskToken(), match, m, openenings = [], maskTokens = [], openingToken, currentOpeningToken, alternator, lastMatch, closeRegexGroup = false; //test definition => {fn: RegExp/function, static: true/false optionality: bool, newBlockMarker: bool, casing: null/upper/lower, def: definitionSymbol, placeholder: placeholder, mask: real maskDefinition} function insertTestDefinition(mtoken, element, position) { position = position !== undefined ? position : mtoken.matches.length; var prevMatch = mtoken.matches[position - 1]; if (regexMask) { if (element.indexOf("[") === 0 || (escaped && /\\d|\\s|\\w/i.test(element)) || element === ".") { mtoken.matches.splice(position++, 0, { fn: new RegExp(element, opts.casing ? "i" : ""), static: false, optionality: false, newBlockMarker: prevMatch === undefined ? "master" : prevMatch.def !== element, casing: null, def: element, placeholder: undefined, nativeDef: element }); } else { if (escaped) element = element[element.length - 1]; element.split("").forEach(function (lmnt, ndx) { prevMatch = mtoken.matches[position - 1]; mtoken.matches.splice(position++, 0, { fn: /[a-z]/i.test((opts.staticDefinitionSymbol || lmnt)) ? new RegExp("[" + (opts.staticDefinitionSymbol || lmnt) + "]", opts.casing ? "i" : "") : null, static: true, optionality: false, newBlockMarker: prevMatch === undefined ? "master" : (prevMatch.def !== lmnt && prevMatch.static !== true), casing: null, def: opts.staticDefinitionSymbol || lmnt, placeholder: opts.staticDefinitionSymbol !== undefined ? lmnt : undefined, nativeDef: (escaped ? "'" : "") + lmnt }); }); } escaped = false; } else { var maskdef = (opts.definitions && opts.definitions[element]) || (opts.usePrototypeDefinitions && Inputmask.prototype.definitions[element]); if (maskdef && !escaped) { mtoken.matches.splice(position++, 0, { fn: maskdef.validator ? typeof maskdef.validator == "string" ? new RegExp(maskdef.validator, opts.casing ? "i" : "") : new function () { this.test = maskdef.validator; } : new RegExp("."), static: maskdef.static || false, optionality: maskdef.optional || false, newBlockMarker: (prevMatch === undefined || maskdef.optional) ? "master" : prevMatch.def !== (maskdef.definitionSymbol || element), casing: maskdef.casing, def: maskdef.definitionSymbol || element, placeholder: maskdef.placeholder, nativeDef: element, generated: maskdef.generated }); } else { mtoken.matches.splice(position++, 0, { fn: /[a-z]/i.test((opts.staticDefinitionSymbol || element)) ? new RegExp("[" + (opts.staticDefinitionSymbol || element) + "]", opts.casing ? "i" : "") : null, static: true, optionality: false, newBlockMarker: prevMatch === undefined ? "master" : (prevMatch.def !== element && prevMatch.static !== true), casing: null, def: opts.staticDefinitionSymbol || element, placeholder: opts.staticDefinitionSymbol !== undefined ? element : undefined, nativeDef: (escaped ? "'" : "") + element }); escaped = false; } } } function verifyGroupMarker(maskToken) { if (maskToken && maskToken.matches) { maskToken.matches.forEach(function (token, ndx) { var nextToken = maskToken.matches[ndx + 1]; if ((nextToken === undefined || (nextToken.matches === undefined || nextToken.isQuantifier === false)) && token && token.isGroup) { //this is not a group but a normal mask => convert token.isGroup = false; if (!regexMask) { insertTestDefinition(token, opts.groupmarker[0], 0); if (token.openGroup !== true) { insertTestDefinition(token, opts.groupmarker[1]); } } } verifyGroupMarker(token); }); } } function defaultCase() { if (openenings.length > 0) { currentOpeningToken = openenings[openenings.length - 1]; insertTestDefinition(currentOpeningToken, m); if (currentOpeningToken.isAlternator) { //handle alternator a | b case alternator = openenings.pop(); for (var mndx = 0; mndx < alternator.matches.length; mndx++) { if (alternator.matches[mndx].isGroup) alternator.matches[mndx].isGroup = false; //don't mark alternate groups as group } if (openenings.length > 0) { currentOpeningToken = openenings[openenings.length - 1]; currentOpeningToken.matches.push(alternator); } else { currentToken.matches.push(alternator); } } } else { insertTestDefinition(currentToken, m); } } function reverseTokens(maskToken) { function reverseStatic(st) { if (st === opts.optionalmarker[0]) { st = opts.optionalmarker[1]; } else if (st === opts.optionalmarker[1]) { st = opts.optionalmarker[0]; } else if (st === opts.groupmarker[0]) { st = opts.groupmarker[1]; } else if (st === opts.groupmarker[1]) st = opts.groupmarker[0]; return st; } maskToken.matches = maskToken.matches.reverse(); for (var match in maskToken.matches) { if (Object.prototype.hasOwnProperty.call(maskToken.matches, match)) { var intMatch = parseInt(match); if (maskToken.matches[match].isQuantifier && maskToken.matches[intMatch + 1] && maskToken.matches[intMatch + 1].isGroup) { //reposition quantifier var qt = maskToken.matches[match]; maskToken.matches.splice(match, 1); maskToken.matches.splice(intMatch + 1, 0, qt); } if (maskToken.matches[match].matches !== undefined) { maskToken.matches[match] = reverseTokens(maskToken.matches[match]); } else { maskToken.matches[match] = reverseStatic(maskToken.matches[match]); } } } return maskToken; } function groupify(matches) { var groupToken = new MaskToken(true); groupToken.openGroup = false; groupToken.matches = matches; return groupToken; } function closeGroup() { // Group closing openingToken = openenings.pop(); openingToken.openGroup = false; //mark group as complete if (openingToken !== undefined) { if (openenings.length > 0) { currentOpeningToken = openenings[openenings.length - 1]; currentOpeningToken.matches.push(openingToken); if (currentOpeningToken.isAlternator) { //handle alternator (a) | (b) case alternator = openenings.pop(); let altMatchesLength = alternator.matches[0].matches ? alternator.matches[0].matches.length : 1; for (var mndx = 0; mndx < alternator.matches.length; mndx++) { alternator.matches[mndx].isGroup = false; //don't mark alternate groups as group alternator.matches[mndx].alternatorGroup = false; if (opts.keepStatic === null && altMatchesLength < (alternator.matches[mndx].matches ? alternator.matches[mndx].matches.length : 1)) { //enable by default when passing multiple masks when the option is not explicitly specified opts.keepStatic = true; } altMatchesLength = alternator.matches[mndx].matches ? alternator.matches[mndx].matches.length : 1; } if (openenings.length > 0) { currentOpeningToken = openenings[openenings.length - 1]; currentOpeningToken.matches.push(alternator); } else { currentToken.matches.push(alternator); } } } else { currentToken.matches.push(openingToken); } } else { defaultCase(); } } function groupQuantifier(matches) { var lastMatch = matches.pop(); if (lastMatch.isQuantifier) { lastMatch = groupify([matches.pop(), lastMatch]); } return lastMatch; } if (regexMask) { opts.optionalmarker[0] = undefined; opts.optionalmarker[1] = undefined; } while ((match = regexMask ? regexTokenizer.exec(mask) : tokenizer.exec(mask))) { m = match[0]; if (regexMask) { switch (m.charAt(0)) { //Quantifier case "?": m = "{0,1}"; break; case "+": case "*": m = "{" + m + "}"; break; case "|": //regex mask alternator ex: [01][0-9]|2[0-3] => ([01][0-9]|2[0-3]) if (openenings.length === 0) { //wrap the mask in a group to form a regex alternator ([01][0-9]|2[0-3]) var altRegexGroup = groupify(currentToken.matches); altRegexGroup.openGroup = true; openenings.push(altRegexGroup); currentToken.matches = []; closeRegexGroup = true; } break; } switch (m) { case "\\d": m = "[0-9]"; break; 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 "(? 0 ? openenings[openenings.length - 1].matches : currentToken.matches; match = matches.pop(); if (match.isAlternator) { //handle quantifier in an alternation [0-9]{2}|[0-9]{3} matches.push(match); //push back alternator matches = match.matches; //remap target matches var groupToken = new MaskToken(true); var tmpMatch = matches.pop(); matches.push(groupToken); //push the group matches = groupToken.matches; match = tmpMatch; } if (!match.isGroup) { // if (regexMask && match.fn === null) { //why is this needed??? // if (match.def === ".") match.fn = new RegExp(match.def, opts.casing ? "i" : ""); // } match = groupify([match]); } matches.push(match); matches.push(quantifier); break; case opts.alternatormarker: if (openenings.length > 0) { currentOpeningToken = openenings[openenings.length - 1]; var subToken = currentOpeningToken.matches[currentOpeningToken.matches.length - 1]; if (currentOpeningToken.openGroup && //regexp alt syntax (subToken.matches === undefined || (subToken.isGroup === false && subToken.isAlternator === false))) { //alternations within group lastMatch = openenings.pop(); } else { lastMatch = groupQuantifier(currentOpeningToken.matches); } } else { lastMatch = groupQuantifier(currentToken.matches); } if (lastMatch.isAlternator) { openenings.push(lastMatch); } else { if (lastMatch.alternatorGroup) { alternator = openenings.pop(); lastMatch.alternatorGroup = false; } else { alternator = new MaskToken(false, false, false, true); } alternator.matches.push(lastMatch); openenings.push(alternator); if (lastMatch.openGroup) { //regexp alt syntax lastMatch.openGroup = false; var alternatorGroup = new MaskToken(true); alternatorGroup.alternatorGroup = true; openenings.push(alternatorGroup); } } break; default: defaultCase(); } } if (closeRegexGroup) closeGroup(); while (openenings.length > 0) { openingToken = openenings.pop(); currentToken.matches.push(openingToken); } if (currentToken.matches.length > 0) { verifyGroupMarker(currentToken); maskTokens.push(currentToken); } if (opts.numericInput || opts.isRTL) { reverseTokens(maskTokens[0]); } // console.log(JSON.stringify(maskTokens)); return maskTokens; }