Skip to content
This repository has been archived by the owner on Sep 4, 2024. It is now read-only.

Commit

Permalink
feat(format): ditch pureMask and use text-mask-core instead
Browse files Browse the repository at this point in the history
BREAKING CHANGE: re-written from the scratch by using `text-mask-core`.
May not work as expected but it bring future to the library.
  • Loading branch information
Max Lyashuk committed Jul 17, 2019
1 parent 3397c4b commit 9dad736
Showing 1 changed file with 51 additions and 62 deletions.
113 changes: 51 additions & 62 deletions src/format.js
Original file line number Diff line number Diff line change
@@ -1,75 +1,64 @@
/* eslint-disable no-param-reassign, no-unused-expressions */
import conformToMask from 'text-mask-core/src/conformToMask';

const NEXT_CHAR_OPTIONAL = {
__nextCharOptional__: true,
};

/**
* Simple format function borrowed from PureMask.js
* {@link https://github.com/romulobrasil/PureMask.js}
*
* @param {String} text String to mask (input value)
* @param {String} [wholeMask] Mask format, like `####-##`
* @returns {string} Formatted text
*/
export default function (text, wholeMask) {
if (!wholeMask) return text;
const replacementMap = {
'#': /\d/,
A: /[a-z]/i,
N: /[a-z0-9]/i,
'?': NEXT_CHAR_OPTIONAL,
X: /./,
};

const maskStartRegExp = /^([^#ANX]+)/;

if (+text.length === 1 && maskStartRegExp.test(wholeMask)) {
text = maskStartRegExp.exec(wholeMask)[0] + text;
}

let newText = '';
let charOffset = 0;

// Cleans data to avoid value loss on dynamic mask changing
for (let maskIndex = 0; maskIndex < wholeMask.length; maskIndex += 1) {
const mask = wholeMask.charAt(maskIndex);
switch (mask) {
case '#':
break;
case 'A':
break;
case '?':
break;
case 'N':
break;
case 'X':
break;
default:
text = text.replace(mask, '');
}
}
for (let maskIndex = 0, x = 1; x && maskIndex < wholeMask.length; maskIndex += 1) {
const char = text.charAt(maskIndex - charOffset);
const mask = wholeMask.charAt(maskIndex);
const stringToRegexp = (str) => {
const lastSlash = str.lastIndexOf('/');
return new RegExp(
str.slice(1, lastSlash),
str.slice(lastSlash + 1),
);
};
const makeRegexpOptional = charRegexp => (
stringToRegexp(
charRegexp.toString()
.replace(
/.(\/)[gmiyus]{0,6}$/,
match => match.replace('/', '?/'),
),
)
)

switch (mask) {
case '#':
/\d/.test(char) ? newText += char : x = 0;
break;
case 'A':
/[a-z]/i.test(char) ? newText += char : x = 0;
break;
case 'N':
/[a-z0-9]/i.test(char) ? newText += char : x = 0;
break;
// Skips testing if optional field is specified
case '?':
charOffset += 1;
break;
case 'X':
newText += char;
break;
default:
newText += mask;
const escapeIfNeeded = char => ('[\\^$.|?*+()'.split('').includes(char) ? `\\${char}` : char);
const charRegexp = char => new RegExp(`/[${escapeIfNeeded(char)}]/`);
const isRegexp = entity => entity instanceof RegExp;
const castToRegexp = char => (isRegexp(char) ? char : charRegexp(char));

// preserve characters that are in the same spot we need to insert a mask
// character by shifting the data over to the right (issue #5, & #7)
if (char && char !== mask) {
text = ` ${text}`;
}
const generatedMask = wholeMask
.split('')
.map((char, index, array) => {
const maskChar = replacementMap[char] || char;
const previousChar = array[index - 1];
const previousMaskChar = replacementMap[previousChar] || previousChar;
if (maskChar === NEXT_CHAR_OPTIONAL) {
return null;
}
if (previousMaskChar === NEXT_CHAR_OPTIONAL) {
const casted = castToRegexp(maskChar);
const optionalRegexp = makeRegexpOptional(casted);
return optionalRegexp;
}
return maskChar;
})
.filter(Boolean);

break;
}
}
return newText;
const { conformedValue } = conformToMask(text, generatedMask, { guide: false });
return conformedValue;
}

0 comments on commit 9dad736

Please sign in to comment.